gpt4 book ai didi

Linux Netlink 套接字通信导致虚拟机崩溃

转载 作者:塔克拉玛干 更新时间:2023-11-03 01:20:33 26 4
gpt4 key购买 nike

我编写了一个内核模块和用户空间程序,内核模块发送 netlink 多播消息,用户空间程序读取这些消息并将它们打印出来。内核模块和用户空间程序可在此处 (https://github.com/akshayknarayan/netlink-test) 获得,并在下方复制。代码改编自这篇文章:Multicast from kernel to user space via Netlink in C

如果用户空间程序的第 69 行(对 usleep 的调用)被注释掉,那么一切正常;加载内核模块后,它会重复多播消息,用户空间程序将它们打印出来。

但是,如果用户空间程序的第 69 行未注释,则在加载内核模块后的一秒内,我的 VM 会挂起并变得无响应。

为什么会这样?如何防止内核挂起?

Linux ubuntu-xenial 4.4.0-75-generic#96-Ubuntu SMP Thu Apr 20 09:56:33 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux

用户空间程序:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#include <unistd.h>

/* Multicast group, consistent in both kernel prog and user prog. */
#define MYMGRP 22

int nl_open(void) {
int sock;
struct sockaddr_nl addr;
int group = MYMGRP;

sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_USERSOCK);
if (sock < 0) {
printf("sock < 0.\n");
return sock;
}

memset((void *) &addr, 0, sizeof(addr));
addr.nl_family = AF_NETLINK;
addr.nl_pid = getpid();

if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
printf("bind < 0.\n");
return -1;
}

if (setsockopt(sock, 270, NETLINK_ADD_MEMBERSHIP, &group, sizeof(group)) < 0) {
printf("setsockopt < 0\n");
return -1;
}

return sock;
}

void nl_recv(int sock) {
struct sockaddr_nl nladdr;
struct msghdr msg;
struct iovec iov;
char buffer[65536];
int ret;

iov.iov_base = (void *) buffer;
iov.iov_len = sizeof(buffer);
msg.msg_name = (void *) &(nladdr);
msg.msg_namelen = sizeof(nladdr);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;

ret = recvmsg(sock, &msg, 0);
if (ret < 0)
printf("ret < 0.\n");
else
printf("Received message payload: %s\n", (char*) NLMSG_DATA((struct nlmsghdr *) &buffer));
}

int main(int argc, char *argv[]) {
int nls;

nls = nl_open();
if (nls < 0)
return nls;

while (1) {
nl_recv(nls);
usleep(5000);
}

return 0;
}

内核模块:

#include <linux/module.h>
#include <linux/netlink.h>
#include <linux/skbuff.h>
#include <linux/gfp.h>
#include <net/sock.h>

#define MYMGRP 22

struct sock *nl_sk = NULL;
static struct timer_list timer;

void nl_send_msg(unsigned long data) {
struct sk_buff *skb_out;
struct nlmsghdr *nlh;
int res;
char *msg = "hello from kernel!\n";
int msg_size = strlen(msg);

skb_out = nlmsg_new(
NLMSG_ALIGN(msg_size), // @payload: size of the message payload
GFP_KERNEL // @flags: the type of memory to allocate.
);
if (!skb_out) {
printk(KERN_ERR "Failed to allocate new skb\n");
return;
}

nlh = nlmsg_put(
skb_out, // @skb: socket buffer to store message in
0, // @portid: netlink PORTID of requesting application
0, // @seq: sequence number of message
NLMSG_DONE, // @type: message type
msg_size, // @payload: length of message payload
0 // @flags: message flags
);

memcpy(nlmsg_data(nlh), msg, msg_size+1);
res = nlmsg_multicast(
nl_sk, // @sk: netlink socket to spread messages to
skb_out, // @skb: netlink message as socket buffer
0, // @portid: own netlink portid to avoid sending to yourself
MYMGRP, // @group: multicast group id
GFP_KERNEL // @flags: allocation flags
);
if (res < 0) {
printk(KERN_INFO "Error while sending to user: %d\n", res);
} else {
mod_timer(&timer, jiffies + msecs_to_jiffies(1));
}
}

static int __init nl_init(void) {
struct netlink_kernel_cfg cfg = {};

printk(KERN_INFO "init NL\n");
nl_sk = netlink_kernel_create(&init_net, NETLINK_USERSOCK, &cfg);
if (!nl_sk) {
printk(KERN_ALERT "Error creating socket.\n");
return -10;
}

init_timer(&timer);
timer.function = nl_send_msg;
timer.expires = jiffies + 1000;
timer.data = 0;
add_timer(&timer);
nl_send_msg(0);

return 0;
}

static void __exit nl_exit(void) {
printk(KERN_INFO "exit NL\n");
del_timer_sync(&timer);
netlink_kernel_release(nl_sk);
}

module_init(nl_init);
module_exit(nl_exit);

MODULE_LICENSE("GPL");

最佳答案

对于子孙后代:我认为问题出在 nlmsg_new 中的分配,它不应出现在中断处理程序(定时器处理程序,nl_send_msg)中,如 here 所述。

如果没有 sleep ,我相信 nlmsg_new 在分配时不需要 sleep ,因此不违反中断处理程序不 sleep 的要求。但是,如果用户空间进程落后于内核,则内核有可能在分配期间休眠,从而导致挂起。

关于Linux Netlink 套接字通信导致虚拟机崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43699713/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com