On Tue, Jan 24, 2017 at 10:07:23AM +0100, Otto Moerbeek wrote:

> Hi,
> 
> malloc(3) has the nice feature to move (subject to alignment
> constraints) allocations that are between the max chunk size (half a
> page) and a page size towards the end of the allocated page, to catch
> more buffer overflows. Due to the allocation being higher up within a
> page, buffer overflows will end up beyond the page in more cases.
> 
> Until now, realloc(3) did not handle this in a smart way. When it
> encountered an existing moved allocation it always did a
> malloc-copy-free dance.
> 
> This diff fixes that, at the same time doing more cases without
> requesting new pages from the kernel. 
> 
> Please review and test,
> 
> BTW, we cannot use this feature for allocations larger than or equal
> to a page, since these should return page-aligned pointers.
> 
>       -Otto
> 

Anybody testing this? I like to make progress on this...

        -Otto

> Index: malloc.c
> ===================================================================
> RCS file: /cvs/src/lib/libc/stdlib/malloc.c,v
> retrieving revision 1.212
> diff -u -p -r1.212 malloc.c
> --- malloc.c  21 Jan 2017 07:47:42 -0000      1.212
> +++ malloc.c  24 Jan 2017 06:08:13 -0000
> @@ -1328,13 +1328,9 @@ ofree(struct dir_info *argpool, void *p)
>                                   sz - mopts.malloc_guard,
>                                   PAGEROUND(sz - mopts.malloc_guard));
>               } else {
> -#if notyetbecause_of_realloc
>                       /* shifted towards the end */
> -                     if (p != ((char *)r->p) + ((MALLOC_PAGESIZE -
> -                         MALLOC_MINSIZE - sz - mopts.malloc_guard) &
> -                         ~(MALLOC_MINSIZE-1))) {
> -                     }
> -#endif
> +                     if (p != MALLOC_MOVE(r->p, sz))
> +                             wrterror(pool, "bogus moved pointer %p", p);
>                       p = r->p;
>               }
>               if (mopts.malloc_guard) {
> @@ -1474,7 +1470,7 @@ orealloc(struct dir_info *argpool, void 
>       if (gnewsz > MALLOC_MAXCHUNK)
>               gnewsz += mopts.malloc_guard;
>  
> -     if (newsz > MALLOC_MAXCHUNK && oldsz > MALLOC_MAXCHUNK && p == r->p &&
> +     if (newsz > MALLOC_MAXCHUNK && oldsz > MALLOC_MAXCHUNK &&
>           !mopts.malloc_realloc) {
>               /* First case: from n pages sized allocation to m pages sized
>                  allocation, no malloc_move in effect */
> @@ -1484,7 +1480,7 @@ orealloc(struct dir_info *argpool, void 
>               if (rnewsz > roldsz) {
>                       /* try to extend existing region */
>                       if (!mopts.malloc_guard) {
> -                             void *hint = (char *)p + roldsz;
> +                             void *hint = (char *)r->p + roldsz;
>                               size_t needed = rnewsz - roldsz;
>  
>                               STATS_INC(pool->cheap_realloc_tries);
> @@ -1502,9 +1498,15 @@ gotit:
>                                       STATS_ADD(pool->malloc_used, needed);
>                                       if (mopts.malloc_junk == 2)
>                                               memset(q, SOME_JUNK, needed);
> -                                     r->size = newsz;
> +                                     r->size = gnewsz;
> +                                     if (r->p != p) {
> +                                             /* old pointer is moved */
> +                                             memmove(r->p, p, oldsz);
> +                                             p = r->p;
> +                                     }
>                                       if (mopts.chunk_canaries)
> -                                             fill_canary(p, newsz, 
> PAGEROUND(newsz));
> +                                             fill_canary(p, newsz,
> +                                                 PAGEROUND(newsz));
>                                       STATS_SETF(r, f);
>                                       STATS_INC(pool->cheap_reallocs);
>                                       ret = p;
> @@ -1517,30 +1519,45 @@ gotit:
>               } else if (rnewsz < roldsz) {
>                       /* shrink number of pages */
>                       if (mopts.malloc_guard) {
> -                             if (mprotect((char *)p + roldsz -
> +                             if (mprotect((char *)r->p + roldsz -
>                                   mopts.malloc_guard, mopts.malloc_guard,
>                                   PROT_READ | PROT_WRITE))
>                                       wrterror(pool, "mprotect");
> -                             if (mprotect((char *)p + rnewsz -
> +                             if (mprotect((char *)r->p + rnewsz -
>                                   mopts.malloc_guard, mopts.malloc_guard,
>                                   PROT_NONE))
>                                       wrterror(pool, "mprotect");
>                       }
> -                     unmap(pool, (char *)p + rnewsz, roldsz - rnewsz);
> +                     unmap(pool, (char *)r->p + rnewsz, roldsz - rnewsz);
>                       r->size = gnewsz;
> -                     if (mopts.chunk_canaries)
> +                     if (MALLOC_MOVE_COND(gnewsz)) {
> +                             void *pp = MALLOC_MOVE(r->p, gnewsz);
> +                             memmove(pp, p, newsz);
> +                             p = pp;
> +                     } else if (mopts.chunk_canaries)
>                               fill_canary(p, newsz, PAGEROUND(newsz));
>                       STATS_SETF(r, f);
>                       ret = p;
>                       goto done;
>               } else {
>                       /* number of pages remains the same */
> -                     if (newsz > oldsz && mopts.malloc_junk == 2)
> -                             memset((char *)p + newsz, SOME_JUNK,
> -                                 rnewsz - mopts.malloc_guard - newsz);
> +                     void *pp = r->p;
> +
>                       r->size = gnewsz;
> -                     if (mopts.chunk_canaries)
> -                             fill_canary(p, newsz, PAGEROUND(newsz));
> +                     if (MALLOC_MOVE_COND(gnewsz))
> +                             pp = MALLOC_MOVE(r->p, gnewsz);
> +                     if (p != pp) {
> +                             memmove(pp, p, oldsz < newsz ? oldsz : newsz);
> +                             p = pp;
> +                     }
> +                     if (p == r->p) {
> +                             if (newsz > oldsz && mopts.malloc_junk == 2)
> +                                     memset((char *)p + newsz, SOME_JUNK,
> +                                         rnewsz - mopts.malloc_guard -
> +                                         newsz);
> +                             if (mopts.chunk_canaries)
> +                                     fill_canary(p, newsz, PAGEROUND(newsz));
> +                     }
>                       STATS_SETF(r, f);
>                       ret = p;
>                       goto done;

Reply via email to