aboutsummaryrefslogtreecommitdiffstats
path: root/fs/proc/base.c
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2006-06-26 03:25:46 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-06-26 12:58:24 -0400
commit0f2fe20f55c85f26efaf14feeb69c7c2eb3f7a75 (patch)
tree93649d0579bed2ed43e69f03c06b325bdb0c312e /fs/proc/base.c
parent22c2c5d75e6ad4b9ac41269476b32ba8c9fe263f (diff)
[PATCH] proc: Properly filter out files that are not visible to a process
Long ago and far away in 2.2 we started checking to ensure the files we displayed in /proc were visible to the current process. It was an unsophisticated time and no one was worried about functions full of FIXMES in a stable kernel. As time passed the function became sacred and was enshrined in the shrine of how things have always been. The fixes came in but only to keep the function working no one really remembering or documenting why we did things that way. The intent and the functionality make a lot of sense. Don't let /proc be an access point for files a process can see no other way. The implementation however is completely wrong. We are currently checking the root directories of the two processes, we are not checking the actual file descriptors themselves. We are strangely checking with a permission method instead of just when we use the data. This patch fixes the logic to actually check the file descriptors and make a note that implementing a permission method for this part of /proc almost certainly indicates a bug in the reasoning. Signed-off-by: Eric W. Biederman <ebiederm@xmission.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs/proc/base.c')
-rw-r--r--fs/proc/base.c101
1 files changed, 68 insertions, 33 deletions
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 2e4356f5d5e3..a85b073408e0 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -74,6 +74,16 @@
74#include <linux/poll.h> 74#include <linux/poll.h>
75#include "internal.h" 75#include "internal.h"
76 76
77/* NOTE:
78 * Implementing inode permission operations in /proc is almost
79 * certainly an error. Permission checks need to happen during
80 * each system call not at open time. The reason is that most of
81 * what we wish to check for permissions in /proc varies at runtime.
82 *
83 * The classic example of a problem is opening file descriptors
84 * in /proc for a task before it execs a suid executable.
85 */
86
77/* 87/*
78 * For hysterical raisins we keep the same inumbers as in the old procfs. 88 * For hysterical raisins we keep the same inumbers as in the old procfs.
79 * Feel free to change the macro below - just keep the range distinct from 89 * Feel free to change the macro below - just keep the range distinct from
@@ -494,13 +504,11 @@ static int proc_oom_score(struct task_struct *task, char *buffer)
494 504
495/* If the process being read is separated by chroot from the reading process, 505/* If the process being read is separated by chroot from the reading process,
496 * don't let the reader access the threads. 506 * don't let the reader access the threads.
497 *
498 * note: this does dput(root) and mntput(vfsmnt) on exit.
499 */ 507 */
500static int proc_check_chroot(struct dentry *root, struct vfsmount *vfsmnt) 508static int proc_check_chroot(struct dentry *de, struct vfsmount *mnt)
501{ 509{
502 struct dentry *de, *base; 510 struct dentry *base;
503 struct vfsmount *our_vfsmnt, *mnt; 511 struct vfsmount *our_vfsmnt;
504 int res = 0; 512 int res = 0;
505 513
506 read_lock(&current->fs->lock); 514 read_lock(&current->fs->lock);
@@ -509,8 +517,6 @@ static int proc_check_chroot(struct dentry *root, struct vfsmount *vfsmnt)
509 read_unlock(&current->fs->lock); 517 read_unlock(&current->fs->lock);
510 518
511 spin_lock(&vfsmount_lock); 519 spin_lock(&vfsmount_lock);
512 de = root;
513 mnt = vfsmnt;
514 520
515 while (mnt != our_vfsmnt) { 521 while (mnt != our_vfsmnt) {
516 if (mnt == mnt->mnt_parent) 522 if (mnt == mnt->mnt_parent)
@@ -526,8 +532,6 @@ static int proc_check_chroot(struct dentry *root, struct vfsmount *vfsmnt)
526exit: 532exit:
527 dput(base); 533 dput(base);
528 mntput(our_vfsmnt); 534 mntput(our_vfsmnt);
529 dput(root);
530 mntput(vfsmnt);
531 return res; 535 return res;
532out: 536out:
533 spin_unlock(&vfsmount_lock); 537 spin_unlock(&vfsmount_lock);
@@ -535,23 +539,6 @@ out:
535 goto exit; 539 goto exit;
536} 540}
537 541
538static int proc_check_root(struct inode *inode)
539{
540 struct dentry *root;
541 struct vfsmount *vfsmnt;
542
543 if (proc_root_link(inode, &root, &vfsmnt)) /* Ewww... */
544 return -ENOENT;
545 return proc_check_chroot(root, vfsmnt);
546}
547
548static int proc_permission(struct inode *inode, int mask, struct nameidata *nd)
549{
550 if (generic_permission(inode, mask, NULL) != 0)
551 return -EACCES;
552 return proc_check_root(inode);
553}
554
555extern struct seq_operations proc_pid_maps_op; 542extern struct seq_operations proc_pid_maps_op;
556static int maps_open(struct inode *inode, struct file *file) 543static int maps_open(struct inode *inode, struct file *file)
557{ 544{
@@ -1048,6 +1035,48 @@ static struct file_operations proc_seccomp_operations = {
1048}; 1035};
1049#endif /* CONFIG_SECCOMP */ 1036#endif /* CONFIG_SECCOMP */
1050 1037
1038static int proc_check_dentry_visible(struct inode *inode,
1039 struct dentry *dentry, struct vfsmount *mnt)
1040{
1041 /* Verify that the current process can already see the
1042 * file pointed at by the file descriptor.
1043 * This prevents /proc from being an accidental information leak.
1044 *
1045 * This prevents access to files that are not visible do to
1046 * being on the otherside of a chroot, in a different
1047 * namespace, or are simply process local (like pipes).
1048 */
1049 struct task_struct *task;
1050 struct files_struct *task_files, *files;
1051 int error = -EACCES;
1052
1053 /* See if the the two tasks share a commone set of
1054 * file descriptors. If so everything is visible.
1055 */
1056 task = proc_task(inode);
1057 if (!task)
1058 goto out;
1059 files = get_files_struct(current);
1060 task_files = get_files_struct(task);
1061 if (files && task_files && (files == task_files))
1062 error = 0;
1063 if (task_files)
1064 put_files_struct(task_files);
1065 if (files)
1066 put_files_struct(files);
1067 if (!error)
1068 goto out;
1069
1070 /* If the two tasks don't share a common set of file
1071 * descriptors see if the destination dentry is already
1072 * visible in the current tasks filesystem namespace.
1073 */
1074 error = proc_check_chroot(dentry, mnt);
1075out:
1076 return error;
1077
1078}
1079
1051static void *proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd) 1080static void *proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd)
1052{ 1081{
1053 struct inode *inode = dentry->d_inode; 1082 struct inode *inode = dentry->d_inode;
@@ -1058,12 +1087,16 @@ static void *proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd)
1058 1087
1059 if (current->fsuid != inode->i_uid && !capable(CAP_DAC_OVERRIDE)) 1088 if (current->fsuid != inode->i_uid && !capable(CAP_DAC_OVERRIDE))
1060 goto out; 1089 goto out;
1061 error = proc_check_root(inode);
1062 if (error)
1063 goto out;
1064 1090
1065 error = PROC_I(inode)->op.proc_get_link(inode, &nd->dentry, &nd->mnt); 1091 error = PROC_I(inode)->op.proc_get_link(inode, &nd->dentry, &nd->mnt);
1066 nd->last_type = LAST_BIND; 1092 nd->last_type = LAST_BIND;
1093 if (error)
1094 goto out;
1095
1096 /* Only return files this task can already see */
1097 error = proc_check_dentry_visible(inode, nd->dentry, nd->mnt);
1098 if (error)
1099 path_release(nd);
1067out: 1100out:
1068 return ERR_PTR(error); 1101 return ERR_PTR(error);
1069} 1102}
@@ -1104,15 +1137,18 @@ static int proc_pid_readlink(struct dentry * dentry, char __user * buffer, int b
1104 1137
1105 if (current->fsuid != inode->i_uid && !capable(CAP_DAC_OVERRIDE)) 1138 if (current->fsuid != inode->i_uid && !capable(CAP_DAC_OVERRIDE))
1106 goto out; 1139 goto out;
1107 error = proc_check_root(inode);
1108 if (error)
1109 goto out;
1110 1140
1111 error = PROC_I(inode)->op.proc_get_link(inode, &de, &mnt); 1141 error = PROC_I(inode)->op.proc_get_link(inode, &de, &mnt);
1112 if (error) 1142 if (error)
1113 goto out; 1143 goto out;
1114 1144
1145 /* Only return files this task can already see */
1146 error = proc_check_dentry_visible(inode, de, mnt);
1147 if (error)
1148 goto out_put;
1149
1115 error = do_proc_readlink(de, mnt, buffer, buflen); 1150 error = do_proc_readlink(de, mnt, buffer, buflen);
1151out_put:
1116 dput(de); 1152 dput(de);
1117 mntput(mnt); 1153 mntput(mnt);
1118out: 1154out:
@@ -1512,7 +1548,6 @@ static struct file_operations proc_task_operations = {
1512 */ 1548 */
1513static struct inode_operations proc_fd_inode_operations = { 1549static struct inode_operations proc_fd_inode_operations = {
1514 .lookup = proc_lookupfd, 1550 .lookup = proc_lookupfd,
1515 .permission = proc_permission,
1516}; 1551};
1517 1552
1518static struct inode_operations proc_task_inode_operations = { 1553static struct inode_operations proc_task_inode_operations = {