| From 1b3044e39a89cb1d4d5313da477e8dfea2b5232d Mon Sep 17 00:00:00 2001 |
| From: Janis Danisevskis <jdanis@google.com> |
| Date: Fri, 20 May 2016 17:00:08 -0700 |
| Subject: procfs: fix pthread cross-thread naming if !PR_DUMPABLE |
| |
| From: Janis Danisevskis <jdanis@google.com> |
| |
| commit 1b3044e39a89cb1d4d5313da477e8dfea2b5232d upstream. |
| |
| The PR_DUMPABLE flag causes the pid related paths of the proc file |
| system to be owned by ROOT. |
| |
| The implementation of pthread_set/getname_np however needs access to |
| /proc/<pid>/task/<tid>/comm. If PR_DUMPABLE is false this |
| implementation is locked out. |
| |
| This patch installs a special permission function for the file "comm" |
| that grants read and write access to all threads of the same group |
| regardless of the ownership of the inode. For all other threads the |
| function falls back to the generic inode permission check. |
| |
| [akpm@linux-foundation.org: fix spello in comment] |
| Signed-off-by: Janis Danisevskis <jdanis@google.com> |
| Acked-by: Kees Cook <keescook@chromium.org> |
| Cc: Al Viro <viro@zeniv.linux.org.uk> |
| Cc: Cyrill Gorcunov <gorcunov@openvz.org> |
| Cc: Alexey Dobriyan <adobriyan@gmail.com> |
| Cc: Colin Ian King <colin.king@canonical.com> |
| Cc: David Rientjes <rientjes@google.com> |
| Cc: Minfei Huang <mnfhuang@gmail.com> |
| Cc: John Stultz <john.stultz@linaro.org> |
| Cc: Calvin Owens <calvinowens@fb.com> |
| Cc: Jann Horn <jann@thejh.net> |
| Signed-off-by: Andrew Morton <akpm@linux-foundation.org> |
| Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| fs/proc/base.c | 42 +++++++++++++++++++++++++++++++++++++++++- |
| 1 file changed, 41 insertions(+), 1 deletion(-) |
| |
| --- a/fs/proc/base.c |
| +++ b/fs/proc/base.c |
| @@ -3083,6 +3083,44 @@ int proc_pid_readdir(struct file *file, |
| } |
| |
| /* |
| + * proc_tid_comm_permission is a special permission function exclusively |
| + * used for the node /proc/<pid>/task/<tid>/comm. |
| + * It bypasses generic permission checks in the case where a task of the same |
| + * task group attempts to access the node. |
| + * The rationale behind this is that glibc and bionic access this node for |
| + * cross thread naming (pthread_set/getname_np(!self)). However, if |
| + * PR_SET_DUMPABLE gets set to 0 this node among others becomes uid=0 gid=0, |
| + * which locks out the cross thread naming implementation. |
| + * This function makes sure that the node is always accessible for members of |
| + * same thread group. |
| + */ |
| +static int proc_tid_comm_permission(struct inode *inode, int mask) |
| +{ |
| + bool is_same_tgroup; |
| + struct task_struct *task; |
| + |
| + task = get_proc_task(inode); |
| + if (!task) |
| + return -ESRCH; |
| + is_same_tgroup = same_thread_group(current, task); |
| + put_task_struct(task); |
| + |
| + if (likely(is_same_tgroup && !(mask & MAY_EXEC))) { |
| + /* This file (/proc/<pid>/task/<tid>/comm) can always be |
| + * read or written by the members of the corresponding |
| + * thread group. |
| + */ |
| + return 0; |
| + } |
| + |
| + return generic_permission(inode, mask); |
| +} |
| + |
| +static const struct inode_operations proc_tid_comm_inode_operations = { |
| + .permission = proc_tid_comm_permission, |
| +}; |
| + |
| +/* |
| * Tasks |
| */ |
| static const struct pid_entry tid_base_stuff[] = { |
| @@ -3100,7 +3138,9 @@ static const struct pid_entry tid_base_s |
| #ifdef CONFIG_SCHED_DEBUG |
| REG("sched", S_IRUGO|S_IWUSR, proc_pid_sched_operations), |
| #endif |
| - REG("comm", S_IRUGO|S_IWUSR, proc_pid_set_comm_operations), |
| + NOD("comm", S_IFREG|S_IRUGO|S_IWUSR, |
| + &proc_tid_comm_inode_operations, |
| + &proc_pid_set_comm_operations, {}), |
| #ifdef CONFIG_HAVE_ARCH_TRACEHOOK |
| ONE("syscall", S_IRUSR, proc_pid_syscall), |
| #endif |