Skip to content

Commit

Permalink
futex: Do not leak robust list to unprivileged process
Browse files Browse the repository at this point in the history
commit bdbb776 upstream.

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>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Kees Cook authored and Greg Kroah-Hartman committed Apr 22, 2012
1 parent a9dd731 commit 631792f
Showing 2 changed files with 26 additions and 46 deletions.
36 changes: 13 additions & 23 deletions kernel/futex.c
Original file line number Diff line number Diff line change
@@ -59,6 +59,7 @@
#include <linux/magic.h>
#include <linux/pid.h>
#include <linux/nsproxy.h>
#include <linux/ptrace.h>

#include <asm/futex.h>

@@ -2443,40 +2444,29 @@ SYSCALL_DEFINE3(get_robust_list, int, pid,
{
struct robust_list_head __user *head;
unsigned long ret;
const struct cred *cred = current_cred(), *pcred;
struct task_struct *p;

if (!futex_cmpxchg_enabled)
return -ENOSYS;

rcu_read_lock();

ret = -ESRCH;
if (!pid)
head = current->robust_list;
p = current;
else {
struct task_struct *p;

ret = -ESRCH;
rcu_read_lock();
p = find_task_by_vpid(pid);
if (!p)
goto err_unlock;
ret = -EPERM;
pcred = __task_cred(p);
/* If victim is in different user_ns, then uids are not
comparable, so we must have CAP_SYS_PTRACE */
if (cred->user->user_ns != pcred->user->user_ns) {
if (!ns_capable(pcred->user->user_ns, CAP_SYS_PTRACE))
goto err_unlock;
goto ok;
}
/* If victim is in same user_ns, then uids are comparable */
if (cred->euid != pcred->euid &&
cred->euid != pcred->uid &&
!ns_capable(pcred->user->user_ns, CAP_SYS_PTRACE))
goto err_unlock;
ok:
head = p->robust_list;
rcu_read_unlock();
}

ret = -EPERM;
if (!ptrace_may_access(p, PTRACE_MODE_READ))
goto err_unlock;

head = p->robust_list;
rcu_read_unlock();

if (put_user(sizeof(*head), len_ptr))
return -EFAULT;
return put_user(head, head_ptr);
36 changes: 13 additions & 23 deletions kernel/futex_compat.c
Original file line number Diff line number Diff line change
@@ -10,6 +10,7 @@
#include <linux/compat.h>
#include <linux/nsproxy.h>
#include <linux/futex.h>
#include <linux/ptrace.h>

#include <asm/uaccess.h>

@@ -136,40 +137,29 @@ compat_sys_get_robust_list(int pid, compat_uptr_t __user *head_ptr,
{
struct compat_robust_list_head __user *head;
unsigned long ret;
const struct cred *cred = current_cred(), *pcred;
struct task_struct *p;

if (!futex_cmpxchg_enabled)
return -ENOSYS;

rcu_read_lock();

ret = -ESRCH;
if (!pid)
head = current->compat_robust_list;
p = current;
else {
struct task_struct *p;

ret = -ESRCH;
rcu_read_lock();
p = find_task_by_vpid(pid);
if (!p)
goto err_unlock;
ret = -EPERM;
pcred = __task_cred(p);
/* If victim is in different user_ns, then uids are not
comparable, so we must have CAP_SYS_PTRACE */
if (cred->user->user_ns != pcred->user->user_ns) {
if (!ns_capable(pcred->user->user_ns, CAP_SYS_PTRACE))
goto err_unlock;
goto ok;
}
/* If victim is in same user_ns, then uids are comparable */
if (cred->euid != pcred->euid &&
cred->euid != pcred->uid &&
!ns_capable(pcred->user->user_ns, CAP_SYS_PTRACE))
goto err_unlock;
ok:
head = p->compat_robust_list;
rcu_read_unlock();
}

ret = -EPERM;
if (!ptrace_may_access(p, PTRACE_MODE_READ))
goto err_unlock;

head = p->compat_robust_list;
rcu_read_unlock();

if (put_user(sizeof(*head), len_ptr))
return -EFAULT;
return put_user(ptr_to_compat(head), head_ptr);

0 comments on commit 631792f

Please sign in to comment.