diff options
author | Andi Kleen <andi@firstfloor.org> | 2008-02-08 07:21:54 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2008-02-08 12:22:41 -0500 |
commit | d20894a23708c2af75966534f8e4dedb46d48db2 (patch) | |
tree | f178118c4f1b1d248d2237f4088d2120e4f42083 /fs | |
parent | 48d13e483c5b450be451f78cc9cb43c0bdd6b7bb (diff) |
Remove a.out interpreter support in ELF loader
Following the deprecation schedule the a.out ELF interpreter support
is removed now with this patch. a.out ELF interpreters were an transition
feature for moving a.out systems to ELF, but they're unlikely to be still
needed. Pure a.out systems will still work of course. This allows to
simplify the hairy ELF loader.
Signed-off-by: Andi Kleen <ak@suse.de>
Cc: David Howells <dhowells@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs')
-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; |