Heap analysis/glibc 2.29
(glibc 2.29) _int_free
lok2h4rd
2022. 5. 15. 23:21
glibc 2.26버전과 비교했을때 핵심 부분만 작성할 것이다
인자 및 변수 (삭제)
변경 및 추가된 코드
- 선언되는 일부 변수 삭제
더보기
const char *errstr = NULL;
int locked = 0;
2.26버전에서 사용되었던 locked와 errstr가 삭제되었다
이를 통해 해당 버전에서는 errstr에 에러 시 출력될 문자열을 errstr에 저장해 출력하는 것이 아닌
malloc_printerrr를 통해 출력한다
initial_check (변경, 추가)
변경 및 추가된 코드
- errorout 레이블 삭제
- tcache관련 코드 추가 및 변경
더보기
errorout 레이블 삭제
if (__builtin_expect ((uintptr_t) p > (uintptr_t) -size, 0)
|| __builtin_expect (misaligned_chunk (p), 0))
malloc_printerr ("free(): invalid pointer");
/* We know that each chunk is at least MINSIZE bytes in size or a
multiple of MALLOC_ALIGNMENT. */
if (__glibc_unlikely (size < MINSIZE || !aligned_OK (size)))
malloc_printerr ("free(): invalid size");
에러를 뱉으면서 errout 레이블에 있는 unlock 코드가 제거되었다
tcache 관련 코드 추가
/* 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->counts[tc_idx] < mp_.tcache_count)
{
tcache_put (p, tc_idx);
return;
}
tcache_put함수가 호출되기 전에 tcache에 double free를 검사하는 코드가 추가되었다
- double free 검사
- tcache_puts 호출
추가된 보안 검사
- tcache관련 검사 추가 ( double free check )
더보기
/* 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. */
}
key의 값이 tcache포인터일 경우(이미 free된 경우)에 루프를 돌면서 double free를 검사한다
fastbin
변경 및 추가된 코드
- 단일 스레드인 경우 처리 코드 추가 (double free)
더보기
if (SINGLE_THREAD_P)
{
/* Check that the top of the bin is not the record we are going to
add (i.e., double free). */
if (__builtin_expect (old == p, 0))
malloc_printerr ("double free or corruption (fasttop)");
p->fd = old;
*fb = p;
}
else
do
{
/* Check that the top of the bin is not the record we are going to
add (i.e., double free). */
if (__builtin_expect (old == p, 0))
malloc_printerr ("double free or corruption (fasttop)");
p->fd = old2 = old;
}
while ((old = catomic_compare_and_exchange_val_rel (fb, p, old2))
!= old2);
double free를 검사한 뒤 fastbinsY배열을 갱신하는 코드가 단일 스레드인 경우와 아닌 경우로 나눴다
추가된 보안 검사
- 없음
not fastbin
변경 및 추가된 코드
- 없음
추가된 보안 검사
- prev chunk와 병합 과정에서 검사 추가
더보기
/* consolidate backward */
if (!prev_inuse(p)) {
prevsize = prev_size (p);
size += prevsize;
p = chunk_at_offset(p, -((long) prevsize));
if (__glibc_unlikely (chunksize(p) != prevsize))
malloc_printerr ("corrupted size vs. prev_size while consolidating");
unlink_chunk (av, p);
}
prev chunk가 free되어 병합 과정에서 unlink를 하기 전에 이전 청크의 size와 prev_size가 다른지 검사한다