调用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
相关产品推荐
相关产品推荐

