Arm Linux Kernel Hacks

rousalome.egloos.com

포토로그 Kernel Crash


통계 위젯 (화이트)

11105
637
415734


[Linux][Kernel] 슬랩 메모리: kfree 소개 [Linux][Kernel] MM

# 리눅스 커널 Memory Management


이번에는 kfree에 대해서 알아봅니다. 이번에도 패치 코드를 하나 작성할게요.


이번에는 kmalloc 함수로 메모리를 할당 kfree 함수를 호출해서 메모리를 해제합니다. 그리고 바로 커널 크래시를 유발하죠.

 

커널 크래시가 발생하면 코어 덤프(vmcore) 생깁니다. 파일을 Trace32 올려서 메모리 해제 어떤 동작을 하는 상세히 알아 보려고 하거든요.

 

우선 할당된 메모리 주소는 0xE7AE1300입니다.

(static u32 *) austin_debug_data = 0xE7AE1300


0xE7AE1300 메모리 공간은 어떤 값들로 구성됐는지 알아볼까요?

_____address|_data________|value_____________|symbol

NSD:E7AE1300|6B 6B 6B 6B  0x6B6B6B6B

NSD:E7AE1304|6B 6B 6B 6B  0x6B6B6B6B

NSD:E7AE1308|6B 6B 6B 6B  0x6B6B6B6B

NSD:E7AE130C|6B 6B 6B 6B  0x6B6B6B6B

NSD:E7AE1310|6B 6B 6B 6B  0x6B6B6B6B

NSD:E7AE1314|6B 6B 6B 6B  0x6B6B6B6B

NSD:E7AE1318|6B 6B 6B 6B  0x6B6B6B6B

//...

NSD:E7AE16F8|6B 6B 6B 6B  0x6B6B6B6B

NSD:E7AE16FC|6B 6B 6B A5  0xA56B6B6B

NSD:E7AE1700|BB BB BB BB  0xBBBBBBBB

NSD:E7AE1704|40 0E AE E7  0xE7AE0E40

NSD:E7AE1708|AC 68 43 C0  0xC04368AC       \\kernel_bsp_debug_stat_set+0x134

NSD:E7AE170C|F0 EB 14 C0  0xC014EBF0       \\kmem_cache_alloc_trace+0xB8

NSD:E7AE1710|AC 68 43 C0  0xC04368AC         \\kernel_bsp_debug_stat_set+0x134

NSD:E7AE1714|10 EF 17 C0  0xC017EF10         \\vmlinux\libfs\simple_attr_write+0xD4

NSD:E7AE1718|60 A7 15 C0  0xC015A760         \\vmlinux\fs/read_write\vfs_write+0xC8

NSD:E7AE171C|EC AB 15 C0  0xC015ABEC         \\vmlinux\fs/read_write\sys_write+0x4C

NSD:E7AE1720|00 F3 00 C0  0xC000F300         \\vmlinux\Global\ret_fast_syscall

NSD:E7AE1724|00 00 00 00  0x0

NSD:E7AE1728|00 00 00 00  0x0

NSD:E7AE172C|00 00 00 00  0x0

NSD:E7AE1730|00 00 00 00  0x0

NSD:E7AE1734|00 00 00 00  0x0

NSD:E7AE1738|00 00 00 00  0x0

NSD:E7AE173C|00 00 00 00  0x0

NSD:E7AE1740|00 00 00 00  0x0

NSD:E7AE1744|00 00 00 00  0x0

NSD:E7AE1748|00 00 00 00  0x0

NSD:E7AE174C|07 00 00 00  0x7              

NSD:E7AE1750|85 16 00 00  0x1685

NSD:E7AE1754|96 20 00 00  0x2096

NSD:E7AE1758|98 F3 3C C0  0xC03CF398         \\perform_memory_free+0x50

NSD:E7AE175C|40 FA 14 C0  0xC014FA40         \\vmlinux\slub\kfree+0x238

NSD:E7AE1760|98 F3 3C C0  0xC03CF398         \\perform_memory_free+0x50

NSD:E7AE1764|2C C2 F5 C0  0xC0F5C22C         \watchdog_kthread+0xF4

NSD:E7AE1768|48 AA 04 C0  0xC004AA48         \\kthread+0xF8

NSD:E7AE176C|D0 F3 00 C0  0xC000F3D0         \\ ret_from_fork+0x14

NSD:E7AE1770|00 00 00 00  0x0

NSD:E7AE1774|00 00 00 00  0x0

NSD:E7AE1778|00 00 00 00  0x0

NSD:E7AE177C|00 00 00 00  0x0

NSD:E7AE1780|00 00 00 00  0x0

NSD:E7AE1784|00 00 00 00  0x0

NSD:E7AE1788|00 00 00 00  0x0

NSD:E7AE178C|00 00 00 00  0x0

NSD:E7AE1790|00 00 00 00  0x0

NSD:E7AE1794|00 00 00 00  0x0

NSD:E7AE1798|00 00 00 00  0x0

NSD:E7AE179C|07 00 00 00  0x7            

NSD:E7AE17A0|42 00 00 00  0x42            

NSD:E7AE17A4|36 28 00 00  0x2836

NSD:E7AE17A8|5A 5A 5A 5A  0x5A5A5A5A

NSD:E7AE17AC|5A 5A 5A 5A  0x5A5A5A5A

NSD:E7AE17B0|5A 5A 5A 5A  0x5A5A5A5A

NSD:E7AE17B4|5A 5A 5A 5A  0x5A5A5A5A

NSD:E7AE17B8|5A 5A 5A 5A  0x5A5A5A5A

NSD:E7AE17BC|5A 5A 5A 5A  0x5A5A5A5A


그런데 한 가지 희한한 점이 있어요. 메모리 공간에0x6B란 값이 꽉 채워져 있잖아요.

kmalloc으로 할당한 메모리를 해제하면 해당 메모리 공간을 0x6b로 채워 넣습니다.

 

이 헥사 값은 POISON_FREE 매크로로 정의됐는데 이미 해제한 메모리를 뜻합니다.

[include/linux/poison.h]

#define POISON_FREE 0x6b


그럼 이런 헥사 값을 왜 채워 넣을까요조금 후 다른 프로세스에서 1024 크기 만큼 메모리 할당을 요청하면 이 메모리 공간을 다음에 할당합니다.

그 때 이 메모리 공간에는 당연히 0x6b 값으로 채워져 있겠죠. 그럼 만약0x6b가 아니라 다른 값이 있으면 어떻게 해석해야 할까요?

 

리눅스 커널은 이 때 메모리가 오염됐다고 판단하고 커널 크래시를 유발합니다. 메모리 오염이라. 좀 애매한 소리죠.

좀 더 구체적으로 설명하면 메모리를 할당하지 않고 메모리를 접근하는 경우를 예를 들 수 있습니다..

그럼 0xE7AE1300 메모리 공간부터 0xE7AE16FC 까지 0x6b로 덮혀 있는 구간까지 살펴볼게요.
_____address|_data________|value_____________|symbol
NSD:E7AE1300| 6B 6B 6B 6B  0x6B6B6B6B
NSD:E7AE1304| 6B 6B 6B 6B  0x6B6B6B6B
NSD:E7AE1308| 6B 6B 6B 6B  0x6B6B6B6B
NSD:E7AE130C| 6B 6B 6B 6B  0x6B6B6B6B
NSD:E7AE1310| 6B 6B 6B 6B  0x6B6B6B6B
NSD:E7AE1314| 6B 6B 6B 6B  0x6B6B6B6B
NSD:E7AE1318| 6B 6B 6B 6B  0x6B6B6B6B
//...
NSD:E7AE16F8| 6B 6B 6B 6B  0x6B6B6B6B
NSD:E7AE16FC| 6B 6B 6B A5  0xA56B6B6B

정확히 메모리를 할당한 사이즈 1024 = 0x400(0xE7AE1700 - 0xE7AE1300) 만큼 0x6B를 채우고 있습니다.
그런데 E7AE16FC 메모리에 0xA56B6B6B 와 같이 첫번째 바이트에 0xA5가 나타났습니다.

이는 아래 코드 같이 메모리 공간에 채운 포이즌 값의 끝을 알려주는 포이즌 값입니다.
[include/linux/poison.h]
#define POISON_END 0xa5 /* end-byte of poisoning */

# Reference: For more information on 'Linux Kernel';

디버깅을 통해 배우는 리눅스 커널의 구조와 원리. 1

디버깅을 통해 배우는 리눅스 커널의 구조와 원리. 2




핑백

덧글

댓글 입력 영역