微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Linux内核filp_open失败,出现NOENT

如何解决Linux内核filp_open失败,出现NOENT

更新:在@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;
    }
    
    ...
}

谢谢你。

解决方法

我需要更多细节才能确定。 您到底在哪里迷上了?

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

当你

从环回发送ping,

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

当你

使用我家中的其他IP对计算机进行ping操作

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

Soft-IRQ上下文与任何用户空间进程都没有关系。

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

文件系统查找代码很有可能需要调用某些需要schedule()的操作,即阻塞直到耗时的操作完成为止(例如在文件系统的底层设备的块中分页以进行抬头)。从SoftIRQ上下文中这是行不通的。

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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。