2017-07-12 55 views
4

我一直认为做open(/proc/self/fd/NUM, flags)相当于dup(NUM),但显然情况并非如此!例如,如果您的文件描述符为dup,那么将新的fd设置为非阻塞,这也会影响原始文件描述符(因为非阻塞状态是文件描述的属性,并且两个文件描述符都指向相同的文件说明)。但是,如果您打开/proc/self/fd/NUM,那么您似乎会得到一个新的独立文件描述,并可以独立设置新旧fds的非阻塞状态。你甚至可以用这个来获得两个文件描述引用相同的匿名管道,否则这是不可能的(example)。另一方面,虽然你可以dup套接字fd,open("/proc/self/fd/NUM", flags)如果NUM引用套接字失败。Linux内核中的代码在哪里打开(“/ proc/self/fd/NUM”)?

现在我希望能够看到这对其他类型的特殊文件是如何工作的,并回答诸如“以这种方式重新打开文件时执行了什么权限检查?”的问题,所以我试图在Linux中找到实际实现这条路径的代码,但是当我开始阅读fs/proc/fd.c时,我很快就迷失在迷宫般的操作结构中,所有这些都完全不同。

所以我的问题是:任何人都可以解释码路径open("/proc/self/fd/NUM", flags)?具体来说,假设NUM指向一个管道,我们正在讨论最新的内核版本。

+0

有趣的问题。这似乎是[proc_fd_link](http://elixir.free-electrons.com/linux/v4.12.1/source/fs/proc/fd.c#L138)中发生的奇迹,用于得到'/ proc/self/fd/NUM'是一个链接。它只是从打开的文件表中复制'struct path *'(dentry,基本上)。这留给任何创建原始'struct path'来实现打开dentry的inode的功能,在这种情况下[open_fifo](http://elixir.free-electrons.com/linux/v4.12.1/source/fs /pipe.c#L883)来自'fs/pipe.c'。另外TIL:Linux有一个“管道”,所有的管道都在这里:O –

回答

3

评论建议看看proc_fd_link,这是一个好主意。如果您无法遵循代码如何到达那里,您可以使用systemtap来帮助自己。这是一个神奇的脚本:

probe kernel.function("proc_fd_link") { 
    print_backtrace(); 
} 

运行它,而从下FD打开文件/给出:

0xffffffffbb2cad70 : proc_fd_link+0x0/0xd0 [kernel] 
0xffffffffbb2c4c3b : proc_pid_get_link+0x6b/0x90 [kernel] (inexact) 
0xffffffffbb36341a : security_inode_follow_link+0x4a/0x70 [kernel] (inexact) 
0xffffffffbb25bf13 : trailing_symlink+0x1e3/0x220 [kernel] (inexact) 
0xffffffffbb25f559 : path_openat+0xe9/0x1380 [kernel] (inexact) 
0xffffffffbb261af1 : do_filp_open+0x91/0x100 [kernel] (inexact) 
0xffffffffbb26fd8f : __alloc_fd+0x3f/0x170 [kernel] (inexact) 
0xffffffffbb24f280 : do_sys_open+0x130/0x220 [kernel] (inexact) 
0xffffffffbb24f38e : sys_open+0x1e/0x20 [kernel] (inexact) 
0xffffffffbb003c57 : do_syscall_64+0x67/0x160 [kernel] (inexact) 
0xffffffffbb8039e1 : return_from_SYSCALL_64+0x0/0x6a [kernel] (inexact) 

在proc_pid_get_link我们看到:

/* Are we allowed to snoop on the tasks file descriptors? */ 
if (!proc_fd_access_allowed(inode)) 
     goto out; 

aaaand

/* permission checks */ 
static int proc_fd_access_allowed(struct inode *inode) 
{ 
     struct task_struct *task; 
     int allowed = 0; 
     /* Allow access to a task's file descriptors if it is us or we 
     * may use ptrace attach to the process and find out that 
     * information. 
     */ 
     task = get_proc_task(inode); 
     if (task) { 
       allowed = ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS); 
       put_task_struct(task); 
     } 
     return allowed; 
} 

显然,你需要相同的权限,就像你使用ptrace一样。

最后,为什么打开套接字失败? strace显示ENXIO正在退回。 。快速的git的grep ENXIO FS/* C揭示:

static int no_open(struct inode *inode, struct file *file) 
{ 
     return -ENXIO; 
} 

检查代码的最终使用no_open就留给读者自己练习。还要注意systemtap可以用于printf式的调试,而不需要修改源代码。它也可以放在函数的“返回”上并报告错误代码。

相关问题