diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/proc/base.c | 101 |
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 | */ |
500 | static int proc_check_chroot(struct dentry *root, struct vfsmount *vfsmnt) | 508 | static 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(¤t->fs->lock); | 514 | read_lock(¤t->fs->lock); |
@@ -509,8 +517,6 @@ static int proc_check_chroot(struct dentry *root, struct vfsmount *vfsmnt) | |||
509 | read_unlock(¤t->fs->lock); | 517 | read_unlock(¤t->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) | |||
526 | exit: | 532 | exit: |
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; |
532 | out: | 536 | out: |
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 | ||
538 | static 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 | |||
548 | static 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 | |||
555 | extern struct seq_operations proc_pid_maps_op; | 542 | extern struct seq_operations proc_pid_maps_op; |
556 | static int maps_open(struct inode *inode, struct file *file) | 543 | static 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 | ||
1038 | static 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); | ||
1075 | out: | ||
1076 | return error; | ||
1077 | |||
1078 | } | ||
1079 | |||
1051 | static void *proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd) | 1080 | static 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); | ||
1067 | out: | 1100 | out: |
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); |
1151 | out_put: | ||
1116 | dput(de); | 1152 | dput(de); |
1117 | mntput(mnt); | 1153 | mntput(mnt); |
1118 | out: | 1154 | out: |
@@ -1512,7 +1548,6 @@ static struct file_operations proc_task_operations = { | |||
1512 | */ | 1548 | */ |
1513 | static struct inode_operations proc_fd_inode_operations = { | 1549 | static struct inode_operations proc_fd_inode_operations = { |
1514 | .lookup = proc_lookupfd, | 1550 | .lookup = proc_lookupfd, |
1515 | .permission = proc_permission, | ||
1516 | }; | 1551 | }; |
1517 | 1552 | ||
1518 | static struct inode_operations proc_task_inode_operations = { | 1553 | static struct inode_operations proc_task_inode_operations = { |