diff options
Diffstat (limited to 'fs/binfmt_elf.c')
-rw-r--r-- | fs/binfmt_elf.c | 173 |
1 files changed, 21 insertions, 152 deletions
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index a93b1170551b..41a958a7585e 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c | |||
@@ -134,8 +134,7 @@ static int padzero(unsigned long elf_bss) | |||
134 | 134 | ||
135 | static int | 135 | static int |
136 | create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec, | 136 | create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec, |
137 | int interp_aout, unsigned long load_addr, | 137 | unsigned long load_addr, unsigned long interp_load_addr) |
138 | unsigned long interp_load_addr) | ||
139 | { | 138 | { |
140 | unsigned long p = bprm->p; | 139 | unsigned long p = bprm->p; |
141 | int argc = bprm->argc; | 140 | int argc = bprm->argc; |
@@ -223,12 +222,7 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec, | |||
223 | 222 | ||
224 | sp = STACK_ADD(p, ei_index); | 223 | sp = STACK_ADD(p, ei_index); |
225 | 224 | ||
226 | items = (argc + 1) + (envc + 1); | 225 | items = (argc + 1) + (envc + 1) + 1; |
227 | if (interp_aout) { | ||
228 | items += 3; /* a.out interpreters require argv & envp too */ | ||
229 | } else { | ||
230 | items += 1; /* ELF interpreters only put argc on the stack */ | ||
231 | } | ||
232 | bprm->p = STACK_ROUND(sp, items); | 226 | bprm->p = STACK_ROUND(sp, items); |
233 | 227 | ||
234 | /* Point sp at the lowest address on the stack */ | 228 | /* Point sp at the lowest address on the stack */ |
@@ -251,16 +245,8 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec, | |||
251 | /* Now, let's put argc (and argv, envp if appropriate) on the stack */ | 245 | /* Now, let's put argc (and argv, envp if appropriate) on the stack */ |
252 | if (__put_user(argc, sp++)) | 246 | if (__put_user(argc, sp++)) |
253 | return -EFAULT; | 247 | return -EFAULT; |
254 | if (interp_aout) { | 248 | argv = sp; |
255 | argv = sp + 2; | 249 | envp = argv + argc + 1; |
256 | envp = argv + argc + 1; | ||
257 | if (__put_user((elf_addr_t)(unsigned long)argv, sp++) || | ||
258 | __put_user((elf_addr_t)(unsigned long)envp, sp++)) | ||
259 | return -EFAULT; | ||
260 | } else { | ||
261 | argv = sp; | ||
262 | envp = argv + argc + 1; | ||
263 | } | ||
264 | 250 | ||
265 | /* Populate argv and envp */ | 251 | /* Populate argv and envp */ |
266 | p = current->mm->arg_end = current->mm->arg_start; | 252 | p = current->mm->arg_end = current->mm->arg_start; |
@@ -513,61 +499,6 @@ out: | |||
513 | return error; | 499 | return error; |
514 | } | 500 | } |
515 | 501 | ||
516 | #ifdef CONFIG_ARCH_SUPPORTS_AOUT | ||
517 | static unsigned long load_aout_interp(struct exec *interp_ex, | ||
518 | struct file *interpreter) | ||
519 | { | ||
520 | unsigned long text_data, elf_entry = ~0UL; | ||
521 | char __user * addr; | ||
522 | loff_t offset; | ||
523 | |||
524 | current->mm->end_code = interp_ex->a_text; | ||
525 | text_data = interp_ex->a_text + interp_ex->a_data; | ||
526 | current->mm->end_data = text_data; | ||
527 | current->mm->brk = interp_ex->a_bss + text_data; | ||
528 | |||
529 | switch (N_MAGIC(*interp_ex)) { | ||
530 | case OMAGIC: | ||
531 | offset = 32; | ||
532 | addr = (char __user *)0; | ||
533 | break; | ||
534 | case ZMAGIC: | ||
535 | case QMAGIC: | ||
536 | offset = N_TXTOFF(*interp_ex); | ||
537 | addr = (char __user *)N_TXTADDR(*interp_ex); | ||
538 | break; | ||
539 | default: | ||
540 | goto out; | ||
541 | } | ||
542 | |||
543 | down_write(¤t->mm->mmap_sem); | ||
544 | do_brk(0, text_data); | ||
545 | up_write(¤t->mm->mmap_sem); | ||
546 | if (!interpreter->f_op || !interpreter->f_op->read) | ||
547 | goto out; | ||
548 | if (interpreter->f_op->read(interpreter, addr, text_data, &offset) < 0) | ||
549 | goto out; | ||
550 | flush_icache_range((unsigned long)addr, | ||
551 | (unsigned long)addr + text_data); | ||
552 | |||
553 | down_write(¤t->mm->mmap_sem); | ||
554 | do_brk(ELF_PAGESTART(text_data + ELF_MIN_ALIGN - 1), | ||
555 | interp_ex->a_bss); | ||
556 | up_write(¤t->mm->mmap_sem); | ||
557 | elf_entry = interp_ex->a_entry; | ||
558 | |||
559 | out: | ||
560 | return elf_entry; | ||
561 | } | ||
562 | #else | ||
563 | /* dummy extern - the function should never be called if !CONFIG_AOUT_BINFMT */ | ||
564 | static inline unsigned long load_aout_interp(struct exec *interp_ex, | ||
565 | struct file *interpreter) | ||
566 | { | ||
567 | return -ELIBACC; | ||
568 | } | ||
569 | #endif | ||
570 | |||
571 | /* | 502 | /* |
572 | * These are the functions used to load ELF style executables and shared | 503 | * These are the functions used to load ELF style executables and shared |
573 | * libraries. There is no binary dependent code anywhere else. | 504 | * libraries. There is no binary dependent code anywhere else. |
@@ -576,13 +507,6 @@ static inline unsigned long load_aout_interp(struct exec *interp_ex, | |||
576 | #define INTERPRETER_NONE 0 | 507 | #define INTERPRETER_NONE 0 |
577 | #define INTERPRETER_ELF 2 | 508 | #define INTERPRETER_ELF 2 |
578 | 509 | ||
579 | #ifdef CONFIG_ARCH_SUPPORTS_AOUT | ||
580 | #define INTERPRETER_AOUT 1 | ||
581 | #define IS_AOUT_INTERP(x) ((x) == INTERPRETER_AOUT) | ||
582 | #else | ||
583 | #define IS_AOUT_INTERP(x) (0) | ||
584 | #endif | ||
585 | |||
586 | #ifndef STACK_RND_MASK | 510 | #ifndef STACK_RND_MASK |
587 | #define STACK_RND_MASK (0x7ff >> (PAGE_SHIFT - 12)) /* 8MB of VA */ | 511 | #define STACK_RND_MASK (0x7ff >> (PAGE_SHIFT - 12)) /* 8MB of VA */ |
588 | #endif | 512 | #endif |
@@ -609,7 +533,6 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) | |||
609 | unsigned long load_addr = 0, load_bias = 0; | 533 | unsigned long load_addr = 0, load_bias = 0; |
610 | int load_addr_set = 0; | 534 | int load_addr_set = 0; |
611 | char * elf_interpreter = NULL; | 535 | char * elf_interpreter = NULL; |
612 | unsigned int interpreter_type = INTERPRETER_NONE; | ||
613 | unsigned long error; | 536 | unsigned long error; |
614 | struct elf_phdr *elf_ppnt, *elf_phdata; | 537 | struct elf_phdr *elf_ppnt, *elf_phdata; |
615 | unsigned long elf_bss, elf_brk; | 538 | unsigned long elf_bss, elf_brk; |
@@ -620,7 +543,6 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) | |||
620 | unsigned long interp_load_addr = 0; | 543 | unsigned long interp_load_addr = 0; |
621 | unsigned long start_code, end_code, start_data, end_data; | 544 | unsigned long start_code, end_code, start_data, end_data; |
622 | unsigned long reloc_func_desc = 0; | 545 | unsigned long reloc_func_desc = 0; |
623 | char passed_fileno[6]; | ||
624 | struct files_struct *files; | 546 | struct files_struct *files; |
625 | int executable_stack = EXSTACK_DEFAULT; | 547 | int executable_stack = EXSTACK_DEFAULT; |
626 | unsigned long def_flags = 0; | 548 | unsigned long def_flags = 0; |
@@ -789,62 +711,18 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) | |||
789 | 711 | ||
790 | /* Some simple consistency checks for the interpreter */ | 712 | /* Some simple consistency checks for the interpreter */ |
791 | if (elf_interpreter) { | 713 | if (elf_interpreter) { |
792 | static int warn; | ||
793 | #ifdef CONFIG_ARCH_SUPPORTS_AOUT | ||
794 | interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT; | ||
795 | |||
796 | /* Now figure out which format our binary is */ | ||
797 | if ((N_MAGIC(loc->interp_ex) != OMAGIC) && | ||
798 | (N_MAGIC(loc->interp_ex) != ZMAGIC) && | ||
799 | (N_MAGIC(loc->interp_ex) != QMAGIC)) | ||
800 | interpreter_type = INTERPRETER_ELF; | ||
801 | #else | ||
802 | interpreter_type = INTERPRETER_ELF; | ||
803 | #endif | ||
804 | if (memcmp(loc->interp_elf_ex.e_ident, ELFMAG, SELFMAG) != 0) | ||
805 | interpreter_type &= ~INTERPRETER_ELF; | ||
806 | |||
807 | if (IS_AOUT_INTERP(interpreter_type) && warn < 10) { | ||
808 | printk(KERN_WARNING "a.out ELF interpreter %s is " | ||
809 | "deprecated and will not be supported " | ||
810 | "after Linux 2.6.25\n", elf_interpreter); | ||
811 | warn++; | ||
812 | } | ||
813 | |||
814 | retval = -ELIBBAD; | 714 | retval = -ELIBBAD; |
815 | if (!interpreter_type) | 715 | /* Not an ELF interpreter */ |
716 | if (memcmp(loc->interp_elf_ex.e_ident, ELFMAG, SELFMAG) != 0) | ||
816 | goto out_free_dentry; | 717 | goto out_free_dentry; |
817 | |||
818 | /* Make sure only one type was selected */ | ||
819 | if ((interpreter_type & INTERPRETER_ELF) && | ||
820 | interpreter_type != INTERPRETER_ELF) { | ||
821 | // FIXME - ratelimit this before re-enabling | ||
822 | // printk(KERN_WARNING "ELF: Ambiguous type, using ELF\n"); | ||
823 | interpreter_type = INTERPRETER_ELF; | ||
824 | } | ||
825 | /* Verify the interpreter has a valid arch */ | 718 | /* Verify the interpreter has a valid arch */ |
826 | if ((interpreter_type == INTERPRETER_ELF) && | 719 | if (!elf_check_arch(&loc->interp_elf_ex)) |
827 | !elf_check_arch(&loc->interp_elf_ex)) | ||
828 | goto out_free_dentry; | 720 | goto out_free_dentry; |
829 | } else { | 721 | } else { |
830 | /* Executables without an interpreter also need a personality */ | 722 | /* Executables without an interpreter also need a personality */ |
831 | SET_PERSONALITY(loc->elf_ex, 0); | 723 | SET_PERSONALITY(loc->elf_ex, 0); |
832 | } | 724 | } |
833 | 725 | ||
834 | /* OK, we are done with that, now set up the arg stuff, | ||
835 | and then start this sucker up */ | ||
836 | if (IS_AOUT_INTERP(interpreter_type) && !bprm->sh_bang) { | ||
837 | char *passed_p = passed_fileno; | ||
838 | sprintf(passed_fileno, "%d", elf_exec_fileno); | ||
839 | |||
840 | if (elf_interpreter) { | ||
841 | retval = copy_strings_kernel(1, &passed_p, bprm); | ||
842 | if (retval) | ||
843 | goto out_free_dentry; | ||
844 | bprm->argc++; | ||
845 | } | ||
846 | } | ||
847 | |||
848 | /* Flush all traces of the currently running executable */ | 726 | /* Flush all traces of the currently running executable */ |
849 | retval = flush_old_exec(bprm); | 727 | retval = flush_old_exec(bprm); |
850 | if (retval) | 728 | if (retval) |
@@ -1022,24 +900,19 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) | |||
1022 | } | 900 | } |
1023 | 901 | ||
1024 | if (elf_interpreter) { | 902 | if (elf_interpreter) { |
1025 | if (IS_AOUT_INTERP(interpreter_type)) { | 903 | unsigned long uninitialized_var(interp_map_addr); |
1026 | elf_entry = load_aout_interp(&loc->interp_ex, | 904 | |
1027 | interpreter); | 905 | elf_entry = load_elf_interp(&loc->interp_elf_ex, |
1028 | } else { | 906 | interpreter, |
1029 | unsigned long uninitialized_var(interp_map_addr); | 907 | &interp_map_addr, |
1030 | 908 | load_bias); | |
1031 | elf_entry = load_elf_interp(&loc->interp_elf_ex, | 909 | if (!IS_ERR((void *)elf_entry)) { |
1032 | interpreter, | 910 | /* |
1033 | &interp_map_addr, | 911 | * load_elf_interp() returns relocation |
1034 | load_bias); | 912 | * adjustment |
1035 | if (!IS_ERR((void *)elf_entry)) { | 913 | */ |
1036 | /* | 914 | interp_load_addr = elf_entry; |
1037 | * load_elf_interp() returns relocation | 915 | elf_entry += loc->interp_elf_ex.e_entry; |
1038 | * adjustment | ||
1039 | */ | ||
1040 | interp_load_addr = elf_entry; | ||
1041 | elf_entry += loc->interp_elf_ex.e_entry; | ||
1042 | } | ||
1043 | } | 916 | } |
1044 | if (BAD_ADDR(elf_entry)) { | 917 | if (BAD_ADDR(elf_entry)) { |
1045 | force_sig(SIGSEGV, current); | 918 | force_sig(SIGSEGV, current); |
@@ -1063,8 +936,7 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) | |||
1063 | 936 | ||
1064 | kfree(elf_phdata); | 937 | kfree(elf_phdata); |
1065 | 938 | ||
1066 | if (!IS_AOUT_INTERP(interpreter_type)) | 939 | sys_close(elf_exec_fileno); |
1067 | sys_close(elf_exec_fileno); | ||
1068 | 940 | ||
1069 | set_binfmt(&elf_format); | 941 | set_binfmt(&elf_format); |
1070 | 942 | ||
@@ -1079,15 +951,12 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) | |||
1079 | compute_creds(bprm); | 951 | compute_creds(bprm); |
1080 | current->flags &= ~PF_FORKNOEXEC; | 952 | current->flags &= ~PF_FORKNOEXEC; |
1081 | retval = create_elf_tables(bprm, &loc->elf_ex, | 953 | retval = create_elf_tables(bprm, &loc->elf_ex, |
1082 | IS_AOUT_INTERP(interpreter_type), | ||
1083 | load_addr, interp_load_addr); | 954 | load_addr, interp_load_addr); |
1084 | if (retval < 0) { | 955 | if (retval < 0) { |
1085 | send_sig(SIGKILL, current, 0); | 956 | send_sig(SIGKILL, current, 0); |
1086 | goto out; | 957 | goto out; |
1087 | } | 958 | } |
1088 | /* N.B. passed_fileno might not be initialized? */ | 959 | /* N.B. passed_fileno might not be initialized? */ |
1089 | if (IS_AOUT_INTERP(interpreter_type)) | ||
1090 | current->mm->arg_start += strlen(passed_fileno) + 1; | ||
1091 | current->mm->end_code = end_code; | 960 | current->mm->end_code = end_code; |
1092 | current->mm->start_code = start_code; | 961 | current->mm->start_code = start_code; |
1093 | current->mm->start_data = start_data; | 962 | current->mm->start_data = start_data; |