brk() and sbrk() change the location ofthe program break, which defines theendoftheprocess’sdatasegment (i.e., the program break is thefirst location aftertheendoftheuninitializeddatasegment). Increasingtheprogram break has the effect of allocating memory totheprocess; decreasing the break deallocates mem-ory.
brk() sets theendofthedatasegmenttothevaluespecifiedbyaddr, whenthatvalueisreasonable, thesystem has enough memory, andtheprocess does not exceed its maximum data size (see setrlimit(2)).
sbrk() increments the program’s data spaceby increment bytes. Calling sbrk() withan increment of0 can be used to find the current location ofthe program break.
//计算堆的开始地址和 bss segment 结束处得空隙大小,注意每次加载程序时这个空隙都是变化的,但是在同一次加载中它不会改变 heap_gap_bss = (long)pmem - (long)&bssvar - 4; printf ("1-gap between heap and bss:%lu\n", heap_gap_bss); //释放内存,归还给堆 free (pmem); //调整 program break 位置(假设现在不知道这个位置在堆头还是堆尾) sbrk(32);
//再一次获取内存块 pmem = (char *)malloc(32); if (pmem == NULL) { perror("malloc"); exit (EXIT_FAILURE); } //检查和第一次获取的内存区的起始地址是否一样 printf ("pmem:%p\n", pmem); //计算调整 program break 后的空隙 heap_gap_bss = (long)pmem - (long)&bssvar - 4; printf ("2-gap between heap and bss:%lu\n", heap_gap_bss); //释放内存块 free(pmem); return0; }
下面,我们分别运行两次程序,并查看其输出:
1 2 3 4 5 6 7 8 9 10 11 12
[lehoon@lehoon build]# ./a.out endof bss section:0x601064 pmem:0x2039010 1-gap between heap and bss:27492268 pmem:0x2039010 2-gap between heap and bss:27492268 [lehoon@lehoon build]# ./a.out endof bss section:0x601064 pmem:0xddf010 1-gap between heap and bss:8249260 pmem:0xddf010 2-gap between heap and bss:8249260
[lehoon@lehoon build]# ./brk pmem:0x636010 heap size on each load: 135152 [lehoon@lehoon build]# ./brk pmem:0x636010 heap size on each load: 135152 [lehoon@lehoon build]# ./brk pmem:0x636010 heap size on each load: 135152
从输出看到,每次加载后,堆头部的其实地址都一样了。但我们不需要这么做,每次堆都一样,容易带来缓冲区溢出攻击 (以前老的 linux 内核就是特定地址加载的),所以还是需要保持 randomize_va_space 这个内核变量值为 1 。