linux-kernellinux-device-driversystems-programmingnetwork-driver

Segmentation fault when calling alloc_netdev


I am having trouble with coding linux driver. When try to allocate netdev in this line:

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

I get segmentation fault. What am I doing wrong?

Here is entries in kernel journal:

[ 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

My kernel version is 6.1.0-16-amd64.

My 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

My dummy network driver code:

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/netdevice.h>
#include <linux/proc_fs.h>

MODULE_DESCRIPTION("Iplementation of IPsec");
MODULE_AUTHOR("Artem");
MODULE_VERSION("1.0");
MODULE_LICENSE("GPL");

#define NET_BUFF_LENGTH 128
#define PROC_FILENAME "IPsec_buffer"

static struct proc_dir_entry* proc_file;

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

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

static int proc_open(struct inode* inode, struct file* filp)
{
    try_module_get(THIS_MODULE);
    return 0;
}

static ssize_t proc_read(struct file* filp, char __user* buffer, size_t len, loff_t* offset)
{
    char* msg = "Reading is not supported!";
    if (buffer == NULL || len < 26)
    {
        return -EINVAL;
    }

    int n = copy_to_user(buffer,msg,26);
    return 26 - n;
}

static ssize_t proc_write(struct file* filp, const char __user* buff, size_t len, loff_t* offset)
{
    if (buff == NULL || len <= 0 || len > NET_BUFF_LENGTH)
    {
        return -EINVAL;
    }
    int n = copy_from_user(priv->dev_buff,buff,len);
    return len - n;

}
static int proc_release(struct inode *, struct file *)
{
    module_put(THIS_MODULE);
    return 0;
}


static const struct proc_ops proc_fops = {
    .proc_open = proc_open,
    .proc_read = proc_read,
    .proc_write = proc_write,
    .proc_release = proc_release,
};

static int open(struct net_device *dev)
{
    pr_info("IPsec: Interface is up\n");
    proc_file = proc_create(PROC_FILENAME, 0444, NULL, &proc_fops);
    if (proc_file == NULL)
    {
        pr_err("IPsec: Can't create proc file!\n");
        return -ENOMEM;
    }
    return 0;
}
static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
{
    pr_info("IPsec: Sending packet\n");
    return NETDEV_TX_OK;
}
static int stop(struct net_device* dev)
{
    pr_info("IPsec: Interface is down\n");
    remove_proc_entry(PROC_FILENAME, NULL);
    return 0;
}

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);
    

    pr_info("IPsec:allocating memory\n");
    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;
    }
    pr_info("IPsec:memory is allocated!\n");
    priv->dev_buff_length = NET_BUFF_LENGTH;

    err = register_netdev(dev);
    if (err)
    {
        free_netdev(dev);
        pr_err("IPsec: Can't register netdev! Error: %d\n",err);
        return err;
    }
    pr_info("IPsec: Module is successfuly initialized!\n");
    return 0;
}

static void __exit ipsec_cleanup(void)
{
    kfree(priv->dev_buff);
    unregister_netdev(dev);
    free_netdev(dev);
    pr_info("IPsec: Module is successfuly removed!\n");
}

module_init(ipsec_init);
module_exit(ipsec_cleanup);`

I have detected that the problem (by printing) is causing right in alloc_netdev function, cause code does not goes after it


Solution

  • I've solved this problem. This comprasion causes error. Look here snippet from source code

    Maximum interface length is contained in IFNAMSIZ constant and equals to 16 bytes. It is defined in Ifdef.h