diff -urNp linux-2.6.16.16/Documentation/aslr.txt linux-2.6.16.16-randparam/Documentation/aslr.txt --- linux-2.6.16.16/Documentation/aslr.txt 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.16.16-randparam/Documentation/aslr.txt 2006-06-03 23:56:50.000000000 -0400 @@ -0,0 +1,119 @@ +Address space layout randomization is randomly selecting the base +offsets of segments of memory in VMA. It is used as a security tool +to prevent sensitive attacks from being carried out by making important +parameters to those attacks volatile and non-discoverable. + +Linux currently employs address space randomization in two places: + +1. mmap() base + The base offset of libraries and anonymous mappings. Randomization is + currently taken to the following degrees by default: + + 32-bit: i386 + Over 1MiB of VMA, giving 8 bits of entropy for 4096 byte pages. + 64-bit: x86-64 + Over 1TiB of VMA, giving 28 bits of entropy for 4096 byte pages. + + The maximum is over an area the size of TASK_SIZE / 12 +2. stack base + The base offset of the stack. Randomization is currently taken to the + following degrees by default: + + 32-bit: i386 + Over 8MiB of VMA, giving 19 bits of entropy, aligned to 16 bytes. + 64-bit: x86-64 + Over 1TiB of VMA, giving 28 bits of entropy, aligned to 16 bytes. + + The maximum allowed is over an area the size of TASK_SIZE / 12 + +Linux does not employ heap randomization. + +Randomization is applied in the following places. + + +STACK RANDOMIZATION + +fs/exec.c +unsigned long arch_align_stack(unsigned long sp) + + This function is called during process initialization to shuffle the + stack pointer to sub-page granularity. It applies a portion of the + stack entropy. + + This function calculates how much randomization to apply in the + following way: + + - Divide PAGE_SIZE by STACK_ALIGN + - Take the long_log2() of that to get MAX_RANDOM_STACK_BITS_PER_PAGE + + If MAX_RANDOM_STACK_BITS_PER_PAGE > total bits of entropy + - page_random_bits = total bits of entropy + + If MAX_RANDOM_STACK_BITS_PER_PAGE <= total bits of entropy + - page_random_bits = MAX_RANDOM_STACK_BITS_PER_PAGE + - Raise 2^page_random_bits to get random_places + - Divide PAGE_SIZE by random_places to get random_interval + - (get_random_int() % random_places) * random_interval = offset + - Subtract offset from the stack pointer + + +fs/binfmt_elf.c +static unsigned long randomize_stack_top(unsigned long stack_top) + + This function is called during process initialization to shuffle the + stack pointer to page granularity. It applies a portion of the stack + entropy. + + This function calculates how much randomization to apply in the + following way: + + - Divide PAGE_SIZE by STACK_ALIGN + - Take the long_log2() of that to get MAX_RANDOM_STACK_BITS_PER_PAGE + + If MAX_RANDOM_STACK_BITS_PER_PAGE > total bits of entropy + - vma_random_bits = 0 + + If MAX_RANDOM_STACK_BITS_PER_PAGE <= total bits of entropy + - vma_random_bits = + total bits entropy - MAX_RANDOM_STACK_BITS_PER_PAGE + - Multiply PAGE_SIZE by 2^random_bits to get random_range + - random_variable = get_random_int() % random_range + - Offset stack in VMA by random_variable and PAGE_ALIGN() result + + +MMAP RANDOMIZATION + +arch/i386/mm/mmap.c +static inline unsigned long mmap_base(struct mm_struct *mm) + + This function is called during process initialization to shuffle the + mmap() baser to page granularity. It applies full mmap() entropy. + + This function is for i386 architectures. + + +arch/x86_64/mm/mmap.c +void arch_pick_mmap_layout(struct mm_struct *mm) + + This function is called during process initialization to shuffle the + mmap() baser to page granularity. It applies full mmap() entropy. + For IA-32 emulation it will call an IA-32 function. + + This function is for x86-64 architectures. + + +arch/x86_64/ia32/mmap32.c +static inline unsigned long mmap_base(struct mm_struct *mm) + + + This function is called during process initialization to shuffle the + mmap() baser to page granularity. It applies full mmap() entropy. + + This function is for i386 architecture processes on x86-64. + +Also note the following: + + - STACK_ALIGN is defined in include/arch-*/processor.h + - include/linux/mm.h defines STACK_ALIGN as PAGE_SIZE if it is not + defined + - ARCH_RANDOM_STACK_BITS and MMAP_RANDOM_STACK_BITS are defined in + include/arch-*/processor.h + - ARCH_RANDOM_STACK_BITS and MMAP_RANDOM_STACK_BITS are defined as + 0 in include/linux/mm.h if not otherwise defined + diff -urNp linux-2.6.16.16/arch/i386/kernel/process.c linux-2.6.16.16-randparam/arch/i386/kernel/process.c --- linux-2.6.16.16/arch/i386/kernel/process.c 2006-05-10 21:56:24.000000000 -0400 +++ linux-2.6.16.16-randparam/arch/i386/kernel/process.c 2006-05-21 03:23:40.000000000 -0400 @@ -905,9 +905,3 @@ asmlinkage int sys_get_thread_area(struc return 0; } -unsigned long arch_align_stack(unsigned long sp) -{ - if (randomize_va_space) - sp -= get_random_int() % 8192; - return sp & ~0xf; -} diff -urNp linux-2.6.16.16/arch/i386/mm/mmap.c linux-2.6.16.16-randparam/arch/i386/mm/mmap.c --- linux-2.6.16.16/arch/i386/mm/mmap.c 2006-05-10 21:56:24.000000000 -0400 +++ linux-2.6.16.16-randparam/arch/i386/mm/mmap.c 2006-06-03 23:40:38.000000000 -0400 @@ -40,9 +40,30 @@ static inline unsigned long mmap_base(st { unsigned long gap = current->signal->rlim[RLIMIT_STACK].rlim_cur; unsigned long random_factor = 0; + long max_random_bits; + unsigned long random_bits; - if (current->flags & PF_RANDOMIZE) - random_factor = get_random_int() % (1024*1024); + random_bits = ARCH_RANDOM_MMAP_BITS; + + /*XXX: Place a hook here to adjust mmap() randomization; + * this hook will change the value of random_bits */ + + /* + * At most we should shift by 1/12 TASK_SIZE. This is 256M on + * 3GiB i386; 85M (64M, 14 bits) on 1GiB i386; 8TiB (31 bits) + * on x86-64 with 47 bits of user VMA... + */ + max_random_bits = MAX_RANDOM_MMAP_BITS; + if (max_random_bits < random_bits) + random_bits = max_random_bits; + + /* + * PAGE_SIZE is 4096 usually. mmap_random_bits means random bits + * of entropy, not how long the range is. If pages are suddenly + * bigger some day, we're still randomizing this much.... + */ + if (current->flags & PF_RANDOMIZE && (mmap_random_bits > 0)) + random_factor = get_random_int() % (PAGE_SIZE << random_bits); if (gap < MIN_GAP) gap = MIN_GAP; diff -urNp linux-2.6.16.16/arch/um/kernel/process_kern.c linux-2.6.16.16-randparam/arch/um/kernel/process_kern.c --- linux-2.6.16.16/arch/um/kernel/process_kern.c 2006-05-10 21:56:24.000000000 -0400 +++ linux-2.6.16.16-randparam/arch/um/kernel/process_kern.c 2006-05-21 03:24:19.000000000 -0400 @@ -454,18 +454,3 @@ int singlestepping(void * t) return 2; } -/* - * Only x86 and x86_64 have an arch_align_stack(). - * All other arches have "#define arch_align_stack(x) (x)" - * in their asm/system.h - * As this is included in UML from asm-um/system-generic.h, - * we can use it to behave as the subarch does. - */ -#ifndef arch_align_stack -unsigned long arch_align_stack(unsigned long sp) -{ - if (randomize_va_space) - sp -= get_random_int() % 8192; - return sp & ~0xf; -} -#endif diff -urNp linux-2.6.16.16/arch/x86_64/ia32/mmap32.c linux-2.6.16.16-randparam/arch/x86_64/ia32/mmap32.c --- linux-2.6.16.16/arch/x86_64/ia32/mmap32.c 2006-05-10 21:56:24.000000000 -0400 +++ linux-2.6.16.16-randparam/arch/x86_64/ia32/mmap32.c 2006-06-03 23:41:56.000000000 -0400 @@ -42,9 +42,30 @@ static inline unsigned long mmap_base(st { unsigned long gap = current->signal->rlim[RLIMIT_STACK].rlim_cur; unsigned long random_factor = 0; + long max_random_bits; + unsigned long random_bits; - if (current->flags & PF_RANDOMIZE) - random_factor = get_random_int() % (1024*1024); + random_bits = ARCH_RANDOM_MMAP_BITS; + + /*XXX: Place a hook here to adjust mmap() randomization; + * this hook will change the value of random_bits */ + + /* + * At most we should shift by 1/12 TASK_SIZE. This is 256M on + * 3GiB i386; 85M (64M, 14 bits) on 1GiB i386; 8TiB (31 bits) + * on x86-64 with 47 of user VMA... + */ + max_random_bits = MAX_RANDOM_MMAP_BITS; + if (max_random_bits < random_bits) + random_bits = max_random_bits; + + /* + * PAGE_SIZE is 4096 usually. mmap_random_bits means random bits + * of entropy, not how long the range is. If pages are suddenly + * bigger some day, we're still randomizing this much.... + */ + if (current->flags & PF_RANDOMIZE && (mmap_random_bits > 0)) + random_factor = get_random_int() % (PAGE_SIZE << random_bits); if (gap < MIN_GAP) gap = MIN_GAP; diff -urNp linux-2.6.16.16/arch/x86_64/kernel/process.c linux-2.6.16.16-randparam/arch/x86_64/kernel/process.c --- linux-2.6.16.16/arch/x86_64/kernel/process.c 2006-05-10 21:56:24.000000000 -0400 +++ linux-2.6.16.16-randparam/arch/x86_64/kernel/process.c 2006-05-21 03:24:06.000000000 -0400 @@ -839,9 +839,3 @@ int dump_task_regs(struct task_struct *t return 1; } -unsigned long arch_align_stack(unsigned long sp) -{ - if (randomize_va_space) - sp -= get_random_int() % 8192; - return sp & ~0xf; -} diff -urNp linux-2.6.16.16/arch/x86_64/mm/mmap.c linux-2.6.16.16-randparam/arch/x86_64/mm/mmap.c --- linux-2.6.16.16/arch/x86_64/mm/mmap.c 2006-05-10 21:56:24.000000000 -0400 +++ linux-2.6.16.16-randparam/arch/x86_64/mm/mmap.c 2006-06-03 23:42:44.000000000 -0400 @@ -11,17 +11,44 @@ void arch_pick_mmap_layout(struct mm_struct *mm) { + unsigned long random_factor = 0; + long max_random_bits; + unsigned long random_bits; + #ifdef CONFIG_IA32_EMULATION if (current_thread_info()->flags & _TIF_IA32) return ia32_pick_mmap_layout(mm); #endif + mm->mmap_base = TASK_UNMAPPED_BASE; + + /*XXX: I *think* this is right, but really I have no fucking + * clue what I'm doing when we get around to 'rnd =' + */ if (current->flags & PF_RANDOMIZE) { - /* Add 28bit randomness which is about 40bits of address space + unsigned rnd; + random_bits = ARCH_RANDOM_MMAP_BITS; + + /*XXX: Place a hook here to adjust mmap() + * randomization; this hook will change the value of + * random_bits */ + + /* + * At most we should shift by 1/12 TASK_SIZE. This + * is 256M on 3GiB i386; 85M (64M, 14 bits) on 1GiB + * i386; 8TiB (31 bits) on x86-64 with 47 bits of user + * VMA... + */ + max_random_bits = MAX_RANDOM_MMAP_BITS; + if (max_random_bits < random_bits) + random_bits = max_random_bits; + + /* Add our randomness. + 28 bits of randomness is about 40bits of address space because mmap base has to be page aligned. or ~1/128 of the total user VM (total user address space is 47bits) */ - unsigned rnd = get_random_int() & 0xfffffff; + rnd = get_random_int() % (1 << random_bits); mm->mmap_base += ((unsigned long)rnd) << PAGE_SHIFT; } mm->get_unmapped_area = arch_get_unmapped_area; diff -urNp linux-2.6.16.16/fs/binfmt_elf.c linux-2.6.16.16-randparam/fs/binfmt_elf.c --- linux-2.6.16.16/fs/binfmt_elf.c 2006-05-10 21:56:24.000000000 -0400 +++ linux-2.6.16.16-randparam/fs/binfmt_elf.c 2006-06-03 23:14:33.000000000 -0400 @@ -504,9 +504,49 @@ out: static unsigned long randomize_stack_top(unsigned long stack_top) { unsigned int random_variable = 0; + unsigned int random_range = 0; + int page_random_bits = 0; + int vma_random_bits = 0; + long random_bits = 0; + long max_random_bits = 0; - if (current->flags & PF_RANDOMIZE) - random_variable = get_random_int() % (8*1024*1024); + random_bits = ARCH_RANDOM_STACK_BITS; + + /*XXX: Place a hook here to adjust stack randomization; + * this hook will change the value of random_bits */ + + /* + * At most we should shift by 1/12 TASK_SIZE. This is 256M on + * 3GiB i386; 85M (64M, 14 bits) on 1GiB i386; 8TiB (31 bits) + * on x86-64 with 47 bits of user VMA... + */ + max_random_bits = MAX_RANDOM_STACK_BITS; + + if (max_random_bits < random_bits) + random_bits = max_random_bits; + + /* + * The code below relies on MAX_RANDOM_STACK_BITS_PER_PAGE, + * which relies on STACK_ALIGN. On architectures without + * sub-page alignment, we're aligned to page boundaries. + */ + /*Cut the bits in the sub-page randomization out*/ + page_random_bits = MAX_RANDOM_STACK_BITS_PER_PAGE; + if (random_bits <= page_random_bits) + vma_random_bits = 0; + else + vma_random_bits = random_bits - page_random_bits; + + /* + * Randomization happens here if doing more bits of entropy than + * handled by sub-page randomization, otherwise look to process.c + * only; the other bits are there. + */ + if (current->flags & PF_RANDOMIZE && vma_random_bits) { + /*Randomize with the bits we have times the page size*/ + random_range = PAGE_SIZE * (1 << vma_random_bits); + random_variable = get_random_int() % (random_range); + } #ifdef CONFIG_STACK_GROWSUP return PAGE_ALIGN(stack_top + random_variable); #else diff -urNp linux-2.6.16.16/fs/exec.c linux-2.6.16.16-randparam/fs/exec.c --- linux-2.6.16.16/fs/exec.c 2006-05-10 21:56:24.000000000 -0400 +++ linux-2.6.16.16-randparam/fs/exec.c 2006-06-03 23:15:09.000000000 -0400 @@ -49,6 +49,7 @@ #include #include #include +#include #include #include @@ -1526,3 +1527,65 @@ fail_unlock: fail: return retval; } + +/* + * Only x86 and x86_64 have an arch_align_stack(). + * All other arches have "#define arch_align_stack(x) (x)" + * in their asm/system.h + * + * In the case of UML, this is included from asm-um/system-generic.h; + * we can use it to behave as the subarch does. + */ +#ifndef arch_align_stack +unsigned long arch_align_stack(unsigned long sp) +{ + unsigned int random_interval = 0; + unsigned int random_places = 0; + int page_random_bits = 0; + long random_bits = 0; + long max_random_bits = 0; + + random_bits = ARCH_RANDOM_STACK_BITS; + + /*XXX: Place a hook here to adjust stack randomization; + * this hook will change the value of random_bits */ + + /* + * At most we should shift by 1/12 TASK_SIZE. This is 256M on + * 3GiB i386; 85M (64M, 14 bits) on 1GiB i386; 8TiB (31 bits) + * on x86-64 with 47 bits of user VMA... + */ + max_random_bits = MAX_RANDOM_STACK_BITS; + + if (random_bits > max_random_bits) + random_bits = max_random_bits; + + /*What's the most randomness we can get in the page*/ + page_random_bits = MAX_RANDOM_STACK_BITS_PER_PAGE; + + /*Are we using less entropy than that?*/ + if (page_random_bits > random_bits) + page_random_bits = random_bits; + + /* + * The stack is shifted around within PAGE_SIZE in intervals of + * 16 bytes. + * + * The position of the stack in VMA is set in binfmt_elf.c + */ + if (randomize_va_space && (page_random_bits > 0)) { + /*Distance we move, typically 16 bytes unless less entropy*/ + random_interval = PAGE_SIZE / (1 << page_random_bits); + + /*How many positions can we have?*/ + random_places = PAGE_SIZE / random_interval; + + /* + * get_random_int() % random_places = how many steps we move + * Multiply this by random_interval to get our position. + */ + sp -= (get_random_int() % random_places) * random_interval; + } + return sp & ~0xf; +} +#endif diff -urNp linux-2.6.16.16/include/asm-i386/processor.h linux-2.6.16.16-randparam/include/asm-i386/processor.h --- linux-2.6.16.16/include/asm-i386/processor.h 2006-05-10 21:56:24.000000000 -0400 +++ linux-2.6.16.16-randparam/include/asm-i386/processor.h 2006-06-03 23:09:26.000000000 -0400 @@ -320,6 +320,13 @@ extern int bootloader_type; */ #define TASK_SIZE (PAGE_OFFSET) +/*Interval in bytes to align the stack to*/ +#define STACK_ALIGN 16 + +/*Random bits of stack and mmap()*/ +#define ARCH_RANDOM_STACK_BITS 19 +#define ARCH_RANDOM_MMAP_BITS 8 + /* This decides where the kernel will search for a free chunk of vm * space during mmap's. */ diff -urNp linux-2.6.16.16/include/asm-x86_64/processor.h linux-2.6.16.16-randparam/include/asm-x86_64/processor.h --- linux-2.6.16.16/include/asm-x86_64/processor.h 2006-05-10 21:56:24.000000000 -0400 +++ linux-2.6.16.16-randparam/include/asm-x86_64/processor.h 2006-06-03 23:56:22.000000000 -0400 @@ -172,6 +172,23 @@ static inline void clear_in_cr4 (unsigne #define TASK_SIZE (test_thread_flag(TIF_IA32) ? IA32_PAGE_OFFSET : TASK_SIZE64) #define TASK_SIZE_OF(child) ((test_tsk_thread_flag(child, TIF_IA32)) ? IA32_PAGE_OFFSET : TASK_SIZE64) +/*Interval in bytes to align the stack to*/ +#define STACK_ALIGN 16 + +/*Random bits of stack and mmap() in IA-32*/ +#define IA32_ARCH_RANDOM_STACK_BITS 19 +#define IA32_ARCH_RANDOM_MMAP_BITS 8 + +/* Random bits of stack and mmap() in 64-bit mode. + * 28 bits is 40 bits of VMA, which is 1TiB, roughly 1/128 + * of the address space. */ +#define ARCH_RANDOM_STACK_BITS64 28 +#define ARCH_RANDOM_MMAP_BITS64 28 + +/*Random bits of stack and mmap()*/ +#define ARCH_RANDOM_STACK_BITS (test_thread_flag(TIF_IA32) ? IA32_ARCH_RANDOM_STACK_BITS : ARCH_RANDOM_STACK_BITS64) +#define ARCH_RANDOM_MMAP_BITS (test_thread_flag(TIF_IA32) ? IA32_ARCH_RANDOM_MMAP_BITS : ARCH_RANDOM_MMAP_BITS64) + #define TASK_UNMAPPED_BASE PAGE_ALIGN(TASK_SIZE/3) /* diff -urNp linux-2.6.16.16/include/linux/mm.h linux-2.6.16.16-randparam/include/linux/mm.h --- linux-2.6.16.16/include/linux/mm.h 2006-05-10 21:56:24.000000000 -0400 +++ linux-2.6.16.16-randparam/include/linux/mm.h 2006-06-03 23:49:39.000000000 -0400 @@ -23,6 +23,38 @@ struct anon_vma; extern unsigned long max_mapnr; #endif +/* Any arch not defining this is assumed to not know of + * sub-page stack alignment. + * Be sure to define these for each arch in + * include/asm-arch/processor.h */ +#ifndef STACK_ALIGN +# define STACK_ALIGN PAGE_SIZE +#endif + +/* If these are not defined, disable randomization. + * Be sure to define these for each arch in + * include/asm-arch/processor.h */ +#ifndef ARCH_RANDOM_STACK_BITS +# define ARCH_RANDOM_STACK_BITS 0 +#endif +#ifndef ARCH_RANDOM_MMAP_BITS +# define ARCH_RANDOM_MMAP_BITS 0 +#endif + +/* + * These are the biggest entropies we can have. + * Our original MAX_RANDOM_STACK_BITS was as below: + * long_log2((PAGE_SIZE / STACK_ALIGN) * (TASK_SIZE / 12) / PAGE_SIZE) + * This simplifies algebraicly to the below: + * long_log2(TASK_SIZE / (12 * STACK_ALIGN)) + */ +#define MAX_RANDOM_STACK_BITS \ + long_log2(TASK_SIZE / (12 * STACK_ALIGN)) +#define MAX_RANDOM_STACK_BITS_PER_PAGE \ + long_log2(PAGE_SIZE / STACK_ALIGN) +#define MAX_RANDOM_MMAP_BITS \ + long_log2((TASK_SIZE / 12) / PAGE_SIZE) + extern unsigned long num_physpages; extern void * high_memory; extern unsigned long vmalloc_earlyreserve;