summaryrefslogtreecommitdiff
path: root/fs/proc/base.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/proc/base.c')
-rw-r--r--fs/proc/base.c124
1 files changed, 29 insertions, 95 deletions
diff --git a/fs/proc/base.c b/fs/proc/base.c
index f0db7f616ac3..f38da6bda269 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(&current->fs->lock);
- our_vfsmnt = mntget(current->fs->rootmnt);
- base = dget(current->fs->root);
- read_unlock(&current->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: