| commit affec03b713c82c43a5b025dddc21bde3334f41e |
| Author: Florian Weimer <fweimer@redhat.com> |
| Date: Mon Nov 26 20:06:37 2018 +0100 |
| |
| malloc: tcache: Validate tc_idx before checking for double-frees [BZ #23907] |
| |
| The previous check could read beyond the end of the tcache entry |
| array. If the e->key == tcache cookie check happened to pass, this |
| would result in crashes. |
| |
| diff --git a/malloc/malloc.c b/malloc/malloc.c |
| index c6b0282e783eaeea..13c52f376859562d 100644 |
| |
| |
| @@ -4159,33 +4159,33 @@ _int_free (mstate av, mchunkptr p, int have_lock) |
| #if USE_TCACHE |
| { |
| size_t tc_idx = csize2tidx (size); |
| - |
| - /* Check to see if it's already in the tcache. */ |
| - tcache_entry *e = (tcache_entry *) chunk2mem (p); |
| - |
| - /* This test succeeds on double free. However, we don't 100% |
| - trust it (it also matches random payload data at a 1 in |
| - 2^<size_t> chance), so verify it's not an unlikely coincidence |
| - before aborting. */ |
| - if (__glibc_unlikely (e->key == tcache && tcache)) |
| + if (tcache != NULL && tc_idx < mp_.tcache_bins) |
| { |
| - tcache_entry *tmp; |
| - LIBC_PROBE (memory_tcache_double_free, 2, e, tc_idx); |
| - for (tmp = tcache->entries[tc_idx]; |
| - tmp; |
| - tmp = tmp->next) |
| - if (tmp == e) |
| - malloc_printerr ("free(): double free detected in tcache 2"); |
| - /* If we get here, it was a coincidence. We've wasted a few |
| - cycles, but don't abort. */ |
| - } |
| + /* Check to see if it's already in the tcache. */ |
| + tcache_entry *e = (tcache_entry *) chunk2mem (p); |
| + |
| + /* This test succeeds on double free. However, we don't 100% |
| + trust it (it also matches random payload data at a 1 in |
| + 2^<size_t> chance), so verify it's not an unlikely |
| + coincidence before aborting. */ |
| + if (__glibc_unlikely (e->key == tcache)) |
| + { |
| + tcache_entry *tmp; |
| + LIBC_PROBE (memory_tcache_double_free, 2, e, tc_idx); |
| + for (tmp = tcache->entries[tc_idx]; |
| + tmp; |
| + tmp = tmp->next) |
| + if (tmp == e) |
| + malloc_printerr ("free(): double free detected in tcache 2"); |
| + /* If we get here, it was a coincidence. We've wasted a |
| + few cycles, but don't abort. */ |
| + } |
| |
| - if (tcache |
| - && tc_idx < mp_.tcache_bins |
| - && tcache->counts[tc_idx] < mp_.tcache_count) |
| - { |
| - tcache_put (p, tc_idx); |
| - return; |
| + if (tcache->counts[tc_idx] < mp_.tcache_count) |
| + { |
| + tcache_put (p, tc_idx); |
| + return; |
| + } |
| } |
| } |
| #endif |