벌써 18번째 인가... 사실 더 있지만 귀찮아서 안하다 보니.. ㅋㅋ
이번엔 GPU/DRM 관련 버그.. 상당히 따끈따근한 새 버그에 대해서 Digging 해 본다.
KERNEL: /share/linuxrpm/vmlinux_repo/64/4.14.35-1818.3.3.el7uek.x86_64/vmlinux
DUMPFILE: vmcore [PARTIAL DUMP]
CPUS: 16
DATE: Tue Apr 16 15:42:21 2019
UPTIME: 6 days, 01:18:20
LOAD AVERAGE: 0.00, 0.00, 0.00
TASKS: 330
NODENAME: *********
RELEASE: 4.14.35-1818.3.3.el7uek.x86_64
VERSION: #2 SMP Mon Sep 24 14:45:01 PDT 2018
MACHINE: x86_64 (3600 Mhz)
MEMORY: 63.3 GB
PANIC: "general protection fault: 0000 [#1] SMP PTI"
PID: 14887
COMMAND: "plymouthd"
TASK: ffff994e9c1adc40 [THREAD_INFO: ffff994e9c1adc40]
CPU: 2
STATE: TASK_RUNNING (PANIC)
crash7latest> mod -s drm usr/lib/debug/lib/modules/4.14.35-1818.3.3.el7uek.x86_64/kernel/drivers/gpu/drm/drm.ko.debug
MODULE NAME SIZE OBJECT FILE
ffffffffc0306b00 drm 385024 usr/lib/debug/lib/modules/4.14.35-1818.3.3.el7uek.x86_64/kernel/drivers/gpu/drm/drm.ko.debug
crash7latest> mod -s drm_kms_helper usr/lib/debug/lib/modules/4.14.35-1818.3.3.el7uek.x86_64/kernel/drivers/gpu/drm/drm_kms_helper.ko.debug
MODULE NAME SIZE OBJECT FILE
ffffffffc0600500 drm_kms_helper 163840 usr/lib/debug/lib/modules/4.14.35-1818.3.3.el7uek.x86_64/kernel/drivers/gpu/drm/drm_kms_helper.ko.debug
모듈을 불러와준다.
crash7latest> bt -l
PID: 14887 TASK: ffff994e9c1adc40 CPU: 2 COMMAND: "plymouthd"
#0 [ffffa5a8096e7908] machine_kexec at ffffffffbd066191
/usr/src/debug/kernel-4.14.35/linux-4.14.35-1818.3.3.el7uek/arch/x86/kernel/machine_kexec_64.c: 342
#1 [ffffa5a8096e7968] __crash_kexec at ffffffffbd12f4c2
/usr/src/debug/kernel-4.14.35/linux-4.14.35-1818.3.3.el7uek/kernel/kexec_core.c: 947
#2 [ffffa5a8096e7a38] crash_kexec at ffffffffbd13061c
/usr/src/debug/kernel-4.14.35/linux-4.14.35-1818.3.3.el7uek/include/linux/compiler.h: 206
#3 [ffffa5a8096e7a58] oops_end at ffffffffbd03148a
/usr/src/debug/kernel-4.14.35/linux-4.14.35-1818.3.3.el7uek/arch/x86/kernel/dumpstack.c: 278
#4 [ffffa5a8096e7a80] die at ffffffffbd031b42
/usr/src/debug/kernel-4.14.35/linux-4.14.35-1818.3.3.el7uek/arch/x86/kernel/dumpstack.c: 357
#5 [ffffa5a8096e7ab0] do_general_protection at ffffffffbd02ec12
/usr/src/debug/kernel-4.14.35/linux-4.14.35-1818.3.3.el7uek/arch/x86/kernel/traps.c: 561
#6 [ffffa5a8096e7ae0] general_protection at ffffffffbda0388c
/usr/src/debug/kernel-4.14.35/linux-4.14.35-1818.3.3.el7uek/arch/x86/entry/entry_64.S: 1272
[exception RIP: drm_helper_probe_single_connector_modes+188]
RIP: ffffffffc05e80ac RSP: ffffa5a8096e7b98 RFLAGS: 00010203
RAX: 00ffff994e98cb08 RBX: ffff994aa7c62088 RCX: 000000000000001e
RDX: ffffa5a8096e7c08 RSI: ffffa5a8096e7c08 RDI: ffff994aa7c65240
RBP: ffffa5a8096e7c50 R8: ffff994e9b493fc0 R9: 0000000000000001
R10: 0000000000000001 R11: 00000000fffffff2 R12: ffff994aa7c65218
R13: ffff994aa7c62028 R14: ffffffffc03321a0 R15: ffff994aa7c62000
ORIG_RAX: ffffffffffffffff CS: 0010 SS: 0018
/usr/src/debug/kernel-4.14.35/linux-4.14.35-1818.3.3.el7uek/drivers/gpu/drm/drm_probe_helper.c: 423
#7 [ffffa5a8096e7c58] drm_mode_getconnector at ffffffffc02db97e [drm]
/usr/src/debug/kernel-4.14.35/linux-4.14.35-1818.3.3.el7uek/drivers/gpu/drm/drm_connector.c: 1321
#8 [ffffa5a8096e7d10] drm_ioctl_kernel at ffffffffc02c4dec [drm]
/usr/src/debug/kernel-4.14.35/linux-4.14.35-1818.3.3.el7uek/drivers/gpu/drm/drm_ioctl.c: 741
#9 [ffffa5a8096e7d50] drm_ioctl at ffffffffc02c51e4 [drm]
/usr/src/debug/kernel-4.14.35/linux-4.14.35-1818.3.3.el7uek/include/linux/uaccess.h: 155
#10 [ffffa5a8096e7e60] do_vfs_ioctl at ffffffffbd29263a
/usr/src/debug/kernel-4.14.35/linux-4.14.35-1818.3.3.el7uek/fs/ioctl.c: 47
#11 [ffffa5a8096e7ee8] sys_ioctl at ffffffffbd292c09
/usr/src/debug/kernel-4.14.35/linux-4.14.35-1818.3.3.el7uek/fs/ioctl.c: 701
#12 [ffffa5a8096e7f28] do_syscall_64 at ffffffffbd003949
/usr/src/debug/kernel-4.14.35/linux-4.14.35-1818.3.3.el7uek/arch/x86/entry/common.c: 295
#13 [ffffa5a8096e7f50] entry_SYSCALL_64_after_hwframe at ffffffffbda00195
/usr/src/debug/kernel-4.14.35/linux-4.14.35-1818.3.3.el7uek/arch/x86/entry/entry_64.S: 247
RIP: 00007f3beba00997 RSP: 00007fffc950e968 RFLAGS: 00000246
RAX: ffffffffffffffda RBX: 000055beb6890720 RCX: 00007f3beba00997
RDX: 00007fffc950e9f0 RSI: 00000000c05064a7 RDI: 0000000000000009
RBP: 00007fffc950e9f0 R8: 0000000000000000 R9: 0000000000000004
R10: 0000000000000009 R11: 0000000000000246 R12: 00000000c05064a7
R13: 0000000000000009 R14: 00007fffc950e9f0 R15: 0000000000000009
ORIG_RAX: 0000000000000010 CS: 0033 SS: 002b
crash7latest>
drm_probe_helper.c 의 423 라인의 drm_helper_probe_single_connector_modes 함수가 호출되면서
갑작스럽게 Kernel Protection 이 동작하였음을 확인 할 수 있다.
라인을 확인해 보면,
421: /* set all old modes to the stale state */
422: list_for_each_entry(mode, &connector->modes, head)
423: mode->status = MODE_STALE;
425: old_status = connector->status;
Disassemble 을 해보자.
crash7latest> dis -rl drm_helper_probe_single_connector_modes+188
/usr/src/debug/kernel-4.14.35/linux-4.14.35-1818.3.3.el7uek/drivers/gpu/drm/drm_probe_helper.c: 419
0xffffffffc05e8098 <drm_helper_probe_single_connector_modes+168>: test %eax,%eax
0xffffffffc05e809a <drm_helper_probe_single_connector_modes+170>: js 0xffffffffc05e8726 <drm_helper_probe_single_connector_modes+1846>
/usr/src/debug/kernel-4.14.35/linux-4.14.35-1818.3.3.el7uek/drivers/gpu/drm/drm_probe_helper.c: 422
0xffffffffc05e80a0 <drm_helper_probe_single_connector_modes+176>: mov 0x88(%r15),%rax
0xffffffffc05e80a7 <drm_helper_probe_single_connector_modes+183>: cmp %rax,%rbx
0xffffffffc05e80aa <drm_helper_probe_single_connector_modes+186>: je 0xffffffffc05e80bb <drm_helper_probe_single_connector_modes+203>
/usr/src/debug/kernel-4.14.35/linux-4.14.35-1818.3.3.el7uek/drivers/gpu/drm/drm_probe_helper.c: 423
0xffffffffc05e80ac <drm_helper_probe_single_connector_modes+188>: movl $0xfffffffd,0x50(%rax)
structure 를 확인해보자.
crash7latest> struct drm_device 0xffff994aa7c65240
struct drm_device {
legacy_dev_list = {
next = 0xffffa5a8096e7c08,
prev = 0xffffa5a8096e7c08
},
if_version = 0,
ref = {
refcount = {
refs = {
counter = 0
}
}
},
dev = 0x0,
driver = 0x0,
dev_private = 0xffff994aa7c65268,
control = 0xffff994aa7c65268,
primary = 0x6000000,
render = 0xffff994e9f1976a1,
registered = false,
master = 0x6000000,
[[[ 중략 ]]]
crash7latest> struct drm_device ffff994aa7c62000
struct drm_device {
legacy_dev_list = {
next = 0xffff994aa7c65000,
prev = 0xffff994e9bc55800
},
if_version = 0,
ref = {
refcount = {
refs = {
counter = 0
}
}
},
dev = 0xffff994aa7c652f8,
driver = 0xffff994aa7c652f8,
dev_private = 0xc0c0c0c00000001e,
control = 0xffff994aa7c62148,
primary = 0x5,
render = 0xffffffffc02d9da0 <drm_connector_free>,
registered = 192,
master = 0x0,
unplugged = {
counter = 0
},
anon_inode = 0xffff994aa7c62060,
unique = 0xffff994aa7c62060 "` \306\247J\231\377\377` \306\247J\231\377\377",
struct_mutex = {
owner = {
counter = 4294967296
},
wait_lock = {
{
rlock = {
raw_lock = {
val = {
counter = 1
}
}
이제 실제 라인에 있는 connector mode, status 의 내용들을 살펴볼 차례다.
crash7latest> struct drm_connector.modes 0xffff994aa7c65240
modes = {
next = 0x1,
prev = 0xffff994e9bc54d28
}
crash7latest> struct drm_display_mode.status ffff994aa7c62000
status = MODE_OK
crash7latest> rd 0xffff994aa7c65240
ffff994aa7c65240: ffffa5a8096e7c08 .|n.....
crash7latest> rd -a 0xffff994e9bf77c08 << Null
crash7latest> device 0xffff994e9bf77c08
struct device {
parent = 0xffff994aa7c65310,
p = 0xffff994aa7c65310,
kobj = {
name = 0xe0e0e0e00000001d <Address 0xe0e0e0e00000001d out of bounds>,
entry = {
next = 0x0,
prev = 0x0
},
parent = 0x0,
kset = 0xffff994e9b493fb8,
ktype = 0x1,
sd = 0x1,
kref = {
refcount = {
refs = {
counter = -1480171520
}
}
},
state_initialized = 0,
state_in_sysfs = 1,
state_add_uevent_sent = 0,
state_remove_uevent_sent = 1,
uevent_suppress = 0
},
init_name = 0x0,
자, 대략 설명하자면.. DRM connector 의 mode 는 MODE_OK 로 정상적인 상태였고,
DRM 을 위한 device 에 대한 내용을 확인 결과 Out of Bound 로 표현되는
잘못된 주소를 참조하고 있다는 것을 알 수 있었다.
따라서 커널은 시스템 보호를 위해 protection 을 수행하게 되었고, 그로 인해 패닉이 발생한 것이다.
사실은 MODE_STALE 로 바뀌어야 했던 상황이며,
이는 drm 모듈이 이미 해제하고 사용하지 않아야 할 메모리 번지를 접근하여 재사용하려 했기 때문에 발생한 문제이다.
커널 4.14.35-1844.4.4 버젼 에 픽스가 포함되어있으므로,
해당 버젼 이상으로 업데이트를 해야 해결할 수 있다.
분석한지 한시간도 안되서 알려진 버그를 찾았다는게 개인적으로 나름 웃긴 부분이며,
물론 실제로 고객이 분석을 요청했을때, 이렇게 상세하게 지원 해주지는 않는다.
업무 특성상 사실, 솔루션만 제공하면 되니까 그러는 것도 있지만,
돈내고 받는 서비스라는 생각에 이해할 수 있는 기반도 없이 스터디를 요구하는 경우가 많아서이기도 하고..
(이전에 사과먹다만 회사 내부 커널개발자라는 놈이
아주 미친/미친듯이 질문을 한적이 있는데 답답해 미치는줄 알았었...)
블로그에 상세내용을 올리는 것은 분석에 대한 기법을 공유하기 위해서다.
끝.
'Skills > mY Technutz' 카테고리의 다른 글
PyKdump extension - pycrashext (0) | 2019.12.14 |
---|---|
The effective crash-utility for vmcore analysis (PyKdump) (0) | 2019.12.13 |
Kernel Dump Analysis #17 (0) | 2019.04.04 |
libfc: Update rport reference counting bug - 1368175 (0) | 2018.03.29 |
Kernel Dump Analysis #16 (0) | 2018.02.22 |