加载自定义模块后内核挂起

加载自定义模块后内核挂起

我有一个简单的内核模块,本质上是在给定接口的每个数据包上打印一条消息(代码如下)。无论我编译并运行它的内核是什么,我的系统都会在运行时挂起几秒钟。我没有从 Linux 本身收到任何消息,但 VMWare 说来宾操作系统已停止 CPU。模块编译和加载没有错误。有什么想法吗?我将如何调试它? Journalctl 不显示任何内容。任何帮助将不胜感激,我对此很陌生,不知道如何调试它。

虚拟机日志:

2024-02-01T11:57:03.994Z In(05) vcpu-0 MsgHint: msg.monitorevent.halt
2024-02-01T11:57:03.994Z In(05)+ vcpu-0 The CPU has been disabled by the guest operating system. Power off or reset the virtual machine.
2024-02-01T11:57:03.994Z In(05)+ vcpu-0 ---------------------------------------```

内核模块源码:

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/ip.h>
#include <linux/inet.h>

static struct nf_hook_ops netfilter_ops;
static char *interface = "ens33"; 
module_param(interface, charp, 0);

static unsigned int hook_func(void *priv, struct sk_buff *skb, const struct nf_hook_state *state) {
    char source[16], dest[16];

    if (!skb) {
        return NF_ACCEPT;
    }

    if (strcmp(state->in->name, interface) == 0 || strcmp(state->out->name, interface) == 0) {

        struct iphdr *ip_header = ip_hdr(skb);
        if (!ip_header) {
            return NF_ACCEPT;
        }


        snprintf(source, 16, "%pI4", &ip_header->saddr);
        snprintf(dest, 16, "%pI4", &ip_header->daddr);

        printk(KERN_INFO "Packet logged on %s: Source IP: %s, Destination IP: %s\n", interface, source, dest);
    }
    return NF_ACCEPT;
}

static int __init my_module_init(void) {
    netfilter_ops.hook = hook_func;
    netfilter_ops.pf = PF_INET;
    netfilter_ops.hooknum = NF_INET_PRE_ROUTING;
    netfilter_ops.priority = NF_IP_PRI_FIRST;

    nf_register_net_hook(&init_net, &netfilter_ops);
    printk(KERN_INFO "Kernel module initialized on interface %s\n", interface);
    return 0;
}

static void __exit my_module_exit(void) {
    nf_unregister_net_hook(&init_net, &netfilter_ops);
    printk(KERN_INFO "Kernel module removed\n");
}

module_init(my_module_init);
module_exit(my_module_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("foo bar baz");
MODULE_DESCRIPTION("Netfilter packet logging module");
MODULE_VERSION("0.1");

答案1

好吧,看来我自己找到了答案。问题是钩子方法在调用时只能设置 state->in 或 state->out 之一(显然)。这是更正后的相关行:

if ((state->in && strcmp(state->in->name, interface) == 0) || (state->out && strcmp(state->out->name, interface) == 0)) {

相关内容