malloc: Add size check when moving fastbin->tcache

Message ID 20250206213709.2394624-2-benjamin.p.kallus.gr@dartmouth.edu (mailing list archive)
State Superseded
Headers
Series malloc: Add size check when moving fastbin->tcache |

Checks

Context Check Description
redhat-pt-bot/TryBot-apply_patch success Patch applied to master at the time it was sent
redhat-pt-bot/TryBot-32bit success Build for i686
linaro-tcwg-bot/tcwg_glibc_build--master-arm success Build passed
linaro-tcwg-bot/tcwg_glibc_build--master-aarch64 success Build passed
linaro-tcwg-bot/tcwg_glibc_check--master-arm success Test passed
linaro-tcwg-bot/tcwg_glibc_check--master-aarch64 success Test passed

Commit Message

Ben Kallus Feb. 6, 2025, 9:37 p.m. UTC
  By overwriting a forward link in a fastbin chunk that is subsequently
moved into the tcache, it's possible to get malloc to return an
arbitrary address [0].

When a chunk is fetched from a fastbin, its size is checked against the
expected chunk size for that fastbin (see malloc.c:3991). This patch
adds a similar check for chunks being moved from a fastbin to tcache,
which renders obsolete the exploitation technique described above.

[0]: https://github.com/shellphish/how2heap/blob/master/glibc_2.39/fastbin_reverse_into_tcache.c

Signed-off-by: Ben Kallus <benjamin.p.kallus.gr@dartmouth.edu>
---
 malloc/malloc.c | 3 +++
 1 file changed, 3 insertions(+)
  

Comments

Adhemerval Zanella Netto Feb. 11, 2025, 6:16 p.m. UTC | #1
On 06/02/25 18:37, Ben Kallus wrote:
> By overwriting a forward link in a fastbin chunk that is subsequently
> moved into the tcache, it's possible to get malloc to return an
> arbitrary address [0].
> 
> When a chunk is fetched from a fastbin, its size is checked against the
> expected chunk size for that fastbin (see malloc.c:3991). This patch
> adds a similar check for chunks being moved from a fastbin to tcache,
> which renders obsolete the exploitation technique described above.
> 
> [0]: https://github.com/shellphish/how2heap/blob/master/glibc_2.39/fastbin_reverse_into_tcache.c
> 
> Signed-off-by: Ben Kallus <benjamin.p.kallus.gr@dartmouth.edu>
> ---
>  malloc/malloc.c | 3 +++
>  1 file changed, 3 insertions(+)
> 
> diff --git a/malloc/malloc.c b/malloc/malloc.c
> index 27dfd1eb90..3e8a20ae87 100644
> --- a/malloc/malloc.c
> +++ b/malloc/malloc.c
> @@ -4005,6 +4005,9 @@ _int_malloc (mstate av, size_t bytes)
>  		    {
>  		      if (__glibc_unlikely (misaligned_chunk (tc_victim)))
>  			malloc_printerr ("malloc(): unaligned fastbin chunk detected 3");
> +		      size_t victim_tc_idx = csize2tidx (chunksize (tc_victim));
> +		      if (__builtin_expect (tc_idx != victim_tc_idx, 0))
> +			malloc_printerr ("malloc(): chunk size mismatch in fastbin");

This test looks ok and should be inexpensive.  Use __glibc_unlikely,
as the test above.

>  		      if (SINGLE_THREAD_P)
>  			*fb = REVEAL_PTR (tc_victim->fd);
>  		      else
  

Patch

diff --git a/malloc/malloc.c b/malloc/malloc.c
index 27dfd1eb90..3e8a20ae87 100644
--- a/malloc/malloc.c
+++ b/malloc/malloc.c
@@ -4005,6 +4005,9 @@  _int_malloc (mstate av, size_t bytes)
 		    {
 		      if (__glibc_unlikely (misaligned_chunk (tc_victim)))
 			malloc_printerr ("malloc(): unaligned fastbin chunk detected 3");
+		      size_t victim_tc_idx = csize2tidx (chunksize (tc_victim));
+		      if (__builtin_expect (tc_idx != victim_tc_idx, 0))
+			malloc_printerr ("malloc(): chunk size mismatch in fastbin");
 		      if (SINGLE_THREAD_P)
 			*fb = REVEAL_PTR (tc_victim->fd);
 		      else