aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorJiri Kosina <jkosina@suse.cz>2008-01-30 07:31:07 -0500
committerIngo Molnar <mingo@elte.hu>2008-01-30 07:31:07 -0500
commitcc503c1b43e002e3f1fed70f46d947e2bf349bb6 (patch)
treedf0d77b7bccf0148c7b7cdd0363354499b259f99 /fs
parent82f74e7159749cc511ebf5954a7b9ea6ad634949 (diff)
x86: PIE executable randomization
main executable of (specially compiled/linked -pie/-fpie) ET_DYN binaries onto a random address (in cases in which mmap() is allowed to perform a randomization). The code has been extraced from Ingo's exec-shield patch http://people.redhat.com/mingo/exec-shield/ [akpm@linux-foundation.org: fix used-uninitialsied warning] [kamezawa.hiroyu@jp.fujitsu.com: fixed ia32 ELF on x86_64 handling] Signed-off-by: Jiri Kosina <jkosina@suse.cz> Cc: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> Cc: Arjan van de Ven <arjan@infradead.org> Cc: Roland McGrath <roland@redhat.com> Cc: Jakub Jelinek <jakub@redhat.com> Cc: "Luck, Tony" <tony.luck@intel.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'fs')
-rw-r--r--fs/binfmt_elf.c107
1 files changed, 85 insertions, 22 deletions
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 043a800c8f71..8193d24be159 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -45,7 +45,7 @@
45 45
46static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs); 46static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs);
47static int load_elf_library(struct file *); 47static int load_elf_library(struct file *);
48static unsigned long elf_map (struct file *, unsigned long, struct elf_phdr *, int, int); 48static unsigned long elf_map (struct file *, unsigned long, struct elf_phdr *, int, int, unsigned long);
49 49
50/* 50/*
51 * If we don't support core dumping, then supply a NULL so we 51 * If we don't support core dumping, then supply a NULL so we
@@ -298,33 +298,70 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec,
298#ifndef elf_map 298#ifndef elf_map
299 299
300static unsigned long elf_map(struct file *filep, unsigned long addr, 300static unsigned long elf_map(struct file *filep, unsigned long addr,
301 struct elf_phdr *eppnt, int prot, int type) 301 struct elf_phdr *eppnt, int prot, int type,
302 unsigned long total_size)
302{ 303{
303 unsigned long map_addr; 304 unsigned long map_addr;
304 unsigned long pageoffset = ELF_PAGEOFFSET(eppnt->p_vaddr); 305 unsigned long size = eppnt->p_filesz + ELF_PAGEOFFSET(eppnt->p_vaddr);
306 unsigned long off = eppnt->p_offset - ELF_PAGEOFFSET(eppnt->p_vaddr);
307 addr = ELF_PAGESTART(addr);
308 size = ELF_PAGEALIGN(size);
305 309
306 down_write(&current->mm->mmap_sem);
307 /* mmap() will return -EINVAL if given a zero size, but a 310 /* mmap() will return -EINVAL if given a zero size, but a
308 * segment with zero filesize is perfectly valid */ 311 * segment with zero filesize is perfectly valid */
309 if (eppnt->p_filesz + pageoffset) 312 if (!size)
310 map_addr = do_mmap(filep, ELF_PAGESTART(addr), 313 return addr;
311 eppnt->p_filesz + pageoffset, prot, type, 314
312 eppnt->p_offset - pageoffset); 315 down_write(&current->mm->mmap_sem);
313 else 316 /*
314 map_addr = ELF_PAGESTART(addr); 317 * total_size is the size of the ELF (interpreter) image.
318 * The _first_ mmap needs to know the full size, otherwise
319 * randomization might put this image into an overlapping
320 * position with the ELF binary image. (since size < total_size)
321 * So we first map the 'big' image - and unmap the remainder at
322 * the end. (which unmap is needed for ELF images with holes.)
323 */
324 if (total_size) {
325 total_size = ELF_PAGEALIGN(total_size);
326 map_addr = do_mmap(filep, addr, total_size, prot, type, off);
327 if (!BAD_ADDR(map_addr))
328 do_munmap(current->mm, map_addr+size, total_size-size);
329 } else
330 map_addr = do_mmap(filep, addr, size, prot, type, off);
331
315 up_write(&current->mm->mmap_sem); 332 up_write(&current->mm->mmap_sem);
316 return(map_addr); 333 return(map_addr);
317} 334}
318 335
319#endif /* !elf_map */ 336#endif /* !elf_map */
320 337
338static unsigned long total_mapping_size(struct elf_phdr *cmds, int nr)
339{
340 int i, first_idx = -1, last_idx = -1;
341
342 for (i = 0; i < nr; i++) {
343 if (cmds[i].p_type == PT_LOAD) {
344 last_idx = i;
345 if (first_idx == -1)
346 first_idx = i;
347 }
348 }
349 if (first_idx == -1)
350 return 0;
351
352 return cmds[last_idx].p_vaddr + cmds[last_idx].p_memsz -
353 ELF_PAGESTART(cmds[first_idx].p_vaddr);
354}
355
356
321/* This is much more generalized than the library routine read function, 357/* This is much more generalized than the library routine read function,
322 so we keep this separate. Technically the library read function 358 so we keep this separate. Technically the library read function
323 is only provided so that we can read a.out libraries that have 359 is only provided so that we can read a.out libraries that have
324 an ELF header */ 360 an ELF header */
325 361
326static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex, 362static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex,
327 struct file *interpreter, unsigned long *interp_load_addr) 363 struct file *interpreter, unsigned long *interp_map_addr,
364 unsigned long no_base)
328{ 365{
329 struct elf_phdr *elf_phdata; 366 struct elf_phdr *elf_phdata;
330 struct elf_phdr *eppnt; 367 struct elf_phdr *eppnt;
@@ -332,6 +369,7 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex,
332 int load_addr_set = 0; 369 int load_addr_set = 0;
333 unsigned long last_bss = 0, elf_bss = 0; 370 unsigned long last_bss = 0, elf_bss = 0;
334 unsigned long error = ~0UL; 371 unsigned long error = ~0UL;
372 unsigned long total_size;
335 int retval, i, size; 373 int retval, i, size;
336 374
337 /* First of all, some simple consistency checks */ 375 /* First of all, some simple consistency checks */
@@ -370,6 +408,12 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex,
370 goto out_close; 408 goto out_close;
371 } 409 }
372 410
411 total_size = total_mapping_size(elf_phdata, interp_elf_ex->e_phnum);
412 if (!total_size) {
413 error = -EINVAL;
414 goto out_close;
415 }
416
373 eppnt = elf_phdata; 417 eppnt = elf_phdata;
374 for (i = 0; i < interp_elf_ex->e_phnum; i++, eppnt++) { 418 for (i = 0; i < interp_elf_ex->e_phnum; i++, eppnt++) {
375 if (eppnt->p_type == PT_LOAD) { 419 if (eppnt->p_type == PT_LOAD) {
@@ -387,9 +431,14 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex,
387 vaddr = eppnt->p_vaddr; 431 vaddr = eppnt->p_vaddr;
388 if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) 432 if (interp_elf_ex->e_type == ET_EXEC || load_addr_set)
389 elf_type |= MAP_FIXED; 433 elf_type |= MAP_FIXED;
434 else if (no_base && interp_elf_ex->e_type == ET_DYN)
435 load_addr = -vaddr;
390 436
391 map_addr = elf_map(interpreter, load_addr + vaddr, 437 map_addr = elf_map(interpreter, load_addr + vaddr,
392 eppnt, elf_prot, elf_type); 438 eppnt, elf_prot, elf_type, total_size);
439 total_size = 0;
440 if (!*interp_map_addr)
441 *interp_map_addr = map_addr;
393 error = map_addr; 442 error = map_addr;
394 if (BAD_ADDR(map_addr)) 443 if (BAD_ADDR(map_addr))
395 goto out_close; 444 goto out_close;
@@ -455,8 +504,7 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex,
455 goto out_close; 504 goto out_close;
456 } 505 }
457 506
458 *interp_load_addr = load_addr; 507 error = load_addr;
459 error = ((unsigned long)interp_elf_ex->e_entry) + load_addr;
460 508
461out_close: 509out_close:
462 kfree(elf_phdata); 510 kfree(elf_phdata);
@@ -553,7 +601,8 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
553 int elf_exec_fileno; 601 int elf_exec_fileno;
554 int retval, i; 602 int retval, i;
555 unsigned int size; 603 unsigned int size;
556 unsigned long elf_entry, interp_load_addr = 0; 604 unsigned long elf_entry;
605 unsigned long interp_load_addr = 0;
557 unsigned long start_code, end_code, start_data, end_data; 606 unsigned long start_code, end_code, start_data, end_data;
558 unsigned long reloc_func_desc = 0; 607 unsigned long reloc_func_desc = 0;
559 char passed_fileno[6]; 608 char passed_fileno[6];
@@ -825,9 +874,7 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
825 current->mm->start_stack = bprm->p; 874 current->mm->start_stack = bprm->p;
826 875
827 /* Now we do a little grungy work by mmaping the ELF image into 876 /* Now we do a little grungy work by mmaping the ELF image into
828 the correct location in memory. At this point, we assume that 877 the correct location in memory. */
829 the image should be loaded at fixed address, not at a variable
830 address. */
831 for(i = 0, elf_ppnt = elf_phdata; 878 for(i = 0, elf_ppnt = elf_phdata;
832 i < loc->elf_ex.e_phnum; i++, elf_ppnt++) { 879 i < loc->elf_ex.e_phnum; i++, elf_ppnt++) {
833 int elf_prot = 0, elf_flags; 880 int elf_prot = 0, elf_flags;
@@ -881,11 +928,15 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
881 * default mmap base, as well as whatever program they 928 * default mmap base, as well as whatever program they
882 * might try to exec. This is because the brk will 929 * might try to exec. This is because the brk will
883 * follow the loader, and is not movable. */ 930 * follow the loader, and is not movable. */
931#ifdef CONFIG_X86
932 load_bias = 0;
933#else
884 load_bias = ELF_PAGESTART(ELF_ET_DYN_BASE - vaddr); 934 load_bias = ELF_PAGESTART(ELF_ET_DYN_BASE - vaddr);
935#endif
885 } 936 }
886 937
887 error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt, 938 error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt,
888 elf_prot, elf_flags); 939 elf_prot, elf_flags,0);
889 if (BAD_ADDR(error)) { 940 if (BAD_ADDR(error)) {
890 send_sig(SIGKILL, current, 0); 941 send_sig(SIGKILL, current, 0);
891 retval = IS_ERR((void *)error) ? 942 retval = IS_ERR((void *)error) ?
@@ -961,13 +1012,25 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
961 } 1012 }
962 1013
963 if (elf_interpreter) { 1014 if (elf_interpreter) {
964 if (interpreter_type == INTERPRETER_AOUT) 1015 if (interpreter_type == INTERPRETER_AOUT) {
965 elf_entry = load_aout_interp(&loc->interp_ex, 1016 elf_entry = load_aout_interp(&loc->interp_ex,
966 interpreter); 1017 interpreter);
967 else 1018 } else {
1019 unsigned long uninitialized_var(interp_map_addr);
1020
968 elf_entry = load_elf_interp(&loc->interp_elf_ex, 1021 elf_entry = load_elf_interp(&loc->interp_elf_ex,
969 interpreter, 1022 interpreter,
970 &interp_load_addr); 1023 &interp_map_addr,
1024 load_bias);
1025 if (!IS_ERR((void *)elf_entry)) {
1026 /*
1027 * load_elf_interp() returns relocation
1028 * adjustment
1029 */
1030 interp_load_addr = elf_entry;
1031 elf_entry += loc->interp_elf_ex.e_entry;
1032 }
1033 }
971 if (BAD_ADDR(elf_entry)) { 1034 if (BAD_ADDR(elf_entry)) {
972 force_sig(SIGSEGV, current); 1035 force_sig(SIGSEGV, current);
973 retval = IS_ERR((void *)elf_entry) ? 1036 retval = IS_ERR((void *)elf_entry) ?