fs/proc/fd.c | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/fs/proc/fd.c b/fs/proc/fd.c index 0ff80f9b930f..7a97dfbb4217 100644 --- a/fs/proc/fd.c +++ b/fs/proc/fd.c @@ -137,6 +137,33 @@ static const struct dentry_operations tid_fd_dentry_operations = { .d_delete = pid_delete_dentry, }; +static inline int match_cred(const struct cred *a, const struct cred *b) +{ + return a->fsuid == b->fsuid && a->fsgid == b->fsgid; +} + +/* + * To get here, we have ptrace() access to the task in question. + * + * But we still require that the file itself was either opened by that + * task or by ourselves, or that we have path search capability. + */ +static int get_fd_path(struct task_struct *task, struct file *file, struct path *path) +{ + if (!match_cred(file->f_cred, current_cred())) { + int match; + + rcu_read_lock(); + match = match_cred(file->f_cred, __task_cred(task)); + rcu_read_unlock(); + if (!match && !capable(CAP_DAC_READ_SEARCH)) + return -EACCES; + } + *path = file->f_path; + path_get(&file->f_path); + return 0; +} + static int proc_fd_link(struct dentry *dentry, struct path *path) { struct files_struct *files = NULL; @@ -155,11 +182,8 @@ static int proc_fd_link(struct dentry *dentry, struct path *path) spin_lock(&files->file_lock); fd_file = fcheck_files(files, fd); - if (fd_file) { - *path = fd_file->f_path; - path_get(&fd_file->f_path); - ret = 0; - } + if (fd_file) + ret = get_fd_path(task, fd_file, path); spin_unlock(&files->file_lock); put_files_struct(files); }