diff options
author | Andrew Morton <akpm@linux-foundation.org> | 2007-07-21 07:37:32 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-07-21 20:49:14 -0400 |
commit | d4e3cc387ea1b74c3ad2ef2f6f5c05fd6fc314b8 (patch) | |
tree | b14dde552be76614fe443eccbb15658f651fc36c /fs/binfmt_elf.c | |
parent | 80e27982a66ea8306a704ba8bdf634ed480d4b46 (diff) |
revert "PIE randomization"
There are reports of this causing userspace failures
(http://lkml.org/lkml/2007/7/20/421).
Revert.
Cc: Jan Kratochvil <honza@jikos.cz>
Cc: Jiri Kosina <jkosina@suse.cz>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Roland McGrath <roland@redhat.com>
Cc: Jakub Jelinek <jakub@redhat.com>
Cc: Ulrich Kunitz <kune@deine-taler.de>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: "Bret Towe" <magnade@gmail.com>
Cc: "Luck, Tony" <tony.luck@intel.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/binfmt_elf.c')
-rw-r--r-- | fs/binfmt_elf.c | 109 |
1 files changed, 23 insertions, 86 deletions
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index ba24cb2ff6ce..4482a0673b15 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c | |||
@@ -45,7 +45,7 @@ | |||
45 | 45 | ||
46 | static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs); | 46 | static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs); |
47 | static int load_elf_library(struct file *); | 47 | static int load_elf_library(struct file *); |
48 | static unsigned long elf_map (struct file *, unsigned long, struct elf_phdr *, int, int, unsigned long); | 48 | static unsigned long elf_map (struct file *, unsigned long, struct elf_phdr *, int, int); |
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 |
@@ -80,7 +80,7 @@ static struct linux_binfmt elf_format = { | |||
80 | .hasvdso = 1 | 80 | .hasvdso = 1 |
81 | }; | 81 | }; |
82 | 82 | ||
83 | #define BAD_ADDR(x) IS_ERR_VALUE(x) | 83 | #define BAD_ADDR(x) ((unsigned long)(x) >= TASK_SIZE) |
84 | 84 | ||
85 | static int set_brk(unsigned long start, unsigned long end) | 85 | static int set_brk(unsigned long start, unsigned long end) |
86 | { | 86 | { |
@@ -295,70 +295,33 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec, | |||
295 | #ifndef elf_map | 295 | #ifndef elf_map |
296 | 296 | ||
297 | static unsigned long elf_map(struct file *filep, unsigned long addr, | 297 | static unsigned long elf_map(struct file *filep, unsigned long addr, |
298 | struct elf_phdr *eppnt, int prot, int type, | 298 | struct elf_phdr *eppnt, int prot, int type) |
299 | unsigned long total_size) | ||
300 | { | 299 | { |
301 | unsigned long map_addr; | 300 | unsigned long map_addr; |
302 | unsigned long size = eppnt->p_filesz + ELF_PAGEOFFSET(eppnt->p_vaddr); | 301 | unsigned long pageoffset = ELF_PAGEOFFSET(eppnt->p_vaddr); |
303 | unsigned long off = eppnt->p_offset - ELF_PAGEOFFSET(eppnt->p_vaddr); | ||
304 | addr = ELF_PAGESTART(addr); | ||
305 | size = ELF_PAGEALIGN(size); | ||
306 | 302 | ||
303 | down_write(¤t->mm->mmap_sem); | ||
307 | /* mmap() will return -EINVAL if given a zero size, but a | 304 | /* mmap() will return -EINVAL if given a zero size, but a |
308 | * segment with zero filesize is perfectly valid */ | 305 | * segment with zero filesize is perfectly valid */ |
309 | if (!size) | 306 | if (eppnt->p_filesz + pageoffset) |
310 | return addr; | 307 | map_addr = do_mmap(filep, ELF_PAGESTART(addr), |
311 | 308 | eppnt->p_filesz + pageoffset, prot, type, | |
312 | down_write(¤t->mm->mmap_sem); | 309 | eppnt->p_offset - pageoffset); |
313 | /* | 310 | else |
314 | * total_size is the size of the ELF (interpreter) image. | 311 | map_addr = ELF_PAGESTART(addr); |
315 | * The _first_ mmap needs to know the full size, otherwise | ||
316 | * randomization might put this image into an overlapping | ||
317 | * position with the ELF binary image. (since size < total_size) | ||
318 | * So we first map the 'big' image - and unmap the remainder at | ||
319 | * the end. (which unmap is needed for ELF images with holes.) | ||
320 | */ | ||
321 | if (total_size) { | ||
322 | total_size = ELF_PAGEALIGN(total_size); | ||
323 | map_addr = do_mmap(filep, addr, total_size, prot, type, off); | ||
324 | if (!BAD_ADDR(map_addr)) | ||
325 | do_munmap(current->mm, map_addr+size, total_size-size); | ||
326 | } else | ||
327 | map_addr = do_mmap(filep, addr, size, prot, type, off); | ||
328 | |||
329 | up_write(¤t->mm->mmap_sem); | 312 | up_write(¤t->mm->mmap_sem); |
330 | return(map_addr); | 313 | return(map_addr); |
331 | } | 314 | } |
332 | 315 | ||
333 | #endif /* !elf_map */ | 316 | #endif /* !elf_map */ |
334 | 317 | ||
335 | static unsigned long total_mapping_size(struct elf_phdr *cmds, int nr) | ||
336 | { | ||
337 | int i, first_idx = -1, last_idx = -1; | ||
338 | |||
339 | for (i = 0; i < nr; i++) { | ||
340 | if (cmds[i].p_type == PT_LOAD) { | ||
341 | last_idx = i; | ||
342 | if (first_idx == -1) | ||
343 | first_idx = i; | ||
344 | } | ||
345 | } | ||
346 | if (first_idx == -1) | ||
347 | return 0; | ||
348 | |||
349 | return cmds[last_idx].p_vaddr + cmds[last_idx].p_memsz - | ||
350 | ELF_PAGESTART(cmds[first_idx].p_vaddr); | ||
351 | } | ||
352 | |||
353 | |||
354 | /* This is much more generalized than the library routine read function, | 318 | /* This is much more generalized than the library routine read function, |
355 | so we keep this separate. Technically the library read function | 319 | so we keep this separate. Technically the library read function |
356 | is only provided so that we can read a.out libraries that have | 320 | is only provided so that we can read a.out libraries that have |
357 | an ELF header */ | 321 | an ELF header */ |
358 | 322 | ||
359 | static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex, | 323 | static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex, |
360 | struct file *interpreter, unsigned long *interp_map_addr, | 324 | struct file *interpreter, unsigned long *interp_load_addr) |
361 | unsigned long no_base) | ||
362 | { | 325 | { |
363 | struct elf_phdr *elf_phdata; | 326 | struct elf_phdr *elf_phdata; |
364 | struct elf_phdr *eppnt; | 327 | struct elf_phdr *eppnt; |
@@ -366,7 +329,6 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex, | |||
366 | int load_addr_set = 0; | 329 | int load_addr_set = 0; |
367 | unsigned long last_bss = 0, elf_bss = 0; | 330 | unsigned long last_bss = 0, elf_bss = 0; |
368 | unsigned long error = ~0UL; | 331 | unsigned long error = ~0UL; |
369 | unsigned long total_size; | ||
370 | int retval, i, size; | 332 | int retval, i, size; |
371 | 333 | ||
372 | /* First of all, some simple consistency checks */ | 334 | /* First of all, some simple consistency checks */ |
@@ -405,12 +367,6 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex, | |||
405 | goto out_close; | 367 | goto out_close; |
406 | } | 368 | } |
407 | 369 | ||
408 | total_size = total_mapping_size(elf_phdata, interp_elf_ex->e_phnum); | ||
409 | if (!total_size) { | ||
410 | error = -EINVAL; | ||
411 | goto out_close; | ||
412 | } | ||
413 | |||
414 | eppnt = elf_phdata; | 370 | eppnt = elf_phdata; |
415 | for (i = 0; i < interp_elf_ex->e_phnum; i++, eppnt++) { | 371 | for (i = 0; i < interp_elf_ex->e_phnum; i++, eppnt++) { |
416 | if (eppnt->p_type == PT_LOAD) { | 372 | if (eppnt->p_type == PT_LOAD) { |
@@ -428,14 +384,9 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex, | |||
428 | vaddr = eppnt->p_vaddr; | 384 | vaddr = eppnt->p_vaddr; |
429 | if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) | 385 | if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) |
430 | elf_type |= MAP_FIXED; | 386 | elf_type |= MAP_FIXED; |
431 | else if (no_base && interp_elf_ex->e_type == ET_DYN) | ||
432 | load_addr = -vaddr; | ||
433 | 387 | ||
434 | map_addr = elf_map(interpreter, load_addr + vaddr, | 388 | map_addr = elf_map(interpreter, load_addr + vaddr, |
435 | eppnt, elf_prot, elf_type, total_size); | 389 | eppnt, elf_prot, elf_type); |
436 | total_size = 0; | ||
437 | if (!*interp_map_addr) | ||
438 | *interp_map_addr = map_addr; | ||
439 | error = map_addr; | 390 | error = map_addr; |
440 | if (BAD_ADDR(map_addr)) | 391 | if (BAD_ADDR(map_addr)) |
441 | goto out_close; | 392 | goto out_close; |
@@ -501,7 +452,8 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex, | |||
501 | goto out_close; | 452 | goto out_close; |
502 | } | 453 | } |
503 | 454 | ||
504 | error = load_addr; | 455 | *interp_load_addr = load_addr; |
456 | error = ((unsigned long)interp_elf_ex->e_entry) + load_addr; | ||
505 | 457 | ||
506 | out_close: | 458 | out_close: |
507 | kfree(elf_phdata); | 459 | kfree(elf_phdata); |
@@ -598,8 +550,7 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) | |||
598 | int elf_exec_fileno; | 550 | int elf_exec_fileno; |
599 | int retval, i; | 551 | int retval, i; |
600 | unsigned int size; | 552 | unsigned int size; |
601 | unsigned long elf_entry; | 553 | unsigned long elf_entry, interp_load_addr = 0; |
602 | unsigned long interp_load_addr = 0; | ||
603 | unsigned long start_code, end_code, start_data, end_data; | 554 | unsigned long start_code, end_code, start_data, end_data; |
604 | unsigned long reloc_func_desc = 0; | 555 | unsigned long reloc_func_desc = 0; |
605 | char passed_fileno[6]; | 556 | char passed_fileno[6]; |
@@ -863,7 +814,9 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) | |||
863 | current->mm->start_stack = bprm->p; | 814 | current->mm->start_stack = bprm->p; |
864 | 815 | ||
865 | /* Now we do a little grungy work by mmaping the ELF image into | 816 | /* Now we do a little grungy work by mmaping the ELF image into |
866 | the correct location in memory. */ | 817 | the correct location in memory. At this point, we assume that |
818 | the image should be loaded at fixed address, not at a variable | ||
819 | address. */ | ||
867 | for(i = 0, elf_ppnt = elf_phdata; | 820 | for(i = 0, elf_ppnt = elf_phdata; |
868 | i < loc->elf_ex.e_phnum; i++, elf_ppnt++) { | 821 | i < loc->elf_ex.e_phnum; i++, elf_ppnt++) { |
869 | int elf_prot = 0, elf_flags; | 822 | int elf_prot = 0, elf_flags; |
@@ -917,15 +870,11 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) | |||
917 | * default mmap base, as well as whatever program they | 870 | * default mmap base, as well as whatever program they |
918 | * might try to exec. This is because the brk will | 871 | * might try to exec. This is because the brk will |
919 | * follow the loader, and is not movable. */ | 872 | * follow the loader, and is not movable. */ |
920 | #ifdef CONFIG_X86 | ||
921 | load_bias = 0; | ||
922 | #else | ||
923 | load_bias = ELF_PAGESTART(ELF_ET_DYN_BASE - vaddr); | 873 | load_bias = ELF_PAGESTART(ELF_ET_DYN_BASE - vaddr); |
924 | #endif | ||
925 | } | 874 | } |
926 | 875 | ||
927 | error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt, | 876 | error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt, |
928 | elf_prot, elf_flags,0); | 877 | elf_prot, elf_flags); |
929 | if (BAD_ADDR(error)) { | 878 | if (BAD_ADDR(error)) { |
930 | send_sig(SIGKILL, current, 0); | 879 | send_sig(SIGKILL, current, 0); |
931 | retval = IS_ERR((void *)error) ? | 880 | retval = IS_ERR((void *)error) ? |
@@ -1001,25 +950,13 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) | |||
1001 | } | 950 | } |
1002 | 951 | ||
1003 | if (elf_interpreter) { | 952 | if (elf_interpreter) { |
1004 | if (interpreter_type == INTERPRETER_AOUT) { | 953 | if (interpreter_type == INTERPRETER_AOUT) |
1005 | elf_entry = load_aout_interp(&loc->interp_ex, | 954 | elf_entry = load_aout_interp(&loc->interp_ex, |
1006 | interpreter); | 955 | interpreter); |
1007 | } else { | 956 | else |
1008 | unsigned long uninitialized_var(interp_map_addr); | ||
1009 | |||
1010 | elf_entry = load_elf_interp(&loc->interp_elf_ex, | 957 | elf_entry = load_elf_interp(&loc->interp_elf_ex, |
1011 | interpreter, | 958 | interpreter, |
1012 | &interp_map_addr, | 959 | &interp_load_addr); |
1013 | load_bias); | ||
1014 | if (!BAD_ADDR(elf_entry)) { | ||
1015 | /* | ||
1016 | * load_elf_interp() returns relocation | ||
1017 | * adjustment | ||
1018 | */ | ||
1019 | interp_load_addr = elf_entry; | ||
1020 | elf_entry += loc->interp_elf_ex.e_entry; | ||
1021 | } | ||
1022 | } | ||
1023 | if (BAD_ADDR(elf_entry)) { | 960 | if (BAD_ADDR(elf_entry)) { |
1024 | force_sig(SIGSEGV, current); | 961 | force_sig(SIGSEGV, current); |
1025 | retval = IS_ERR((void *)elf_entry) ? | 962 | retval = IS_ERR((void *)elf_entry) ? |