You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

调用alloc_netdev触发Segmentation fault的Linux驱动问题排查

问题:调用alloc_netdev分配网络设备时触发Segmentation Fault

问题详情

开发Linux虚拟网络驱动时,执行以下代码触发段错误:

dev = alloc_netdev(sizeof(struct dev_priv),"super_giga_interface",NET_NAME_UNKNOWN,ipsec_setup);

内核日志输出:

[ 2055.285970] invalid opcode: 0000 [#1] PREEMPT SMP NOPTI
[ 2055.285972] CPU: 3 PID: 3714 Comm: insmod Tainted: G           OE      6.1.0-16-amd64 #1  Debian 6.1.67-1
[ 2055.285974] Hardware name: innotek GmbH VirtualBox/VirtualBox, BIOS VirtualBox 12/01/2006
[ 2055.285975] RIP: 0010:alloc_netdev_mqs+0x418/0x420
[ 2055.285979] Code: e8 dd b2 ae ff 41 0f b7 86 66 02 00 00 4c 89 f7 48 29 c7 e8 5a 2d ae ff e9 4b ff ff ff 49 c7 86 08 02 00 00 00 4b 93 b2 eb b4 <0f> 0b 66 0f 1f 44 00 00 0f 1f 44 00 00 41 57 49 89 cf 41 56 49 89

内核版本:6.1.0-16-amd64

Makefile内容:

obj-m += net.o

PWD := $(CURDIR)

all:
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

驱动核心代码片段:

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/netdevice.h>

struct dev_priv {
    char* dev_buff;
    ssize_t dev_buff_length;
};

static struct net_device* dev;
static struct dev_priv* priv;

static struct net_device_ops net_ops = {
    .ndo_open = open,
    .ndo_stop = stop,
    .ndo_start_xmit = start_xmit,
};

static void ipsec_setup(struct net_device* dev)
{
    dev->netdev_ops = &net_ops;
}

static int __init ipsec_init(void)
{
    int err;
    dev = alloc_netdev(sizeof(struct dev_priv),"super_giga_interface",NET_NAME_UNKNOWN,ipsec_setup);
    
    if (!dev)
    {
        pr_err("IPsec: Can't allocate netdev!\n");
        return -ENOMEM;
    }
    priv = netdev_priv(dev);
    
    priv->dev_buff = kmalloc(NET_BUFF_LENGTH,GFP_KERNEL);
    if (!priv)
    {
        pr_err("IPsec: Can't allocate memory for net device private data!\n");
        return -ENOMEM;
    }
    // ... 后续注册代码
}

问题原因及修复方案

1. 核心错误:未调用默认网络设备初始化函数

你的ipsec_setup函数仅设置了netdev_ops,但未调用内核提供的默认初始化函数(如ether_setup)。alloc_netdev分配设备后会执行传入的setup函数,而默认初始化函数会填充struct net_device中大量必要字段(MTU、硬件头长度、设备标志等),缺失这些初始化会导致内核后续操作访问未初始化内存,触发段错误。

修复代码:

static void ipsec_setup(struct net_device* dev)
{
    ether_setup(dev); // 先初始化以太网设备默认参数
    dev->netdev_ops = &net_ops;
}

2. 次要错误:内存分配后的检查逻辑错误

初始化私有数据时,你错误地检查priv是否为空,实际应检查priv->dev_buff,且错误分支需释放已分配的netdev避免内存泄漏:

// 错误代码
priv->dev_buff = kmalloc(NET_BUFF_LENGTH,GFP_KERNEL);
if (!priv) { ... }

// 正确代码
priv->dev_buff = kmalloc(NET_BUFF_LENGTH,GFP_KERNEL);
if (!priv->dev_buff) {
    pr_err("IPsec: Can't allocate memory for device buffer!\n");
    free_netdev(dev);
    return -ENOMEM;
}

3. 其他优化点

  • 卸载模块时,先判断priv->dev_buff不为空再调用kfree,避免空指针访问;
  • proc_create权限设置为0444,但proc_write允许写入,建议调整为0644。

验证修复

修改后重新编译驱动,执行insmod加载,alloc_netdev可正常执行,后续设备注册流程也能顺利完成。

内容的提问来源于stack exchange,提问作者Artem Dudich

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 07:54:55