aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/futex.c
diff options
context:
space:
mode:
authorKees Cook <keescook@chromium.org>2012-03-19 19:12:53 -0400
committerThomas Gleixner <tglx@linutronix.de>2012-03-29 05:37:17 -0400
commitbdbb776f882f5ad431aa1e694c69c1c3d6a4a5b8 (patch)
tree854b6b5869857d40a02d21bb51b375812bdb2ed0 /kernel/futex.c
parentb5174fa3a7f4f8f150bfa3b917c92608953dfa0f (diff)
futex: Do not leak robust list to unprivileged process
It was possible to extract the robust list head address from a setuid process if it had used set_robust_list(), allowing an ASLR info leak. This changes the permission checks to be the same as those used for similar info that comes out of /proc. Running a setuid program that uses robust futexes would have had: cred->euid != pcred->euid cred->euid == pcred->uid so the old permissions check would allow it. I'm not aware of any setuid programs that use robust futexes, so this is just a preventative measure. (This patch is based on changes from grsecurity.) Signed-off-by: Kees Cook <keescook@chromium.org> Cc: Darren Hart <dvhart@linux.intel.com> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Jiri Kosina <jkosina@suse.cz> Cc: Eric W. Biederman <ebiederm@xmission.com> Cc: David Howells <dhowells@redhat.com> Cc: Serge E. Hallyn <serge.hallyn@canonical.com> Cc: kernel-hardening@lists.openwall.com Cc: spender@grsecurity.net Link: http://lkml.kernel.org/r/20120319231253.GA20893@www.outflux.net Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'kernel/futex.c')
-rw-r--r--kernel/futex.c36
1 files changed, 13 insertions, 23 deletions
diff --git a/kernel/futex.c b/kernel/futex.c
index 72efa1e4359a..d701be57c423 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -59,6 +59,7 @@
59#include <linux/magic.h> 59#include <linux/magic.h>
60#include <linux/pid.h> 60#include <linux/pid.h>
61#include <linux/nsproxy.h> 61#include <linux/nsproxy.h>
62#include <linux/ptrace.h>
62 63
63#include <asm/futex.h> 64#include <asm/futex.h>
64 65
@@ -2443,40 +2444,29 @@ SYSCALL_DEFINE3(get_robust_list, int, pid,
2443{ 2444{
2444 struct robust_list_head __user *head; 2445 struct robust_list_head __user *head;
2445 unsigned long ret; 2446 unsigned long ret;
2446 const struct cred *cred = current_cred(), *pcred; 2447 struct task_struct *p;
2447 2448
2448 if (!futex_cmpxchg_enabled) 2449 if (!futex_cmpxchg_enabled)
2449 return -ENOSYS; 2450 return -ENOSYS;
2450 2451
2452 rcu_read_lock();
2453
2454 ret = -ESRCH;
2451 if (!pid) 2455 if (!pid)
2452 head = current->robust_list; 2456 p = current;
2453 else { 2457 else {
2454 struct task_struct *p;
2455
2456 ret = -ESRCH;
2457 rcu_read_lock();
2458 p = find_task_by_vpid(pid); 2458 p = find_task_by_vpid(pid);
2459 if (!p) 2459 if (!p)
2460 goto err_unlock; 2460 goto err_unlock;
2461 ret = -EPERM;
2462 pcred = __task_cred(p);
2463 /* If victim is in different user_ns, then uids are not
2464 comparable, so we must have CAP_SYS_PTRACE */
2465 if (cred->user->user_ns != pcred->user->user_ns) {
2466 if (!ns_capable(pcred->user->user_ns, CAP_SYS_PTRACE))
2467 goto err_unlock;
2468 goto ok;
2469 }
2470 /* If victim is in same user_ns, then uids are comparable */
2471 if (cred->euid != pcred->euid &&
2472 cred->euid != pcred->uid &&
2473 !ns_capable(pcred->user->user_ns, CAP_SYS_PTRACE))
2474 goto err_unlock;
2475ok:
2476 head = p->robust_list;
2477 rcu_read_unlock();
2478 } 2461 }
2479 2462
2463 ret = -EPERM;
2464 if (!ptrace_may_access(p, PTRACE_MODE_READ))
2465 goto err_unlock;
2466
2467 head = p->robust_list;
2468 rcu_read_unlock();
2469
2480 if (put_user(sizeof(*head), len_ptr)) 2470 if (put_user(sizeof(*head), len_ptr))
2481 return -EFAULT; 2471 return -EFAULT;
2482 return put_user(head, head_ptr); 2472 return put_user(head, head_ptr);