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

相关文章

Oracle数据库定时备份脚本方式(Linux)

《Oracle数据库定时备份脚本方式(Linux)》文章介绍Oracle数据库自动备份方案,包含主机备份传输与备机解压导入流程,强调需提前全量删除原库数据避免报错,并需配置无密传输、定时任务及验证脚本... 目录说明主机脚本备机上自动导库脚本整个自动备份oracle数据库的过程(建议全程用root用户)总结

Linux如何查看文件权限的命令

《Linux如何查看文件权限的命令》Linux中使用ls-R命令递归查看指定目录及子目录下所有文件和文件夹的权限信息,以列表形式展示权限位、所有者、组等详细内容... 目录linux China编程查看文件权限命令输出结果示例这里是查看tomcat文件夹总结Linux 查看文件权限命令ls -l 文件或文件夹

idea的终端(Terminal)cmd的命令换成linux的命令详解

《idea的终端(Terminal)cmd的命令换成linux的命令详解》本文介绍IDEA配置Git的步骤:安装Git、修改终端设置并重启IDEA,强调顺序,作为个人经验分享,希望提供参考并支持脚本之... 目录一编程、设置前二、前置条件三、android设置四、设置后总结一、php设置前二、前置条件

Linux系统中查询JDK安装目录的几种常用方法

《Linux系统中查询JDK安装目录的几种常用方法》:本文主要介绍Linux系统中查询JDK安装目录的几种常用方法,方法分别是通过update-alternatives、Java命令、环境变量及目... 目录方法 1:通过update-alternatives查询(推荐)方法 2:检查所有已安装的 JDK方

Linux系统之lvcreate命令使用解读

《Linux系统之lvcreate命令使用解读》lvcreate是LVM中创建逻辑卷的核心命令,支持线性、条带化、RAID、镜像、快照、瘦池和缓存池等多种类型,实现灵活存储资源管理,需注意空间分配、R... 目录lvcreate命令详解一、命令概述二、语法格式三、核心功能四、选项详解五、使用示例1. 创建逻

Linux下在线安装启动VNC教程

《Linux下在线安装启动VNC教程》本文指导在CentOS7上在线安装VNC,包含安装、配置密码、启动/停止、清理重启步骤及注意事项,强调需安装VNC桌面以避免黑屏,并解决端口冲突和目录权限问题... 目录描述安装VNC安装 VNC 桌面可能遇到的问题总结描js述linux中的VNC就类似于Window

linux下shell脚本启动jar包实现过程

《linux下shell脚本启动jar包实现过程》确保APP_NAME和LOG_FILE位于目录内,首次启动前需手动创建log文件夹,否则报错,此为个人经验,供参考,欢迎支持脚本之家... 目录linux下shell脚本启动jar包样例1样例2总结linux下shell脚本启动jar包样例1#!/bin

在IntelliJ IDEA中高效运行与调试Spring Boot项目的实战步骤

《在IntelliJIDEA中高效运行与调试SpringBoot项目的实战步骤》本章详解SpringBoot项目导入IntelliJIDEA的流程,教授运行与调试技巧,包括断点设置与变量查看,奠定... 目录引言:为良驹配上好鞍一、为何选择IntelliJ IDEA?二、实战:导入并运行你的第一个项目步骤1

Linux之platform平台设备驱动详解

《Linux之platform平台设备驱动详解》Linux设备驱动模型中,Platform总线作为虚拟总线统一管理无物理总线依赖的嵌入式设备,通过platform_driver和platform_de... 目录platform驱动注册platform设备注册设备树Platform驱动和设备的关系总结在 l

linux批量替换文件内容的实现方式

《linux批量替换文件内容的实现方式》本文总结了Linux中批量替换文件内容的几种方法,包括使用sed替换文件夹内所有文件、单个文件内容及逐行字符串,强调使用反引号和绝对路径,并分享个人经验供参考... 目录一、linux批量替换文件内容 二、替换文件内所有匹配的字符串 三、替换每一行中全部str1为st