UPDATE:作为@kisch伟大答案的延续,我读到了软文本上下文,似乎(出于一个非常合理的原因)不可能在这个上下文中访问用户模式。我认为这确实是它失败的原因。
目前在内核模块上工作,我在其中处理用户空间文件。我知道这被认为是一种糟糕的做法,但我仍然需要。
该模块使用netfilter设置一个钩子来捕获系统中的每个传出数据包,并在调用钩子时调用filp_open。
巫毒从这里开始。当我从环回发送ping时,一切正常,在这种情况下,文件(/etc/fstab)正在被成功打开。当我从家里的另一个IP中打开机器时,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;
}
...
}非常感谢。
发布于 2020-09-29 23:38:01
我需要更多的细节才能确定。你到底上哪儿去了?
很可能,不同的行为是由内核调用钩子函数的不同上下文造成的。
当你
从环回发送一个ping,
您有一个用户空间进程发出sendmsg() syscall。内核在附加到该进程的用户上下文中启动一个调用链。在将数据包放入队列进行进一步的分离处理之前,可能会在该调用链中直接调用netfilter钩子。
当你
在我的房子里用不同的IP平了机器,
您有一个从NET_RX_SOFTIRQ的软IRQ上下文开始的调用链,从net_rx_action()开始。该调用链将传入的数据包分类为ICMP,将其传递给内部ICMP接收例程,后者直接发送ping应答数据包,后者可能会调用netfilter挂钩。
软IRQ上下文与任何用户空间进程无关。
现在取决于内核设置,文件系统查找代码完全可能依赖于用户上下文中的信息来决定访问限制。您可能有挂载名称空间,因此如果没有用户上下文的进程ID,/etc文件系统甚至可能不会被挂载,这将解释ENOENT。
文件系统查找代码也很可能需要调用一些需要schedule()的操作,即阻塞,直到一个耗时的操作完成(比如在文件系统底层设备块中分页进行查找)。这在SoftIRQ上下文中是行不通的。
这还不是一个完整的答案,太多的“可能”,但我很确定这是正确的方向找到它。
https://stackoverflow.com/questions/64126415
复制相似问题