Check all chunks in the delayed free list for write-after-free.
authorotto <otto@openbsd.org>
Sat, 1 Apr 2023 18:47:51 +0000 (18:47 +0000)
committerotto <otto@openbsd.org>
Sat, 1 Apr 2023 18:47:51 +0000 (18:47 +0000)
Should catch more of them and closer (in time) to the WAF.  ok tb@

lib/libc/stdlib/malloc.3
lib/libc/stdlib/malloc.c

index 9bd498a..b35b922 100644 (file)
@@ -30,9 +30,9 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\"    $OpenBSD: malloc.3,v 1.129 2022/03/31 17:27:16 naddy Exp $
+.\"    $OpenBSD: malloc.3,v 1.130 2023/04/01 18:47:51 otto Exp $
 .\"
-.Dd $Mdocdate: March 31 2022 $
+.Dd $Mdocdate: April 1 2023 $
 .Dt MALLOC 3
 .Os
 .Sh NAME
@@ -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 c049b2d..2ac4b73 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: malloc.c,v 1.278 2023/03/25 15:22:06 otto Exp $       */
+/*     $OpenBSD: malloc.c,v 1.279 2023/04/01 18:47:51 otto Exp $       */
 /*
  * Copyright (c) 2008, 2010, 2011, 2016 Otto Moerbeek <otto@drijf.net>
  * Copyright (c) 2012 Matthew Dempsky <matthew@openbsd.org>
@@ -1554,11 +1554,25 @@ ofree(struct dir_info **argpool, void *p, int clear, int check, size_t argsz)
                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, int clear, int check, size_t argsz)
                        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);
                }
        }