Post

(glibc) malloc - 3

* ASLR is disabled

application’s initial heap

프로그램이 malloc()등 직접 heap을 할당받는 코드를 실행하지 않더라도, 기본적으로 ` 0x21000`(132KB) 크기의 initial heap을 가지고 있으며 이 heap은 main_arena에 해당한다.

1
2
3
4
5
6
00400000-00401000 r-xp 00000000 08:01 1442324             /home/umbum/heap\_study/no\_malloc
00600000-00601000 r--p 00000000 08:01 1442324             /home/umbum/heap\_study/no\_malloc
00601000-00602000 rw-p 00001000 08:01 1442324             /home/umbum/heap\_study/no\_malloc
00602000-00623000 rw-p 00000000 00:00 0                   [heap]
7ffff7a0d000-7ffff7bcd000 r-xp 00000000 08:01 548924      /lib/x86\_64-linux-gnu/libc-2.23.so
...

너무 크지 않은 요청에 대해 main_arena에 요청을 처리할 수 있을 정도의 빈 공간이 있는 경우이면 arena의 일부분을 chunk로 반환한다.

1
2
3
4
5
6
==Heap malloc test==
Before malloc

  

After malloc::0x602830  (size:4096)
1
00602000-00623000 rw-p 00000000 00:00 0                   [heap]

mchunkptr은 64bit에서는 0x10이전을 가리키므로, 거기서 부터 출력해보면,

1
2
3
4
gdb-peda$ x/12x 0x602820
0x602820:      0x0000000000000000(prev\_size)     0x0000000000001011(size|flag) => chunk의 시작지점
0x602830:      0x0000000074736574(payload)       0x0000000000000000

payload에는 “test” 문자열이 잘 들어간 것을 확인할 수 있다. size|flag에는 0x1011이 들어갔는데, 요청한 payload size 0x1000size|flag를 나타내기 위한 0x8 bytes를 확보하면서 16의 배수로 align했기 때문에 0x10이 추가되었고, P(0x1) flag가 지정되어 있음을 알 수 있다. 무조건 0x10을 반올림 하는게 아니라 0x8 byte를 확보한 다음 align하는 것이다. 64bit os에서 24만큼 요청하면 24+8이 되어 32가 되므로, align시 추가되는 byte가 없어 0x21이 된다. 25부터 0x31.

heap growth

할당할 heap memory가 부족한 경우 malloc()은 내부적으로 brk() / mmap() system call 중 하나를 호출한다.

MMAP_THRESHOLD가 넘는 크기의 할당을 요청하는 경우 : mmap()

mmap()을 사용해 아예 다른 곳에 메모리를 할당한다. MMAP_THRESHOLD값이 따로 설정되지 않은 경우에는 dynamic하게 결정된다.

1
2
3
4
5
6
==Heap malloc test==
Before malloc

  

After malloc::0x7ffff7fb7010  (size:151552)
1
2
3
4
5
6
7
8
9
10
11
12
00400000-00401000 r-xp 00000000 08:01 1442317             /home/umbum/heap\_study/heap\_test
00600000-00601000 r--p 00000000 08:01 1442317             /home/umbum/heap\_study/heap\_test
00601000-00602000 rw-p 00001000 08:01 1442317             /home/umbum/heap\_study/heap\_test
00602000-00623000 rw-p 00000000 00:00 0                   [heap]
7ffff7a0d000-7ffff7bcd000 r-xp 00000000 08:01 548924      /lib/x86\_64-linux-gnu/libc-2.23.so
7ffff7bcd000-7ffff7dcd000 ---p 001c0000 08:01 548924      /lib/x86\_64-linux-gnu/libc-2.23.so
7ffff7dcd000-7ffff7dd1000 r--p 001c0000 08:01 548924      /lib/x86\_64-linux-gnu/libc-2.23.so
7ffff7dd1000-7ffff7dd3000 rw-p 001c4000 08:01 548924      /lib/x86\_64-linux-gnu/libc-2.23.so
7ffff7dd3000-7ffff7dd7000 rw-p 00000000 00:00 0
7ffff7dd7000-7ffff7dfd000 r-xp 00000000 08:01 548898      /lib/x86\_64-linux-gnu/ld-2.23.so
7ffff7fb7000-7ffff7fe0000 rw-p 00000000 00:00 0              !!!! 여기에 할당 !!!!
...

추가적인 메모리를 할당하기 위해 syscall mmap()을 사용하는 것을 알 수 있다.

1
2
3
4
...
mmap(NULL, 155648, PROT\_READ|PROT\_WRITE, MAP\_PRIVATE|MAP\_ANONYMOUS, -1, 0) = 0x7ffff7fb7000
write(1, "After malloc::0x7ffff7fb7010 \n", 29After malloc::0x7ffff7fb7010 ) = 29
...

free()하면 munmap()을 호출한다.

1
2
munmap(0x7f572c15c000, 155648)          = 0
write(1, "After free\n", 11After free)            = 11
작은 크기를 요청했는데 arena에 공간이 부족한 경우 : brk()

brk()는 program break 위치를 변경해서 data segment size를 조정하는 system call이다. * program break는 uninitialized data segment의 끝 바로 다음 위치를 의미한다. 이를 이용해 top chunk의 크기를 증가시켜 여분의 공간을 확보하거나 줄일 수 있다. * top chunk : arena의 최상단 chunk

1
2
3
4
5
6
7
8
9
10
11
12
==Heap malloc test==
Before malloc

  

After malloc::0x602830  (size:4096)
After malloc::0x603840  (size:4096)
After malloc::0x604850  (size:4096)
.......
After malloc::0x625a60  (size:4096)
After malloc::0x626a70  (size:4096)

initial heap의 size가 증가했다.

1
00602000-00644000 rw-p 00000000 00:00 0                   [heap]

arena를 확장하기 위해 brk()를 사용한다는 것을 알 수 있다.

1
2
3
4
5
...
write(1, "After malloc::0x621a20  (size:40"..., 36After malloc::0x621a20  (size:4096)) = 36
brk(0x644000)                           = 0x644000
write(1, "After malloc::0x622a30  (size:40"..., 36After malloc::0x622a30  (size:4096)) = 36
...

free()에도 brk()를 사용한다

1
2
brk(0x623000)                           = 0x623000
write(1, "After free\n", 11After free)            = 11
This post is licensed under CC BY 4.0 by the author.