diff options
| author | Kees Cook <keescook@chromium.org> | 2012-03-19 16:12:53 -0700 | 
|---|---|---|
| committer | Thomas Gleixner <tglx@linutronix.de> | 2012-03-29 11:37:17 +0200 | 
| commit | bdbb776f882f5ad431aa1e694c69c1c3d6a4a5b8 (patch) | |
| tree | 854b6b5869857d40a02d21bb51b375812bdb2ed0 /kernel/futex.c | |
| parent | b5174fa3a7f4f8f150bfa3b917c92608953dfa0f (diff) | |
| download | olio-linux-3.10-bdbb776f882f5ad431aa1e694c69c1c3d6a4a5b8.tar.xz olio-linux-3.10-bdbb776f882f5ad431aa1e694c69c1c3d6a4a5b8.zip  | |
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.c | 36 | 
1 files changed, 13 insertions, 23 deletions
diff --git a/kernel/futex.c b/kernel/futex.c index 72efa1e4359..d701be57c42 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -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);  |