free함수로 청크를 해제하면, ptmalloc2는 이를 tcache나 bins에 추가하여 관리한다.
그리고 이후에 malloc으로 비슷한 크기의 동적 할당이 발생하면, 이 연결리스트를 탐색하여 청크를 재할당해준다.
free list 관점에서 free는 청크를 추가해주는 함수, malloc은 청크를 꺼내는 함수이다. 그러므로 임의의 청크에 대해 free를 두 번이상 적용할 수 있다는 것은, 청크를 free list에 여러번 추가할 수 있다는 것이다.
청크가 free list에 중복해서 존재하면 청크가 duplicated됐다고 표현하는데, 해커들은 duplicated free list를 이용하면 임의 주소에 청크를 할당할 수 있음을 밝혀냈다.
Double Free Bug를 이용하면 duplicated free list를 만드는 것이 가능한데, 이는 청크와 연결리스트의 구조때문이다. ptmalloc2에서 free list의 각 청크들은 fd와 bk로 연결된다. fd는 자신보다 이후에 해제된 청크를, bk는 이전에 해체된 청크를 가리킨다.
그런데, 해제된 청크에서 fd와 bk 값을 저장하는 공간은 할당된 청크에서 데이터를 저장하는 데 사용된다. 그러므로 만약 어떤 청크가 free list에 중복해서 포함된다면, 첫 번째 재할당에서 fd와 bk를 조작하여 free list에 임의 주소를 포함시킬 수 있다.
Mitigation for Tcache DFBtcache_entry for freetypedef struct tcache_entry {
struct tcache_entry *next;
+ /* This field exists to detect double frees. */
+ struct tcache_perthread_struct *key;
} tcache_entry;
key 포인터가 tcache_entry에 추가되었다.fd가 next로 대체되고, LIFO로 사용되므로 bk에 대응되는 값은 없다.tcache_put for freetcache_put(mchunkptr chunk, size_t tc_idx) {
tcache_entry *e = (tcache_entry *)chunk2mem(chunk);
assert(tc_idx < TCACHE_MAX_BINS);
+ /* Mark this chunk as "in the tcache" so the test in _int_free will detect a
double free. */
+ e->key = tcache;
e->next = tcache->entries[tc_idx];
tcache->entries[tc_idx] = e;
++(tcache->counts[tc_idx]);
}
tcache_put은 해제한 청크를 tcache에 추가하는 함수이다.tcache_put 함수는 해제되는 청크의 key에 tacache라는 값을 대입한다.tcache_get for malloctcache_get (size_t tc_idx)
assert (tcache->entries[tc_idx] > 0);
tcache->entries[tc_idx] = e->next;
--(tcache->counts[tc_idx]);
+ e->key = NULL;
return (void *) e;
}
tcache_get은 tcache에 연결된 청크를 재사용할 때 사용하는 함수이다.key 값에 NULL을 대입한다._int_free for free_int_free는 청크를 해제할 때 호출되는 함수이다.key 값이 tcache이면 Double Free가 발생했다고 보고 프로그램을 abort시킨다.Tcache Duplicationkey가 위치한 부분을 조작하면 된다.