2017-07-12 52 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式的調試,而不需要修改源代碼。它也可以放在函數的「返回」上並報告錯誤代碼。

相關問題