2008-01-30 13:31:07 +01:00
/*
2008-01-30 13:31:10 +01:00
* Flexible mmap layout support
2008-01-30 13:31:07 +01:00
*
* Based on code by Ingo Molnar and Andi Kleen , copyrighted
* as follows :
*
2009-01-31 02:03:42 +01:00
* Copyright 2003 - 2009 Red Hat Inc .
2008-01-30 13:31:07 +01:00
* All Rights Reserved .
* Copyright 2005 Andi Kleen , SUSE Labs .
* Copyright 2007 Jiri Kosina , SUSE Labs .
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
2006-01-17 07:03:38 +01:00
*/
2008-01-30 13:31:07 +01:00
# include <linux/personality.h>
2006-01-17 07:03:38 +01:00
# include <linux/mm.h>
# include <linux/random.h>
2008-01-30 13:31:07 +01:00
# include <linux/limits.h>
# include <linux/sched.h>
2009-09-08 11:01:55 +02:00
# include <asm/elf.h>
2011-08-06 14:31:38 +02:00
struct __read_mostly va_alignment va_align = {
. flags = - 1 ,
} ;
2009-09-08 11:01:55 +02:00
static unsigned int stack_maxrandom_size ( void )
{
unsigned int max = 0 ;
if ( ( current - > flags & PF_RANDOMIZE ) & &
! ( current - > personality & ADDR_NO_RANDOMIZE ) ) {
max = ( ( - 1U ) & STACK_RND_MASK ) < < PAGE_SHIFT ;
}
return max ;
}
2008-01-30 13:31:07 +01:00
/*
* Top of mmap area ( just below the process stack ) .
*
2009-09-08 11:01:55 +02:00
* Leave an at least ~ 128 MB hole with possible stack randomization .
2008-01-30 13:31:07 +01:00
*/
2009-09-08 11:01:55 +02:00
# define MIN_GAP (128*1024*1024UL + stack_maxrandom_size())
2008-01-30 13:31:07 +01:00
# define MAX_GAP (TASK_SIZE / 6*5)
2006-01-17 07:03:38 +01:00
2008-01-30 13:31:07 +01:00
static int mmap_is_legacy ( void )
2008-01-30 13:31:07 +01:00
{
if ( current - > personality & ADDR_COMPAT_LAYOUT )
return 1 ;
2010-01-27 17:32:22 +01:00
if ( rlimit ( RLIMIT_STACK ) = = RLIM_INFINITY )
2008-01-30 13:31:07 +01:00
return 1 ;
return sysctl_legacy_va_layout ;
}
2008-01-30 13:31:10 +01:00
static unsigned long mmap_rnd ( void )
{
unsigned long rnd = 0 ;
/*
* 8 bits of randomness in 32 bit mmaps , 20 address space bits
* 28 bits of randomness in 64 bit mmaps , 40 address space bits
*/
if ( current - > flags & PF_RANDOMIZE ) {
if ( mmap_is_ia32 ( ) )
2011-11-15 14:46:46 -08:00
rnd = get_random_int ( ) % ( 1 < < 8 ) ;
2008-01-30 13:31:10 +01:00
else
2011-11-15 14:46:46 -08:00
rnd = get_random_int ( ) % ( 1 < < 28 ) ;
2008-01-30 13:31:10 +01:00
}
return rnd < < PAGE_SHIFT ;
}
static unsigned long mmap_base ( void )
{
2010-01-27 17:32:22 +01:00
unsigned long gap = rlimit ( RLIMIT_STACK ) ;
2008-01-30 13:31:10 +01:00
if ( gap < MIN_GAP )
gap = MIN_GAP ;
else if ( gap > MAX_GAP )
gap = MAX_GAP ;
return PAGE_ALIGN ( TASK_SIZE - gap - mmap_rnd ( ) ) ;
}
/*
* Bottom - up ( legacy ) layout on X86_32 did not support randomization , X86_64
* does , but not when emulating X86_32
*/
2013-08-22 09:13:06 -07:00
static unsigned long mmap_legacy_base ( void )
2008-01-30 13:31:10 +01:00
{
if ( mmap_is_ia32 ( ) )
return TASK_UNMAPPED_BASE ;
else
return TASK_UNMAPPED_BASE + mmap_rnd ( ) ;
}
2008-01-30 13:31:07 +01:00
/*
* This function , called very early during the creation of a new
* process VM image , sets up which VM layout function to use :
*/
void arch_pick_mmap_layout ( struct mm_struct * mm )
{
2013-08-21 20:55:59 +03:00
mm - > mmap_legacy_base = mmap_legacy_base ( ) ;
mm - > mmap_base = mmap_base ( ) ;
2008-01-30 13:31:10 +01:00
if ( mmap_is_legacy ( ) ) {
2013-08-21 20:55:59 +03:00
mm - > mmap_base = mm - > mmap_legacy_base ;
2008-01-30 13:31:07 +01:00
mm - > get_unmapped_area = arch_get_unmapped_area ;
} else {
mm - > get_unmapped_area = arch_get_unmapped_area_topdown ;
}
2006-01-17 07:03:38 +01:00
}