@@ -3016,31 +3016,43 @@ SYSCALL_DEFINE3(get_robust_list, int, pid,
if (!futex_cmpxchg_enabled)
return -ENOSYS;
- rcu_read_lock();
-
- ret = -ESRCH;
- if (!pid)
+ if (!pid) {
p = current;
- else {
+ get_task_struct(p);
+ } else {
+ rcu_read_lock();
p = find_task_by_vpid(pid);
+ /* pin the task to permit dropping the RCU read lock before
+ * acquiring the mutex
+ */
+ if (p)
+ get_task_struct(p);
+ rcu_read_unlock();
if (!p)
- goto err_unlock;
+ return -ESRCH;
}
+ ret = mutex_lock_killable(&p->signal->cred_guard_light);
+ if (ret)
+ goto err_put;
+
ret = -EPERM;
if (!ptrace_may_access(p, PTRACE_MODE_READ_REALCREDS))
goto err_unlock;
head = p->robust_list;
- rcu_read_unlock();
+
+ mutex_unlock(&p->signal->cred_guard_light);
+ put_task_struct(p);
if (put_user(sizeof(*head), len_ptr))
return -EFAULT;
return put_user(head, head_ptr);
err_unlock:
- rcu_read_unlock();
-
+ mutex_unlock(¤t->signal->cred_guard_light);
+err_put:
+ put_task_struct(p);
return ret;
}
@@ -143,31 +143,43 @@ COMPAT_SYSCALL_DEFINE3(get_robust_list, int, pid,
if (!futex_cmpxchg_enabled)
return -ENOSYS;
- rcu_read_lock();
-
- ret = -ESRCH;
- if (!pid)
+ if (!pid) {
p = current;
- else {
+ get_task_struct(p);
+ } else {
+ rcu_read_lock();
p = find_task_by_vpid(pid);
+ /* pin the task to permit dropping the RCU read lock before
+ * acquiring the mutex
+ */
+ if (p)
+ get_task_struct(p);
+ rcu_read_unlock();
if (!p)
- goto err_unlock;
+ return -ESRCH;
}
+ ret = mutex_lock_killable(&p->signal->cred_guard_light);
+ if (ret)
+ goto err_put;
+
ret = -EPERM;
if (!ptrace_may_access(p, PTRACE_MODE_READ_REALCREDS))
goto err_unlock;
head = p->compat_robust_list;
- rcu_read_unlock();
+
+ mutex_unlock(&p->signal->cred_guard_light);
+ put_task_struct(p);
if (put_user(sizeof(*head), len_ptr))
return -EFAULT;
return put_user(ptr_to_compat(head), head_ptr);
err_unlock:
- rcu_read_unlock();
-
+ mutex_unlock(¤t->signal->cred_guard_light);
+err_put:
+ put_task_struct(p);
return ret;
}
This prevents an attacker from determining the robust_list or compat_robust_list userspace pointer of a process created by executing a setuid binary. Such an attack could be performed by racing get_robust_list() with a setuid execution. The impact of this issue is that an attacker could theoretically bypass ASLR when attacking setuid binaries. changed in v2: - only get_task_struct(p) if p!=NULL (Ben Hutchings) - move the -ESRCH return check Signed-off-by: Jann Horn <jann@thejh.net> --- kernel/futex.c | 30 +++++++++++++++++++++--------- kernel/futex_compat.c | 30 +++++++++++++++++++++--------- 2 files changed, 42 insertions(+), 18 deletions(-)