Unable to handle kernel NULL pointer dereference at virtual address 0000000d[ 435.859000] pgd = c9

文章描述了一位新手在学习Linux驱动开发时遇到的问题,具体是关于混杂设备注册的代码导致的NULL指针异常。作者经过调试发现,驱动层的open函数返回值为1是问题所在,修改为返回0后解决了问题。这表明驱动的open函数应按照标准返回0以表示成功。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

由于本人刚学驱动新手,不会太多反向操作。看了很多博主也没有解决。

经过我一个下午尝试,把代码缩减缩减在缩减之后,我发现了

先看下面的代码,有问题的代码(扫一眼就行了,估计没人看的出来

#include <linux/init.h>
#include <linux/module.h>
#include <linux/gpio.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/errno.h>

int misc_open(struct inode *inode, struct file *file)
{
    printk(KERN_INFO "打开\n");
    return 1;
}

int misc_release(struct inode *inode, struct file *file)
{
    printk(KERN_INFO "关闭\n");
    return 1;
}

static struct file_operations misc_operations = {
    .owner = THIS_MODULE,
    .open = misc_open,
    .release = misc_release};

// 混杂设备结构体
static struct miscdevice misc_misc =
    {.minor = MISC_DYNAMIC_MINOR,
     .name = "my_misc",
     .fops = &misc_operations};

static int __init mymisc_init(void)
{
    int rt;
    printk(KERN_INFO "混杂设备初始化\n");

    // 注册混杂设备
    // 混杂设备注册后都会在/sys/class/misc/下面看到,主设备号为10,此设备号可以
    // 自己分配。也可系统自动分配。misc_register原型其实就高度封装了字符设备注册
    rt = misc_register(&misc_misc);
    if (rt < 0)
    {
        printk(KERN_ERR "注册混杂设备失败\n");
        goto err_misc_register;
    }
    return 0;

err_misc_register:
    return rt;
}

static void __exit mymisc_exit(void)
{
    // 注销混杂设备
    misc_deregister(&misc_misc);
    printk(KERN_INFO "注销混杂设备成功\n");
}

module_init(mymisc_init);

module_exit(mymisc_exit);

MODULE_LICENSE("GPL");

应用层

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, char const *argv[])
{
    int fd_led = open("/dev/my_misc", O_RDWR);
    if (fd_led < 0)
    {
        printf("/dev/my_misc 打开失败\n");
        return -1;
    }
    printf("/dev/my_misc 打开成功!!!!!!!!!!!!!!!!!!!\n");

    close(fd_led);

    return 0;
}

这段代码就是混杂设备注册代码,没有啥的但是当我下载到开发板之后运行就会报错

[root@GEC6818 /Drive/Misc]#./misc_open 
[  763.422000] 打开    //这个是驱动层调试用的,由驱动层打印
[  763.422000] Unable to handle kernel NULL pointer dereference at virtual address 0000000d
[  763.427000] pgd = c9690000
[  763.429000] [0000000d] *pgd=49ab4831, *pte=00000000, *ppte=00000000
[  763.435000] Internal error: Oops: 17 [#9] PREEMPT SMP ARM
[  763.441000] Modules linked in: misc_drv(O) rtl8723bu_wifi(O) x6818_humidity(O) stepmotor(O) relay(O) led(O) gec6818_beep(O) gas_drv(O) dc_motor(O) buttons_drv(O) [last unloaded: misc_drv]
[  763.457000] CPU: 1    Tainted: G      D    O  (3.4.39-gec #21)
[  763.463000] PC is at do_sys_open+0xf8/0x174
[  763.467000] LR is at path_openat+0xf4/0x3dc
[  763.472000] pc : [<c0123428>]    lr : [<c0131f00>]    psr: 000b0013
[  763.472000] sp : c96dff70  ip : ffffffff  fp : bea05b1c
[  763.483000] r10: 00000000  r9 : c96de000  r8 : ffffff9c
[  763.488000] r7 : 00000001  r6 : 00000003  r5 : c9a6d000  r4 : 00000001
[  763.495000] r3 : 00000000  r2 : c96dfe50  r1 : 200b0013  r0 : 00000001
[  763.501000] Flags: nzcv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment user
[  763.508000] Control: 10c5383d  Table: 4969006a  DAC: 00000015
[  763.514000] 
[  763.514000] PC: 0xc01233a8:
[  763.518000] 33a8  e58d3010 e58d2014 0a000004 e31c0080 e3823c02 13822c06 e58d3014 158d2014
[  763.526000] 33c8  e31c0901 e1a00001 13a07002 03a07000 e31c0902 03877001 eb002889 e3700a01
[  763.535000] 33e8  e1a05000 81a06000 8a000024 e1a01004 e3a00000 eb00692f e2506000 ba00001d
[  763.543000] 3408  e1a00008 e1a03007 e1a01005 e28d2008 eb003b9c e3700a01 e1a04000 8a00001a
[  763.551000] 3428  e590100c e2807008 e1a00007 e5918020 e1d890b0 e2099a0f e3590901 03a09181
[  763.559000] 3448  13a09020 e1a02009 eb00e5dc e3a0c000 e1a01009 e1a00008 e1a02007 e58dc000
[  763.567000] 3468  e3a03001 e58dc004 eb00e4ea e1a00006 e1a01004 ebfffc6d e1a00005 eb002863
[  763.575000] 3488  e1a00006 e28dd01c e8bd83f0 e1a00006 e1a06004 ebfffc1b eafffff6 e1a0c001
[  763.583000] 
[  763.583000] LR: 0xc0131e80:
[  763.588000] 1e80  e2503000 1a000028 e1a0000d e1a01004 e3c09d7f e1a00006 e3c9903f e599200c
[  763.596000] 1ea0  e5823308 ebfff682 e2503000 1a00001e e28d8020 e1a00004 e1a01008 e1a02005
[  763.604000] 1ec0  e1a03006 ebfffbdc e2507000 0a000018 e5943014 e3530000 0a000002 e5943020
[  763.612000] 1ee0  e3130a02 0a000008 e59d001c e3500000 0a000000 ebffce7c e1a00004 ebffffb8
[  763.620000] 1f00  e1a00007 e28dd034 e8bd8ff0 e5940018 eb0019e4 e5940014 eb00353d eafffff1
[  763.628000] 1f20  e3e00016 e28dd034 e8bd8ff0 e1a07003 eaffffe6 e5943020 e28d2028 e8980003
[  763.637000] 1f40  e58d2014 e3130001 e8820003 0a00003c e3c32c07 e3130040 e59d702c e3823010
[  763.645000] 1f60  e5843020 1a00009e e59d0028 e5943000 e1500003 0a000098 e599300c e5933308
[  763.653000] 
[  763.653000] SP: 0xc96dfef0:
[  763.657000] fef0  00000041 c0a68d38 c98ab550 e2e02e10 ce270431 00000007 c9a6d005 00000000
[  763.665000] ff10  c0123428 000b0013 ffffffff c96dff5c ffffff9c c000e7d8 00000001 200b0013
[  763.673000] ff30  c96dfe50 00000000 00000001 c9a6d000 00000003 00000001 ffffff9c c96de000
[  763.682000] ff50  00000000 bea05b1c ffffffff c96dff70 c0131f00 c0123428 000b0013 ffffffff
[  763.690000] ff70  08100871 c06fbad8 00000002 e3130000 00000026 00000100 b6fbe000 00000000
[  763.698000] ff90  00000000 00010324 00000005 c000edc4 c96de000 c000ec40 00000000 00000000
[  763.706000] ffb0  00010558 00000002 bea05c7c 0001044c 00000000 00000000 00010324 00000005
[  763.714000] ffd0  00000000 00000000 b6fef000 bea05b1c 00000000 bea05b04 00010474 b6f3c870
[  763.722000] 
[  763.722000] R2: 0xc96dfdd0:
[  763.727000] fdd0  00000017 c9963800 c96dff28 c9963800 0000000d c06f28d0 c99f3c00 c001924c
[  763.735000] fdf0  00000001 00000001 c96dfe0c c0072d10 00000000 00000000 c9963848 00000000
[  763.743000] fe10  00010000 00000000 c96dfef8 c95ae540 00000001 e2e02e5c c0a60520 c98ab540
[  763.751000] fe30  00000001 00000001 c96dfe4c c0072d10 c96dfef8 c993d478 bea05b1c c013e2b4
[  763.759000] fe50  c0a4c34c c0131160 e2c23000 e316c030 c96dfef8 00000017 c0018f78 c0a68b38
[  763.767000] fe70  0000000d c96dff28 c96de000 00000000 bea05b1c c0008424 c96de000 00000000
[  763.776000] fe90  bea05b1c c0131ec8 c96dfeb4 00000000 e2e447a0 00000000 b6fef000 c9963804
[  763.784000] feb0  b6fee000 00000000 c98ab550 e2e02e10 e3137738 c0af18d0 b6fef000 c96dff78
[  763.792000] 
[  763.792000] R5: 0xc9a6cf80:
[  763.796000] cf80  e7fddef0 e7fddef0 e7fddef0 e7fddef0 e7fddef0 e7fddef0 e7fddef0 e7fddef0
[  763.804000] cfa0  e7fddef0 e7fddef0 e7fddef0 e7fddef0 e7fddef0 e7fddef0 e7fddef0 e7fddef0
[  763.813000] cfc0  e7fddef0 e7fddef0 e7fddef0 e7fddef0 e7fddef0 e7fddef0 e7fddef0 e7fddef0
[  763.821000] cfe0  e7fddef0 e7fddef0 e7fddef0 e7fddef0 e7fddef0 e7fddef0 e7fddef0 e7fddef0
[  763.829000] d000  7665642f 5f796d2f 6373696d 6f003600 0000362e 00362e6f 00362e6f 00362e6f
[  763.837000] d020  62696c00 6f732e63 6f00362e 0000362e 00362e6f 00362e6f 00362e6f 00000000
[  763.845000] d040  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[  763.853000] d060  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[  763.861000] 
[  763.861000] R9: 0xc96ddf80:
[  763.866000] df80  00000000 c00491f0 00000000 00000001 00000000 b6ebf798 000000f8 c0049274
[  763.874000] dfa0  00000000 c000ec40 00000001 00000000 00000000 b6ec20ac 00000000 00000000
[  763.882000] dfc0  00000001 00000000 b6ebf798 000000f8 b6ec20ac 00000000 b6fad000 00000000
[  763.890000] dfe0  00000000 bee4dcc4 b6daebd8 b6e1e734 600b0010 00000000 00000000 00000000
[  763.898000] e000  00000000 00000002 00000000 c99f3c00 c0a72c6c 00000001 00000015 c9a06f40
[  763.907000] e020  00000000 c99f3c00 e30ba300 c1504980 c0a60520 c96de028 c96dfed4 c96dfe28
[  763.915000] e040  c06faa10 00000000 00000000 00000000 00000000 00000000 01000000 00000000
[  763.923000] e060  b6fec4c0 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[  763.931000] Process misc_open (pid: 365, stack limit = 0xc96de2f0)
[  763.937000] Stack: (0xc96dff70 to 0xc96e0000)
[  763.942000] ff60:                                     08100871 c06fbad8 00000002 e3130000
[  763.950000] ff80: 00000026 00000100 b6fbe000 00000000 00000000 00010324 00000005 c000edc4
[  763.958000] ffa0: c96de000 c000ec40 00000000 00000000 00010558 00000002 bea05c7c 0001044c
[  763.966000] ffc0: 00000000 00000000 00010324 00000005 00000000 00000000 b6fef000 bea05b1c
[  763.974000] ffe0: 00000000 bea05b04 00010474 b6f3c870 600b0010 00010558 635f5821 635f5c21
[  763.982000] [<c0123428>] (do_sys_open+0xf8/0x174) from [<c000ec40>] (ret_fast_syscall+0x0/0x30)
[  763.991000] Code: eb003b9c e3700a01 e1a04000 8a00001a (e590100c) 
[  763.997000] ---[ end trace 4883a96b125639a6 ]---
Segmentation fault

最终发现是驱动层 open 函数返回值为 1 的问题

修改后

int misc_open(struct inode *inode, struct file *file)
{
    printk(KERN_INFO "打开\n");
    return 0;
}

[root@GEC6818 /Drive/Misc]# ./misc_open 
[  900.025000] 打开
[  900.025000] 关闭
/dev/my_misc 打开成功!!!!!!!!!!!!!!!!!!!

真的无语,有谁知道原因啊。我也不懂。。。

<think>好的,用户遇到了“Unable to handle kernel NULL pointer dereference at virtual address 0000000000000038”这个错误,我需要详细解释这个问题以及解决方法。首先,我得确定用户对这个错误的了解程度。他们可能是一个Linux系统开发者或者运维人员,遇到了内核崩溃的问题,需要排查原因。 这个错误通常是因为内核代码试图访问一个空指针,具体地址是0x38,看起来像是某个结构体的成员偏移量。比如,可能是一个结构体指针为NULL,然后代码试图访问该结构体的0x38偏移处的成员。例如,task_struct结构体中的某个成员可能位于这个偏移量,所以用户可能是在操作进程管理相关的代码时出了问题。 接下来,我需要解释这个错误的原因。可能的原因包括未正确初始化的指针、内存释放后未置空导致的Use-after-free,或者并发访问导致的竞态条件。需要分步骤说明如何分析这个问题,比如查看Oops日志,使用drgn或crash工具分析转储文件,以及检查代码中的潜在问题。 用户可能需要具体的命令示例,比如如何用drgn查找引发问题的指针,或者如何从Oops日志中获取调用堆栈。同时,还要提醒他们在生产环境中如何处理,比如启用kdump,保留调试符号等。此外,预防措施也很重要,比如代码审查、静态分析工具的使用,以及利用内核内置的调试功能。 需要确保语言通俗易懂,结构清晰,分点列出原因、分析步骤、解决方法和预防措施。还要注意使用用户提到的工具drgn,给出实际案例,比如如何通过drgn找到引发问题的结构体实例。同时,提醒用户注意内核版本差异,不同版本的结构体偏移可能不同,需要确认具体的内核版本信息。</think>以下是对 **"Unable to handle kernel NULL pointer dereference at virtual address 0000000000000038"** 内核错误的全方位解析与处理指南: --- ### **一、错误本质剖析** 该错误表示内核尝试访问地址 `0x38`,但此地址对应的内存页未被映射(即 **NULL指针解引用**)。具体特征: - `0x38` 通常是结构体成员的偏移量(如 `struct task_struct` 的 `files` 字段偏移量是 `0x38`) - 触发场景:当指针本身为 NULL 时,访问其 `+0x38` 偏移位置 - 常见于:进程管理、文件操作、设备驱动等涉及结构体操作的场景 --- ### **二、错误根源分类** | 错误类型 | 典型场景 | 示例代码片段 | |-------------------------|---------------------------------------------|--------------------------------| | **未初始化指针** | 结构体指针未分配内存即访问成员 | `p->member`(`p` 未初始化) | | **Use-After-Free** | 对象释放后未置空指针仍被访问 | `kfree(obj); obj->func()` | | **竞态条件** | 并发操作导致指针被意外置空 | 未加锁的共享资源访问 | | **硬件寄存器误读** | 驱动未检查设备状态直接访问寄存器 | `readl(dev->reg_base + 0x38)` | --- ### **三、诊断步骤** #### 1. 分析内核 Oops 日志 ```bash [ 1273.451699] BUG: unable to handle kernel NULL pointer dereference at 0000000000000038 [ 1273.452412] PGD 0 P4D 0 [ 1273.452728] Oops: 0000 [#1] SMP PTI [ 1273.453153] CPU: 2 PID: 1815 Comm: my_module Tainted: G OE 4.19.0-17-generic [ 1273.453912] RIP: 0010:my_module_func+0x42/0x60 [my_module] # 关键行:定位出错函数 [ 1273.454696] RSP: 0018:ffffb77b827a3d80 EFLAGS: 00010246 [ 1273.455271] RAX: 0000000000000000 RBX: ffff9263cf5e8000 RCX: 0000000000000000 [ 1273.456025] RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000 [ 1273.456767] RBP: ffffb77b827a3da0 R08: 0000000000000000 R09: 0000000000000000 [ 1273.457514] R10: 0000000000000000 R11: 0000000000000000 R12: ffff9263cf5e8000 [ 1273.458258] R13: 0000000000000000 R14: 0000000000000000 R15: 0000000000000000 [ 1273.459008] FS: 00007f8a7f5e7740(0000) GS:ffff9263d6c80000(0000) knlGS:0000000000000000 [ 1273.459864] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 1273.460435] CR2: 0000000000000038 CR3: 00000001c220a002 CR4: 00000000003606e0 ``` 重点关注: - **RIP**:定位崩溃的函数 (`my_module_func+0x42`) - **CR2**:确认故障地址 (`0x38`) - **调用栈**:回溯函数调用链 #### 2. 使用 drgn 动态分析 ```python # 启动 drgn 调试运行中的内核 sudo drgn -k # 定位出错地址对应的结构体 >>> prog = drgn.program() >>> task = find_task(pid) # 替换为实际 PID >>> hex(task.address_of_().value_() + 0x38) # 验证是否为合法成员 &#39;0xffff88800345d038&#39; # 检查指针是否 NULL >>> ptr = prog[&#39;my_global_var&#39;] >>> print(ptr.value_()) (nil) # 如果输出 nil 表示指针为 NULL ``` #### 3. 反汇编定位代码 ```bash # 使用 objdump 反汇编内核模块 objdump -dS my_module.ko > disassembly.txt # 在反汇编结果中搜索偏移量 0x42(根据 Oops 中的 RIP+0x42) grep -A 10 &#39;42:&#39; disassembly.txt ``` --- ### **四、修复方案** #### 1. 基础防护 ```c // 在访问指针前增加判空检查 if (likely(ptr != NULL)) { access_ptr->member = value; // 安全访问 } else { pr_warn("NULL pointer detected at %s\n", __func__); return -EINVAL; } ``` #### 2. 高级防御(内核机制) ```c // 使用 RCU 安全访问 rcu_read_lock(); struct my_struct *p = rcu_dereference(ptr); if (p) { // 安全操作 tmp = p->member; } rcu_read_unlock(); // 使用 refcount 引用计数 if (refcount_inc_not_zero(&obj->refcount)) { // 安全操作 refcount_dec(&obj->refcount); } ``` #### 3. 内存调试工具 ```bash # 启用 KASAN(内核地址消毒剂) CONFIG_KASAN=y CONFIG_KASAN_INLINE=y # 启用 SLUB 调试 CONFIG_SLUB_DEBUG=y CONFIG_SLUB_DEBUG_ON=y # 使用 kmemleak 检测内存泄漏 echo scan > /sys/kernel/debug/kmemleak ``` --- ### **五、实战案例** #### 案例:task_struct 的 files 成员访问崩溃 ```c // 错误代码 struct task_struct *tsk = NULL; struct files_struct *files = tsk->files; // 访问 tsk+0x38 // 修复代码 struct task_struct *tsk = get_current(); // 正确获取当前任务 if (tsk && tsk->files) { struct files_struct *files = tsk->files; } ``` --- ### **六、生产环境处理流程** 1. **紧急响应** ```bash # 捕获崩溃现场 echo c > /proc/sysrq-trigger
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值