glibc 2.26버전에 대한 이해가 있다라고 가정하고 바뀐 코드 위주로 정리할 것이다
각 소제목에 해당되는 상세 설명은 각 리스트 아래 더보기 참고
전체 코드는 아래 더보기
인자 및 변수 (삭제)
변경 및 추가된 코드
- errstr변수 삭제
const char *errstr = NULL;
이전에 버전에서 에러 문자열을 저장하는 errstr을 더 이상 사용하지 않는다
initical check (동일)
glibc 2.26버전과 동일
fastbin (변경, 추가)
변경 및 추가된 코드
- 초기에 REMOVE_FB 매크로로 vicitm에 값을 저장하는 것이 아닌 *fb로 최상단 청크를 저장
- fastbinsY를 갱신과 freed chunk 재사용을 하기 전에 freed chunk가 있는지 검사
- fastbin에 있는 청크를 tcache로 옮기는 과정에서 단일 스레드일 때 처리되는 코드 추가
변수
mchunkptr pp;
victim = *fb;
fb를 통해 해당 fastbin의 최상단에 있는 freed chunk를 pp가 아닌 victim에 저장한다 ( 이전에는 pp에 저장했다 )
pp는 초기화하지 않는다
※ fastbinsY를 갱신하고 fastbin 및 tcache를 재사용하는 코드를 수행하기 전에 freed chunk가 있는지 확인하는 조건문이 수행된다
fastbinsY 갱신
if (victim != NULL)
{
if (SINGLE_THREAD_P)
*fb = victim->fd;
else
REMOVE_FB (fb, pp, victim);
...
fastbinsY배열을 갱신하기 전에 freed chunk가 있는지 검사한다
단일 스레드일때와 아닐때 fastbinsY를 갱신하는 코드가 추가 되었다
- 단일 스레드일 경우 : *fb에 victim의 다음 freed chunk를 저장한다 ( fastbinsY에 최상단 청크를 제거 )
- 단일 스레드 아닐 경우 : REMOVE_FB 매크로를 통해 pp에 최상단 청크를 저장하고 fastbinsY를 갱신한다
tcache 재사용할 때
/* While bin not empty and tcache not full, copy chunks. */
while (tcache->counts[tc_idx] < mp_.tcache_count
&& (tc_victim = *fb) != NULL)
{
if (SINGLE_THREAD_P)
*fb = tc_victim->fd;
else
{
REMOVE_FB (fb, pp, tc_victim);
if (__glibc_unlikely (tc_victim == NULL))
break;
}
tcache_put (tc_victim, tc_idx);
}
fastbin에 있는 freed chunk를 tcache를 옮기는 과정에서 단일 스레드일 경우 처리해주는 코드가 추가 되었다 ( fastbinsY 갱신과 동일한 과정 )
추가된 보안 검사
- 없음
small bin (동일)
glibc 2.26버전과 동일
large bin (동일)
glibc 2.26버전과 동일
using unsorted bin (추가, 변경)
변경 및 추가된 코드
- 보안 검사를 위한 변수 선언 및 size구하는 코드 검사 이전으로 이동
변수
size = chunksize (victim);
mchunkptr next = chunk_at_offset (victim, size);
bck를 구한 뒤 위 코드가 추가 되었다
size가 관련된 검사가 추가 되면서 검사 이후에 size를 구하는 코드가 bck를 구한 뒤 바로 수행된다
검사를 위해 next 변수를 선언하고 victim의 다음 청크 주소를 저장한다
추가된 보안 검사
- while문 초입 부분
- next의 size 검사
- next의 prev_size와 victim의 size 동일한지 검사
- victim->bk의 fd가 vicitm이고 victim->fd가 해당 bins주소인지 검사
- next에 prev_inuse 비트가 설정되어 있는지 검사
- unsorted bin에서 victim 제거하기 전
- bck의 fd가 victim인지 검사
while문 초입 부분
if (__glibc_unlikely (chunksize_nomask (next) < 2 * SIZE_SZ)
|| __glibc_unlikely (chunksize_nomask (next) > av->system_mem))
malloc_printerr ("malloc(): invalid next size (unsorted)");
if (__glibc_unlikely ((prev_size (next) & ~(SIZE_BITS)) != size))
malloc_printerr ("malloc(): mismatching next->prev_size (unsorted)");
if (__glibc_unlikely (bck->fd != victim)
|| __glibc_unlikely (victim->fd != unsorted_chunks (av)))
malloc_printerr ("malloc(): unsorted double linked list corrupted");
if (__glibc_unlikely (prev_inuse (next)))
malloc_printerr ("malloc(): invalid next->prev_inuse (unsorted)");
unsorted bin에서 victim 제거하기 전
/* remove from unsorted list */
if (__glibc_unlikely (bck->fd != victim))
malloc_printerr ("malloc(): corrupted unsorted chunks 3");
unsorted_chunks (av)->bk = bck;
bck->fd = unsorted_chunks (av);
리스트에서 victim을 제거하기 전에 검사가 추가 되었다
large bin으로 재할당 (동일)
glibc 2.26버전과 동일
binmap 탐색을 통해 재할당 (동일)
glibc 2.26버전과 동일
top chunk로 재할당 (추가)
추가된 보안 검사
- top chunk로 재할당하기 전
- top 청크의 size 검사
victim = av->top;
size = chunksize (victim);
if (__glibc_unlikely (size > av->system_mem))
malloc_printerr ("malloc(): corrupted top size");
if ((unsigned long) (size) >= (unsigned long) (nb + MINSIZE))
{
...
top 청크를 통해 재할당을 하기 전에 top 청크 size가 av->system_mem보다 큰지 검사한다
이를 제외한 코드는 2.26버전과 동일하다
'Heap analysis > glibc 2.29' 카테고리의 다른 글
(glibc 2.29) tcache_get (0) | 2022.05.19 |
---|---|
(glibc 2.29) tcache_init (0) | 2022.05.19 |
(glibc 2.29) _int_free (0) | 2022.05.15 |
(glibc 2.29) free (0) | 2022.05.15 |
(glibc 2.29) malloc (0) | 2022.05.07 |