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 DFB
tcache_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 Duplication
key
가 위치한 부분을 조작하면 된다.