diff options
Diffstat (limited to 'fs/binfmt_elf.c')
-rw-r--r-- | fs/binfmt_elf.c | 62 |
1 files changed, 52 insertions, 10 deletions
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index bcb884e2d613..48ffb3dc610a 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 *); |
@@ -712,7 +713,6 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) | |||
712 | goto out_free_dentry; | 713 | goto out_free_dentry; |
713 | 714 | ||
714 | /* OK, This is the point of no return */ | 715 | /* OK, This is the point of no return */ |
715 | current->flags &= ~PF_FORKNOEXEC; | ||
716 | current->mm->def_flags = def_flags; | 716 | current->mm->def_flags = def_flags; |
717 | 717 | ||
718 | /* Do this immediately, since STACK_TOP as used in setup_arg_pages | 718 | /* Do this immediately, since STACK_TOP as used in setup_arg_pages |
@@ -934,7 +934,6 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) | |||
934 | #endif /* ARCH_HAS_SETUP_ADDITIONAL_PAGES */ | 934 | #endif /* ARCH_HAS_SETUP_ADDITIONAL_PAGES */ |
935 | 935 | ||
936 | install_exec_creds(bprm); | 936 | install_exec_creds(bprm); |
937 | current->flags &= ~PF_FORKNOEXEC; | ||
938 | retval = create_elf_tables(bprm, &loc->elf_ex, | 937 | retval = create_elf_tables(bprm, &loc->elf_ex, |
939 | load_addr, interp_load_addr); | 938 | load_addr, interp_load_addr); |
940 | if (retval < 0) { | 939 | if (retval < 0) { |
@@ -1095,6 +1094,29 @@ out: | |||
1095 | */ | 1094 | */ |
1096 | 1095 | ||
1097 | /* | 1096 | /* |
1097 | * The purpose of always_dump_vma() is to make sure that special kernel mappings | ||
1098 | * that are useful for post-mortem analysis are included in every core dump. | ||
1099 | * In that way we ensure that the core dump is fully interpretable later | ||
1100 | * without matching up the same kernel and hardware config to see what PC values | ||
1101 | * meant. These special mappings include - vDSO, vsyscall, and other | ||
1102 | * architecture specific mappings | ||
1103 | */ | ||
1104 | static bool always_dump_vma(struct vm_area_struct *vma) | ||
1105 | { | ||
1106 | /* Any vsyscall mappings? */ | ||
1107 | if (vma == get_gate_vma(vma->vm_mm)) | ||
1108 | return true; | ||
1109 | /* | ||
1110 | * arch_vma_name() returns non-NULL for special architecture mappings, | ||
1111 | * such as vDSO sections. | ||
1112 | */ | ||
1113 | if (arch_vma_name(vma)) | ||
1114 | return true; | ||
1115 | |||
1116 | return false; | ||
1117 | } | ||
1118 | |||
1119 | /* | ||
1098 | * Decide what to dump of a segment, part, all or none. | 1120 | * Decide what to dump of a segment, part, all or none. |
1099 | */ | 1121 | */ |
1100 | static unsigned long vma_dump_size(struct vm_area_struct *vma, | 1122 | static unsigned long vma_dump_size(struct vm_area_struct *vma, |
@@ -1102,10 +1124,13 @@ static unsigned long vma_dump_size(struct vm_area_struct *vma, | |||
1102 | { | 1124 | { |
1103 | #define FILTER(type) (mm_flags & (1UL << MMF_DUMP_##type)) | 1125 | #define FILTER(type) (mm_flags & (1UL << MMF_DUMP_##type)) |
1104 | 1126 | ||
1105 | /* The vma can be set up to tell us the answer directly. */ | 1127 | /* always dump the vdso and vsyscall sections */ |
1106 | if (vma->vm_flags & VM_ALWAYSDUMP) | 1128 | if (always_dump_vma(vma)) |
1107 | goto whole; | 1129 | goto whole; |
1108 | 1130 | ||
1131 | if (vma->vm_flags & VM_NODUMP) | ||
1132 | return 0; | ||
1133 | |||
1109 | /* Hugetlb memory check */ | 1134 | /* Hugetlb memory check */ |
1110 | if (vma->vm_flags & VM_HUGETLB) { | 1135 | if (vma->vm_flags & VM_HUGETLB) { |
1111 | if ((vma->vm_flags & VM_SHARED) && FILTER(HUGETLB_SHARED)) | 1136 | if ((vma->vm_flags & VM_SHARED) && FILTER(HUGETLB_SHARED)) |
@@ -1390,6 +1415,22 @@ static void do_thread_regset_writeback(struct task_struct *task, | |||
1390 | regset->writeback(task, regset, 1); | 1415 | regset->writeback(task, regset, 1); |
1391 | } | 1416 | } |
1392 | 1417 | ||
1418 | #ifndef PR_REG_SIZE | ||
1419 | #define PR_REG_SIZE(S) sizeof(S) | ||
1420 | #endif | ||
1421 | |||
1422 | #ifndef PRSTATUS_SIZE | ||
1423 | #define PRSTATUS_SIZE(S) sizeof(S) | ||
1424 | #endif | ||
1425 | |||
1426 | #ifndef PR_REG_PTR | ||
1427 | #define PR_REG_PTR(S) (&((S)->pr_reg)) | ||
1428 | #endif | ||
1429 | |||
1430 | #ifndef SET_PR_FPVALID | ||
1431 | #define SET_PR_FPVALID(S, V) ((S)->pr_fpvalid = (V)) | ||
1432 | #endif | ||
1433 | |||
1393 | static int fill_thread_core_info(struct elf_thread_core_info *t, | 1434 | static int fill_thread_core_info(struct elf_thread_core_info *t, |
1394 | const struct user_regset_view *view, | 1435 | const struct user_regset_view *view, |
1395 | long signr, size_t *total) | 1436 | long signr, size_t *total) |
@@ -1404,11 +1445,11 @@ static int fill_thread_core_info(struct elf_thread_core_info *t, | |||
1404 | */ | 1445 | */ |
1405 | fill_prstatus(&t->prstatus, t->task, signr); | 1446 | fill_prstatus(&t->prstatus, t->task, signr); |
1406 | (void) view->regsets[0].get(t->task, &view->regsets[0], | 1447 | (void) view->regsets[0].get(t->task, &view->regsets[0], |
1407 | 0, sizeof(t->prstatus.pr_reg), | 1448 | 0, PR_REG_SIZE(t->prstatus.pr_reg), |
1408 | &t->prstatus.pr_reg, NULL); | 1449 | PR_REG_PTR(&t->prstatus), NULL); |
1409 | 1450 | ||
1410 | fill_note(&t->notes[0], "CORE", NT_PRSTATUS, | 1451 | fill_note(&t->notes[0], "CORE", NT_PRSTATUS, |
1411 | sizeof(t->prstatus), &t->prstatus); | 1452 | PRSTATUS_SIZE(t->prstatus), &t->prstatus); |
1412 | *total += notesize(&t->notes[0]); | 1453 | *total += notesize(&t->notes[0]); |
1413 | 1454 | ||
1414 | do_thread_regset_writeback(t->task, &view->regsets[0]); | 1455 | do_thread_regset_writeback(t->task, &view->regsets[0]); |
@@ -1421,7 +1462,7 @@ static int fill_thread_core_info(struct elf_thread_core_info *t, | |||
1421 | for (i = 1; i < view->n; ++i) { | 1462 | for (i = 1; i < view->n; ++i) { |
1422 | const struct user_regset *regset = &view->regsets[i]; | 1463 | const struct user_regset *regset = &view->regsets[i]; |
1423 | do_thread_regset_writeback(t->task, regset); | 1464 | do_thread_regset_writeback(t->task, regset); |
1424 | if (regset->core_note_type && | 1465 | if (regset->core_note_type && regset->get && |
1425 | (!regset->active || regset->active(t->task, regset))) { | 1466 | (!regset->active || regset->active(t->task, regset))) { |
1426 | int ret; | 1467 | int ret; |
1427 | size_t size = regset->n * regset->size; | 1468 | size_t size = regset->n * regset->size; |
@@ -1438,7 +1479,7 @@ static int fill_thread_core_info(struct elf_thread_core_info *t, | |||
1438 | regset->core_note_type, | 1479 | regset->core_note_type, |
1439 | size, data); | 1480 | size, data); |
1440 | else { | 1481 | else { |
1441 | t->prstatus.pr_fpvalid = 1; | 1482 | SET_PR_FPVALID(&t->prstatus, 1); |
1442 | fill_note(&t->notes[i], "CORE", | 1483 | fill_note(&t->notes[i], "CORE", |
1443 | NT_PRFPREG, size, data); | 1484 | NT_PRFPREG, size, data); |
1444 | } | 1485 | } |
@@ -2077,7 +2118,8 @@ out: | |||
2077 | 2118 | ||
2078 | static int __init init_elf_binfmt(void) | 2119 | static int __init init_elf_binfmt(void) |
2079 | { | 2120 | { |
2080 | return register_binfmt(&elf_format); | 2121 | register_binfmt(&elf_format); |
2122 | return 0; | ||
2081 | } | 2123 | } |
2082 | 2124 | ||
2083 | static void __exit exit_elf_binfmt(void) | 2125 | static void __exit exit_elf_binfmt(void) |