Double free¶
Aynı chunk'ı iki kez free ederek allocator'ın freelist'ini corrupt etmek.
Mechanism¶
Aynı adres üzerinde free()'yi iki kez çağırmak allocator'ın freelist'ini öyle
corrupt eder ki sonraki iki malloc() call'u aynı pointer'ı geri verebilir; bu
da overlapping allocation'lar ve write-what-where'e giden bir yol sağlar. Free
edilmiş chunk bir bin'in listesinde birden çok kez görünür; liste üzerindeyken
object A için allocate edildiğinde, sonraki bir allocation onu tekrar object B için
döndürür ve ikisini alias'lar.
Note
CWE-415. glibc'de bu, tcache-poisoning ve fastbin-dup'a giriş noktasıdır:
duplicate edilmiş chunk'ın fd/next pointer'ı, sonraki allocation'ı keyfi bir
adrese yönlendirmek için overwrite edilebilir.
Walkthrough¶
Generic CWE-415 biçimi:
char *ptr = malloc(SIZE);
if (abrt) { free(ptr); }
// ...
free(ptr); // second free on same address -> freelist corruption
glibc 2.29+ bir tcache double-free guard'ı ekledi. Free sırasında her tcache_entry
bir key saklar; eğer bu zaten tcache'e eşitse, allocator bin'i tarar ve abort
eder:
typedef struct tcache_entry {
struct tcache_entry *next;
struct tcache_perthread_struct *key; /* set on free */
} tcache_entry;
if (__glibc_unlikely (e->key == tcache)) {
for (tmp = tcache->entries[tc_idx]; tmp; tmp = tmp->next)
if (tmp == e)
malloc_printerr ("free(): double free detected in tcache 2");
}
Bu, naif bir tekrar free'yi durdurur. Bypass: herhangi bir UAF, ikinci free'den
önce e->key'i clobber etmenize izin verir ve tcache_get() hiçbir key check
yapmaz — dolayısıyla tcache poisoning uygulanabilir kalır (tcache-key-bypass).
glibc 2.34+, heap-pointer leak yan etkisini de gidermek için pointer key'i bir
__getrandom() değeriyle değiştirdi.
Detection¶
ASan/KASAN ikinci free'de "double-free" raporlar; glibc'nin built-in tcache/fastbin
kontrolleri malloc_printerr ile abort eder. glibc tunable'ları ve MALLOC_CHECK_
ekstra consistency kontrolleri ekler.
Mitigation¶
Free'den sonra pointer'ları null'la; glibc tcache key ve fastbin fasttop head
kontrolleri; allocator quarantine ve randomized key'ler. Metadata'yı clobber eden bir
UAF verildiğinde hepsi bypass edilebilir.