# echo 0 > /proc/sys/kernel/randomize_va_spaceCan it be disabled for a specific program by modifying the ELF headers? Maybe not. But it can be disabled for a specific program invocation (and forked off children) by
% setarch `uname -m` -R program program_argsThe utility setarch uses the personality() system call to set the ADDR_NO_RANDOMIZE personality flag, and then execs the given program. However, for setuid programs the kernel again strips the ADDR_NO_RANDOMIZE (and ADDR_COMPAT_LAYOUT. MMAP_PAGE_ZERO, READ_IMPLIES_EXEC) flags from the personality, even for the root user.
This randomize_va_space variable can have the values 0 (do not randomize), 1 (randomize stack and vdso page and mmap), and 2 (also randomize brk base address). Initially it is 0 when the kernel is booted with the norandmaps boot parameter, 1 when the kernel was compiled with CONFIG_COMPAT_BRK set, and 2 otherwise. When the brk base address is not randomized, it is the first address past the executable code.
% cc -z execstack prog.c -o prog % objdump -p prog | grep -i -A1 stack STACK off 0x0000000000000000 vaddr 0x0000000000000000 paddr 0x0000000000000000 align 2**3 filesz 0x0000000000000000 memsz 0x0000000000000000 flags rwx % readelf -l prog | grep -i -A1 stack GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000 0x0000000000000000 0x0000000000000000 RWE 8 % scanelf -e prog TYPE STK/REL/PTL FILE ET_EXEC RWX R-- RW- progIt can be examined and changed on an existing binary using the execstack utility.
% cc prog.c -o prog % execstack prog - prog % execstack -s prog % execstack prog X prog
Example:
% cat trampoline.c #include <stdio.h> int main(int ac, char **av) { int localfn(int a) { return a+ac; } int (*fptr)(int) = localfn; printf("%d\n", fptr(-1)); return 0; } % cc -S -Os trampoline.c % cat trampoline.s .file "trampoline.c" .text .type localfn.1658, @function localfn.1658: pushl %ebp // save frame pointer movl (%ecx), %eax // get the non-local variable ac movl %esp, %ebp // addl 8(%ebp), %eax // add the local variable a = -1 popl %ebp // restore frame pointer ret .size localfn.1658, .-localfn.1658 .section .rodata.str1.1,"aMS",@progbits,1 .LC0: .string "%d\n" .text .globl main .type main, @function main: pushl %ebp // save frame pointer movl %esp, %ebp // set new frame pointer subl $16, %esp // stack space for vars and trampoline movl 8(%ebp), %eax // get parameter ac leal -16(%ebp), %edx // movl %eax, -16(%ebp) // copy to a local variable movl $localfn.1658+2, %eax // subl %ebp, %eax // %eax = $localfn.1658+2-%ebp leal -12(%ebp), %ecx // %ecx = trampoline address movl %edx, -11(%ebp) // 2nd half of following: D = %edx movb $-71, -12(%ebp) // B9: movl D %ecx movb $-23, -7(%ebp) // E9: jmp .+A movl %eax, -6(%ebp) // 2nd half of previous: A = %eax pushl $-1 call *%ecx // call fptr(-1) pushl %eax pushl $.LC0 call printf xorl %eax, %eax leave ret .size main, .-main .ident "GCC: (GNU) 4.0.2 20050901 (prerelease) (SUSE Linux)" .section .note.GNU-stack,"x",@progbits %This sets up a stack area S, with first a copy of the variable ac, and then a 2-instruction trampoline: (i) the instruction movl D %ecx, where D is the address of the stack area S, and (ii) the instruction jmp .+A where A is computed as $localfn.1658 + 2 - %ebp where . = %ebp - 2, so that the jmp jumps to $localfn.1658. The call fptr(-1) is translated as call *%ecx with -1 on the stack. The %ecx register points to the start of the code (the movl) on the stack trampoline. The result is that $localfn.1658 is called with %ecx pointing to an area containing the necessary non-local variables.
Compiler. In its assembler output gcc outputs a line
.section .note.GNU-stack,"x",@progbitswhen a trampoline was generated, and
.section .note.GNU-stack,"",@progbitsotherwise.
% cc -S prog.c % tail -1 prog.s .section .note.GNU-stack,"",@progbitsMaybe there are no gcc flags to override.
Assembler. The assembler will do the right thing (and can be guided using the --execstack or --noexecstack flags). E.g.:
% cc -Wa,--execstack -c prog.c % objdump -h ./prog.o | tail -2 6 .note.GNU-stack 00000000 0000000000000000 0000000000000000 000000cd 2**0 CONTENTS, READONLY, CODE
Linker. The linker will do the right thing (and can be guided using the -z execstack or -z noexecstack flags).
% cat ff.c #include <string.h> int main(int ac, char **av) { char buf[10]; strcpy(buf, av[1]); return buf[5]; } % cc -o ff ff.c % ./ff xxxxxxxxxxxxxx % ./ff xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx *** stack smashing detected ***: ./ff terminated Segmentation fault % ./ff xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx *** stack smashing detected ***: ./ff terminated ======= Backtrace: ========= /lib/libc.so.6(__fortify_fail+0x37)[0x2b1f97f6c887] /lib/libc.so.6(__fortify_fail+0x0)[0x2b1f97f6c850] ./ff[0x4005c9] /lib/libc.so.6(__libc_start_main+0xe6)[0x2b1f97e8b466] ./ff[0x4004b9] ======= Memory map: ======== ...Here stack smashing is detected when a value on the stack is overwritten, and __stack_chk_fail is called. The presence of this check can be tested:
% objdump -d ff | grep __stack_chk_fail 0000000000400468 <__stack_chk_fail@plt>: 4005c4: e8 9f fe ff ff callq 400468 <__stack_chk_fail@plt>The check can be disabled:
% cc -fno-stack-protector -o ff ff.c % ./ff xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx Segmentation fault % objdump -d ff | grep __stack_chk_fail %