about summary refs log tree commit diff
diff options
context:
space:
mode:
authorSzabolcs Nagy <szabolcs.nagy@arm.com>2022-12-19 13:18:10 +0000
committerSzabolcs Nagy <szabolcs.nagy@arm.com>2022-12-19 14:59:06 +0000
commitbbce0c75f35f55b9f5e43dd4fa01a82cc27bf020 (patch)
treed9ab159f3cd796bd4cc9d4e331cd8b82c501f9dc
parentdc23cc80210799f8d8ab5b1ea2e00341e613a1a7 (diff)
downloadglibc-bbce0c75f35f55b9f5e43dd4fa01a82cc27bf020.tar.gz
glibc-bbce0c75f35f55b9f5e43dd4fa01a82cc27bf020.tar.xz
glibc-bbce0c75f35f55b9f5e43dd4fa01a82cc27bf020.zip
cheri: malloc: Fix realloc to copy all relevant bytes
New code in realloc that handles when new allocation is needed for
alignment reasons (for capability narrowing) used the wrong size in
memcpy (size was off by SIZE_SZ unless memory tagging was enabled)
and used wrongly tagged pointer for untagging the old memory.

Due to this bug realloc sometimes failed to copy tail bytes of an old
allocation to the new allocation when capability narrowing is enabled.
-rw-r--r--malloc/malloc.c4
-rw-r--r--malloc/tst-realloc.c19
2 files changed, 21 insertions, 2 deletions
diff --git a/malloc/malloc.c b/malloc/malloc.c
index 392116a5ac..ededc5cfe2 100644
--- a/malloc/malloc.c
+++ b/malloc/malloc.c
@@ -3762,9 +3762,9 @@ __libc_realloc (void *oldmem, size_t bytes)
       void *newmem = _mid_memalign (align, bytes, 0);
       if (!cap_narrow_check (newmem, oldmem))
 	return newmem;
-      size_t sz = oldsize - CHUNK_HDR_SZ;
+      size_t sz = memsize (oldp);
       memcpy (newmem, oldmem, sz < bytes ? sz : bytes);
-      (void) tag_region (oldmem, sz);
+      (void) tag_region (chunk2mem (oldp), sz);
       _int_free (ar_ptr, oldp, 0);
       return newmem;
     }
diff --git a/malloc/tst-realloc.c b/malloc/tst-realloc.c
index 5eb62a770f..2e14d318ab 100644
--- a/malloc/tst-realloc.c
+++ b/malloc/tst-realloc.c
@@ -83,6 +83,25 @@ do_test (void)
 
   free (p);
 
+  /* Check as above with larger size increase.  */
+  p = malloc (34);
+  if (p == NULL)
+    FAIL_EXIT1 ("malloc (34) failed.");
+  memset (p, 'a', 34);
+  p = realloc (p, 80000);
+  if (p == NULL)
+    FAIL_EXIT1 ("realloc (p, 80000) failed.");
+  c = p;
+  ok = 1;
+  for (i = 0; i < 34; i++)
+    {
+      if (c[i] != 'a')
+        ok = 0;
+    }
+  if (ok == 0)
+    FAIL_EXIT1 ("first 34 bytes were not preserved");
+  free (p);
+
   p = realloc (NULL, 100);
   if (p == NULL)
     FAIL_EXIT1 ("realloc (NULL, 100) failed.");