【问题标题】:Linux kernel filp_open fails with NOENTLinux 内核 filp_open 失败并显示 NOENT
【发布时间】:2020-09-29 19:32:22
【问题描述】:

更新:在继续@kisch 的出色回答,我阅读了有关softirq 上下文的信息,并且似乎(出于非常合理的原因)无法从该上下文中访问用户模式.我认为这确实是它失败的原因。

目前在我处理用户空间文件的内核模块上工作。我知道这被认为是一种不好的做法,但我仍然需要。

该模块使用 netfilter 放置一个钩子来捕获系统中的每个传出数据包,并且在调用该钩子时 - 它调用 filp_open。

巫术从这里开始。 当我从环回发送 ping 时,一切正常,在这种情况下,文件 (/etc/fstab) 已成功打开。 当我从家里的不同 IP ping 机器时,filp_open 失败并显示ENOENT。

为了弄清楚它实际失败的地方,我在 QEMU 仿真上运行了该模块,成功地重现了奇怪的行为。显然,它在内核内部函数do_last 中失败了,在下一个代码中(取自fs/namei.c):

if (unlikely(d_is_negative(path.dentry))) {
        path_to_nameidata(&path, nd);
        return -ENOENT;
    }

我完全不知道是什么导致它失败,因为文件一直存在。

有人知道吗?

这是代码中失败的部分:

unsigned int nf_sendfile_hook(void *priv,
                              struct sk_buff *skb,
                              const struct nf_hook_state *state)
{    
    if (NULL == g_get_payload_func) {
        // as long as we don't have a way to get our payloads, we don't 
        // have much to do.
        return NF_ACCEPT;
    }

    struct file *filp;
    filp = filp_open("/etc/fstab", O_RDONLY, 0);
    if (IS_ERR(filp)) {
        printk(KERN_ERR "%p\n", filp);
        return NF_ACCEPT;
    }
    
    ...
}

提前感谢。

【问题讨论】:

    标签: c linux-kernel low-level kernel-mode


    【解决方案1】:

    我需要更多细节才能确定。 你到底是在哪里上钩的?

    很可能,不同的行为是由内核调用钩子函数的不同上下文引起的。

    当你

    从环回发送一个 ping,

    您有一个用户空间进程发出 sendmsg() 系统调用。 内核在附加到该进程的用户上下文中启动一个调用链。 在将数据包放入队列进行进一步分离处理之前,可能直接在该调用链中调用 netfilter 挂钩。

    当你

    从我家的不同 IP ping 机器,

    你有一个从NET_RX_SOFTIRQ 的Soft-IRQ 上下文开始的调用链,从net_rx_action() 开始。该调用链将传入数据包分类为 ICMP,将其传递给内部 ICMP 接收例程,该例程直接发送 ping 回复数据包,然后 可能调用 netfilter 钩子。

    Soft-IRQ 上下文与任何用户空间进程无关。

    现在取决于您的内核设置,文件系统查找代码完全有可能取决于用户上下文中存在的信息,以决定访问限制。您可能有挂载命名空间,因此如果没有用户上下文的进程 ID,甚至可能不会挂载 /etc 文件系统,这可以解释 ENOENT。

    文件系统查找代码也很可能需要调用一些需要schedule()的操作,即阻塞直到一个耗时的操作完成(例如在文件系统的底层设备的块中分页以进行查找) .这在 SoftIRQ 上下文中不起作用。

    这还不是一个完整的答案,太多“可能”,但我很确定这是在哪里找到它的正确方向。

    【讨论】:

    • 酷!我也考虑了上下文。虽然我确实使用了in_XXX 函数(in_softirq()、in_irq() 等),但似乎在两种情况下都返回了相同的结果,这很奇怪。无论如何,回到你的答案 - 如果是这样的话,你能想办法解决它吗?每当我收到来自“外部”的 ping 时,我都考虑过启动 Loopback ping,但也许有更好的方法。
    • 我挂上了NF_INET_POST_ROUTING。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-03-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-31
    相关资源
    最近更新 更多