diff options
Diffstat (limited to 'fs/binfmt_elf.c')
-rw-r--r-- | fs/binfmt_elf.c | 83 |
1 files changed, 57 insertions, 26 deletions
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 07d096c4992..16f73541707 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <asm/uaccess.h> | 35 | #include <asm/uaccess.h> |
36 | #include <asm/param.h> | 36 | #include <asm/param.h> |
37 | #include <asm/page.h> | 37 | #include <asm/page.h> |
38 | #include <asm/exec.h> | ||
38 | 39 | ||
39 | static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs); | 40 | static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs); |
40 | static int load_elf_library(struct file *); | 41 | static int load_elf_library(struct file *); |
@@ -81,9 +82,7 @@ static int set_brk(unsigned long start, unsigned long end) | |||
81 | end = ELF_PAGEALIGN(end); | 82 | end = ELF_PAGEALIGN(end); |
82 | if (end > start) { | 83 | if (end > start) { |
83 | unsigned long addr; | 84 | unsigned long addr; |
84 | down_write(¤t->mm->mmap_sem); | 85 | addr = vm_brk(start, end - start); |
85 | addr = do_brk(start, end - start); | ||
86 | up_write(¤t->mm->mmap_sem); | ||
87 | if (BAD_ADDR(addr)) | 86 | if (BAD_ADDR(addr)) |
88 | return addr; | 87 | return addr; |
89 | } | 88 | } |
@@ -513,9 +512,7 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex, | |||
513 | elf_bss = ELF_PAGESTART(elf_bss + ELF_MIN_ALIGN - 1); | 512 | elf_bss = ELF_PAGESTART(elf_bss + ELF_MIN_ALIGN - 1); |
514 | 513 | ||
515 | /* Map the last of the bss segment */ | 514 | /* Map the last of the bss segment */ |
516 | down_write(¤t->mm->mmap_sem); | 515 | error = vm_brk(elf_bss, last_bss - elf_bss); |
517 | error = do_brk(elf_bss, last_bss - elf_bss); | ||
518 | up_write(¤t->mm->mmap_sem); | ||
519 | if (BAD_ADDR(error)) | 516 | if (BAD_ADDR(error)) |
520 | goto out_close; | 517 | goto out_close; |
521 | } | 518 | } |
@@ -712,7 +709,6 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) | |||
712 | goto out_free_dentry; | 709 | goto out_free_dentry; |
713 | 710 | ||
714 | /* OK, This is the point of no return */ | 711 | /* OK, This is the point of no return */ |
715 | current->flags &= ~PF_FORKNOEXEC; | ||
716 | current->mm->def_flags = def_flags; | 712 | current->mm->def_flags = def_flags; |
717 | 713 | ||
718 | /* Do this immediately, since STACK_TOP as used in setup_arg_pages | 714 | /* Do this immediately, since STACK_TOP as used in setup_arg_pages |
@@ -934,7 +930,6 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) | |||
934 | #endif /* ARCH_HAS_SETUP_ADDITIONAL_PAGES */ | 930 | #endif /* ARCH_HAS_SETUP_ADDITIONAL_PAGES */ |
935 | 931 | ||
936 | install_exec_creds(bprm); | 932 | install_exec_creds(bprm); |
937 | current->flags &= ~PF_FORKNOEXEC; | ||
938 | retval = create_elf_tables(bprm, &loc->elf_ex, | 933 | retval = create_elf_tables(bprm, &loc->elf_ex, |
939 | load_addr, interp_load_addr); | 934 | load_addr, interp_load_addr); |
940 | if (retval < 0) { | 935 | if (retval < 0) { |
@@ -963,10 +958,8 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) | |||
963 | and some applications "depend" upon this behavior. | 958 | and some applications "depend" upon this behavior. |
964 | Since we do not have the power to recompile these, we | 959 | Since we do not have the power to recompile these, we |
965 | emulate the SVr4 behavior. Sigh. */ | 960 | emulate the SVr4 behavior. Sigh. */ |
966 | down_write(¤t->mm->mmap_sem); | 961 | error = vm_mmap(NULL, 0, PAGE_SIZE, PROT_READ | PROT_EXEC, |
967 | error = do_mmap(NULL, 0, PAGE_SIZE, PROT_READ | PROT_EXEC, | ||
968 | MAP_FIXED | MAP_PRIVATE, 0); | 962 | MAP_FIXED | MAP_PRIVATE, 0); |
969 | up_write(¤t->mm->mmap_sem); | ||
970 | } | 963 | } |
971 | 964 | ||
972 | #ifdef ELF_PLAT_INIT | 965 | #ifdef ELF_PLAT_INIT |
@@ -1051,8 +1044,7 @@ static int load_elf_library(struct file *file) | |||
1051 | eppnt++; | 1044 | eppnt++; |
1052 | 1045 | ||
1053 | /* Now use mmap to map the library into memory. */ | 1046 | /* Now use mmap to map the library into memory. */ |
1054 | down_write(¤t->mm->mmap_sem); | 1047 | error = vm_mmap(file, |
1055 | error = do_mmap(file, | ||
1056 | ELF_PAGESTART(eppnt->p_vaddr), | 1048 | ELF_PAGESTART(eppnt->p_vaddr), |
1057 | (eppnt->p_filesz + | 1049 | (eppnt->p_filesz + |
1058 | ELF_PAGEOFFSET(eppnt->p_vaddr)), | 1050 | ELF_PAGEOFFSET(eppnt->p_vaddr)), |
@@ -1060,7 +1052,6 @@ static int load_elf_library(struct file *file) | |||
1060 | MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE, | 1052 | MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE, |
1061 | (eppnt->p_offset - | 1053 | (eppnt->p_offset - |
1062 | ELF_PAGEOFFSET(eppnt->p_vaddr))); | 1054 | ELF_PAGEOFFSET(eppnt->p_vaddr))); |
1063 | up_write(¤t->mm->mmap_sem); | ||
1064 | if (error != ELF_PAGESTART(eppnt->p_vaddr)) | 1055 | if (error != ELF_PAGESTART(eppnt->p_vaddr)) |
1065 | goto out_free_ph; | 1056 | goto out_free_ph; |
1066 | 1057 | ||
@@ -1073,11 +1064,8 @@ static int load_elf_library(struct file *file) | |||
1073 | len = ELF_PAGESTART(eppnt->p_filesz + eppnt->p_vaddr + | 1064 | len = ELF_PAGESTART(eppnt->p_filesz + eppnt->p_vaddr + |
1074 | ELF_MIN_ALIGN - 1); | 1065 | ELF_MIN_ALIGN - 1); |
1075 | bss = eppnt->p_memsz + eppnt->p_vaddr; | 1066 | bss = eppnt->p_memsz + eppnt->p_vaddr; |
1076 | if (bss > len) { | 1067 | if (bss > len) |
1077 | down_write(¤t->mm->mmap_sem); | 1068 | vm_brk(len, bss - len); |
1078 | do_brk(len, bss - len); | ||
1079 | up_write(¤t->mm->mmap_sem); | ||
1080 | } | ||
1081 | error = 0; | 1069 | error = 0; |
1082 | 1070 | ||
1083 | out_free_ph: | 1071 | out_free_ph: |
@@ -1095,6 +1083,29 @@ out: | |||
1095 | */ | 1083 | */ |
1096 | 1084 | ||
1097 | /* | 1085 | /* |
1086 | * The purpose of always_dump_vma() is to make sure that special kernel mappings | ||
1087 | * that are useful for post-mortem analysis are included in every core dump. | ||
1088 | * In that way we ensure that the core dump is fully interpretable later | ||
1089 | * without matching up the same kernel and hardware config to see what PC values | ||
1090 | * meant. These special mappings include - vDSO, vsyscall, and other | ||
1091 | * architecture specific mappings | ||
1092 | */ | ||
1093 | static bool always_dump_vma(struct vm_area_struct *vma) | ||
1094 | { | ||
1095 | /* Any vsyscall mappings? */ | ||
1096 | if (vma == get_gate_vma(vma->vm_mm)) | ||
1097 | return true; | ||
1098 | /* | ||
1099 | * arch_vma_name() returns non-NULL for special architecture mappings, | ||
1100 | * such as vDSO sections. | ||
1101 | */ | ||
1102 | if (arch_vma_name(vma)) | ||
1103 | return true; | ||
1104 | |||
1105 | return false; | ||
1106 | } | ||
1107 | |||
1108 | /* | ||
1098 | * Decide what to dump of a segment, part, all or none. | 1109 | * Decide what to dump of a segment, part, all or none. |
1099 | */ | 1110 | */ |
1100 | static unsigned long vma_dump_size(struct vm_area_struct *vma, | 1111 | static unsigned long vma_dump_size(struct vm_area_struct *vma, |
@@ -1102,10 +1113,13 @@ static unsigned long vma_dump_size(struct vm_area_struct *vma, | |||
1102 | { | 1113 | { |
1103 | #define FILTER(type) (mm_flags & (1UL << MMF_DUMP_##type)) | 1114 | #define FILTER(type) (mm_flags & (1UL << MMF_DUMP_##type)) |
1104 | 1115 | ||
1105 | /* The vma can be set up to tell us the answer directly. */ | 1116 | /* always dump the vdso and vsyscall sections */ |
1106 | if (vma->vm_flags & VM_ALWAYSDUMP) | 1117 | if (always_dump_vma(vma)) |
1107 | goto whole; | 1118 | goto whole; |
1108 | 1119 | ||
1120 | if (vma->vm_flags & VM_NODUMP) | ||
1121 | return 0; | ||
1122 | |||
1109 | /* Hugetlb memory check */ | 1123 | /* Hugetlb memory check */ |
1110 | if (vma->vm_flags & VM_HUGETLB) { | 1124 | if (vma->vm_flags & VM_HUGETLB) { |
1111 | if ((vma->vm_flags & VM_SHARED) && FILTER(HUGETLB_SHARED)) | 1125 | if ((vma->vm_flags & VM_SHARED) && FILTER(HUGETLB_SHARED)) |
@@ -1390,6 +1404,22 @@ static void do_thread_regset_writeback(struct task_struct *task, | |||
1390 | regset->writeback(task, regset, 1); | 1404 | regset->writeback(task, regset, 1); |
1391 | } | 1405 | } |
1392 | 1406 | ||
1407 | #ifndef PR_REG_SIZE | ||
1408 | #define PR_REG_SIZE(S) sizeof(S) | ||
1409 | #endif | ||
1410 | |||
1411 | #ifndef PRSTATUS_SIZE | ||
1412 | #define PRSTATUS_SIZE(S) sizeof(S) | ||
1413 | #endif | ||
1414 | |||
1415 | #ifndef PR_REG_PTR | ||
1416 | #define PR_REG_PTR(S) (&((S)->pr_reg)) | ||
1417 | #endif | ||
1418 | |||
1419 | #ifndef SET_PR_FPVALID | ||
1420 | #define SET_PR_FPVALID(S, V) ((S)->pr_fpvalid = (V)) | ||
1421 | #endif | ||
1422 | |||
1393 | static int fill_thread_core_info(struct elf_thread_core_info *t, | 1423 | static int fill_thread_core_info(struct elf_thread_core_info *t, |
1394 | const struct user_regset_view *view, | 1424 | const struct user_regset_view *view, |
1395 | long signr, size_t *total) | 1425 | long signr, size_t *total) |
@@ -1404,11 +1434,11 @@ static int fill_thread_core_info(struct elf_thread_core_info *t, | |||
1404 | */ | 1434 | */ |
1405 | fill_prstatus(&t->prstatus, t->task, signr); | 1435 | fill_prstatus(&t->prstatus, t->task, signr); |
1406 | (void) view->regsets[0].get(t->task, &view->regsets[0], | 1436 | (void) view->regsets[0].get(t->task, &view->regsets[0], |
1407 | 0, sizeof(t->prstatus.pr_reg), | 1437 | 0, PR_REG_SIZE(t->prstatus.pr_reg), |
1408 | &t->prstatus.pr_reg, NULL); | 1438 | PR_REG_PTR(&t->prstatus), NULL); |
1409 | 1439 | ||
1410 | fill_note(&t->notes[0], "CORE", NT_PRSTATUS, | 1440 | fill_note(&t->notes[0], "CORE", NT_PRSTATUS, |
1411 | sizeof(t->prstatus), &t->prstatus); | 1441 | PRSTATUS_SIZE(t->prstatus), &t->prstatus); |
1412 | *total += notesize(&t->notes[0]); | 1442 | *total += notesize(&t->notes[0]); |
1413 | 1443 | ||
1414 | do_thread_regset_writeback(t->task, &view->regsets[0]); | 1444 | do_thread_regset_writeback(t->task, &view->regsets[0]); |
@@ -1438,7 +1468,7 @@ static int fill_thread_core_info(struct elf_thread_core_info *t, | |||
1438 | regset->core_note_type, | 1468 | regset->core_note_type, |
1439 | size, data); | 1469 | size, data); |
1440 | else { | 1470 | else { |
1441 | t->prstatus.pr_fpvalid = 1; | 1471 | SET_PR_FPVALID(&t->prstatus, 1); |
1442 | fill_note(&t->notes[i], "CORE", | 1472 | fill_note(&t->notes[i], "CORE", |
1443 | NT_PRFPREG, size, data); | 1473 | NT_PRFPREG, size, data); |
1444 | } | 1474 | } |
@@ -2077,7 +2107,8 @@ out: | |||
2077 | 2107 | ||
2078 | static int __init init_elf_binfmt(void) | 2108 | static int __init init_elf_binfmt(void) |
2079 | { | 2109 | { |
2080 | return register_binfmt(&elf_format); | 2110 | register_binfmt(&elf_format); |
2111 | return 0; | ||
2081 | } | 2112 | } |
2082 | 2113 | ||
2083 | static void __exit exit_elf_binfmt(void) | 2114 | static void __exit exit_elf_binfmt(void) |