关于各种free错误的定位方法

前言:glibc在free一块堆内存的时候会检查堆头,如果堆头有异常,就报free err、double free等问题,然而实际上这可能是另外一个地方的堆溢出导致的本堆块堆头被踩导致的,并不是什么double free。这个时候就有个简单的定位方法去定位这种问题。

 

1. 现象:

 

Continuing.
*** glibc detected *** ...: double free or corruption (out): 0x0000000000627f90 ***
======= Backtrace: =========
/lib64/libc.so.6(+0x76628)[0x7ffff720b628]
/lib64/libc.so.6(cfree+0x6c)[0x7ffff72105cc]
...
======= Memory map: ========
...
0061c000-00682000 rw-p 00000000 00:00 0 [heap]
7ffff0000000-7ffff0021000 rw-p 00000000 00:00 0
7ffff0021000-7ffff4000000 ---p 00000000 00:00 0
7ffff6d67000-7ffff6d7d000 r-xp 00000000 08:07 803123 /usr/local/lib64/libgcc_s.so.1

 

2. 定位方法:

gdb拉入目标程序,先在free上下断点,制作command另其自动打印调用栈、自动继续,这样我们可以看到glibc报错时候的调用栈:

  b free

       command 1

    >silent

    >bt

    >c

    >end

运行crash样本,发现free出错点和释放出错的堆结构体:

(gdb) bt
#0 0x00007ffff7210560 in free () from /lib64/libc.so.6
#1 0x00000000004140c0 in av_free (ptr=<optimized out>) at libavutil/mem.c:282
#2 av_freep (arg=arg@entry=0x61d178) at libavutil/mem.c:289
#3 0x00000000004048c1 in hevc_decode_free (avctx=<optimized out>) at libavcodec/hevc.c:3281
#4 0x00000000004137ad in avcodec_close (avctx=0x61cbf0) at libavcodec/utils.c:106
#5 0x0000000000402ba7 in hevc_decode_end (s=s@entry=0x61c010) at libbpg.c:564
#6 0x0000000000403edc in bpg_decoder_decode (img=img@entry=0x61c010, buf=buf@entry=0x61c250 "BPG\373 ", buf_len=buf_len@entry=2450) at libbpg.c:1882
#7 0x0000000000401410 in main (argc=<optimized out>, argv=<optimized out>) at bpgdec.c:332

*** glibc detected *** ...: double free or corruption (out): 0x0000000000627f90 ***
======= Backtrace: =========
/lib64/libc.so.6(+0x76628)[0x7ffff720b628]
/lib64/libc.so.6(cfree+0x6c)[0x7ffff72105cc]

源码定位到该结构体申请时的代码,下断点并重新运行crash样本,在断点处获取到该结构体的内存地址addr(此处malloc返回的地址为0x627f90),然后在addr - 8地址处(chunk head)下硬件断点(为了检测堆头被破坏的过程):

 

(gdb) watch *0x627f90 - 8
Hardware watchpoint 8: *0x627f88
(gdb) c
Continuing.
Hardware watchpoint 8: *0x627f88

Old value = 209
New value = 0
restore_tqb_pixels (s=s@entry=0x61d050, src1=src1@entry=0x64b010 "M", dst1=dst1@entry=0x63a7c6 "M", stride_src=256, stride_dst=132, x0=<optimized out>, y0=192, width=64, height=64, c_idx=0) at libavcodec/hevc_filter.c:228
228 memcpy(src, dst, len);
(gdb)

 

3. 成功抓到罪魁祸首:堆溢出。

 

posted @ 2017-10-12 18:05  rec0rd  阅读(2330)  评论(0编辑  收藏  举报