Commit 3f12d688 authored by Alexander Kartashov's avatar Alexander Kartashov Committed by Pavel Emelyanov

sys_mmap: fixed the error detection logic.

The current sys_mmap error analysis code doesn't work on 32-bit architectures
with 3G/1G userspace/kernel virtual address space split since the syscall
allocates anonymous memory above the first 2G of the address space ---
such an address is a negative integer so it's interpreted as a error code.
The problem isn't encountered on x86-64 becauase it doesn't use negative
virtual addresses in the userspace.

The 3G/1G split is used because memory allocation is currently broken for other
values of the split on ARM: the value of TASK_UNMAPPED_BASE (arch/arm/include/asm/memory.h)
isn't page-aligned if other split value is used so the value of the field
mm_struct::mmap_base is initialized with a page-unaligned value by
the function arch_pick_mmap_layout() (arch/arm/mm/mmap.c) in some circumstances
that breaks page-alignment checks in the kernel memory management code.

This patch modifies sys_mmap return value analysis code replacing tests
for negativeness of the signed return value with tests that checks that
the return value isn't greater than TASK_SIZE.
Signed-off-by: 's avatarAlexander Kartashov <alekskartashov@parallels.com>
Signed-off-by: 's avatarPavel Emelyanov <xemul@parallels.com>
parent b1e8f70b
...@@ -239,7 +239,7 @@ static void *mmap_seized(struct parasite_ctl *ctl, ...@@ -239,7 +239,7 @@ static void *mmap_seized(struct parasite_ctl *ctl,
err = syscall_seized(ctl, __NR_mmap, &map, err = syscall_seized(ctl, __NR_mmap, &map,
(unsigned long)addr, length, prot, flags, fd, offset); (unsigned long)addr, length, prot, flags, fd, offset);
if (err < 0 || (long)map < 0) if (err < 0 || map > TASK_SIZE)
map = 0; map = 0;
return (void *)map; return (void *)map;
......
...@@ -45,7 +45,7 @@ static int brk_init(void) ...@@ -45,7 +45,7 @@ static int brk_init(void)
ret = sys_mmap(NULL, MAX_HEAP_SIZE, ret = sys_mmap(NULL, MAX_HEAP_SIZE,
PROT_READ | PROT_WRITE, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (ret < 0) if (ret > TASK_SIZE)
return -ENOMEM; return -ENOMEM;
brk_start = brk_tail = (void *)ret; brk_start = brk_tail = (void *)ret;
...@@ -427,7 +427,7 @@ static int init(struct parasite_init_args *args) ...@@ -427,7 +427,7 @@ static int init(struct parasite_init_args *args)
PROT_READ | PROT_WRITE, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, MAP_PRIVATE | MAP_ANONYMOUS,
-1, 0); -1, 0);
if ((long)tid_state < 0) if ((unsigned long)tid_state > TASK_SIZE)
return -ENOMEM; return -ENOMEM;
nr_tid_state = args->nr_threads; nr_tid_state = args->nr_threads;
......
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