Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 30243
b: refs/heads/master
c: 0f2fe20
h: refs/heads/master
i:
  30241: 5acecfe
  30239: 980766f
v: v3
  • Loading branch information
Eric W. Biederman authored and Linus Torvalds committed Jun 26, 2006
1 parent e728f21 commit 80986e5
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 34 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 22c2c5d75e6ad4b9ac41269476b32ba8c9fe263f
refs/heads/master: 0f2fe20f55c85f26efaf14feeb69c7c2eb3f7a75
101 changes: 68 additions & 33 deletions trunk/fs/proc/base.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,16 @@
#include <linux/poll.h>
#include "internal.h"

/* NOTE:
* Implementing inode permission operations in /proc is almost
* certainly an error. Permission checks need to happen during
* each system call not at open time. The reason is that most of
* what we wish to check for permissions in /proc varies at runtime.
*
* The classic example of a problem is opening file descriptors
* in /proc for a task before it execs a suid executable.
*/

/*
* For hysterical raisins we keep the same inumbers as in the old procfs.
* Feel free to change the macro below - just keep the range distinct from
Expand Down Expand Up @@ -494,13 +504,11 @@ static int proc_oom_score(struct task_struct *task, char *buffer)

/* If the process being read is separated by chroot from the reading process,
* don't let the reader access the threads.
*
* note: this does dput(root) and mntput(vfsmnt) on exit.
*/
static int proc_check_chroot(struct dentry *root, struct vfsmount *vfsmnt)
static int proc_check_chroot(struct dentry *de, struct vfsmount *mnt)
{
struct dentry *de, *base;
struct vfsmount *our_vfsmnt, *mnt;
struct dentry *base;
struct vfsmount *our_vfsmnt;
int res = 0;

read_lock(&current->fs->lock);
Expand All @@ -509,8 +517,6 @@ static int proc_check_chroot(struct dentry *root, struct vfsmount *vfsmnt)
read_unlock(&current->fs->lock);

spin_lock(&vfsmount_lock);
de = root;
mnt = vfsmnt;

while (mnt != our_vfsmnt) {
if (mnt == mnt->mnt_parent)
Expand All @@ -526,32 +532,13 @@ static int proc_check_chroot(struct dentry *root, struct vfsmount *vfsmnt)
exit:
dput(base);
mntput(our_vfsmnt);
dput(root);
mntput(vfsmnt);
return res;
out:
spin_unlock(&vfsmount_lock);
res = -EACCES;
goto exit;
}

static int proc_check_root(struct inode *inode)
{
struct dentry *root;
struct vfsmount *vfsmnt;

if (proc_root_link(inode, &root, &vfsmnt)) /* Ewww... */
return -ENOENT;
return proc_check_chroot(root, vfsmnt);
}

static int proc_permission(struct inode *inode, int mask, struct nameidata *nd)
{
if (generic_permission(inode, mask, NULL) != 0)
return -EACCES;
return proc_check_root(inode);
}

extern struct seq_operations proc_pid_maps_op;
static int maps_open(struct inode *inode, struct file *file)
{
Expand Down Expand Up @@ -1048,6 +1035,48 @@ 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;
struct files_struct *task_files, *files;
int error = -EACCES;

/* See if the the two tasks share a commone set of
* file descriptors. If so everything is visible.
*/
task = proc_task(inode);
if (!task)
goto out;
files = get_files_struct(current);
task_files = get_files_struct(task);
if (files && task_files && (files == task_files))
error = 0;
if (task_files)
put_files_struct(task_files);
if (files)
put_files_struct(files);
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;
Expand All @@ -1058,12 +1087,16 @@ static void *proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd)

if (current->fsuid != inode->i_uid && !capable(CAP_DAC_OVERRIDE))
goto out;
error = proc_check_root(inode);
if (error)
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);
}
Expand Down Expand Up @@ -1104,15 +1137,18 @@ static int proc_pid_readlink(struct dentry * dentry, char __user * buffer, int b

if (current->fsuid != inode->i_uid && !capable(CAP_DAC_OVERRIDE))
goto out;
error = proc_check_root(inode);
if (error)
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:
Expand Down Expand Up @@ -1512,7 +1548,6 @@ static struct file_operations proc_task_operations = {
*/
static struct inode_operations proc_fd_inode_operations = {
.lookup = proc_lookupfd,
.permission = proc_permission,
};

static struct inode_operations proc_task_inode_operations = {
Expand Down

0 comments on commit 80986e5

Please sign in to comment.