mm: untag user pointers passed to memory syscalls

This patch is a part of a series that extends kernel ABI to allow to pass
tagged user pointers (with the top byte set to something else other than
0x00) as syscall arguments.

This patch allows tagged pointers to be passed to the following memory
syscalls: get_mempolicy, madvise, mbind, mincore, mlock, mlock2, mprotect,
mremap, msync, munlock, move_pages.

The mmap and mremap syscalls do not currently accept tagged addresses.
Architectures may interpret the tag as a background colour for the
corresponding vma.

Link: http://lkml.kernel.org/r/aaf0c0969d46b2feb9017f3e1b3ef3970b633d91.1563904656.git.andreyknvl@google.com
Signed-off-by: Andrey Konovalov <andreyknvl@google.com>
Reviewed-by: Khalid Aziz <khalid.aziz@oracle.com>
Reviewed-by: Vincenzo Frascino <vincenzo.frascino@arm.com>
Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
Reviewed-by: Kees Cook <keescook@chromium.org>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Dave Hansen <dave.hansen@intel.com>
Cc: Eric Auger <eric.auger@redhat.com>
Cc: Felix Kuehling <Felix.Kuehling@amd.com>
Cc: Jens Wiklander <jens.wiklander@linaro.org>
Cc: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
Cc: Mike Rapoport <rppt@linux.ibm.com>
Cc: Will Deacon <will@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
Andrey Konovalov 2019-09-25 16:48:30 -07:00 committed by Linus Torvalds
parent 903f433f8f
commit 057d338910
8 changed files with 23 additions and 1 deletions

View File

@ -784,6 +784,8 @@ SYSCALL_DEFINE3(madvise, unsigned long, start, size_t, len_in, int, behavior)
size_t len; size_t len;
struct blk_plug plug; struct blk_plug plug;
start = untagged_addr(start);
if (!madvise_behavior_valid(behavior)) if (!madvise_behavior_valid(behavior))
return error; return error;

View File

@ -1405,6 +1405,7 @@ static long kernel_mbind(unsigned long start, unsigned long len,
int err; int err;
unsigned short mode_flags; unsigned short mode_flags;
start = untagged_addr(start);
mode_flags = mode & MPOL_MODE_FLAGS; mode_flags = mode & MPOL_MODE_FLAGS;
mode &= ~MPOL_MODE_FLAGS; mode &= ~MPOL_MODE_FLAGS;
if (mode >= MPOL_MAX) if (mode >= MPOL_MAX)
@ -1558,6 +1559,8 @@ static int kernel_get_mempolicy(int __user *policy,
int uninitialized_var(pval); int uninitialized_var(pval);
nodemask_t nodes; nodemask_t nodes;
addr = untagged_addr(addr);
if (nmask != NULL && maxnode < nr_node_ids) if (nmask != NULL && maxnode < nr_node_ids)
return -EINVAL; return -EINVAL;

View File

@ -1612,7 +1612,7 @@ static int do_pages_move(struct mm_struct *mm, nodemask_t task_nodes,
goto out_flush; goto out_flush;
if (get_user(node, nodes + i)) if (get_user(node, nodes + i))
goto out_flush; goto out_flush;
addr = (unsigned long)p; addr = (unsigned long)untagged_addr(p);
err = -ENODEV; err = -ENODEV;
if (node < 0 || node >= MAX_NUMNODES) if (node < 0 || node >= MAX_NUMNODES)

View File

@ -256,6 +256,8 @@ SYSCALL_DEFINE3(mincore, unsigned long, start, size_t, len,
unsigned long pages; unsigned long pages;
unsigned char *tmp; unsigned char *tmp;
start = untagged_addr(start);
/* Check the start address: needs to be page-aligned.. */ /* Check the start address: needs to be page-aligned.. */
if (start & ~PAGE_MASK) if (start & ~PAGE_MASK)
return -EINVAL; return -EINVAL;

View File

@ -674,6 +674,8 @@ static __must_check int do_mlock(unsigned long start, size_t len, vm_flags_t fla
unsigned long lock_limit; unsigned long lock_limit;
int error = -ENOMEM; int error = -ENOMEM;
start = untagged_addr(start);
if (!can_do_mlock()) if (!can_do_mlock())
return -EPERM; return -EPERM;
@ -735,6 +737,8 @@ SYSCALL_DEFINE2(munlock, unsigned long, start, size_t, len)
{ {
int ret; int ret;
start = untagged_addr(start);
len = PAGE_ALIGN(len + (offset_in_page(start))); len = PAGE_ALIGN(len + (offset_in_page(start)));
start &= PAGE_MASK; start &= PAGE_MASK;

View File

@ -459,6 +459,8 @@ static int do_mprotect_pkey(unsigned long start, size_t len,
const bool rier = (current->personality & READ_IMPLIES_EXEC) && const bool rier = (current->personality & READ_IMPLIES_EXEC) &&
(prot & PROT_READ); (prot & PROT_READ);
start = untagged_addr(start);
prot &= ~(PROT_GROWSDOWN|PROT_GROWSUP); prot &= ~(PROT_GROWSDOWN|PROT_GROWSUP);
if (grows == (PROT_GROWSDOWN|PROT_GROWSUP)) /* can't be both */ if (grows == (PROT_GROWSDOWN|PROT_GROWSUP)) /* can't be both */
return -EINVAL; return -EINVAL;

View File

@ -606,6 +606,13 @@ SYSCALL_DEFINE5(mremap, unsigned long, addr, unsigned long, old_len,
LIST_HEAD(uf_unmap_early); LIST_HEAD(uf_unmap_early);
LIST_HEAD(uf_unmap); LIST_HEAD(uf_unmap);
/*
* Architectures may interpret the tag passed to mmap as a background
* colour for the corresponding vma. For mremap we don't allow tagged
* new_addr to preserve similar behaviour to mmap.
*/
addr = untagged_addr(addr);
if (flags & ~(MREMAP_FIXED | MREMAP_MAYMOVE)) if (flags & ~(MREMAP_FIXED | MREMAP_MAYMOVE))
return ret; return ret;

View File

@ -37,6 +37,8 @@ SYSCALL_DEFINE3(msync, unsigned long, start, size_t, len, int, flags)
int unmapped_error = 0; int unmapped_error = 0;
int error = -EINVAL; int error = -EINVAL;
start = untagged_addr(start);
if (flags & ~(MS_ASYNC | MS_INVALIDATE | MS_SYNC)) if (flags & ~(MS_ASYNC | MS_INVALIDATE | MS_SYNC))
goto out; goto out;
if (offset_in_page(start)) if (offset_in_page(start))