Arm Linux Kernel Hacks

rousalome.egloos.com

포토로그 Kernel Crash


통계 위젯 (화이트)

1148
469
422441


[0410] Slab Memory Corruption Case Study#1 - 디버깅(2) [Linux][Kernel] MM


여기까지 커널 로그의 의미를 알아봤으니 이제는 슬랩 오브젝트가 오염돼서 커널 크래시 디버깅을 할 차례입니다.
[701.043491][7] BUG kmalloc-512 (Tainted: G        W     ): Poison overwritten
[701.043515][7] -----------------------------------------------------------------------------
[701.043515][7] 
[701.043550][7] INFO: 0xe411ec00-0xe411ec92. First byte 0x87 instead of 0x6b
 
위와 같이 커널 크래시 발생 전 로그를 보면 가장 먼저 슬랩 오브젝트 종류(kmalloc-512)이 오브젝트 메모리 시작 주소를 알려줍니다. 시작 주소는 0xe411ec00인데 이 메모리 주소에 0x6b이란 포이즌 값이 있어야 하는데 0x87이라는 게 문제였죠.

그럼 0xe411ec00 메모리 공간 전 후로 어떤 메모리 덤프 값인지 조금 더 상세히 볼까요?
희한한 점은 할당하려는 슬랩 오브젝트 메모리 주소가 0xE411EC00 인데 이 메모리 주소 전 후로 계속 0x87878787 값이네요. 뭔가 이상합니다.
_____address|_data________|value______|symbol
1  NSD:E411EBE8| 87 87 87 87  0x87878787
2  NSD:E411EBEC| 87 87 87 87  0x87878787
3  NSD:E411EBF0| 87 87 87 87  0x87878787
4  NSD:E411EBF4| 87 87 87 87  0x87878787
5  NSD:E411EBF8| 87 87 87 87  0x87878787
6  NSD:E411EBFC| 87 87 87 87  0x87878787
7  NSD:E411EC00| 87 87 87 87  0x87878787
8  NSD:E411EC04| 87 87 87 87  0x87878787
9  NSD:E411EC08| 87 87 87 87  0x87878787
10 NSD:E411EC0C| 87 87 87 87  0x87878787
11 NSD:E411EC10| 87 87 87 87  0x87878787
12//..
13 NSD:E411EC7C| 87 87 87 87  0x87878787
14 NSD:E411EC80| 87 87 87 87  0x87878787
15 NSD:E411EC84| 87 87 87 87  0x87878787
16 NSD:E411EC88| 87 87 87 87  0x87878787
17 NSD:E411EC8C| 87 87 87 87  0x87878787
18 NSD:E411EC90| 87 87 87 6B  0x6B878787
19 NSD:E411EC94| 6B 6B 6B 6B  0x6B6B6B6B
20 NSD:E411EC98| 6B 6B 6B 6B  0x6B6B6B6B
21 NSD:E411EC9C| 6B 6B 6B 6B  0x6B6B6B6B
22 NSD:E411ECA0| 6B 6B 6B 6B  0x6B6B6B6B
23 NSD:E411ECA4| 6B 6B 6B 6B  0x6B6B6B6B
24 NSD:E411ECA8| 6B 6B 6B 6B  0x6B6B6B6B
25 NSD:E411ECAC| 6B 6B 6B 6B  0x6B6B6B6B
26 NSD:E411ECB0| 6B 6B 6B 6B  0x6B6B6B6B
27 NSD:E411ECB4| 6B 6B 6B 6B  0x6B6B6B6B
28 NSD:E411ECB8| 6B 6B 6B 6B  0x6B6B6B6B
29 NSD:E411ECBC| 6B 6B 6B 6B  0x6B6B6B6B
30 NSD:E411ECC0| 6B 6B 6B 6B  0x6B6B6B6B
31 NSD:E411ECC4| 6B 6B 6B 6B  0x6B6B6B6B
 
이제부터 크래시 유틸리티 프로그램으로 슬랩 디버깅을 할 차례입니다.
크래시 유틸리티 프로그램의 가장 강력한 기능 중 하나가 슬랩 오브젝트 디버깅이거든요.

그럼 0xe411ec00 메모리 속성을 알아볼까요? 
[701.043491][7] BUG kmalloc-512 (Tainted: G        W     ): Poison overwritten
[701.043515][7] -----------------------------------------------------------------------------
[701.043515][7] 
[701.043550][7] INFO: 0xe411ec00-0xe411ec92. First byte 0x87 instead of 0x6b  

이를 알아보기 위해 "kmem [메모리 주소]" 명령어를 입력합니다. 
1 crash> kmem 0xe411ec00
2 CACHE    NAME                 OBJSIZE  ALLOCATED     TOTAL  SLABS  SSIZE
3 eac023c0 kmalloc-512              512       2914      3772    164    16k
4  SLAB      MEMORY    NODE  TOTAL  ALLOCATED  FREE
5  ec797e00  e411c000     0     23         23     0
6  FREE / [ALLOCATED]
7  [e411ec00]

8  PAGE    PHYSICAL   MAPPING    INDEX CNT FLAGS
9 ec797f00  a411e000         0         0  0 8000 tail

세번째 줄 메시지에서 이 메모리는 "kmalloc-512" 타입의 슬랩이라고 알려주네요. 
3 eac023c0 kmalloc-512              512       2914      3772    164    16k
 
그 다음 6번과 7번째 줄 디버깅 정보를 유심히 봐야 합니다.
6  FREE / [ALLOCATED]
7  [e411ec00]
 
이 슬랩 오브젝트는 메모리를 할당한 상태([ALLOCATED])이며 해당 오브젝트가 시작하는 주소는 e411ec00란 의미입니다. 처음 커널 로그에서 봤던 디버깅 정보와 일치하죠. "INFO: 0xe411ec00-0xe411ec92"
[701.043491][7] BUG kmalloc-512 (Tainted: G        W     ): Poison overwritten
[701.043515][7] -----------------------------------------------------------------------------
[701.043515][7] 
[701.043550][7] INFO: 0xe411ec00-0xe411ec92. First byte 0x87 instead of 0x6b  
 
그런데 0xe411ec00 메모리 공간 이전 주소인 E411EBFC 메모리 주소에도 0x87878787란 값이 담겨져 있습니다.
1  NSD:E411EBE8| 87 87 87 87  0x87878787
2  NSD:E411EBEC| 87 87 87 87  0x87878787
3  NSD:E411EBF0| 87 87 87 87  0x87878787
4  NSD:E411EBF4| 87 87 87 87  0x87878787
5  NSD:E411EBF8| 87 87 87 87  0x87878787
6  NSD:E411EBFC| 87 87 87 87  0x87878787
7  NSD:E411EC00| 87 87 87 87  0x87878787
8  NSD:E411EC04| 87 87 87 87  0x87878787
 
뭔가 0xe411ebfc 이전 메모리 주소에서 0xe411ec00 메모리를 오염시키는 것 같은데요.
그럼 0xe411ebfc 메모리 속성을 볼까요? 그럼 다음 명령어를 입력해서 알아볼께요.
crash> kmem 0xe411ebfc
CACHE    NAME                 OBJSIZE  ALLOCATED     TOTAL  SLABS  SSIZE
eac023c0 kmalloc-512              512       2914      3772    164    16k
  SLAB      MEMORY    NODE  TOTAL  ALLOCATED  FREE
  ec797e00  e411c000     0     23         23     0
  FREE / [ALLOCATED]
  [e411e940]

  PAGE    PHYSICAL   MAPPING    INDEX CNT FLAGS
ec797f00  a411e000         0         0  0 8000 tail
 
여기서 아주 유용한 디버깅 정보가 보입니다. "kmalloc-512" 이란 슬랩인데 e411e940 메모리 공간부터 시작하군요.
또한 이 슬랩은 이미 할당한 슬랩 메모리 속성입니다.

그럼 0xe411e940 메모리 덤프가 어떤 값인지 알아볼까요?
_____address|_data________|value_____________|symbol
NSD:E411E938| 87 87 87 87  0x87878787
NSD:E411E93C| 87 87 87 87  0x87878787
NSD:E411E940| 87 87 87 87  0x87878787
NSD:E411E944| 87 87 87 87  0x87878787
NSD:E411E948| 87 87 87 87  0x87878787
NSD:E411E94C| 87 87 87 87  0x87878787
NSD:E411E950| 87 87 87 87  0x87878787
NSD:E411E954| 87 87 87 87  0x87878787
NSD:E411E958| 87 87 87 87  0x87878787
NSD:E411E95C| 87 87 87 87  0x87878787
NSD:E411E960| 87 87 87 87  0x87878787
NSD:E411E964| 87 87 87 87  0x87878787
NSD:E411E968| 87 87 87 87  0x87878787
NSD:E411E96C| 87 87 87 87  0x87878787
NSD:E411E970| 87 87 87 87  0x87878787
NSD:E411E974| 87 87 87 87  0x87878787
NSD:E411E978| 87 87 87 87  0x87878787
NSD:E411E97C| 87 87 87 87  0x87878787
NSD:E411E980| 87 87 87 87  0x87878787
NSD:E411E984| 87 87 87 87  0x87878787
NSD:E411E988| 87 87 87 87  0x87878787
NSD:E411E98C| 87 87 87 87  0x87878787
NSD:E411E990| 87 87 87 87  0x87878787
NSD:E411E994| 87 87 87 87  0x87878787
NSD:E411E998| 87 87 87 87  0x87878787
NSD:E411E99C| 87 87 87 87  0x87878787
NSD:E411E9A0| 87 87 87 87  0x87878787
NSD:E411E9A4| 87 87 87 87  0x87878787
NSD:E411E9A8| 87 87 87 87  0x87878787
NSD:E411E9AC| 87 87 87 87  0x87878787
NSD:E411E9B0| 87 87 87 87  0x87878787
NSD:E411E9B4| 87 87 87 87  0x87878787
NSD:E411E9B8| 87 87 87 87  0x87878787
NSD:E411E9BC| 87 87 87 87  0x87878787
NSD:E411E9C0| 87 87 87 87  0x87878787
NSD:E411E9C4| 87 87 87 87  0x87878787
NSD:E411E9C8| 87 87 87 87  0x87878787
NSD:E411E9CC| 87 87 87 87  0x87878787
NSD:E411E9D0| 87 87 87 87  0x87878787
NSD:E411E9D4| 87 87 87 87  0x87878787
NSD:E411E9D8| 87 87 87 87  0x87878787
NSD:E411E9DC| 87 87 87 87  0x87878787
NSD:E411E9E0| 87 87 87 87  0x87878787
NSD:E411E9E4| 87 87 87 87  0x87878787
NSD:E411E9E8| 87 87 87 87  0x87878787
NSD:E411E9EC| 87 87 87 87  0x87878787
NSD:E411E9F0| 87 87 87 87  0x87878787
NSD:E411E9F4| 87 87 87 87  0x87878787
NSD:E411E9F8| 87 87 87 87  0x87878787
NSD:E411E9FC| 87 87 87 87  0x87878787
NSD:E411EA00| 87 87 87 87  0x87878787
NSD:E411EA04| 87 87 87 87  0x87878787
NSD:E411EBF8| 87 87 87 87  0x87878787
NSD:E411EBFC| 87 87 87 87  0x87878787
NSD:E411EC00| 87 87 87 87  0x87878787
NSD:E411EC04| 87 87 87 87  0x87878787

위 메모리 덤프에서 다음과 같은 정보를 얻어 낼 수 있습니다.
1. 이 슬랩 오브젝트가 위치한 E411E940--E411EBF8 메모리 공간은 0x87878787 값으로 덮혀 있습니다.
2. 이 슬랩 오브젝트는 이미 할당 됐습니다. 그런데 이 메모리 덤프 안에 (struct track*)에 대응하는 메모리 할당 정보도 없습니다. 
3. E411E940 이전 메모리 공간인 E411E938/E411E93C 에 있는 덤프 값을 봐도 0x87878787으로 돼있군요.
 
정리하면 E411E940 메모리 이전에 누군가가 0x87878787 값으로 이 메모리를 오염시킨 것 같군요.

그럼 E411E93C 메모리 속성을 알아볼까요?
crash> kmem E411E93C
CACHE    NAME                 OBJSIZE  ALLOCATED     TOTAL  SLABS  SSIZE
eac023c0 kmalloc-512              512       2914      3772    164    16k
  SLAB      MEMORY    NODE  TOTAL  ALLOCATED  FREE
  ec797e00  e411c000     0     23         23     0
  FREE / [ALLOCATED]
  [e411e680]

  PAGE    PHYSICAL   MAPPING    INDEX CNT FLAGS
ec797f00  a411e000         0         0  0 8000 tail

이번에도 "kmalloc-512" 타입의 슬랩인데 e411e680 메모리 주소가 시작점이라는 군요. 
물론 이미 할당된 슬랩 오브젝트라고 합니다. 
_____address|value_____________|symbol
NSD:E411E618|0xC0D55730         \\vmlinux\skbuff\skb_free_head+0x68
NSD:E411E61C|0xC014FA40         \\vmlinux\slub\kfree+0x238
NSD:E411E620|0xC0D55730         \\vmlinux\skbuff\skb_free_head+0x68
NSD:E411E624|0xC0D55964         \\vmlinux\skbuff\skb_release_data+0xCC
NSD:E411E628|0xC0D5599C         \\vmlinux\skbuff\skb_release_all+0x30
NSD:E411E62C|0xC0D559BC         \\vmlinux\skbuff\__kfree_skb+0x1C
NSD:E411E630|0xC0D55B58         \\vmlinux\skbuff\consume_skb+0xE8
NSD:E411E634|0xC0D5BF0C         \\vmlinux\core/datagram\skb_free_datagram+0x20
NSD:E411E638|0xC0E58B08         \\vmlinux\af_unix\unix_dgram_recvmsg\out_unlock
NSD:E411E63C|0xC0E58B60         \\vmlinux\af_unix\unix_seqpacket_recvmsg+0x38
NSD:E411E640|0xC0D4DBD0         \\vmlinux\socket\sock_recvmsg+0xA8
NSD:E411E644|0xC0D4FEC8         \\vmlinux\socket\sys_recvfrom+0xD4
NSD:E411E648|0xC000F300         \\vmlinux\Global\ret_fast_syscall
NSD:E411E64C|0x0
NSD:E411E650|0x0
NSD:E411E654|0x0
NSD:E411E658|0x0
NSD:E411E65C|0x6                 
NSD:E411E660|0x18EA
NSD:E411E664|0x3B3F
NSD:E411E668|0x5A5A5A5A
NSD:E411E66C|0x5A5A5A5A
NSD:E411E670|0x5A5A5A5A
NSD:E411E674|0x5A5A5A5A
NSD:E411E678|0x5A5A5A5A
NSD:E411E67C|0x5A5A5A5A
NSD:E411E680|0x87878787
NSD:E411E684|0x87878787
NSD:E411E688|0x87878787
NSD:E411E68C|0x87878787
NSD:E411E690|0x87878787
 
이번에는 뭔가 다른 메모리 덤프가 보입니다. E411E680 메모리 주소부터 0x87878787란 값이 보이네요.
E411E680 메모리 주소 이전 주소부터 0x5A5A5A5A란 슬랩 오브젝트 경계를 알려주는 패딩 값이 제대로 보이는군요.
또한 슬랩 메모리 프로파일링 정보도 E411E61C 주소부터 저장됐구요.

여기까지 얻은 디버깅 정보로 정리를 해볼게요.
0xe411e680 주소부터 써진 0x87878787 이란 값이 다음 슬랩 오브젝트 메모리 공간까지 밀려서 오염시킨 정보를 확인할 수 있습니다.  
0xe411e680 -> 0xe411e940 -> 0xe411ec00 
[701.043491][7] BUG kmalloc-512 (Tainted: G        W     ): Poison overwritten
[701.043515][7] -----------------------------------------------------------------------------
[701.043515][7] 
[701.043550][7] INFO: 0xe411ec00-0xe411ec92. First byte 0x87 instead of 0x6b 
 
이런 메모리 패턴을 리눅스 커널 커뮤니티에서는 out-of-bound copy라고도 합니다.

그럼 0xe411e680 슬랩 오브젝트가 메모리를 오염시킨 정보를 확인했습니다.
이제는 어떤 코드가 이런 문제를 일으켰는지 알아볼 시간입니다.

슬랩 오브젝트는 대부분 포인터 변수가 가르키므로, 0xe411e680 슬랩 오브젝트를 누가 가르키고 있는지 알아봐야 합니다. 이를 위해 크래시 유틸리티 프로그램에서 제공하는 search란 기능을 활용하려 합니다.

다음 명령어를 입력하면 커널 메모리 공간에서 e411e680 주소를 담고 있는 주소를 출력합니다.
crash> search e411e680
c1c7d2bc: e411e680
d56cdc2c: e411e680
d56cdccc: e411e680
e411fbc4: e411e680
 
커맨드 입력 결과 4군데에서 e411e680 주소를 가르키고 있군요.

이 4군데 주소 중 c1c7d2bc 주소가 어떤 유형인지 알아보기 위해 다음 kmem 명령어를 입력합니다.
crash> kmem c1c7d2bc
c1c7d2bc (B) austin_debug_mem_data

  PAGE    PHYSICAL   MAPPING    INDEX CNT FLAGS
eb672e80  81c7d000         0         0  1 400 reserved

crash> p austin_debug_mem_data
austin_debug_mem_data = $1 = (u32 *) 0xe411e680
 
오라, austin_debug_mem_data이란 포인터 타입의 전역 변수가 0xe411e680를 가르키고 있군요.

해당 코드를 열어 보고 슬랩 메모리를 오염시키 주범을 찾았습니다. 
512 바이트 만큼 메모리를 할당하고 1555 바이트 만큼 메모리를 0x87 복사하고 있습니다. 
u32 *austin_debug_data;

109        austin_debug_mem_data = kmalloc(512, GFP_KERNEL);
110        memset(austin_debug_mem_data, 0x87, 1555);

말 그대로 out-of-bound 동작 오류로 슬랩 오브젝트 오염을 시켰군요.


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

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

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






핑백

덧글

댓글 입력 영역