[Pwn]how2heap-tcache_idx.c

김민주·2025년 9월 27일

security

목록 보기
3/13

tcache?

개념

tcache(Thread local Caching)란 멀티 스레드 환경에서 메모리 할당 속도를 높이기 위한 것으로 각 스레드에 독립적으로 할당되는 캐시 저장소이다.
작은 단위의 메모리는 arena를 참조하지 않고 바로 메모리를 할당한다.
glibc2.26 버전 이상부터 도입되었으며, 멀티 스레드 환경에 더욱 최적화된 메모리 관리 메커니즘을 제공한다.

※arena?
-> 멀티스레드 환경을 지원하기 위해 도입되었다.
-> fastbin, smallbin, largebin 등의 정보를 모두 담고있는 객체이다.
-> 과도한 멀티 쓰레드 환경에서는 병목 현상이 발생한다.

특징

  • 각 스레드별로 64개의 single linked list 구조의 tcache bin 존재한다.
  • 각 bin에는 7개의 동일한 크기의 chunk가 존재한다.
  • 32바이트 ~ 1040바이트 크기를 갖는 청크들이 보관된다.

구조

1. tcache_entry

/* We overlay this structure on the user-data portion of a chunk when
   the chunk is stored in the per-thread cache.  */

typedef struct tcache_entry
{
  struct tcache_entry *next;
} tcache_entry;
  • 사용 가능한 청크 구조를 연결하는 데 사용되며, 다음 포인터는 동일한 크기의 다음 청크를 가리킨다.
  • next 포인터를 통해 다음 동일한 크기의 free chunk를 연결한다.

2. tcache_perthread_struct

/* There is one of these for each thread, which contains the
   per-thread cache (hence "tcache_perthread_struct").  Keeping
   overall size low is mildly important.  Note that COUNTS and ENTRIES
   are redundant (we could have just counted the linked list each
   time), this is for performance reasons.  */

typedef struct tcache_perthread_struct
{
  char counts[TCACHE_MAX_BINS];
  tcache_entry *entries[TCACHE_MAX_BINS];
} tcache_perthread_struct;

# define TCACHE_MAX_BINS                64

static __thread tcache_perthread_struct *tcache = NULL;
  • 전체적인 tcache list를 관리한다.
  • counts[TCACHE_MAX_BINS] : entries 배열의 single linked list로 연결되어 있는 청크의 개수를 기록한다.
  • entries[TCACHE_MAX_BINS] : fastbin과 같이 single linked list의 구조로 동일한 크기의 free chunk들로 연결되어 있다.

calc_tcache_idx.c

1. malloc_chunk

struct malloc_chunk {

  size_t      mchunk_prev_size;  /* Size of previous chunk (if free).  */
  size_t      mchunk_size;       /* Size in bytes, including overhead. */

  struct malloc_chunk* fd;         /* double links -- used only if free. */
  struct malloc_chunk* bk;

  /* Only used for large blocks: pointer to next larger size.  */
  struct malloc_chunk* fd_nextsize; /* double links -- used only if free. */
  struct malloc_chunk* bk_nextsize;
};
  • fd, bk, fd_nextsize, bknextsize는 free 된 경우에만 사용한다.
  • fd_nextsize, bk_nextsize 는 크기가 큰 chunk를 관리할 때 사용한다.

2. basic formula

IDX = (CHUNKSIZE - MINSIZE + MALLOC_ALIGNMENT -1) / MALLOC_ALIGNMENT

이때 64bit 에서는 MINSIZE = 0x20, MALLOC_ALIGNMENT = 0x10이다.
따라서, IDX = (CHUNKSIZE - 0x11) / 0x10 이 된다.

CHUNKSIZE와 malloc(x)의 x는 같은 값이 아님을 조심하자

  • CHUNKSIZE 계산 방법
    1) x + SIZE_SZ + MALLOC_ALIGN_MASK < MINSIZE(0x20) 의 경우
    CHUNKSIZE = 0x20(MINSIZE)
    2) 그 외
    CHUNKSIZE = (x + SIZE_SZ + MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK+
    <=> CHUNKSIZE = (x + 0x8 + 0xf) & ~0xf

여기서 & ~0xf는 (x + 0x8 + 0xf)의 하위 4비트를 날리는 행위이다.

conclusion

tcache idx의 계산 방법을 알려주는 코드이다.

0개의 댓글