Explorar o código

Merge branch 'core-locking-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull core locking updates from Thomas Gleixner.

* 'core-locking-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  futex: Mark get_robust_list as deprecated
  futex: Do not leak robust list to unprivileged process
Linus Torvalds %!s(int64=13) %!d(string=hai) anos
pai
achega
3a0d184943
Modificáronse 3 ficheiros con 40 adicións e 46 borrados
  1. 10 0
      Documentation/feature-removal-schedule.txt
  2. 15 23
      kernel/futex.c
  3. 15 23
      kernel/futex_compat.c

+ 10 - 0
Documentation/feature-removal-schedule.txt

@@ -529,3 +529,13 @@ When:	3.5
 Why:	The old kmap_atomic() with two arguments is deprecated, we only
 Why:	The old kmap_atomic() with two arguments is deprecated, we only
 	keep it for backward compatibility for few cycles and then drop it.
 	keep it for backward compatibility for few cycles and then drop it.
 Who:	Cong Wang <amwang@redhat.com>
 Who:	Cong Wang <amwang@redhat.com>
+
+----------------------------
+
+What:	get_robust_list syscall
+When:	2013
+Why:	There appear to be no production users of the get_robust_list syscall,
+	and it runs the risk of leaking address locations, allowing the bypass
+	of ASLR. It was only ever intended for debugging, so it should be
+	removed.
+Who:	Kees Cook <keescook@chromium.org>

+ 15 - 23
kernel/futex.c

@@ -59,6 +59,7 @@
 #include <linux/magic.h>
 #include <linux/magic.h>
 #include <linux/pid.h>
 #include <linux/pid.h>
 #include <linux/nsproxy.h>
 #include <linux/nsproxy.h>
+#include <linux/ptrace.h>
 
 
 #include <asm/futex.h>
 #include <asm/futex.h>
 
 
@@ -2443,40 +2444,31 @@ SYSCALL_DEFINE3(get_robust_list, int, pid,
 {
 {
 	struct robust_list_head __user *head;
 	struct robust_list_head __user *head;
 	unsigned long ret;
 	unsigned long ret;
-	const struct cred *cred = current_cred(), *pcred;
+	struct task_struct *p;
 
 
 	if (!futex_cmpxchg_enabled)
 	if (!futex_cmpxchg_enabled)
 		return -ENOSYS;
 		return -ENOSYS;
 
 
+	WARN_ONCE(1, "deprecated: get_robust_list will be deleted in 2013.\n");
+
+	rcu_read_lock();
+
+	ret = -ESRCH;
 	if (!pid)
 	if (!pid)
-		head = current->robust_list;
+		p = current;
 	else {
 	else {
-		struct task_struct *p;
-
-		ret = -ESRCH;
-		rcu_read_lock();
 		p = find_task_by_vpid(pid);
 		p = find_task_by_vpid(pid);
 		if (!p)
 		if (!p)
 			goto err_unlock;
 			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))
 	if (put_user(sizeof(*head), len_ptr))
 		return -EFAULT;
 		return -EFAULT;
 	return put_user(head, head_ptr);
 	return put_user(head, head_ptr);

+ 15 - 23
kernel/futex_compat.c

@@ -10,6 +10,7 @@
 #include <linux/compat.h>
 #include <linux/compat.h>
 #include <linux/nsproxy.h>
 #include <linux/nsproxy.h>
 #include <linux/futex.h>
 #include <linux/futex.h>
+#include <linux/ptrace.h>
 
 
 #include <asm/uaccess.h>
 #include <asm/uaccess.h>
 
 
@@ -136,40 +137,31 @@ compat_sys_get_robust_list(int pid, compat_uptr_t __user *head_ptr,
 {
 {
 	struct compat_robust_list_head __user *head;
 	struct compat_robust_list_head __user *head;
 	unsigned long ret;
 	unsigned long ret;
-	const struct cred *cred = current_cred(), *pcred;
+	struct task_struct *p;
 
 
 	if (!futex_cmpxchg_enabled)
 	if (!futex_cmpxchg_enabled)
 		return -ENOSYS;
 		return -ENOSYS;
 
 
+	WARN_ONCE(1, "deprecated: get_robust_list will be deleted in 2013.\n");
+
+	rcu_read_lock();
+
+	ret = -ESRCH;
 	if (!pid)
 	if (!pid)
-		head = current->compat_robust_list;
+		p = current;
 	else {
 	else {
-		struct task_struct *p;
-
-		ret = -ESRCH;
-		rcu_read_lock();
 		p = find_task_by_vpid(pid);
 		p = find_task_by_vpid(pid);
 		if (!p)
 		if (!p)
 			goto err_unlock;
 			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))
 	if (put_user(sizeof(*head), len_ptr))
 		return -EFAULT;
 		return -EFAULT;
 	return put_user(ptr_to_compat(head), head_ptr);
 	return put_user(ptr_to_compat(head), head_ptr);