아래 글에서 stack canary에 대한 내용을 다뤘습니다. 스택을 깨는 지 점검하는 루틴인데요.
이번에는 다른 디버깅 패치를 작성해서 어떤 루틴이 스택 오염을 시켰는지 점검해보겠습니다.
우선 스택이 깨지는 순서를 살펴보겠습니다.
1. 아래 함수가 처음 실행될 때 순서로 스택을 푸쉬합니다.
current_sp-0x1c--- R14 // 0xC06FAE8C 실행 시 스택 주소(스택 푸쉬 후)
current_sp-0x18--- R3
current_sp-0x14--- R4
current_sp-0x10--- R11
current_sp-0xc---- R12
current_sp-0x8---- LR
current_sp-0x4---- PC
current_sp--------- 0xC06FAE80 주소에서의 스택 주소
해당 코드는 아래와 같습니다.
NSR:C06FAE80|E1A0C00D touch_irq_handler: cpy r12,r13
NSR:C06FAE84|E92DD818 push {r3-r4,r11-r12,r14,pc}
NSR:C06FAE88|E24CB004 sub r11,r12,#0x4 ; r11,r12,#4
NSR:C06FAE8C|E52DE004 push {r14}
2. touch_irq_handler() 함수에서 bald_bsp() 란 함수를 호출했다고 가정할께요.
NSR:C06FDE84|E1A0C00D bald_bsp: cpy r12,r13
NSR:C06FDE88|E92DD818 push {r3-r4, r14}
bald_bsp()의 0xC06FDE88 코드에서 스택 푸쉬를 하고 나면 아래와 같이 스택 푸쉬를 합니다.
current_sp-0x28---- R3 //<<-- bald_bsp()의 0xC06FDE88 코드에서 스택 푸쉬 후 스택 주소
current_sp-0x24---- R4
current_sp-0x20---- R14 // touch_irq_handler에서 bald_bsp()를 호출했으니 touch_irq_handler 함수 내 주소일 것임
current_sp-0x1c--- R14 // 0xC06FAE8C(touch_irq_handler 내) 실행 시 스택 주소(스택 푸쉬 후)
current_sp-0x18--- R3
current_sp-0x14--- R4
current_sp-0x10--- R11
current_sp-0xc---- R12
current_sp-0x8---- LR
current_sp-0x4---- PC
3. bald_bsp() 함수에서 코드를 누군가 잘못 짜서 string copy를 out-of-bound로 처리하면 아래와 같이 스택이 오염됩니다.
current_sp-0x28---- "A"
current_sp-0x24---- "B"
current_sp-0x20---- "C" // R14 // touch_irq_handler에서 bald_bsp()를 호출했으니 touch_irq_handler 함수 내 주소일 것임
current_sp-0x1c--- "D" // 0xC06FAE8C(touch_irq_handler 내) 실행 시 스택 주소(스택 푸쉬 후)
current_sp-0x18--- "E // "R3가 저장된 주소
current_sp-0x14--- "F" // R4 가 저장된 주소
current_sp-0x10--- R11
current_sp-0xc---- R12
current_sp-0x8---- LR
current_sp-0x4---- PC
이제 패치 코드를 작성해 볼 시간입니다. 아래 패치 코드는 touch_irq_handler 함수가 실행되기 직전 스택 주소를 얻어서 스택 덤프를 출력합니다.
diff --git a/drivers/input/touchscreen/touch_core.c b/drivers/input/touchscreen/touch_core.c
index 9cbf6ad..989c6d8 100644
--- a/drivers/input/touchscreen/touch_core.c
+++ b/drivers/input/touchscreen/touch_core.c
@@ -168,10 +168,24 @@ static void touch_core_initialize(struct touch_core_data *ts)
touch_report_all_event(ts);
}
+#define GET_LR *((unsigned long*)(current_sp+0x20))
+#define ADDRESS_OFFSET 4 // this is 4 bit architecture
+static unsigned int push_stack_size = 10; // 0x18 in hexa format
+
+static unsigned long stack_array = 0;
+static unsigned long stack_address_offset = 0;
+
irqreturn_t touch_irq_handler(int irq, void *dev_id)
{
+ register unsigned long current_sp asm ("sp");
struct touch_core_data *ts = (struct touch_core_data *) dev_id;
+ printk("==== start dump stack dump ==== \n");
+ for( stack_array = 0; stack_array < push_stack_size; stack_array++) {
+ stack_address_offset = stack_array * ADDRESS_OFFSET;
+ printk("[0x%lx] = 0x%lx \n", current_sp + stack_address_offset, *((unsigned long*)(current_sp + stack_address_offset)) );
+ }
+
bald_bsp();
+ printk("==== start dump stack dump ==== \n");
+ for( stack_array = 0; stack_array < push_stack_size; stack_array++) {
+ stack_address_offset = stack_array * ADDRESS_OFFSET;
+ printk("[0x%lx] = 0x%lx \n", current_sp + stack_address_offset, *((unsigned long*)(current_sp + stack_address_offset)) );
+ }
+
위 패치의 핵심 코드는 #define GET_LR *((unsigned long*)(current_sp+0x20))인데, 패치 코드를 반영하고 나서 스택 푸쉬되는 바이트를 0x20로 계산했습니다.
NSR:C06FAE80|E1A0C00D touch_irq_handler: cpy r12,r13
NSR:C06FAE84|E92DD818 push {r3-r4,r11-r12,r14,pc}
NSR:C06FAE88|E24CB004 sub r11,r12,#0x4 ; r11,r12,#4
NSR:C06FAE8C|E52DE004 push {r14}
위 패치를 빌드해서 커널 로그를 받아보면 아래와 같이 bald_bsp() 함수가 호출된 후 스택 덤프가 깨져 있습니다.
<6>[ 154.878931 / 02-06 16:59:35.892][0] ==== start dump stack dump ====
<6>[ 154.878960 / 02-06 16:59:35.892][0] [0xc5233b58] = 0xc06fae80
<6>[ 154.878976 / 02-06 16:59:35.892][0] [0xc5233b5c] = 0xc4226e80
<6>[ 154.878992 / 02-06 16:59:35.892][0] [0xc5233b60] = 0xe1
<6>[ 154.879007 / 02-06 16:59:35.892][0] [0xc5233b64] = 0x0
<6>[ 154.879022 / 02-06 16:59:35.892][0] [0xc5233b68] = 0xc5233bb4
<6>[ 154.879037 / 02-06 16:59:35.892][0] [0xc5233b6c] = 0xc5233b78
<6>[ 154.879052 / 02-06 16:59:35.892][0] [0xc5233b70] = 0xc0085440
<6>[ 154.879067 / 02-06 16:59:35.892][0] [0xc5233b74] = 0xc06fae8c
<6>[ 154.879083 / 02-06 16:59:35.892][0] [0xc5233b78] = 0x20000193
<6>[ 154.879098 / 02-06 16:59:35.892][0] [0xc5233b7c] = 0xc0f72564
<6>[ 154.895630 / 02-06 16:59:35.912][0] ==== start dump stack dump ====
<6>[ 154.895660 / 02-06 16:59:35.912][0] [0xc5233e58] = 0xA
<6>[ 154.895676 / 02-06 16:59:35.912][0] [0xc5233e5c] = 0xB
<6>[ 154.895691 / 02-06 16:59:35.912][0] [0xc5233e60] = 0xC
<6>[ 154.895706 / 02-06 16:59:35.912][0] [0xc5233e64] = 0xD
<6>[ 154.895723 / 02-06 16:59:35.912][0] [0xc5233e68] = 0xE
<6>[ 154.895740 / 02-06 16:59:35.912][0] [0xc5233e6c] = 0xF
<6>[ 154.895755 / 02-06 16:59:35.912][0] [0xc5233e70] = 0x10
<6>[ 154.895771 / 02-06 16:59:35.912][0] [0xc5233e74] = 0x11
<6>[ 154.895786 / 02-06 16:59:35.912][0] [0xc5233e78] = 0x12
<6>[ 154.895801 / 02-06 16:59:35.912][0] [0xc5233e7c] = 0x13
이런 방식으로 분석하면 어떤 함수가 스택을 깨는 지 점검할 수 있습니다.
'[Debugging] Tips' 카테고리의 다른 글
crash-utility(crashtool) - runq awk 명령어 (0) | 2023.05.04 |
---|---|
[crash-utility] wakelock 디버깅(rbtree: wakelocks_tree) (0) | 2023.05.04 |
[Kernel] wakelock debug patch (0) | 2023.05.04 |
[Kernel][Debug] 런큐에서 CFS 스케쥴러에 큐잉된 프로세스 찾기 (0) | 2023.05.04 |
[Trace32] 폰트 색상 변경 - setup.color (0) | 2023.05.04 |