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 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) | |||
| 532 | /************************************************************************/ | 532 | /************************************************************************/ |
| 533 | 533 | ||
| 534 | /* permission checks */ | 534 | /* permission checks */ |
| 535 | 535 | static int proc_fd_access_allowed(struct inode *inode) | |
| 536 | /* If the process being read is separated by chroot from the reading process, | ||
| 537 | * don't let the reader access the threads. | ||
| 538 | */ | ||
| 539 | static int proc_check_chroot(struct dentry *de, struct vfsmount *mnt) | ||
| 540 | { | 536 | { |
| 541 | struct dentry *base; | 537 | struct task_struct *task; |
| 542 | struct vfsmount *our_vfsmnt; | 538 | int allowed = 0; |
| 543 | int res = 0; | 539 | /* Allow access to a task's file descriptors if either we may |
| 544 | 540 | * use ptrace attach to the process and find out that | |
| 545 | read_lock(¤t->fs->lock); | 541 | * information, or if the task cannot possibly be ptraced |
| 546 | our_vfsmnt = mntget(current->fs->rootmnt); | 542 | * allow access if we have the proper capability. |
| 547 | base = dget(current->fs->root); | 543 | */ |
| 548 | read_unlock(¤t->fs->lock); | 544 | task = get_proc_task(inode); |
| 549 | 545 | if (task == current) | |
| 550 | spin_lock(&vfsmount_lock); | 546 | allowed = 1; |
| 547 | if (task && !allowed) { | ||
| 548 | int alive; | ||
| 551 | 549 | ||
| 552 | while (mnt != our_vfsmnt) { | 550 | task_lock(task); |
| 553 | if (mnt == mnt->mnt_parent) | 551 | alive = !!task->mm; |
| 554 | goto out; | 552 | task_unlock(task); |
| 555 | de = mnt->mnt_mountpoint; | 553 | if (alive) |
| 556 | mnt = mnt->mnt_parent; | 554 | /* For a living task obey ptrace_may_attach */ |
| 555 | allowed = ptrace_may_attach(task); | ||
| 556 | else | ||
| 557 | /* For a special task simply check the capability */ | ||
| 558 | allowed = capable(CAP_SYS_PTRACE); | ||
| 557 | } | 559 | } |
| 558 | 560 | if (task) | |
| 559 | if (!is_subdir(de, base)) | 561 | put_task_struct(task); |
| 560 | goto out; | 562 | return allowed; |
| 561 | spin_unlock(&vfsmount_lock); | ||
| 562 | |||
| 563 | exit: | ||
| 564 | dput(base); | ||
| 565 | mntput(our_vfsmnt); | ||
| 566 | return res; | ||
| 567 | out: | ||
| 568 | spin_unlock(&vfsmount_lock); | ||
| 569 | res = -EACCES; | ||
| 570 | goto exit; | ||
| 571 | } | 563 | } |
| 572 | 564 | ||
| 573 | extern struct seq_operations mounts_op; | 565 | extern struct seq_operations mounts_op; |
| @@ -1062,52 +1054,6 @@ static struct file_operations proc_seccomp_operations = { | |||
| 1062 | }; | 1054 | }; |
| 1063 | #endif /* CONFIG_SECCOMP */ | 1055 | #endif /* CONFIG_SECCOMP */ |
| 1064 | 1056 | ||
| 1065 | static int proc_check_dentry_visible(struct inode *inode, | ||
| 1066 | struct dentry *dentry, struct vfsmount *mnt) | ||
| 1067 | { | ||
| 1068 | /* Verify that the current process can already see the | ||
| 1069 | * file pointed at by the file descriptor. | ||
| 1070 | * This prevents /proc from being an accidental information leak. | ||
| 1071 | * | ||
| 1072 | * This prevents access to files that are not visible do to | ||
| 1073 | * being on the otherside of a chroot, in a different | ||
| 1074 | * namespace, or are simply process local (like pipes). | ||
| 1075 | */ | ||
| 1076 | struct task_struct *task; | ||
| 1077 | int error = -EACCES; | ||
| 1078 | |||
| 1079 | /* See if the the two tasks share a commone set of | ||
| 1080 | * file descriptors. If so everything is visible. | ||
| 1081 | */ | ||
| 1082 | rcu_read_lock(); | ||
| 1083 | task = tref_task(proc_tref(inode)); | ||
| 1084 | if (task) { | ||
| 1085 | struct files_struct *task_files, *files; | ||
| 1086 | /* This test answeres the question: | ||
| 1087 | * Is there a point in time since we looked up the | ||
| 1088 | * file descriptor where the two tasks share the | ||
| 1089 | * same files struct? | ||
| 1090 | */ | ||
| 1091 | rmb(); | ||
| 1092 | files = current->files; | ||
| 1093 | task_files = task->files; | ||
| 1094 | if (files && (files == task_files)) | ||
| 1095 | error = 0; | ||
| 1096 | } | ||
| 1097 | rcu_read_unlock(); | ||
| 1098 | if (!error) | ||
| 1099 | goto out; | ||
| 1100 | |||
| 1101 | /* If the two tasks don't share a common set of file | ||
| 1102 | * descriptors see if the destination dentry is already | ||
| 1103 | * visible in the current tasks filesystem namespace. | ||
| 1104 | */ | ||
| 1105 | error = proc_check_chroot(dentry, mnt); | ||
| 1106 | out: | ||
| 1107 | return error; | ||
| 1108 | |||
| 1109 | } | ||
| 1110 | |||
| 1111 | static void *proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd) | 1057 | static void *proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd) |
| 1112 | { | 1058 | { |
| 1113 | struct inode *inode = dentry->d_inode; | 1059 | struct inode *inode = dentry->d_inode; |
| @@ -1116,18 +1062,12 @@ static void *proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd) | |||
| 1116 | /* We don't need a base pointer in the /proc filesystem */ | 1062 | /* We don't need a base pointer in the /proc filesystem */ |
| 1117 | path_release(nd); | 1063 | path_release(nd); |
| 1118 | 1064 | ||
| 1119 | if (current->fsuid != inode->i_uid && !capable(CAP_DAC_OVERRIDE)) | 1065 | /* Are we allowed to snoop on the tasks file descriptors? */ |
| 1066 | if (!proc_fd_access_allowed(inode)) | ||
| 1120 | goto out; | 1067 | goto out; |
| 1121 | 1068 | ||
| 1122 | error = PROC_I(inode)->op.proc_get_link(inode, &nd->dentry, &nd->mnt); | 1069 | error = PROC_I(inode)->op.proc_get_link(inode, &nd->dentry, &nd->mnt); |
| 1123 | nd->last_type = LAST_BIND; | 1070 | nd->last_type = LAST_BIND; |
| 1124 | if (error) | ||
| 1125 | goto out; | ||
| 1126 | |||
| 1127 | /* Only return files this task can already see */ | ||
| 1128 | error = proc_check_dentry_visible(inode, nd->dentry, nd->mnt); | ||
| 1129 | if (error) | ||
| 1130 | path_release(nd); | ||
| 1131 | out: | 1071 | out: |
| 1132 | return ERR_PTR(error); | 1072 | return ERR_PTR(error); |
| 1133 | } | 1073 | } |
| @@ -1165,21 +1105,15 @@ static int proc_pid_readlink(struct dentry * dentry, char __user * buffer, int b | |||
| 1165 | struct dentry *de; | 1105 | struct dentry *de; |
| 1166 | struct vfsmount *mnt = NULL; | 1106 | struct vfsmount *mnt = NULL; |
| 1167 | 1107 | ||
| 1168 | 1108 | /* Are we allowed to snoop on the tasks file descriptors? */ | |
| 1169 | if (current->fsuid != inode->i_uid && !capable(CAP_DAC_OVERRIDE)) | 1109 | if (!proc_fd_access_allowed(inode)) |
| 1170 | goto out; | 1110 | goto out; |
| 1171 | 1111 | ||
| 1172 | error = PROC_I(inode)->op.proc_get_link(inode, &de, &mnt); | 1112 | error = PROC_I(inode)->op.proc_get_link(inode, &de, &mnt); |
| 1173 | if (error) | 1113 | if (error) |
| 1174 | goto out; | 1114 | goto out; |
| 1175 | 1115 | ||
| 1176 | /* Only return files this task can already see */ | ||
| 1177 | error = proc_check_dentry_visible(inode, de, mnt); | ||
| 1178 | if (error) | ||
| 1179 | goto out_put; | ||
| 1180 | |||
| 1181 | error = do_proc_readlink(de, mnt, buffer, buflen); | 1116 | error = do_proc_readlink(de, mnt, buffer, buflen); |
| 1182 | out_put: | ||
| 1183 | dput(de); | 1117 | dput(de); |
| 1184 | mntput(mnt); | 1118 | mntput(mnt); |
| 1185 | out: | 1119 | out: |
