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가 다른지 검사한다