Oops! Depuración de Kernel Panics

Oops! Depuración de Kernel Panics

Una mirada a las causas del pánico del núcleo y algunas utilidades para ayudar a obtener más información.

Trabajando en un entorno Linux, ¿con qué frecuencia ha visto un kernel panic? Cuando sucede, su sistema queda en un estado lisiado hasta que lo reinicie por completo. E, incluso después de volver a poner su sistema en un estado funcional, todavía tiene la pregunta: ¿por qué? Es posible que no tenga idea de lo que sucedió o por qué sucedió. Sin embargo, esas preguntas pueden responderse, y la siguiente guía lo ayudará a descubrir la causa de algunas de las condiciones que llevaron al accidente original.


Figura 1: Un típico Kernel Panic
Comencemos mirando un conjunto de utilidades conocidas como kexec y kdump . kexec permite iniciar en otro kernel desde un kernel existente (y en ejecución), y kdump es un kexec de kexec caída basado en kexec para Linux.

Instalar los paquetes requeridos

En primer lugar, su núcleo debe tener los siguientes componentes integrados estáticamente en su imagen:
 
CONFIG_RELOCATABLE=y CONFIG_KEXEC=y CONFIG_CRASH_DUMP=y CONFIG_DEBUG_INFO=y CONFIG_MAGIC_SYSRQ=y CONFIG_PROC_VMCORE=y
CONFIG_RELOCATABLE=y CONFIG_KEXEC=y CONFIG_CRASH_DUMP=y CONFIG_DEBUG_INFO=y CONFIG_MAGIC_SYSRQ=y CONFIG_PROC_VMCORE=y 

Puede encontrar esto en /boot/config-`uname -r` .

Asegúrese de que su sistema operativo esté actualizado con las últimas y mejores versiones de paquetes:
 
$ sudo apt update && sudo apt upgrade
$ sudo apt update && sudo apt upgrade 

Instale los siguientes paquetes (actualmente estoy usando Debian, pero lo mismo debería aplicarse a Ubuntu):
 
$ sudo apt install gcc make binutils linux-headers-`uname -r` ↪kdump-tools crash `uname -r`-dbg
$ sudo apt install gcc make binutils linux-headers-`uname -r` ↪kdump-tools crash `uname -r`-dbg 
 
Nota: Los nombres de los paquetes pueden variar según las distribuciones.
Durante la instalación, se le harán preguntas para permitir que kexec maneje los reinicios (responda lo que quiera, pero yo respondí "no"; consulte la Figura 2).

Figura 2. Menú de configuración de kexec
 Y para permitir que kdump ejecute y cargue al iniciar el sistema, responda "sí" (Figura 3).

Figura 3. Menú de configuración de kdump

Configurando kdump

Abra el archivo / etc / default / kdump-tools, y en la parte superior, debería ver lo siguiente:
 
USE_KDUMP=1 #KDUMP_SYSCTL="kernel.panic_on_oops=1"
USE_KDUMP=1 #KDUMP_SYSCTL="kernel.panic_on_oops=1" 

Eventualmente, escribirá un módulo personalizado que activará una condición del núcleo OOPS, y para que kdump reúna y guarde el estado del sistema para el análisis post-mortem, deberá habilitar su núcleo para entrar en pánico en este OOPS condición. Para hacer esto, descomente la línea que comienza con KDUMP_SYSCTL :
 
USE_KDUMP=1 KDUMP_SYSCTL="kernel.panic_on_oops=1"
USE_KDUMP=1 KDUMP_SYSCTL="kernel.panic_on_oops=1" 

La prueba inicial requerirá que SysRq esté habilitado. Hay algunas formas de hacerlo, pero aquí proporciono instrucciones para habilitar la compatibilidad con esta función en el reinicio del sistema. Abra el archivo /etc/sysctl.d/99-sysctl.conf y asegúrese de que la siguiente línea (más cerca de la parte inferior del archivo) no esté comentada:
 
kernel.sysrq=1
kernel.sysrq=1 

Ahora, abra este archivo: /etc/default/grub.d/kdump-tools.default. Encontrará una sola línea que se ve así:
 
GRUB_CMDLINE_LINUX_DEFAULT="$GRUB_CMDLINE_LINUX_DEFAULT ↪crashkernel=384M-:128M"
GRUB_CMDLINE_LINUX_DEFAULT="$GRUB_CMDLINE_LINUX_DEFAULT ↪crashkernel=384M-:128M" 

Modifique la sección que dice crashkernel=384M-:128M a crashkernel=128M .
Ahora, actualice su archivo de configuración de arranque GRUB:
 
$ sudo update-grub [sudo] password for petros: Generating grub configuration file ... Found linux image: /boot/vmlinuz-4.9.0-8-amd64 Found initrd image: /boot/initrd.img-4.9.0-8-amd64 done
$ sudo update-grub [sudo] password for petros: Generating grub configuration file ... Found linux image: /boot/vmlinuz-4.9.0-8-amd64 Found initrd image: /boot/initrd.img-4.9.0-8-amd64 done 

Y reinicie el sistema.

Verificación de su entorno kdump

Después de regresar del reinicio, dmesg registrará lo siguiente:
 
$ sudo dmesg |grep -i crash [ 0.000000] Command line: BOOT_IMAGE=/boot/vmlinuz-4.9.0-8-amd64 ↪root=UUID=bd76b0fe-9d09-40a9-a0d8-a7533620f6fa ro quiet ↪crashkernel=128M [ 0.000000] Reserving 128MB of memory at 720MB for crashkernel ↪(System RAM: 4095MB) [ 0.000000] Kernel command line: BOOT_IMAGE=/boot/ ↪vmlinuz-4.9.0-8-amd64 ↪root=UUID=bd76b0fe-9d09-40a9-a0d8-a7533620f6fa ro ↪quiet crashkernel=128M
$ sudo dmesg |grep -i crash [ 0.000000] Command line: BOOT_IMAGE=/boot/vmlinuz-4.9.0-8-amd64 ↪root=UUID=bd76b0fe-9d09-40a9-a0d8-a7533620f6fa ro quiet ↪crashkernel=128M [ 0.000000] Reserving 128MB of memory at 720MB for crashkernel ↪(System RAM: 4095MB) [ 0.000000] Kernel command line: BOOT_IMAGE=/boot/ ↪vmlinuz-4.9.0-8-amd64 ↪root=UUID=bd76b0fe-9d09-40a9-a0d8-a7533620f6fa ro ↪quiet crashkernel=128M 

Mientras que su núcleo tendrá las siguientes características habilitadas (un "1" significa habilitado):
 
$ sudo sysctl -a|grep kernel|grep -e panic_on_oops -e sysrq kernel.panic_on_oops = 1 kernel.sysrq = 1
$ sudo sysctl -a|grep kernel|grep -e panic_on_oops -e sysrq kernel.panic_on_oops = 1 kernel.sysrq = 1 

Su servicio kdump debería estar ejecutándose:
 
$ sudo systemctl status kdump-tools.service kdump-tools.service - Kernel crash dump capture service Loaded: loaded (/lib/systemd/system/kdump-tools.service; ↪enabled; vendor preset: enabled) Active: active (exited) since Tue 2019-02-26 08:13:34 CST; ↪1h 33min ago Process: 371 ExecStart=/etc/init.d/kdump-tools start ↪(code=exited, status=0/SUCCESS) Main PID: 371 (code=exited, status=0/SUCCESS) Tasks: 0 (limit: 4915) CGroup: /system.slice/kdump-tools.service Feb 26 08:13:34 deb-panic systemd[1]: Starting Kernel crash ↪dump capture service... Feb 26 08:13:34 deb-panic kdump-tools[371]: Starting ↪kdump-tools: loaded kdump kernel. Feb 26 08:13:34 deb-panic kdump-tools[505]: /sbin/kexec -p ↪--command-line="BOOT_IMAGE=/boot/vmlinuz-4.9.0-8-amd64 root= Feb 26 08:13:34 deb-panic kdump-tools[506]: loaded kdump kernel Feb 26 08:13:34 deb-panic systemd[1]: Started Kernel crash dump ↪capture service.
$ sudo systemctl status kdump-tools.service kdump-tools.service - Kernel crash dump capture service Loaded: loaded (/lib/systemd/system/kdump-tools.service; ↪enabled; vendor preset: enabled) Active: active (exited) since Tue 2019-02-26 08:13:34 CST; ↪1h 33min ago Process: 371 ExecStart=/etc/init.d/kdump-tools start ↪(code=exited, status=0/SUCCESS) Main PID: 371 (code=exited, status=0/SUCCESS) Tasks: 0 (limit: 4915) CGroup: /system.slice/kdump-tools.service Feb 26 08:13:34 deb-panic systemd[1]: Starting Kernel crash ↪dump capture service... Feb 26 08:13:34 deb-panic kdump-tools[371]: Starting ↪kdump-tools: loaded kdump kernel. Feb 26 08:13:34 deb-panic kdump-tools[505]: /sbin/kexec -p ↪--command-line="BOOT_IMAGE=/boot/vmlinuz-4.9.0-8-amd64 root= Feb 26 08:13:34 deb-panic kdump-tools[506]: loaded kdump kernel Feb 26 08:13:34 deb-panic systemd[1]: Started Kernel crash dump ↪capture service. 

Su núcleo de bloqueo debe cargarse (en la memoria y en la región de 128M que definió anteriormente):
 
$ cat /sys/kernel/kexec_crash_loaded 1
$ cat /sys/kernel/kexec_crash_loaded 1 

Puede verificar su configuración de kdump más aquí:
 
$ sudo kdump-config show DUMP_MODE: kdump USE_KDUMP: 1 KDUMP_SYSCTL: kernel.panic_on_oops=1 KDUMP_COREDIR: /var/crash crashkernel addr: 0x2d000000 /var/lib/kdump/vmlinuz: symbolic link to /boot/ ↪vmlinuz-4.9.0-8-amd64 kdump initrd: /var/lib/kdump/initrd.img: symbolic link to /var/lib/kdump/ ↪initrd.img-4.9.0-8-amd64 current state: ready to kdump kexec command: /sbin/kexec -p --command-line="BOOT_IMAGE=/boot/ ↪vmlinuz-4.9.0-8-amd64 root=UUID=bd76b0fe-9d09-40a9- ↪a0d8-a7533620f6fa ro quiet irqpoll nr_cpus=1 nousb ↪systemd.unit=kdump-tools.service ↪ata_piix.prefer_ms_hyperv=0" ↪--initrd=/var/lib/kdump/initrd.img /var/lib/kdump/vmlinuz
$ sudo kdump-config show DUMP_MODE: kdump USE_KDUMP: 1 KDUMP_SYSCTL: kernel.panic_on_oops=1 KDUMP_COREDIR: /var/crash crashkernel addr: 0x2d000000 /var/lib/kdump/vmlinuz: symbolic link to /boot/ ↪vmlinuz-4.9.0-8-amd64 kdump initrd: /var/lib/kdump/initrd.img: symbolic link to /var/lib/kdump/ ↪initrd.img-4.9.0-8-amd64 current state: ready to kdump kexec command: /sbin/kexec -p --command-line="BOOT_IMAGE=/boot/ ↪vmlinuz-4.9.0-8-amd64 root=UUID=bd76b0fe-9d09-40a9- ↪a0d8-a7533620f6fa ro quiet irqpoll nr_cpus=1 nousb ↪systemd.unit=kdump-tools.service ↪ata_piix.prefer_ms_hyperv=0" ↪--initrd=/var/lib/kdump/initrd.img /var/lib/kdump/vmlinuz 

Probemos también sin ejecutarlo realmente:
 
$ sudo kdump-config test USE_KDUMP: 1 KDUMP_SYSCTL: kernel.panic_on_oops=1 KDUMP_COREDIR: /var/crash crashkernel addr: 0x2d000000 kdump kernel addr: kdump kernel: /var/lib/kdump/vmlinuz: symbolic link to /boot/ ↪vmlinuz-4.9.0-8-amd64 kdump initrd: /var/lib/kdump/initrd.img: symbolic link to ↪/var/lib/kdump/initrd.img-4.9.0-8-amd64 kexec command to be used: /sbin/kexec -p --command-line="BOOT_IMAGE=/boot/ ↪vmlinuz-4.9.0-8-amd64 root=UUID=bd76b0fe-9d09-40a9- ↪a0d8-a7533620f6fa ro quiet irqpoll nr_cpus=1 nousb ↪systemd.unit=kdump-tools.service ↪ata_piix.prefer_ms_hyperv=0" ↪--initrd=/var/lib/kdump/initrd.img /var/lib/kdump/vmlinuz
$ sudo kdump-config test USE_KDUMP: 1 KDUMP_SYSCTL: kernel.panic_on_oops=1 KDUMP_COREDIR: /var/crash crashkernel addr: 0x2d000000 kdump kernel addr: kdump kernel: /var/lib/kdump/vmlinuz: symbolic link to /boot/ ↪vmlinuz-4.9.0-8-amd64 kdump initrd: /var/lib/kdump/initrd.img: symbolic link to ↪/var/lib/kdump/initrd.img-4.9.0-8-amd64 kexec command to be used: /sbin/kexec -p --command-line="BOOT_IMAGE=/boot/ ↪vmlinuz-4.9.0-8-amd64 root=UUID=bd76b0fe-9d09-40a9- ↪a0d8-a7533620f6fa ro quiet irqpoll nr_cpus=1 nousb ↪systemd.unit=kdump-tools.service ↪ata_piix.prefer_ms_hyperv=0" ↪--initrd=/var/lib/kdump/initrd.img /var/lib/kdump/vmlinuz 

El momento de la verdad

Ahora que su entorno está cargado para hacer uso de kdump , probablemente debería probarlo, y la mejor manera de hacerlo es forzando un bloqueo del kernel sobre SysRq. Asumiendo que su núcleo está construido con soporte SysRq, bloquear un núcleo en ejecución es tan simple como escribir:
 
$ echo "c" | sudo tee -a /proc/sysrq-trigger
$ echo "c" | sudo tee -a /proc/sysrq-trigger 

¿Qué deberías esperar? Verá un kernel panic / crash similar al que se muestra en la Figura 1. Después de este crash, el kernel cargado sobre kexec recopilará el estado del sistema, que incluye todo lo relevante en la memoria, en la CPU, en dmesg, en módulos cargados y más. A continuación, guardará estos valiosos datos de bloqueo en algún lugar de / var / crash para su posterior análisis. Una vez que se completa la recopilación de información, el sistema se reiniciará automáticamente y lo devolverá a un estado funcional.

¿Ahora que?

Ahora tiene su archivo de bloqueo y, nuevamente, se encuentra en / var / crash:
 
$ cd /var/crash/ $ ls 201902261006 kexec_cmd $ cd 201902261006/
$ cd /var/crash/ $ ls 201902261006 kexec_cmd $ cd 201902261006/ 

Aunque antes de abrir el archivo de bloqueo, probablemente debería instalar el paquete fuente del núcleo:
 
$ sudo apt source linux-image-`uname -r`
$ sudo apt source linux-image-`uname -r` 

Anteriormente, instaló una versión de depuración de su kernel de Linux que contiene los símbolos de depuración sin tirar necesarios para este tipo de análisis de depuración. Ahora necesitas ese núcleo. Abra el archivo de bloqueo del kernel con la utilidad de crash :
 
$ sudo crash dump.201902261006 /usr/lib/debug/ ↪vmlinux-4.9.0-8-amd64
$ sudo crash dump.201902261006 /usr/lib/debug/ ↪vmlinux-4.9.0-8-amd64 

Una vez que todo se carga, aparecerá un resumen del pánico en la pantalla:
 
KERNEL: /usr/lib/debug/vmlinux-4.9.0-8-amd64 DUMPFILE: dump.201902261006 [PARTIAL DUMP] CPUS: 4 DATE: Tue Feb 26 10:07:21 2019 UPTIME: 00:04:09 LOAD AVERAGE: 0.00, 0.00, 0.00 TASKS: 100 NODENAME: deb-panic RELEASE: 4.9.0-8-amd64 VERSION: #1 SMP Debian 4.9.144-3 (2019-02-02) MACHINE: x86_64 (2592 Mhz) MEMORY: 4 GB PANIC: "sysrq: SysRq : Trigger a crash" PID: 563 COMMAND: "tee" TASK: ffff88e69628c080 [THREAD_INFO: ffff88e69628c080] CPU: 2 STATE: TASK_RUNNING (SYSRQ)
KERNEL: /usr/lib/debug/vmlinux-4.9.0-8-amd64 DUMPFILE: dump.201902261006 [PARTIAL DUMP] CPUS: 4 DATE: Tue Feb 26 10:07:21 2019 UPTIME: 00:04:09 LOAD AVERAGE: 0.00, 0.00, 0.00 TASKS: 100 NODENAME: deb-panic RELEASE: 4.9.0-8-amd64 VERSION: #1 SMP Debian 4.9.144-3 (2019-02-02) MACHINE: x86_64 (2592 Mhz) MEMORY: 4 GB PANIC: "sysrq: SysRq : Trigger a crash" PID: 563 COMMAND: "tee" TASK: ffff88e69628c080 [THREAD_INFO: ffff88e69628c080] CPU: 2 STATE: TASK_RUNNING (SYSRQ) 

Observe la razón del pánico: sysrq: SysRq : Trigger a crash . Además, observe el comando que lo condujo: tee . Nada de esto debería ser una sorpresa ya que lo activó.
Si ejecuta una traza inversa de las funciones del núcleo que llevaron al pánico, debería ver lo siguiente (procesado por el núcleo de la CPU no. 2):
 
crash> bt PID: 563 TASK: ffff88e69628c080 CPU: 2 COMMAND: "tee" #0 [ffffa67440b23ba0] machine_kexec at ffffffffa0c53f68 #1 [ffffa67440b23bf8] __crash_kexec at ffffffffa0d086d1 #2 [ffffa67440b23cb8] crash_kexec at ffffffffa0d08738 #3 [ffffa67440b23cd0] oops_end at ffffffffa0c298b3 #4 [ffffa67440b23cf0] no_context at ffffffffa0c619b1 #5 [ffffa67440b23d50] __do_page_fault at ffffffffa0c62476 #6 [ffffa67440b23dc0] page_fault at ffffffffa121a618 [exception RIP: sysrq_handle_crash+18] RIP: ffffffffa102be62 RSP: ffffa67440b23e78 RFLAGS: 00010282 RAX: ffffffffa102be50 RBX: 0000000000000063 RCX: 0000000000000000 RDX: 0000000000000000 RSI: ffff88e69fd10648 RDI: 0000000000000063 RBP: ffffffffa18bf320 R8: 0000000000000001 R9: 0000000000007eb8 R10: 0000000000000001 R11: 0000000000000001 R12: 0000000000000004 R13: 0000000000000000 R14: 0000000000000000 R15: 0000000000000000 ORIG_RAX: ffffffffffffffff CS: 0010 SS: 0018 #7 [ffffa67440b23e78] __handle_sysrq at ffffffffa102c597 #8 [ffffa67440b23ea0] write_sysrq_trigger at ffffffffa102c9db #9 [ffffa67440b23eb0] proc_reg_write at ffffffffa0e7ac00 #10 [ffffa67440b23ec8] vfs_write at ffffffffa0e0b3b0 #11 [ffffa67440b23ef8] sys_write at ffffffffa0e0c7f2 #12 [ffffa67440b23f38] do_syscall_64 at ffffffffa0c03b7d #13 [ffffa67440b23f50] entry_SYSCALL_64_after_swapgs at ffffffffa121924e RIP: 00007f3952463970 RSP: 00007ffc7f3a4e58 RFLAGS: 00000246 RAX: ffffffffffffffda RBX: 0000000000000002 RCX: 00007f3952463970 RDX: 0000000000000002 RSI: 00007ffc7f3a4f60 RDI: 0000000000000003 RBP: 00007ffc7f3a4f60 R8: 00005648f508b610 R9: 00007f3952944480 R10: 0000000000000839 R11: 0000000000000246 R12: 0000000000000002 R13: 0000000000000001 R14: 00005648f508b530 R15: 0000000000000002 ORIG_RAX: 0000000000000001 CS: 0033 SS: 002b
crash> bt PID: 563 TASK: ffff88e69628c080 CPU: 2 COMMAND: "tee" #0 [ffffa67440b23ba0] machine_kexec at ffffffffa0c53f68 #1 [ffffa67440b23bf8] __crash_kexec at ffffffffa0d086d1 #2 [ffffa67440b23cb8] crash_kexec at ffffffffa0d08738 #3 [ffffa67440b23cd0] oops_end at ffffffffa0c298b3 #4 [ffffa67440b23cf0] no_context at ffffffffa0c619b1 #5 [ffffa67440b23d50] __do_page_fault at ffffffffa0c62476 #6 [ffffa67440b23dc0] page_fault at ffffffffa121a618 [exception RIP: sysrq_handle_crash+18] RIP: ffffffffa102be62 RSP: ffffa67440b23e78 RFLAGS: 00010282 RAX: ffffffffa102be50 RBX: 0000000000000063 RCX: 0000000000000000 RDX: 0000000000000000 RSI: ffff88e69fd10648 RDI: 0000000000000063 RBP: ffffffffa18bf320 R8: 0000000000000001 R9: 0000000000007eb8 R10: 0000000000000001 R11: 0000000000000001 R12: 0000000000000004 R13: 0000000000000000 R14: 0000000000000000 R15: 0000000000000000 ORIG_RAX: ffffffffffffffff CS: 0010 SS: 0018 #7 [ffffa67440b23e78] __handle_sysrq at ffffffffa102c597 #8 [ffffa67440b23ea0] write_sysrq_trigger at ffffffffa102c9db #9 [ffffa67440b23eb0] proc_reg_write at ffffffffa0e7ac00 #10 [ffffa67440b23ec8] vfs_write at ffffffffa0e0b3b0 #11 [ffffa67440b23ef8] sys_write at ffffffffa0e0c7f2 #12 [ffffa67440b23f38] do_syscall_64 at ffffffffa0c03b7d #13 [ffffa67440b23f50] entry_SYSCALL_64_after_swapgs at ffffffffa121924e RIP: 00007f3952463970 RSP: 00007ffc7f3a4e58 RFLAGS: 00000246 RAX: ffffffffffffffda RBX: 0000000000000002 RCX: 00007f3952463970 RDX: 0000000000000002 RSI: 00007ffc7f3a4f60 RDI: 0000000000000003 RBP: 00007ffc7f3a4f60 R8: 00005648f508b610 R9: 00007f3952944480 R10: 0000000000000839 R11: 0000000000000246 R12: 0000000000000002 R13: 0000000000000001 R14: 00005648f508b530 R15: 0000000000000002 ORIG_RAX: 0000000000000001 CS: 0033 SS: 002b 

En su rastreo, debe notar la dirección del símbolo de lo que está almacenado en su Puntero de instrucción de retorno (RIP): ffffffffa102be62 . Echemos un vistazo a esta dirección de símbolo:
 
crash> sym ffffffffa102be62 ffffffffa102be62 (t) sysrq_handle_crash+18 ./debian/build/ ↪build_amd64_none_amd64/./drivers/tty/sysrq.c: 144
crash> sym ffffffffa102be62 ffffffffa102be62 (t) sysrq_handle_crash+18 ./debian/build/ ↪build_amd64_none_amd64/./drivers/tty/sysrq.c: 144 

¡Espera un minuto! La excepción parece haberse activado en la línea 144 del archivo drivers / tty / sysrq.c y dentro de la función sysrq_handle_crash . Hmm ... Me pregunto qué está pasando en este archivo fuente del núcleo. (Esta es la razón por la que instalé su paquete fuente del núcleo hace unos momentos). Vayamos al directorio / usr / src y descomprimamos el paquete fuente:
 
$ cd /usr/src $ ls linux_4.9.144-3.debian.tar.xz linux_4.9.144.orig.tar.xz ↪linux-headers-4.9.0-8-common linux_4.9.144-3.dsc linux-headers-4.9.0-8-amd64 ↪linux-kbuild-4.9 $ sudo tar xJf linux_4.9.144.orig.tar.xz $ vim linux-4.9.144/drivers/tty/sysrq.c
$ cd /usr/src $ ls linux_4.9.144-3.debian.tar.xz linux_4.9.144.orig.tar.xz ↪linux-headers-4.9.0-8-common linux_4.9.144-3.dsc linux-headers-4.9.0-8-amd64 ↪linux-kbuild-4.9 $ sudo tar xJf linux_4.9.144.orig.tar.xz $ vim linux-4.9.144/drivers/tty/sysrq.c 

Localice la función sysrq_handle_crash :
 
static void sysrq_handle_crash(int key) { char *killer = NULL; /* we need to release the RCU read lock here, * otherwise we get an annoying * 'BUG: sleeping function called from invalid context' * complaint from the kernel before the panic. */ rcu_read_unlock(); panic_on_oops = 1; /* force panic */ wmb(); *killer = 1; }
static void sysrq_handle_crash(int key) { char *killer = NULL; /* we need to release the RCU read lock here, * otherwise we get an annoying * 'BUG: sleeping function called from invalid context' * complaint from the kernel before the panic. */ rcu_read_unlock(); panic_on_oops = 1; /* force panic */ wmb(); *killer = 1; } 

Y más específicamente, mire la línea 144:
 
*killer = 1;
*killer = 1; 

Fue esta línea la que condujo a la falla de la página registrada en la línea # 6 de la traza inversa:
 
#6 [ffffa67440b23dc0] page_fault at ffffffffa121a618
#6 [ffffa67440b23dc0] page_fault at ffffffffa121a618 

Bueno. Entonces, ahora debe tener una comprensión básica de cómo depurar código de kernel incorrecto, pero ¿qué sucede si desea depurar sus propios módulos de kernel personalizados (por ejemplo, controladores)? Escribí un simple módulo de kernel de Linux que esencialmente invoca un estilo similar de bloqueo del kernel cuando se carga. Llámelo test-module.c y guárdelo en algún lugar de su directorio de inicio:
 
#include <linux/init.h> #include <linux/module.h> #include <linux/version.h> static int test_module_init(void) { int *p = 1; printk("%d\n", *p); return 0; } static void test_module_exit(void) { return; } module_init(test_module_init); module_exit(test_module_exit);
#include <linux/init.h> #include <linux/module.h> #include <linux/version.h> static int test_module_init(void) { int *p = 1; printk("%d\n", *p); return 0; } static void test_module_exit(void) { return; } module_init(test_module_init); module_exit(test_module_exit); 

Necesitará un Makefile para compilar este módulo del kernel (guárdelo en el mismo directorio):
 
obj-m += test-module.o all: $(MAKE) -C/lib/modules/$(shell uname -r)/build M=$(PWD)
obj-m += test-module.o all: $(MAKE) -C/lib/modules/$(shell uname -r)/build M=$(PWD) 

Ejecute el comando make para compilar el módulo y no elimine ninguno de los artefactos de compilación; los necesitarás más tarde:
 
$ make make -C/lib/modules/4.9.0-8-amd64/build M=/home/petros make[1]: Entering directory '/usr/src/ ↪linux-headers-4.9.0-8-amd64' CC [M] /home/petros/test-module.o /home/petros/test-module.c: In function "test_module_init": /home/petros/test-module.c:7:11: warning: initialization makes ↪pointer from integer without a cast [-Wint-conversion] int *p = 1; ^ Building modules, stage 2. MODPOST 1 modules LD [M] /home/petros/test-module.ko make[1]: Leaving directory '/usr/src/ ↪linux-headers-4.9.0-8-amd64'
$ make make -C/lib/modules/4.9.0-8-amd64/build M=/home/petros make[1]: Entering directory '/usr/src/ ↪linux-headers-4.9.0-8-amd64' CC [M] /home/petros/test-module.o /home/petros/test-module.c: In function "test_module_init": /home/petros/test-module.c:7:11: warning: initialization makes ↪pointer from integer without a cast [-Wint-conversion] int *p = 1; ^ Building modules, stage 2. MODPOST 1 modules LD [M] /home/petros/test-module.ko make[1]: Leaving directory '/usr/src/ ↪linux-headers-4.9.0-8-amd64' 
 
Nota: puede ver una advertencia de compilación. Ignóralo por ahora. Esta advertencia será lo que desencadena el bloqueo del kernel.
 
Ten cuidado ahora. Una vez que cargue el archivo .ko, el sistema se bloqueará, así que asegúrese de que todo esté guardado y sincronizado en el disco:
 
$ sync && sudo insmod test-module.ko
$ sync && sudo insmod test-module.ko 

Al igual que antes, el sistema se bloqueará, el núcleo / entorno kexec ayudará a reunir todo y guardarlo en algún lugar en / var / crash, seguido de un reinicio automático. Después de reiniciar y volver a un estado funcional, busque el nuevo directorio de bloqueo y cámbielo:
 
$ cd /var/crash/201902261035/
$ cd /var/crash/201902261035/ 
 
Además, copie el archivo de objeto kernel sin tirar para su test-module de test-module desde su directorio de inicio y en el directorio de trabajo actual:
 
$ sudo cp ~/test.o /var/crash/201902261035/
$ sudo cp ~/test.o /var/crash/201902261035/ 

Cargue el archivo de bloqueo con su núcleo de depuración:
 
$ sudo crash dump.201902261035 /usr/lib/debug/ ↪vmlinux-4.9.0-8-amd64
$ sudo crash dump.201902261035 /usr/lib/debug/ ↪vmlinux-4.9.0-8-amd64 
 
Su resumen debería verse así:
 
KERNEL: /usr/lib/debug/vmlinux-4.9.0-8-amd64 DUMPFILE: dump.201902261035 [PARTIAL DUMP] CPUS: 4 DATE: Tue Feb 26 10:37:47 2019 UPTIME: 00:11:16 LOAD AVERAGE: 0.24, 0.06, 0.02 TASKS: 102 NODENAME: deb-panic RELEASE: 4.9.0-8-amd64 VERSION: #1 SMP Debian 4.9.144-3 (2019-02-02) MACHINE: x86_64 (2592 Mhz) MEMORY: 4 GB PANIC: "BUG: unable to handle kernel NULL pointer ↪dereference at 0000000000000001" PID: 1493 COMMAND: "insmod" TASK: ffff893c5a5a5080 [THREAD_INFO: ffff893c5a5a5080] CPU: 3 STATE: TASK_RUNNING (PANIC)
KERNEL: /usr/lib/debug/vmlinux-4.9.0-8-amd64 DUMPFILE: dump.201902261035 [PARTIAL DUMP] CPUS: 4 DATE: Tue Feb 26 10:37:47 2019 UPTIME: 00:11:16 LOAD AVERAGE: 0.24, 0.06, 0.02 TASKS: 102 NODENAME: deb-panic RELEASE: 4.9.0-8-amd64 VERSION: #1 SMP Debian 4.9.144-3 (2019-02-02) MACHINE: x86_64 (2592 Mhz) MEMORY: 4 GB PANIC: "BUG: unable to handle kernel NULL pointer ↪dereference at 0000000000000001" PID: 1493 COMMAND: "insmod" TASK: ffff893c5a5a5080 [THREAD_INFO: ffff893c5a5a5080] CPU: 3 STATE: TASK_RUNNING (PANIC) 

El motivo del bloqueo del kernel se resume de la siguiente manera: BUG: unable to handle kernel NULL pointer dereference at 0000000000000001 . El comando de espacio de usuario que provocó el pánico fue su insmod .
 
Una traza inversa revelará una excepción de falla de página en la dirección ffffffffc05ed005 :
 
crash> bt PID: 1493 TASK: ffff893c5a5a5080 CPU: 3 COMMAND: "insmod" #0 [ffff9dcd013b79f0] machine_kexec at ffffffffa3a53f68 #1 [ffff9dcd013b7a48] __crash_kexec at ffffffffa3b086d1 #2 [ffff9dcd013b7b08] crash_kexec at ffffffffa3b08738 #3 [ffff9dcd013b7b20] oops_end at ffffffffa3a298b3 #4 [ffff9dcd013b7b40] no_context at ffffffffa3a619b1 #5 [ffff9dcd013b7ba0] __do_page_fault at ffffffffa3a62476 #6 [ffff9dcd013b7c10] page_fault at ffffffffa401a618 [exception RIP: init_module+5] RIP: ffffffffc05ed005 RSP: ffff9dcd013b7cc8 RFLAGS: 00010246 RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000000 RDX: 0000000080000000 RSI: ffff893c5a5a5ac0 RDI: ffffffffc05ed000 RBP: ffffffffc05ed000 R8: 0000000000020098 R9: 0000000000000006 R10: 0000000000000000 R11: ffff893c5a4d8100 R12: ffff893c5880d460 R13: ffff893c56500e80 R14: ffffffffc05ef000 R15: ffffffffc05ef050 ORIG_RAX: ffffffffffffffff CS: 0010 SS: 0018 #7 [ffff9dcd013b7cc8] do_one_initcall at ffffffffa3a0218e #8 [ffff9dcd013b7d38] do_init_module at ffffffffa3b81531 #9 [ffff9dcd013b7d58] load_module at ffffffffa3b04aaa #10 [ffff9dcd013b7e90] SYSC_finit_module at ffffffffa3b051f6 #11 [ffff9dcd013b7f38] do_syscall_64 at ffffffffa3a03b7d #12 [ffff9dcd013b7f50] entry_SYSCALL_64_after_swapgs at ffffffffa401924e RIP: 00007f124662c469 RSP: 00007fffc4ca04a8 RFLAGS: 00000246 RAX: ffffffffffffffda RBX: 0000564213d111f0 RCX: 00007f124662c469 RDX: 0000000000000000 RSI: 00005642129d3638 RDI: 0000000000000003 RBP: 00005642129d3638 R8: 0000000000000000 R9: 00007f12468e3ea0 R10: 0000000000000003 R11: 0000000000000246 R12: 0000000000000000 R13: 0000564213d10130 R14: 0000000000000000 R15: 0000000000000000 ORIG_RAX: 0000000000000139 CS: 0033 SS: 002b
crash> bt PID: 1493 TASK: ffff893c5a5a5080 CPU: 3 COMMAND: "insmod" #0 [ffff9dcd013b79f0] machine_kexec at ffffffffa3a53f68 #1 [ffff9dcd013b7a48] __crash_kexec at ffffffffa3b086d1 #2 [ffff9dcd013b7b08] crash_kexec at ffffffffa3b08738 #3 [ffff9dcd013b7b20] oops_end at ffffffffa3a298b3 #4 [ffff9dcd013b7b40] no_context at ffffffffa3a619b1 #5 [ffff9dcd013b7ba0] __do_page_fault at ffffffffa3a62476 #6 [ffff9dcd013b7c10] page_fault at ffffffffa401a618 [exception RIP: init_module+5] RIP: ffffffffc05ed005 RSP: ffff9dcd013b7cc8 RFLAGS: 00010246 RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000000 RDX: 0000000080000000 RSI: ffff893c5a5a5ac0 RDI: ffffffffc05ed000 RBP: ffffffffc05ed000 R8: 0000000000020098 R9: 0000000000000006 R10: 0000000000000000 R11: ffff893c5a4d8100 R12: ffff893c5880d460 R13: ffff893c56500e80 R14: ffffffffc05ef000 R15: ffffffffc05ef050 ORIG_RAX: ffffffffffffffff CS: 0010 SS: 0018 #7 [ffff9dcd013b7cc8] do_one_initcall at ffffffffa3a0218e #8 [ffff9dcd013b7d38] do_init_module at ffffffffa3b81531 #9 [ffff9dcd013b7d58] load_module at ffffffffa3b04aaa #10 [ffff9dcd013b7e90] SYSC_finit_module at ffffffffa3b051f6 #11 [ffff9dcd013b7f38] do_syscall_64 at ffffffffa3a03b7d #12 [ffff9dcd013b7f50] entry_SYSCALL_64_after_swapgs at ffffffffa401924e RIP: 00007f124662c469 RSP: 00007fffc4ca04a8 RFLAGS: 00000246 RAX: ffffffffffffffda RBX: 0000564213d111f0 RCX: 00007f124662c469 RDX: 0000000000000000 RSI: 00005642129d3638 RDI: 0000000000000003 RBP: 00005642129d3638 R8: 0000000000000000 R9: 00007f12468e3ea0 R10: 0000000000000003 R11: 0000000000000246 R12: 0000000000000000 R13: 0000564213d10130 R14: 0000000000000000 R15: 0000000000000000 ORIG_RAX: 0000000000000139 CS: 0033 SS: 002b 

Intentemos mirar el símbolo en la dirección ffffffffc05ed005 :
 
crash> sym ffffffffc05ed005 ffffffffc05ed005 (t) init_module+5 [test-module]
crash> sym ffffffffc05ed005 ffffffffc05ed005 (t) init_module+5 [test-module] 
 
Hmm El problema ocurrió en algún lugar del código de inicialización del test-module controlador del núcleo del test-module . Pero, ¿qué pasó con todos los detalles mostrados en el análisis anterior? Bueno, debido a que este código no es parte de la imagen del núcleo de depuración, necesitará encontrar una manera de cargarlo en su análisis de bloqueo. Esta es la razón por la que le indiqué que copie el archivo de objetos sin tirar en su directorio de trabajo actual. Ahora es el momento de cargar el archivo objeto del módulo:
 
crash> mod -s test ./test.o MODULE NAME SIZE OBJECT FILE ffffffffc05ef000 test 16384 ./test.o
crash> mod -s test ./test.o MODULE NAME SIZE OBJECT FILE ffffffffc05ef000 test 16384 ./test.o 

Ahora puede regresar y mirar la misma dirección de símbolo:
 
crash> sym ffffffffc05ed005 ffffffffc05ed005 (T) init_module+5 [test-module] ↪/home/petros/test-module.c: 8
crash> sym ffffffffc05ed005 ffffffffc05ed005 (T) init_module+5 [test-module] ↪/home/petros/test-module.c: 8 

Y, ahora es el momento de volver a visitar su código y mirar la línea 8:
 
$ sed -n 8p test.c printk("%d\n", *p);
$ sed -n 8p test.c printk("%d\n", *p); 
 
Ahí tienes. El error de página se produjo cuando intentó imprimir el puntero mal definido.
   
¿Recuerdas la advertencia de compilación de antes? Bueno, te estaba advirtiendo por una razón, y en este caso actual, es la razón que provocó el pánico del kernel. Es posible que no sea tan afortunado en futuros casos de codificación.

¿Qué más puedes hacer aquí?

El archivo de bloqueo del kernel preservará muchos artefactos de su sistema en caso de bloqueo. Puede enumerar un breve resumen de los comandos disponibles con el comando de help :
 
crash> help * files mach repeat timer alias foreach mod runq tree ascii fuser mount search union bt gdb net set vm btop help p sig vtop dev ipcs ps struct waitq dis irq pte swap whatis eval kmem ptob sym wr exit list ptov sys q extend log rd task
crash> help * files mach repeat timer alias foreach mod runq tree ascii fuser mount search union bt gdb net set vm btop help p sig vtop dev ipcs ps struct waitq dis irq pte swap whatis eval kmem ptob sym wr exit list ptov sys q extend log rd task 

Por ejemplo, si desea ver un resumen general de la utilización de la memoria:
 
crash> kmem -i PAGES TOTAL PERCENTAGE TOTAL MEM 979869 3.7 GB ---- FREE 835519 3.2 GB 85% of TOTAL MEM USED 144350 563.9 MB 14% of TOTAL MEM SHARED 8374 32.7 MB 0% of TOTAL MEM BUFFERS 3849 15 MB 0% of TOTAL MEM CACHED 0 0 0% of TOTAL MEM SLAB 5911 23.1 MB 0% of TOTAL MEM TOTAL SWAP 1047807 4 GB ---- SWAP USED 0 0 0% of TOTAL SWAP SWAP FREE 1047807 4 GB 100% of TOTAL SWAP COMMIT LIMIT 1537741 5.9 GB ---- COMMITTED 16370 63.9 MB 1% of TOTAL LIMIT
crash> kmem -i PAGES TOTAL PERCENTAGE TOTAL MEM 979869 3.7 GB ---- FREE 835519 3.2 GB 85% of TOTAL MEM USED 144350 563.9 MB 14% of TOTAL MEM SHARED 8374 32.7 MB 0% of TOTAL MEM BUFFERS 3849 15 MB 0% of TOTAL MEM CACHED 0 0 0% of TOTAL MEM SLAB 5911 23.1 MB 0% of TOTAL MEM TOTAL SWAP 1047807 4 GB ---- SWAP USED 0 0 0% of TOTAL SWAP SWAP FREE 1047807 4 GB 100% of TOTAL SWAP COMMIT LIMIT 1537741 5.9 GB ---- COMMITTED 16370 63.9 MB 1% of TOTAL LIMIT 

Si desea ver qué dmesg registró hasta el punto del error:
 
crash> log [ 0.000000] Linux version 4.9.0-8-amd64 ↪( debian-kernel@lists.debian.org ) (gcc version 6.3.0 ↪20170516 (Debian 6.3.0-18+deb9u1) ) #1 SMP Debian ↪4.9.144-3 (2019-02-02) [ 0.000000] Command line: BOOT_IMAGE=/boot/ ↪vmlinuz-4.9.0-8-amd64 root=UUID=bd76b0fe-9d09-40a9- ↪a0d8-a7533620f6fa ro quiet crashkernel=128M [ 0.000000] x86/fpu: Supporting XSAVE feature 0x001: ↪'x87 floating point registers' [ 0.000000] x86/fpu: Supporting XSAVE feature 0x002: ↪'SSE registers' [ 0.000000] x86/fpu: Supporting XSAVE feature 0x004: ↪'AVX registers' [ 0.000000] x86/fpu: xstate_offset[2]: 576, xstate_sizes[2]: ↪256 [ .... ]
crash> log [ 0.000000] Linux version 4.9.0-8-amd64 ↪( debian-kernel@lists.debian.org ) (gcc version 6.3.0 ↪20170516 (Debian 6.3.0-18+deb9u1) ) #1 SMP Debian ↪4.9.144-3 (2019-02-02) [ 0.000000] Command line: BOOT_IMAGE=/boot/ ↪vmlinuz-4.9.0-8-amd64 root=UUID=bd76b0fe-9d09-40a9- ↪a0d8-a7533620f6fa ro quiet crashkernel=128M [ 0.000000] x86/fpu: Supporting XSAVE feature 0x001: ↪'x87 floating point registers' [ 0.000000] x86/fpu: Supporting XSAVE feature 0x002: ↪'SSE registers' [ 0.000000] x86/fpu: Supporting XSAVE feature 0x004: ↪'AVX registers' [ 0.000000] x86/fpu: xstate_offset[2]: 576, xstate_sizes[2]: ↪256 [ .... ] 

Usando la misma utilidad de bloqueo, puede profundizar aún más en las ubicaciones de memoria y su contenido, lo que maneja cada núcleo de la CPU en el momento del bloqueo y mucho más. Si desea obtener más información sobre estas funciones, simplemente escriba help seguido del nombre de la función:
 
crash> help mount
crash> help mount 

Algo similar a una página de manual se cargará en su pantalla.


Fuente: https://www.linuxjournal.com/content/oops-debugging-kernel-panics-0