Re: malloc: handle to be cleaned chunks the same as regular ones

2023-02-24 Thread Theo Buehler
On Fri, Feb 24, 2023 at 08:13:13AM +0100, Otto Moerbeek wrote:
> On Sat, Feb 18, 2023 at 04:12:08PM +0100, Otto Moerbeek wrote:
> 
> > Hi,
> > 
> > these recent sshd double free issue prompted me to look at malloc
> > again. I have something bigger brewing, but this diff makes sure the
> > to be cleaned chunks (via freezero() or malloc_conceal) particpate in
> > the delayed freeing just as others.
> 
> I'd like to see tests/reviews of this.

I have tested this for a few days on my main machines (amd64 and arm64).
I also tested it on sparc64 and i386 (machines mostly used for building).

The diff reads fine

ok tb

> 
> > 
> > -Otto
> > 
> > Index: stdlib/malloc.c
> > ===
> > RCS file: /home/cvs/src/lib/libc/stdlib/malloc.c,v
> > retrieving revision 1.276
> > diff -u -p -r1.276 malloc.c
> > --- stdlib/malloc.c 27 Dec 2022 17:31:09 -  1.276
> > +++ stdlib/malloc.c 16 Feb 2023 14:11:50 -
> > @@ -1515,42 +1515,38 @@ ofree(struct dir_info **argpool, void *p
> > unmap(pool, p, PAGEROUND(sz), clear ? argsz : 0);
> > delete(pool, r);
> > } else {
> > +   void *tmp;
> > +   u_int i;
> > +
> > /* Validate and optionally canary check */
> > struct chunk_info *info = (struct chunk_info *)r->size;
> > if (info->size != sz)
> > wrterror(pool, "internal struct corrupt");
> > find_chunknum(pool, info, p, mopts.chunk_canaries);
> > -   if (!clear) {
> > -   void *tmp;
> > -   int i;
> >  
> > -   if (mopts.malloc_freecheck) {
> > -   for (i = 0; i <= MALLOC_DELAYED_CHUNK_MASK; i++)
> > -   if (p == pool->delayed_chunks[i])
> > -   wrterror(pool,
> > -   "double free %p", p);
> > -   }
> > -   junk_free(pool->malloc_junk, p, sz);
> > -   i = getrbyte(pool) & MALLOC_DELAYED_CHUNK_MASK;
> > -   tmp = p;
> > -   p = pool->delayed_chunks[i];
> > -   if (tmp == p)
> > -   wrterror(pool, "double free %p", tmp);
> > -   pool->delayed_chunks[i] = tmp;
> > -   if (p != NULL) {
> > -   r = find(pool, p);
> > -   REALSIZE(sz, r);
> > -   if (r != NULL)
> > -   validate_junk(pool, p, sz);
> > -   }
> > -   } else if (argsz > 0) {
> > -   r = find(pool, p);
> > -   explicit_bzero(p, argsz);
> > +   if (mopts.malloc_freecheck) {
> > +   for (i = 0; i <= MALLOC_DELAYED_CHUNK_MASK; i++)
> > +   if (p == pool->delayed_chunks[i])
> > +   wrterror(pool,
> > +   "double free %p", p);
> > }
> > +   if (clear && argsz > 0)
> > +   explicit_bzero(p, argsz);
> > +   junk_free(pool->malloc_junk, p, sz);
> > +
> > +   i = getrbyte(pool) & MALLOC_DELAYED_CHUNK_MASK;
> > +   tmp = p;
> > +   p = pool->delayed_chunks[i];
> > +   if (tmp == p)
> > +   wrterror(pool, "double free %p", p);
> > +   pool->delayed_chunks[i] = tmp;
> > if (p != NULL) {
> > +   r = find(pool, p);
> > if (r == NULL)
> > wrterror(pool,
> > "bogus pointer (double free?) %p", p);
> > +   REALSIZE(sz, r);
> > +   validate_junk(pool, p, sz);
> > free_bytes(pool, r, p);
> > }
> > }
> > 
> 



Re: malloc: handle to be cleaned chunks the same as regular ones

2023-02-23 Thread Otto Moerbeek
On Sat, Feb 18, 2023 at 04:12:08PM +0100, Otto Moerbeek wrote:

> Hi,
> 
> these recent sshd double free issue prompted me to look at malloc
> again. I have something bigger brewing, but this diff makes sure the
> to be cleaned chunks (via freezero() or malloc_conceal) particpate in
> the delayed freeing just as others.

I'd like to see tests/reviews of this.

> 
>   -Otto
> 
> Index: stdlib/malloc.c
> ===
> RCS file: /home/cvs/src/lib/libc/stdlib/malloc.c,v
> retrieving revision 1.276
> diff -u -p -r1.276 malloc.c
> --- stdlib/malloc.c   27 Dec 2022 17:31:09 -  1.276
> +++ stdlib/malloc.c   16 Feb 2023 14:11:50 -
> @@ -1515,42 +1515,38 @@ ofree(struct dir_info **argpool, void *p
>   unmap(pool, p, PAGEROUND(sz), clear ? argsz : 0);
>   delete(pool, r);
>   } else {
> + void *tmp;
> + u_int i;
> +
>   /* Validate and optionally canary check */
>   struct chunk_info *info = (struct chunk_info *)r->size;
>   if (info->size != sz)
>   wrterror(pool, "internal struct corrupt");
>   find_chunknum(pool, info, p, mopts.chunk_canaries);
> - if (!clear) {
> - void *tmp;
> - int i;
>  
> - if (mopts.malloc_freecheck) {
> - for (i = 0; i <= MALLOC_DELAYED_CHUNK_MASK; i++)
> - if (p == pool->delayed_chunks[i])
> - wrterror(pool,
> - "double free %p", p);
> - }
> - junk_free(pool->malloc_junk, p, sz);
> - i = getrbyte(pool) & MALLOC_DELAYED_CHUNK_MASK;
> - tmp = p;
> - p = pool->delayed_chunks[i];
> - if (tmp == p)
> - wrterror(pool, "double free %p", tmp);
> - pool->delayed_chunks[i] = tmp;
> - if (p != NULL) {
> - r = find(pool, p);
> - REALSIZE(sz, r);
> - if (r != NULL)
> - validate_junk(pool, p, sz);
> - }
> - } else if (argsz > 0) {
> - r = find(pool, p);
> - explicit_bzero(p, argsz);
> + if (mopts.malloc_freecheck) {
> + for (i = 0; i <= MALLOC_DELAYED_CHUNK_MASK; i++)
> + if (p == pool->delayed_chunks[i])
> + wrterror(pool,
> + "double free %p", p);
>   }
> + if (clear && argsz > 0)
> + explicit_bzero(p, argsz);
> + junk_free(pool->malloc_junk, p, sz);
> +
> + i = getrbyte(pool) & MALLOC_DELAYED_CHUNK_MASK;
> + tmp = p;
> + p = pool->delayed_chunks[i];
> + if (tmp == p)
> + wrterror(pool, "double free %p", p);
> + pool->delayed_chunks[i] = tmp;
>   if (p != NULL) {
> + r = find(pool, p);
>   if (r == NULL)
>   wrterror(pool,
>   "bogus pointer (double free?) %p", p);
> + REALSIZE(sz, r);
> + validate_junk(pool, p, sz);
>   free_bytes(pool, r, p);
>   }
>   }
> 



malloc: handle to be cleaned chunks the same as regular ones

2023-02-18 Thread Otto Moerbeek
Hi,

these recent sshd double free issue prompted me to look at malloc
again. I have something bigger brewing, but this diff makes sure the
to be cleaned chunks (via freezero() or malloc_conceal) particpate in
the delayed freeing just as others.

-Otto

Index: stdlib/malloc.c
===
RCS file: /home/cvs/src/lib/libc/stdlib/malloc.c,v
retrieving revision 1.276
diff -u -p -r1.276 malloc.c
--- stdlib/malloc.c 27 Dec 2022 17:31:09 -  1.276
+++ stdlib/malloc.c 16 Feb 2023 14:11:50 -
@@ -1515,42 +1515,38 @@ ofree(struct dir_info **argpool, void *p
unmap(pool, p, PAGEROUND(sz), clear ? argsz : 0);
delete(pool, r);
} else {
+   void *tmp;
+   u_int i;
+
/* Validate and optionally canary check */
struct chunk_info *info = (struct chunk_info *)r->size;
if (info->size != sz)
wrterror(pool, "internal struct corrupt");
find_chunknum(pool, info, p, mopts.chunk_canaries);
-   if (!clear) {
-   void *tmp;
-   int i;
 
-   if (mopts.malloc_freecheck) {
-   for (i = 0; i <= MALLOC_DELAYED_CHUNK_MASK; i++)
-   if (p == pool->delayed_chunks[i])
-   wrterror(pool,
-   "double free %p", p);
-   }
-   junk_free(pool->malloc_junk, p, sz);
-   i = getrbyte(pool) & MALLOC_DELAYED_CHUNK_MASK;
-   tmp = p;
-   p = pool->delayed_chunks[i];
-   if (tmp == p)
-   wrterror(pool, "double free %p", tmp);
-   pool->delayed_chunks[i] = tmp;
-   if (p != NULL) {
-   r = find(pool, p);
-   REALSIZE(sz, r);
-   if (r != NULL)
-   validate_junk(pool, p, sz);
-   }
-   } else if (argsz > 0) {
-   r = find(pool, p);
-   explicit_bzero(p, argsz);
+   if (mopts.malloc_freecheck) {
+   for (i = 0; i <= MALLOC_DELAYED_CHUNK_MASK; i++)
+   if (p == pool->delayed_chunks[i])
+   wrterror(pool,
+   "double free %p", p);
}
+   if (clear && argsz > 0)
+   explicit_bzero(p, argsz);
+   junk_free(pool->malloc_junk, p, sz);
+
+   i = getrbyte(pool) & MALLOC_DELAYED_CHUNK_MASK;
+   tmp = p;
+   p = pool->delayed_chunks[i];
+   if (tmp == p)
+   wrterror(pool, "double free %p", p);
+   pool->delayed_chunks[i] = tmp;
if (p != NULL) {
+   r = find(pool, p);
if (r == NULL)
wrterror(pool,
"bogus pointer (double free?) %p", p);
+   REALSIZE(sz, r);
+   validate_junk(pool, p, sz);
free_bytes(pool, r, p);
}
}