Linux内核模块调试一

2024-09-05 20:08
文章标签 linux 调试 内核模块

本文主要是介绍Linux内核模块调试一,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

      接下来写个专栏专门讲我们写的linux内核模块出现异常时如何定位和调试。我们先构造一个最简单的内核空指针玩玩。

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>struct __ops_dev{char dev_name[64];}ops_dev_t;int __init oops_init(void)
{int * p =NULL;pr_warn("will init\n");*p=1;return 0;
}void __exit oops_uninit(void)
{pr_warn("will exit\n");return ;
}module_init(oops_init);
module_exit(oops_uninit);
MODULE_LICENSE("GPL");           

 来看看我们的makefile写法

obj-m:=oops.o
EXTRA_CFLAGS += -g
else
KERNELDIR:=/lib/modules/$(shell uname -r)/build
PWD:=$(shell pwd)
default:$(MAKE) -C $(KERNELDIR)  M=$(PWD) modules
clean:rm -rf *.o *.mod.c *.mod.o *.ko
endif

插入模块后dmesg我们可以看到,发生了Oops,其实需要一些背景信息就是寄存器,这里以x86为实验,所以看到有RIP,RIP标识的是当前指令执行地址,我们可以看到是在init_module符号的偏移0x17处。意味着在0x17偏移处出现了错误。

[  237.823288] oops: loading out-of-tree module taints kernel.
[  237.823320] oops: module verification failed: signature and/or required key missing - tainting kernel
[  237.823664] will init
[  237.823668] BUG: kernel NULL pointer dereference, address: 0000000000000000
[  237.823670] #PF: supervisor write access in kernel mode
[  237.823671] #PF: error_code(0x0002) - not-present page
[  237.823672] PGD 0 P4D 0 
[  237.823674] Oops: 0002 [#1] SMP NOPTI
[  237.823676] CPU: 0 PID: 2451 Comm: insmod Tainted: G           OE     5.11.0-22-generic #23-Ubuntu
[  237.823678] Hardware name: VMware, Inc. VMware Virtual Platform/440BX Desktop Reference Platform, BIOS 6.00 02/27/2020
[  237.823679] RIP: 0010:init_module+0x17/0x1000 [oops]
[  237.823682] Code: Unable to access opcode bytes at RIP 0xffffffffc07d1fed.
[  237.823683] RSP: 0018:ffffb59843c43d60 EFLAGS: 00010246
[  237.823685] RAX: 0000000000000000 RBX: 0000000000000000 RCX: ffff981539e18ac8
[  237.823686] RDX: 0000000000000000 RSI: 0000000000000027 RDI: ffff981539e18ac0
[  237.823687] RBP: ffffb59843c43d60 R08: 0000000000000000 R09: ffffb59843c43b58
[  237.823687] R10: ffffb59843c43b50 R11: ffff98153fec68a8 R12: ffffffffc07d2000
[  237.823688] R13: ffff981429558510 R14: 0000000000000000 R15: ffffffffc0848000
[  237.823689] FS:  00007f11f3cc1580(0000) GS:ffff981539e00000(0000) knlGS:0000000000000000
[  237.823691] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[  237.823692] CR2: ffffffffc07d1fed CR3: 000000001feee002 CR4: 00000000003706f0
[  237.823709] Call Trace:
[  237.823712]  do_one_initcall+0x48/0x1d0
[  237.823715]  ? kmem_cache_alloc_trace+0xf6/0x200
[  237.823718]  ? do_init_module+0x28/0x290
[  237.823720]  do_init_module+0x62/0x290
[  237.823722]  load_module+0x6fd/0x780
[  237.823723]  __do_sys_finit_module+0xc2/0x120
[  237.823725]  __x64_sys_finit_module+0x1a/0x20
[  237.823726]  do_syscall_64+0x38/0x90
[  237.823728]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
[  237.823730] RIP: 0033:0x7f11f3dfcf6d
[  237.823732] Code: 28 0d 00 0f 05 eb a9 66 0f 1f 44 00 00 f3 0f 1e fa 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d cb de 0c 00 f7 d8 64 89 01 48
[  237.823734] RSP: 002b:00007fff7002cdb8 EFLAGS: 00000246 ORIG_RAX: 0000000000000139
[  237.823736] RAX: ffffffffffffffda RBX: 000055f0f974d790 RCX: 00007f11f3dfcf6d
[  237.823736] RDX: 0000000000000000 RSI: 000055f0f7b04260 RDI: 0000000000000003
[  237.823737] RBP: 0000000000000000 R08: 0000000000000000 R09: 00007f11f3ecf520
[  237.823738] R10: 0000000000000003 R11: 0000000000000246 R12: 000055f0f7b04260
[  237.823739] R13: 0000000000000000 R14: 000055f0f974d760 R15: 0000000000000000
[  237.823740] Modules linked in: oops(OE+) nls_utf8 isofs rfcomm xt_conntrack nft_chain_nat xt_MASQUERADE nf_nat nf_conntrack_netlink nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 xfrm_user xfrm_algo nft_counter xt_addrtype nft_compat nf_tables libcrc32c nfnetlink br_netfilter bridge stp llc overlay bnep vsock_loopback vmw_vsock_virtio_transport_common vmw_vsock_vmci_transport vsock nls_iso8859_1 intel_rapl_msr intel_rapl_common snd_ens1371 snd_ac97_codec crct10dif_pclmul gameport ghash_clmulni_intel ac97_bus snd_pcm snd_seq_midi snd_seq_midi_event aesni_intel crypto_simd cryptd glue_helper rapl vmw_balloon snd_rawmidi snd_seq joydev input_leds snd_seq_device serio_raw snd_timer snd soundcore vmw_vmci mac_hid btusb btrtl btbcm btintel bluetooth ecdh_generic ecc sch_fq_codel vmwgfx ttm drm_kms_helper cec rc_core fb_sys_fops syscopyarea sysfillrect sysimgblt msr parport_pc ppdev drm lp parport ip_tables x_tables autofs4 hid_generic usbhid hid crc32_pclmul mptspi mptscsih psmouse ahci e1000
[  237.823777]  libahci mptbase scsi_transport_spi i2c_piix4 pata_acpi
[  237.823781] CR2: 0000000000000000
[  237.823782] ---[ end trace 4f3baa0cf2fdf2af ]---
[  237.823783] RIP: 0010:init_module+0x17/0x1000 [oops]
[  237.823786] Code: Unable to access opcode bytes at RIP 0xffffffffc07d1fed.
[  237.823787] RSP: 0018:ffffb59843c43d60 EFLAGS: 00010246
[  237.823788] RAX: 0000000000000000 RBX: 0000000000000000 RCX: ffff981539e18ac8
[  237.823789] RDX: 0000000000000000 RSI: 0000000000000027 RDI: ffff981539e18ac0
[  237.823790] RBP: ffffb59843c43d60 R08: 0000000000000000 R09: ffffb59843c43b58
[  237.823790] R10: ffffb59843c43b50 R11: ffff98153fec68a8 R12: ffffffffc07d2000
[  237.823791] R13: ffff981429558510 R14: 0000000000000000 R15: ffffffffc0848000
[  237.823792] FS:  00007f11f3cc1580(0000) GS:ffff981539e00000(0000) knlGS:0000000000000000
[  237.823793] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[  237.823794] CR2: ffffffffc07d1fed CR3: 000000001feee002 CR4: 00000000003706f0
[ 5705.181536] audit: type=1400 audit(1632931211.345:41): apparmor="DENIED" operation="capable" profile="/usr/sbin/cupsd" pid=2786 comm="cupsd" capability=12  capname="net_admin"

反汇编ko文件,使用命令 objdump -S  oops.ko ,可以定位到0x17的地方,正是指针解引用赋值的地方。需要注意的是,想反汇编出源码对应汇编这种格式,需要在编译的时候指定-g,都懂得。

 12 int __init oops_init(void)13 {14    0:   e8 00 00 00 00          call   5 <init_module+0x5>15    5:   55                      push   %rbp16         int * p =NULL;17         pr_warn("will init\n");18    6:   48 c7 c7 00 00 00 00    mov    $0x0,%rdi19 {20    d:   48 89 e5                mov    %rsp,%rbp21         pr_warn("will init\n");22   10:   e8 00 00 00 00          call   15 <init_module+0x15>23         *p=1;24         return 0;25 }26   15:   31 c0                   xor    %eax,%eax27         *p=1;28   17:   c7 04 25 00 00 00 00    movl   $0x1,0x029   1e:   01 00 00 0030 }31   22:   5d                      pop    %rbp32   23:   c3                      ret33 

当然gdb也可以加载ko然后反汇编函数

gdb *.ko(gdb)  disassemble /m oops_init
Dump of assembler code for function oops_init:
warning: Source file is more recent than executable.
12	{0x000000000000003c <+0>:	call   0x41 <oops_init+5>0x0000000000000041 <+5>:	push   %rbp0x0000000000000049 <+13>:	mov    %rsp,%rbp13		int * p =NULL;14		pr_warn("will init\n");0x0000000000000042 <+6>:	mov    $0x0,%rdi0x000000000000004c <+16>:	call   0x51 <oops_init+21>15		*p=1;0x0000000000000053 <+23>:	movl   $0x1,0x016		return 0;17	}0x0000000000000051 <+21>:	xor    %eax,%eax0x000000000000005e <+34>:	pop    %rbp0x000000000000005f <+35>:	ret    End of assembler dump.
(gdb) 

这篇关于Linux内核模块调试一的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1139937

相关文章

Linux ls命令操作详解

《Linuxls命令操作详解》通过ls命令,我们可以查看指定目录下的文件和子目录,并结合不同的选项获取详细的文件信息,如权限、大小、修改时间等,:本文主要介绍Linuxls命令详解,需要的朋友可... 目录1. 命令简介2. 命令的基本语法和用法2.1 语法格式2.2 使用示例2.2.1 列出当前目录下的文

使用Python自建轻量级的HTTP调试工具

《使用Python自建轻量级的HTTP调试工具》这篇文章主要为大家详细介绍了如何使用Python自建一个轻量级的HTTP调试工具,文中的示例代码讲解详细,感兴趣的小伙伴可以参考一下... 目录一、为什么需要自建工具二、核心功能设计三、技术选型四、分步实现五、进阶优化技巧六、使用示例七、性能对比八、扩展方向建

Linux中的计划任务(crontab)使用方式

《Linux中的计划任务(crontab)使用方式》:本文主要介绍Linux中的计划任务(crontab)使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、前言1、linux的起源与发展2、什么是计划任务(crontab)二、crontab基础1、cro

Linux换行符的使用方法详解

《Linux换行符的使用方法详解》本文介绍了Linux中常用的换行符LF及其在文件中的表示,展示了如何使用sed命令替换换行符,并列举了与换行符处理相关的Linux命令,通过代码讲解的非常详细,需要的... 目录简介检测文件中的换行符使用 cat -A 查看换行符使用 od -c 检查字符换行符格式转换将

Linux系统配置NAT网络模式的详细步骤(附图文)

《Linux系统配置NAT网络模式的详细步骤(附图文)》本文详细指导如何在VMware环境下配置NAT网络模式,包括设置主机和虚拟机的IP地址、网关,以及针对Linux和Windows系统的具体步骤,... 目录一、配置NAT网络模式二、设置虚拟机交换机网关2.1 打开虚拟机2.2 管理员授权2.3 设置子

Linux系统中卸载与安装JDK的详细教程

《Linux系统中卸载与安装JDK的详细教程》本文详细介绍了如何在Linux系统中通过Xshell和Xftp工具连接与传输文件,然后进行JDK的安装与卸载,安装步骤包括连接Linux、传输JDK安装包... 目录1、卸载1.1 linux删除自带的JDK1.2 Linux上卸载自己安装的JDK2、安装2.1

Linux卸载自带jdk并安装新jdk版本的图文教程

《Linux卸载自带jdk并安装新jdk版本的图文教程》在Linux系统中,有时需要卸载预装的OpenJDK并安装特定版本的JDK,例如JDK1.8,所以本文给大家详细介绍了Linux卸载自带jdk并... 目录Ⅰ、卸载自带jdkⅡ、安装新版jdkⅠ、卸载自带jdk1、输入命令查看旧jdkrpm -qa

Linux samba共享慢的原因及解决方案

《Linuxsamba共享慢的原因及解决方案》:本文主要介绍Linuxsamba共享慢的原因及解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录linux samba共享慢原因及解决问题表现原因解决办法总结Linandroidux samba共享慢原因及解决

新特性抢先看! Ubuntu 25.04 Beta 发布:Linux 6.14 内核

《新特性抢先看!Ubuntu25.04Beta发布:Linux6.14内核》Canonical公司近日发布了Ubuntu25.04Beta版,这一版本被赋予了一个活泼的代号——“Plu... Canonical 昨日(3 月 27 日)放出了 Beta 版 Ubuntu 25.04 系统镜像,代号“Pluc

Linux安装MySQL的教程

《Linux安装MySQL的教程》:本文主要介绍Linux安装MySQL的教程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录linux安装mysql1.Mysql官网2.我的存放路径3.解压mysql文件到当前目录4.重命名一下5.创建mysql用户组和用户并修