diff options
-rw-r--r-- | fs/proc/base.c | 124 |
1 files changed, 29 insertions, 95 deletions
diff --git a/fs/proc/base.c b/fs/proc/base.c index f0db7f616ac..f38da6bda26 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -532,42 +532,34 @@ static int proc_oom_score(struct task_struct *task, char *buffer) /************************************************************************/ /* permission checks */ - -/* If the process being read is separated by chroot from the reading process, - * don't let the reader access the threads. - */ -static int proc_check_chroot(struct dentry *de, struct vfsmount *mnt) +static int proc_fd_access_allowed(struct inode *inode) { - struct dentry *base; - struct vfsmount *our_vfsmnt; - int res = 0; - - read_lock(¤t->fs->lock); - our_vfsmnt = mntget(current->fs->rootmnt); - base = dget(current->fs->root); - read_unlock(¤t->fs->lock); - - spin_lock(&vfsmount_lock); + struct task_struct *task; + int allowed = 0; + /* Allow access to a task's file descriptors if either we may + * use ptrace attach to the process and find out that + * information, or if the task cannot possibly be ptraced + * allow access if we have the proper capability. + */ + task = get_proc_task(inode); + if (task == current) + allowed = 1; + if (task && !allowed) { + int alive; - while (mnt != our_vfsmnt) { - if (mnt == mnt->mnt_parent) - goto out; - de = mnt->mnt_mountpoint; - mnt = mnt->mnt_parent; + task_lock(task); + alive = !!task->mm; + task_unlock(task); + if (alive) + /* For a living task obey ptrace_may_attach */ + allowed = ptrace_may_attach(task); + else + /* For a special task simply check the capability */ + allowed = capable(CAP_SYS_PTRACE); } - - if (!is_subdir(de, base)) - goto out; - spin_unlock(&vfsmount_lock); - -exit: - dput(base); - mntput(our_vfsmnt); - return res; -out: - spin_unlock(&vfsmount_lock); - res = -EACCES; - goto exit; + if (task) + put_task_struct(task); + return allowed; } extern struct seq_operations mounts_op; @@ -1062,52 +1054,6 @@ static struct file_operations proc_seccomp_operations = { }; #endif /* CONFIG_SECCOMP */ -static int proc_check_dentry_visible(struct inode *inode, - struct dentry *dentry, struct vfsmount *mnt) -{ - /* Verify that the current process can already see the - * file pointed at by the file descriptor. - * This prevents /proc from being an accidental information leak. - * - * This prevents access to files that are not visible do to - * being on the otherside of a chroot, in a different - * namespace, or are simply process local (like pipes). - */ - struct task_struct *task; - int error = -EACCES; - - /* See if the the two tasks share a commone set of - * file descriptors. If so everything is visible. - */ - rcu_read_lock(); - task = tref_task(proc_tref(inode)); - if (task) { - struct files_struct *task_files, *files; - /* This test answeres the question: - * Is there a point in time since we looked up the - * file descriptor where the two tasks share the - * same files struct? - */ - rmb(); - files = current->files; - task_files = task->files; - if (files && (files == task_files)) - error = 0; - } - rcu_read_unlock(); - if (!error) - goto out; - - /* If the two tasks don't share a common set of file - * descriptors see if the destination dentry is already - * visible in the current tasks filesystem namespace. - */ - error = proc_check_chroot(dentry, mnt); -out: - return error; - -} - static void *proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd) { struct inode *inode = dentry->d_inode; @@ -1116,18 +1062,12 @@ static void *proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd) /* We don't need a base pointer in the /proc filesystem */ path_release(nd); - if (current->fsuid != inode->i_uid && !capable(CAP_DAC_OVERRIDE)) + /* Are we allowed to snoop on the tasks file descriptors? */ + if (!proc_fd_access_allowed(inode)) goto out; error = PROC_I(inode)->op.proc_get_link(inode, &nd->dentry, &nd->mnt); nd->last_type = LAST_BIND; - if (error) - goto out; - - /* Only return files this task can already see */ - error = proc_check_dentry_visible(inode, nd->dentry, nd->mnt); - if (error) - path_release(nd); out: return ERR_PTR(error); } @@ -1165,21 +1105,15 @@ static int proc_pid_readlink(struct dentry * dentry, char __user * buffer, int b struct dentry *de; struct vfsmount *mnt = NULL; - - if (current->fsuid != inode->i_uid && !capable(CAP_DAC_OVERRIDE)) + /* Are we allowed to snoop on the tasks file descriptors? */ + if (!proc_fd_access_allowed(inode)) goto out; error = PROC_I(inode)->op.proc_get_link(inode, &de, &mnt); if (error) goto out; - /* Only return files this task can already see */ - error = proc_check_dentry_visible(inode, de, mnt); - if (error) - goto out_put; - error = do_proc_readlink(de, mnt, buffer, buflen); -out_put: dput(de); mntput(mnt); out: |