malloc中的系統調用brk和mmap
環境
-
ubuntu14.04
-
malloc通過系統調用的方式從操作系統申請內存,malloc內部又通過系統調用brk()或mmap來申請內存的。入下圖進程虛擬內存布局所示,mmap對應Memory Mapping Segment,brk對應Heap.
brk
-
brk通過增加program break的位置(brk)從內核申請(非零值初始化)內存。一開始堆段(heap segment)的其實位置(start_brk)和結束位置(brk)指向同一個位置。
- 當ASLR(Address Space Layout Randomization)關閉時,start_brk和brk同時指向data/bss段的結束位置(end_data)
- 當ASLR打開時,start_brk和brk同時指向data/bss段的結束位置(end_data)再加上一個隨機的brk偏移。
-
上面的進程虛擬內存布局展示了,start_brk是堆段的開始位置 ,brk(program break)是堆棧的結束位置。
例子
/* sbrk, brk 例子 */
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main()
{
void *curr_brk, *tmp_brk = NULL;
printf("Welcome to sbrk example:%d\n", getpid());
/* sbrk(0) 獲取當前 program break 位置 */
tmp_brk = curr_brk = sbrk(0);
printf("Program Break Location1:%p\n", curr_brk);
getchar();
/* 使用 brk 增加 program break 位置 */
brk(curr_brk+4096);
curr_brk = sbrk(0);
printf("Program break Location2:%p\n", curr_brk);
getchar();
/* 使用 brk 減小 program break 位置 */
brk(tmp_brk);
curr_brk = sbrk(0);
printf("Program Break Location3:%p\n", curr_brk);
getchar();
return 0;
}
-
在增加program break之前,輸出如下:
-
start_brk=brk=end_data=0x602000
-
在增加program break之后,輸入如下:
-
start_brk=end_data=0x602000,brk=0x603000.
-
可以觀察到堆段
00602000-00603000 rw-p 00000000 00:00 0 [heap]
- 00602000-00603000是堆段的虛擬地址范圍
- rw-p的標准含義是Read、Write、 NoeXecute、Private
- 00000000 是文件偏移量,由於沒有映射任何文件所以為0
- 00:00 是major/minor device number,由於沒有映射任何文件所以為0
- 0是inode 也是沒有映射任何文件所以為0
- 【heap】是堆段
mmap
- malloc使用mmap創建一個私有匿名的映射段,這個映射段的主要目的是申請一塊(零值初始化的)新內存,並且這塊內存只能被調用的這個進程獨占使用。
/* 使用mmap系統調用做私有匿名映射的例子 */
#include <stdio.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
void static inline errExit(const char* msg)
{
printf("%s failed. Exiting the process\n", msg);
exit(-1);
}
int main()
{
int ret = -1;
printf("Welcome to private anonymous mapping example::PID:%d\n", getpid());
printf("Before mmap\n");
getchar();
char* addr = NULL;
addr = mmap(NULL, (size_t)132*1024, PROT_READ|PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (addr == MAP_FAILED)
errExit("mmap");
printf("After mmap\n");
getchar();
/* Unmap mapped region. */
ret = munmap(addr, (size_t)132*1024);
if(ret == -1)
errExit("munmap");
printf("After munmap\n");
getchar();
return 0;
}
-
調用mmap之前:可以看到,屬於libc.so和ld-linux.so共享庫的內存映射段。
-
調用mmap之后:如下我們可以看到,mmap映射的內存段已經從上圖紅色框內分配出去(0xe0000-0xbf000=0x21000).
- 調用munmap之后,如下輸出可以看到mmap已經被解除映射了。
- 以上實現ASLR是關閉的sudo sh -c "echo 0 > /proc/sys/kernel/randomize_va_space"
- 原文地址:
- https://sploitfun.wordpress.com/2015/02/11/syscalls-used-by-malloc/
- https://www.pengrl.com/p/20032/