2005-04-17 02:20:36 +04:00
|
|
|
#include <linux/errno.h>
|
|
|
|
#include <linux/sched.h>
|
|
|
|
#include <linux/syscalls.h>
|
|
|
|
#include <linux/mm.h>
|
2007-07-30 02:36:13 +04:00
|
|
|
#include <linux/fs.h>
|
2005-04-17 02:20:36 +04:00
|
|
|
#include <linux/smp.h>
|
|
|
|
#include <linux/sem.h>
|
|
|
|
#include <linux/msg.h>
|
|
|
|
#include <linux/shm.h>
|
|
|
|
#include <linux/stat.h>
|
|
|
|
#include <linux/mman.h>
|
|
|
|
#include <linux/file.h>
|
|
|
|
#include <linux/utsname.h>
|
|
|
|
#include <linux/personality.h>
|
2008-01-30 15:31:07 +03:00
|
|
|
#include <linux/random.h>
|
2008-07-29 09:48:56 +04:00
|
|
|
#include <linux/uaccess.h>
|
2011-09-28 11:42:14 +04:00
|
|
|
#include <linux/elf.h>
|
2005-04-17 02:20:36 +04:00
|
|
|
|
|
|
|
#include <asm/ia32.h>
|
2008-07-21 20:04:13 +04:00
|
|
|
#include <asm/syscalls.h>
|
2005-04-17 02:20:36 +04:00
|
|
|
|
2011-08-05 17:15:08 +04:00
|
|
|
/*
|
|
|
|
* Align a virtual address to avoid aliasing in the I$ on AMD F15h.
|
|
|
|
*/
|
2012-12-12 04:01:52 +04:00
|
|
|
static unsigned long get_align_mask(void)
|
2011-08-05 17:15:08 +04:00
|
|
|
{
|
|
|
|
/* handle 32- and 64-bit case with a single conditional */
|
|
|
|
if (va_align.flags < 0 || !(va_align.flags & (2 - mmap_is_ia32())))
|
2012-12-12 04:01:52 +04:00
|
|
|
return 0;
|
2011-08-05 17:15:08 +04:00
|
|
|
|
|
|
|
if (!(current->flags & PF_RANDOMIZE))
|
2012-12-12 04:01:52 +04:00
|
|
|
return 0;
|
2011-08-05 17:15:08 +04:00
|
|
|
|
2012-12-12 04:01:52 +04:00
|
|
|
return va_align.mask;
|
|
|
|
}
|
2011-08-05 17:15:08 +04:00
|
|
|
|
2012-12-12 04:01:52 +04:00
|
|
|
unsigned long align_vdso_addr(unsigned long addr)
|
|
|
|
{
|
|
|
|
unsigned long align_mask = get_align_mask();
|
|
|
|
return (addr + align_mask) & ~align_mask;
|
2011-08-05 17:15:08 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static int __init control_va_addr_alignment(char *str)
|
|
|
|
{
|
|
|
|
/* guard against enabling this on other CPU families */
|
|
|
|
if (va_align.flags < 0)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
if (*str == 0)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
if (*str == '=')
|
|
|
|
str++;
|
|
|
|
|
|
|
|
if (!strcmp(str, "32"))
|
|
|
|
va_align.flags = ALIGN_VA_32;
|
|
|
|
else if (!strcmp(str, "64"))
|
|
|
|
va_align.flags = ALIGN_VA_64;
|
|
|
|
else if (!strcmp(str, "off"))
|
|
|
|
va_align.flags = 0;
|
|
|
|
else if (!strcmp(str, "on"))
|
|
|
|
va_align.flags = ALIGN_VA_32 | ALIGN_VA_64;
|
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
__setup("align_va_addr", control_va_addr_alignment);
|
|
|
|
|
2009-08-11 00:53:11 +04:00
|
|
|
SYSCALL_DEFINE6(mmap, unsigned long, addr, unsigned long, len,
|
|
|
|
unsigned long, prot, unsigned long, flags,
|
|
|
|
unsigned long, fd, unsigned long, off)
|
2005-04-17 02:20:36 +04:00
|
|
|
{
|
|
|
|
long error;
|
|
|
|
error = -EINVAL;
|
|
|
|
if (off & ~PAGE_MASK)
|
|
|
|
goto out;
|
|
|
|
|
2009-12-01 01:37:04 +03:00
|
|
|
error = sys_mmap_pgoff(addr, len, prot, flags, fd, off >> PAGE_SHIFT);
|
2005-04-17 02:20:36 +04:00
|
|
|
out:
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void find_start_end(unsigned long flags, unsigned long *begin,
|
|
|
|
unsigned long *end)
|
|
|
|
{
|
2012-02-07 01:03:09 +04:00
|
|
|
if (!test_thread_flag(TIF_ADDR32) && (flags & MAP_32BIT)) {
|
2008-01-30 15:31:07 +03:00
|
|
|
unsigned long new_begin;
|
2005-04-17 02:20:36 +04:00
|
|
|
/* This is usually used needed to map code in small
|
|
|
|
model, so it needs to be in the first 31bit. Limit
|
|
|
|
it to that. This means we need to move the
|
|
|
|
unmapped base down for this case. This can give
|
|
|
|
conflicts with the heap, but we assume that glibc
|
|
|
|
malloc knows how to fall back to mmap. Give it 1GB
|
2008-07-29 09:48:56 +04:00
|
|
|
of playground for now. -AK */
|
|
|
|
*begin = 0x40000000;
|
|
|
|
*end = 0x80000000;
|
2008-01-30 15:31:07 +03:00
|
|
|
if (current->flags & PF_RANDOMIZE) {
|
|
|
|
new_begin = randomize_range(*begin, *begin + 0x02000000, 0);
|
|
|
|
if (new_begin)
|
|
|
|
*begin = new_begin;
|
|
|
|
}
|
[PATCH] x86_64: TASK_SIZE fixes for compatibility mode processes
Appended patch will setup compatibility mode TASK_SIZE properly. This will
fix atleast three known bugs that can be encountered while running
compatibility mode apps.
a) A malicious 32bit app can have an elf section at 0xffffe000. During
exec of this app, we will have a memory leak as insert_vm_struct() is
not checking for return value in syscall32_setup_pages() and thus not
freeing the vma allocated for the vsyscall page. And instead of exec
failing (as it has addresses > TASK_SIZE), we were allowing it to
succeed previously.
b) With a 32bit app, hugetlb_get_unmapped_area/arch_get_unmapped_area
may return addresses beyond 32bits, ultimately causing corruption
because of wrap-around and resulting in SEGFAULT, instead of returning
ENOMEM.
c) 32bit app doing this below mmap will now fail.
mmap((void *)(0xFFFFE000UL), 0x10000UL, PROT_READ|PROT_WRITE,
MAP_FIXED|MAP_PRIVATE|MAP_ANON, 0, 0);
Signed-off-by: Zou Nan hai <nanhai.zou@intel.com>
Signed-off-by: Suresh Siddha <suresh.b.siddha@intel.com>
Cc: Andi Kleen <ak@muc.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2005-06-22 04:14:32 +04:00
|
|
|
} else {
|
2013-08-21 21:55:59 +04:00
|
|
|
*begin = current->mm->mmap_legacy_base;
|
2008-07-29 09:48:56 +04:00
|
|
|
*end = TASK_SIZE;
|
[PATCH] x86_64: TASK_SIZE fixes for compatibility mode processes
Appended patch will setup compatibility mode TASK_SIZE properly. This will
fix atleast three known bugs that can be encountered while running
compatibility mode apps.
a) A malicious 32bit app can have an elf section at 0xffffe000. During
exec of this app, we will have a memory leak as insert_vm_struct() is
not checking for return value in syscall32_setup_pages() and thus not
freeing the vma allocated for the vsyscall page. And instead of exec
failing (as it has addresses > TASK_SIZE), we were allowing it to
succeed previously.
b) With a 32bit app, hugetlb_get_unmapped_area/arch_get_unmapped_area
may return addresses beyond 32bits, ultimately causing corruption
because of wrap-around and resulting in SEGFAULT, instead of returning
ENOMEM.
c) 32bit app doing this below mmap will now fail.
mmap((void *)(0xFFFFE000UL), 0x10000UL, PROT_READ|PROT_WRITE,
MAP_FIXED|MAP_PRIVATE|MAP_ANON, 0, 0);
Signed-off-by: Zou Nan hai <nanhai.zou@intel.com>
Signed-off-by: Suresh Siddha <suresh.b.siddha@intel.com>
Cc: Andi Kleen <ak@muc.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2005-06-22 04:14:32 +04:00
|
|
|
}
|
2008-07-29 09:48:56 +04:00
|
|
|
}
|
2005-04-17 02:20:36 +04:00
|
|
|
|
|
|
|
unsigned long
|
|
|
|
arch_get_unmapped_area(struct file *filp, unsigned long addr,
|
|
|
|
unsigned long len, unsigned long pgoff, unsigned long flags)
|
|
|
|
{
|
|
|
|
struct mm_struct *mm = current->mm;
|
|
|
|
struct vm_area_struct *vma;
|
2012-12-12 04:01:52 +04:00
|
|
|
struct vm_unmapped_area_info info;
|
2005-04-17 02:20:36 +04:00
|
|
|
unsigned long begin, end;
|
2008-07-29 09:48:56 +04:00
|
|
|
|
2007-05-07 01:50:11 +04:00
|
|
|
if (flags & MAP_FIXED)
|
|
|
|
return addr;
|
|
|
|
|
2008-07-29 09:48:56 +04:00
|
|
|
find_start_end(flags, &begin, &end);
|
2005-04-17 02:20:36 +04:00
|
|
|
|
|
|
|
if (len > end)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
if (addr) {
|
|
|
|
addr = PAGE_ALIGN(addr);
|
|
|
|
vma = find_vma(mm, addr);
|
|
|
|
if (end - len >= addr &&
|
|
|
|
(!vma || addr + len <= vma->vm_start))
|
|
|
|
return addr;
|
|
|
|
}
|
2005-06-22 04:14:49 +04:00
|
|
|
|
2012-12-12 04:01:52 +04:00
|
|
|
info.flags = 0;
|
|
|
|
info.length = len;
|
|
|
|
info.low_limit = begin;
|
|
|
|
info.high_limit = end;
|
|
|
|
info.align_mask = filp ? get_align_mask() : 0;
|
2012-12-12 04:01:56 +04:00
|
|
|
info.align_offset = pgoff << PAGE_SHIFT;
|
2012-12-12 04:01:52 +04:00
|
|
|
return vm_unmapped_area(&info);
|
2005-04-17 02:20:36 +04:00
|
|
|
}
|
|
|
|
|
2008-01-30 15:31:07 +03:00
|
|
|
unsigned long
|
|
|
|
arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,
|
|
|
|
const unsigned long len, const unsigned long pgoff,
|
|
|
|
const unsigned long flags)
|
|
|
|
{
|
|
|
|
struct vm_area_struct *vma;
|
|
|
|
struct mm_struct *mm = current->mm;
|
2012-12-12 04:01:52 +04:00
|
|
|
unsigned long addr = addr0;
|
|
|
|
struct vm_unmapped_area_info info;
|
2008-01-30 15:31:07 +03:00
|
|
|
|
|
|
|
/* requested length too big for entire address space */
|
|
|
|
if (len > TASK_SIZE)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
if (flags & MAP_FIXED)
|
|
|
|
return addr;
|
|
|
|
|
2012-12-17 13:42:56 +04:00
|
|
|
/* for MAP_32BIT mappings we force the legacy mmap base */
|
2012-02-07 01:03:09 +04:00
|
|
|
if (!test_thread_flag(TIF_ADDR32) && (flags & MAP_32BIT))
|
2008-01-30 15:31:07 +03:00
|
|
|
goto bottomup;
|
|
|
|
|
|
|
|
/* requesting a specific address */
|
|
|
|
if (addr) {
|
|
|
|
addr = PAGE_ALIGN(addr);
|
|
|
|
vma = find_vma(mm, addr);
|
|
|
|
if (TASK_SIZE - len >= addr &&
|
|
|
|
(!vma || addr + len <= vma->vm_start))
|
|
|
|
return addr;
|
|
|
|
}
|
|
|
|
|
2012-12-12 04:01:52 +04:00
|
|
|
info.flags = VM_UNMAPPED_AREA_TOPDOWN;
|
|
|
|
info.length = len;
|
|
|
|
info.low_limit = PAGE_SIZE;
|
|
|
|
info.high_limit = mm->mmap_base;
|
|
|
|
info.align_mask = filp ? get_align_mask() : 0;
|
2012-12-12 04:01:56 +04:00
|
|
|
info.align_offset = pgoff << PAGE_SHIFT;
|
2012-12-12 04:01:52 +04:00
|
|
|
addr = vm_unmapped_area(&info);
|
|
|
|
if (!(addr & ~PAGE_MASK))
|
|
|
|
return addr;
|
|
|
|
VM_BUG_ON(addr != -ENOMEM);
|
2012-03-22 03:33:56 +04:00
|
|
|
|
2008-01-30 15:31:07 +03:00
|
|
|
bottomup:
|
|
|
|
/*
|
|
|
|
* A failed mmap() very likely causes application failure,
|
|
|
|
* so fall back to the bottom-up function here. This scenario
|
|
|
|
* can happen with large stack limits and large mmap()
|
|
|
|
* allocations.
|
|
|
|
*/
|
2012-12-12 04:01:52 +04:00
|
|
|
return arch_get_unmapped_area(filp, addr0, len, pgoff, flags);
|
2008-01-30 15:31:07 +03:00
|
|
|
}
|