diff options
Diffstat (limited to 'fs/proc/base.c')
-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: |