Commit b5a16892 authored by Linus Torvalds's avatar Linus Torvalds Committed by Ben Hutchings

Sanitize 'move_pages()' permission checks

commit 197e7e52 upstream.

The 'move_paghes()' system call was introduced long long ago with the
same permission checks as for sending a signal (except using
CAP_SYS_NICE instead of CAP_SYS_KILL for the overriding capability).

That turns out to not be a great choice - while the system call really
only moves physical page allocations around (and you need other
capabilities to do a lot of it), you can check the return value to map
out some the virtual address choices and defeat ASLR of a binary that
still shares your uid.

So change the access checks to the more common 'ptrace_may_access()'
model instead.

This tightens the access checks for the uid, and also effectively
changes the CAP_SYS_NICE check to CAP_SYS_PTRACE, but it's unlikely that
anybody really _uses_ this legacy system call any more (we hav ebetter
NUMA placement models these days), so I expect nobody to notice.

Famous last words.
Reported-by: default avatarOtto Ebeling <otto.ebeling@iki.fi>
Acked-by: default avatarEric W. Biederman <ebiederm@xmission.com>
Cc: Willy Tarreau <w@1wt.eu>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
[bwh: Backported to 3.16: adjust context]
Signed-off-by: default avatarBen Hutchings <ben@decadent.org.uk>
parent 32cb2d4a
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
#include <linux/gfp.h> #include <linux/gfp.h>
#include <linux/balloon_compaction.h> #include <linux/balloon_compaction.h>
#include <linux/mmu_notifier.h> #include <linux/mmu_notifier.h>
#include <linux/ptrace.h>
#include <asm/tlbflush.h> #include <asm/tlbflush.h>
...@@ -1484,7 +1485,6 @@ SYSCALL_DEFINE6(move_pages, pid_t, pid, unsigned long, nr_pages, ...@@ -1484,7 +1485,6 @@ SYSCALL_DEFINE6(move_pages, pid_t, pid, unsigned long, nr_pages,
const int __user *, nodes, const int __user *, nodes,
int __user *, status, int, flags) int __user *, status, int, flags)
{ {
const struct cred *cred = current_cred(), *tcred;
struct task_struct *task; struct task_struct *task;
struct mm_struct *mm; struct mm_struct *mm;
int err; int err;
...@@ -1508,14 +1508,9 @@ SYSCALL_DEFINE6(move_pages, pid_t, pid, unsigned long, nr_pages, ...@@ -1508,14 +1508,9 @@ SYSCALL_DEFINE6(move_pages, pid_t, pid, unsigned long, nr_pages,
/* /*
* Check if this process has the right to modify the specified * Check if this process has the right to modify the specified
* process. The right exists if the process has administrative * process. Use the regular "ptrace_may_access()" checks.
* capabilities, superuser privileges or the same
* userid as the target process.
*/ */
tcred = __task_cred(task); if (!ptrace_may_access(task, PTRACE_MODE_READ_REALCREDS)) {
if (!uid_eq(cred->euid, tcred->suid) && !uid_eq(cred->euid, tcred->uid) &&
!uid_eq(cred->uid, tcred->suid) && !uid_eq(cred->uid, tcred->uid) &&
!capable(CAP_SYS_NICE)) {
rcu_read_unlock(); rcu_read_unlock();
err = -EPERM; err = -EPERM;
goto out; goto out;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment