Netlink giving kernel panic

半世苍凉 提交于 2019-12-19 11:57:15

问题


I tried this program. This program send "hello" to kernel and kernel replies "hello" to user space again for one time.

My requirement: user has to send "hello" and have to receive message for every 2 seconds.

What I have tried.

User app: added loopfor sending and receiving

#define NETLINK_USER 31    
#define MAX_PAYLOAD 1024 /* maximum payload size*/

struct sockaddr_nl src_addr, dest_addr;
struct nlmsghdr *nlh = NULL;
struct iovec iov;
int sock_fd;
struct msghdr msg;

int main()
{
    sock_fd=socket(PF_NETLINK, SOCK_RAW, NETLINK_USER);
    if(sock_fd<0)
        return -1;

    memset(&src_addr, 0, sizeof(src_addr));
    src_addr.nl_family = AF_NETLINK;
    src_addr.nl_pid = getpid(); /* self pid */

    bind(sock_fd, (struct sockaddr*)&src_addr, sizeof(src_addr));

    memset(&dest_addr, 0, sizeof(dest_addr));
    memset(&dest_addr, 0, sizeof(dest_addr));
    dest_addr.nl_family = AF_NETLINK;
    dest_addr.nl_pid = 0; /* For Linux Kernel */
    dest_addr.nl_groups = 0; /* unicast */

    nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD));
    memset(nlh, 0, NLMSG_SPACE(MAX_PAYLOAD));
    nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD);
    nlh->nlmsg_pid = getpid();
    nlh->nlmsg_flags = 0;

    strcpy(NLMSG_DATA(nlh), "Hello");

    iov.iov_base = (void *)nlh;
    iov.iov_len = nlh->nlmsg_len;
    msg.msg_name = (void *)&dest_addr;
    msg.msg_namelen = sizeof(dest_addr);
    msg.msg_iov = &iov;
    msg.msg_iovlen = 1;
    while(1) {           // <--- loop here. only works once.
        sleep(2);
        printf("Sending message to kernel\n");
        sendmsg(sock_fd,&msg,0);

        recvmsg(sock_fd, &msg, 0);
        printf("Received message payload: %s\n", (char *)NLMSG_DATA(nlh));
    }

    close(sock_fd);
}

Kernel module: didn't changed anything.

#define NETLINK_USER 31
struct sock *nl_sk = NULL;

static void hello_nl_recv_msg(struct sk_buff *skb) 
{
    struct nlmsghdr *nlh;
    int pid;
    struct sk_buff *skb_out;
    int msg_size;
    char *msg="Hello from kernel";
    int res;

    printk(KERN_INFO "Entering: %s\n", __FUNCTION__);

    msg_size=strlen(msg);

    nlh=(struct nlmsghdr*)skb->data;
    printk(KERN_INFO "Netlink received msg payload:%s\n",(char*)nlmsg_data(nlh));
    pid = nlh->nlmsg_pid; /*pid of sending process */

    skb_out = nlmsg_new(msg_size,0);

    if(!skb_out)
    {
        printk(KERN_ERR "Failed to allocate new skb\n");
        return;
    } 
    nlh=nlmsg_put(skb_out,0,0,NLMSG_DONE,msg_size,0);  
    NETLINK_CB(skb_out).dst_group = 0; /* not in mcast group */
    strncpy(nlmsg_data(nlh),msg,msg_size);

    res=nlmsg_unicast(nl_sk,skb_out,pid);

    if(res<0)
        printk(KERN_INFO "Error while sending bak to user\n"); 
}

static int __init hello_init(void)
{
    struct netlink_kernel_cfg cfg = {
        .input = hello_nl_recv_msg
    };

    nl_sk = netlink_kernel_create(&init_net, NETLINK_USER, &cfg);

    printk("Entering: %s\n",__FUNCTION__);

    if(!nl_sk)
    {    
        printk(KERN_ALERT "Error creating socket.\n");
        return -10;
    }
    return 0;
}

static void __exit hello_exit(void) 
{
    printk(KERN_INFO "exiting hello module\n");
    netlink_kernel_release(nl_sk);
}

module_init(hello_init);
module_exit(hello_exit);

This code works for first loop only. next time kernel is crashing and giving kernel panic error in black screen. Every time I'm doing reboot. Why it is giving kernel panic? Where I have to modify? I think problem is in kernel module.
Kernel: 3.13.0-24-generic


回答1:


Well, I thought the problem is in Kernel module. But the problem is in user module. I worked 3 days to identify this problem. The problem is at

while(1) {           
    sleep(2);
    printf("Sending message to kernel\n");
    sendmsg(sock_fd,&msg,0);     // In 2nd iteration msg value chaged

    recvmsg(sock_fd, &msg, 0);  // <--- msg will update
    printf("Received message payload: %s\n", (char *)NLMSG_DATA(nlh));
}

This loops works only once. That is true. After receiving the message using recvmsg, msg variable is updated and I used that variable to send again. This is because of the code is over smart, both(source and destination) are referring to same pointer.

By writing different variables for sendmsg and recvmsg will remove the problem.

int main()
{
    int seq_no = 1;
    sock_fd=socket(PF_NETLINK, SOCK_RAW, NETLINK_USER);
    if(sock_fd<0)
            return -1;

    memset(&src_addr, 0, sizeof(src_addr));
    src_addr.nl_family = AF_NETLINK;
    src_addr.nl_pid = getpid(); /* self pid */

    bind(sock_fd, (struct sockaddr*)&src_addr, sizeof(src_addr));

    memset(&dest_addr, 0, sizeof(dest_addr));
    dest_addr.nl_family = AF_NETLINK;
    dest_addr.nl_pid = 0; /* For Linux Kernel */
    dest_addr.nl_groups = 0; /* unicast */

    nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD));
    memset(nlh, 0, NLMSG_SPACE(MAX_PAYLOAD));
    nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD);
    nlh->nlmsg_pid = getpid();
    nlh->nlmsg_flags = 0;

    strcpy(NLMSG_DATA(nlh), "Hello");

    iov.iov_base = (void *)nlh;
    iov.iov_len = nlh->nlmsg_len;
    msg.msg_name = (void *)&dest_addr;
    msg.msg_namelen = sizeof(dest_addr);
    msg.msg_iov = &iov;
    msg.msg_iovlen = 1;
                                            /* receiver parameters */
    nlh_in = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD));
    iov_in.iov_base = (void *)nlh_in;
    iov_in.iov_len = nlh->nlmsg_len;
    msg_in.msg_iov = &iov_in;
    msg_in.msg_iovlen = 1;                  /* end */

    while(1) {
        printf("sending message to kernel\n");
        sendmsg(sock_fd,&msg,0);

        recvmsg(sock_fd, &msg_in, 0);
        printf("Received message payload: %s\n", (char *)NLMSG_DATA(nlh_in));
        sleep(1);
    }
    free(nlh);
    close(sock_fd);
}


来源:https://stackoverflow.com/questions/23852866/netlink-giving-kernel-panic

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!