On Thu, Mar 30, 2023 at 04:53:05PM +0200, Otto Moerbeek wrote:
> Hi,
>
> this came up after a remark by tb@; it does a more thorough check of
> the chunks in the delay list if malloc option F (which is included in
> S).
>
> Catches way more use-after-free's as otherwise we'll have to wait
> until a chunk is actively re-used. With the new bucket code that might
> take longer (or not happen at all because the program terminates). The
> catch also happens closer (in time) to the actual write after free.
> That might help finding the root cause.
Thank you. This works indeed a lot better in my testing.
ok tb
>
> -Otto
>
> Index: stdlib/malloc.3
> ===
> RCS file: /home/cvs/src/lib/libc/stdlib/malloc.3,v
> retrieving revision 1.129
> diff -u -p -r1.129 malloc.3
> --- stdlib/malloc.3 31 Mar 2022 17:27:16 - 1.129
> +++ stdlib/malloc.3 30 Mar 2023 14:47:19 -
> @@ -293,7 +293,8 @@ order to have any effect.
> .It Cm F
> .Dq Freecheck .
> Enable more extensive double free and use after free detection.
> -All chunks in the delayed free list will be checked for double frees.
> +All chunks in the delayed free list will be checked for double frees and
> +write after frees.
> Unused pages on the freelist are read and write protected to
> cause a segmentation fault upon access.
> .It Cm G
> Index: stdlib/malloc.c
> ===
> RCS file: /home/cvs/src/lib/libc/stdlib/malloc.c,v
> retrieving revision 1.278
> diff -u -p -r1.278 malloc.c
> --- stdlib/malloc.c 25 Mar 2023 15:22:06 - 1.278
> +++ stdlib/malloc.c 30 Mar 2023 14:47:19 -
> @@ -1554,11 +1554,25 @@ ofree(struct dir_info **argpool, void *p
> find_chunknum(pool, info, p, mopts.chunk_canaries);
>
> if (mopts.malloc_freecheck) {
> - for (i = 0; i <= MALLOC_DELAYED_CHUNK_MASK; i++)
> - if (p == pool->delayed_chunks[i])
> + for (i = 0; i <= MALLOC_DELAYED_CHUNK_MASK; i++) {
> + tmp = pool->delayed_chunks[i];
> + if (tmp == p)
> wrterror(pool,
> "double free %p", p);
> + if (tmp != NULL) {
> + size_t tmpsz;
> +
> + r = find(pool, tmp);
> + if (r == NULL)
> + wrterror(pool,
> + "bogus pointer ("
> + "double free?) %p", tmp);
> + REALSIZE(tmpsz, r);
> + validate_junk(pool, tmp, tmpsz);
> + }
> + }
> }
> +
> if (clear && argsz > 0)
> explicit_bzero(p, argsz);
> junk_free(pool->malloc_junk, p, sz);
> @@ -1574,8 +1588,10 @@ ofree(struct dir_info **argpool, void *p
> if (r == NULL)
> wrterror(pool,
> "bogus pointer (double free?) %p", p);
> - REALSIZE(sz, r);
> - validate_junk(pool, p, sz);
> + if (!mopts.malloc_freecheck) {
> + REALSIZE(sz, r);
> + validate_junk(pool, p, sz);
> + }
> free_bytes(pool, r, p);
> }
> }
>