i春秋作家:Bug制造机
原文来自:Glibc堆块的向前向后合并与unlink原理机制探究
玩pwn有一段时间了,最近有点生疏了,调起来都不顺手了,所以读读malloc源码回炉一点一点总结反思下。
Unlink是把free掉的chunk从所属的bins链中,卸下来的操作(当然还包括一系列的检测机制),它是在free掉一块chunk(除fastbin大小的chunk外)之后,glibc检查这块chunk相邻的上下两块chunk的free状态之后,做出的向后合并或者向前合并引起的。
向前、向后合并
p是指向free掉的chunk的指针(注意不是指向data的指针,是chunk),size是这块chunk的size。
/* consolidate backward */
4277 if (!prev_inuse(p)) {
4278 prevsize = prev_size (p);
4279 size += prevsize;
4280 p = chunk_at_offset(p, -((long) prevsize));
4281 unlink(av, p, bck, fwd);
4282 }
4283
4284 if (nextchunk != av->top) {
4285 /* get and clear inuse bit */
4286 nextinuse = inuse_bit_at_offset(nextchunk, nextsize);
4287
4288 /* consolidate forward */
4289 if (!nextinuse) {
4290 unlink(av, nextchunk, bck, fwd);
4291 size += nextsize;
4292 } else
4293 clear_inuse_bit_at_offset(nextchunk, 0);
4294
4295 /*
4296 Place the chunk in unsorted chunk list. Chunks are
4297 not placed into regular bins until after they have
4298 been given one chance to be used in malloc.
4299 */
4300
4301 bck = unsorted_chunks(av);
4302 fwd = bck->fd;
4303 if (__glibc_unlikely (fwd->bk != bck))
4304 malloc_printerr ("free(): corrupted unsorted chunks");
4305 p->fd = fwd;
4306 p->bk = bck;
4307 if (!in_smallbin_range(size))
4308 {
4309 p->fd_nextsize = NULL;
4310 p->bk_nextsize = NULL;
4311 }
4312 bck->fd = p;
4313 fwd->bk = p;
4314
4315 set_head(p, size | PREV_INUSE);
4316 set_foot(p, size);
4317
4318 check_free_chunk(av, p);
4319 }
4320
4321 /*
4322 If the chunk borders the current high end of memory,
4323 consolidate into top
4324 */
4325
4326 else {
4327 size += nextsize;
4328 set_head(p, size | PREV_INUSE);
4329 av->top = p;
4330 check_chunk(av, p);
4331 }
向后合并
向后合并部分的代码在4277-4282行
向后合并流程:
-
检查p指向chunk的size字段的pre_inuse位,是否为0(也就是检查当前chunk的前一块chunk是否是free的,如果是则进入向前合并的流程)
-
获取前一块chunk的size,并加到size中