Skip to content

Commit fb97d2e

Browse files
romank-msftkees
authored andcommitted
binfmt_elf, coredump: Log the reason of the failed core dumps
Missing, failed, or corrupted core dumps might impede crash investigations. To improve reliability of that process and consequently the programs themselves, one needs to trace the path from producing a core dumpfile to analyzing it. That path starts from the core dump file written to the disk by the kernel or to the standard input of a user mode helper program to which the kernel streams the coredump contents. There are cases where the kernel will interrupt writing the core out or produce a truncated/not-well-formed core dump without leaving a note. Add logging for the core dump collection failure paths to be able to reason what has gone wrong when the core dump is malformed or missing. Report the size of the data written to aid in diagnosing the user mode helper. Signed-off-by: Roman Kisel <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Kees Cook <[email protected]>
1 parent c114e99 commit fb97d2e

File tree

4 files changed

+150
-34
lines changed

4 files changed

+150
-34
lines changed

fs/binfmt_elf.c

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2027,8 +2027,10 @@ static int elf_core_dump(struct coredump_params *cprm)
20272027
* Collect all the non-memory information about the process for the
20282028
* notes. This also sets up the file header.
20292029
*/
2030-
if (!fill_note_info(&elf, e_phnum, &info, cprm))
2030+
if (!fill_note_info(&elf, e_phnum, &info, cprm)) {
2031+
coredump_report_failure("Error collecting note info");
20312032
goto end_coredump;
2033+
}
20322034

20332035
has_dumped = 1;
20342036

@@ -2043,8 +2045,10 @@ static int elf_core_dump(struct coredump_params *cprm)
20432045
sz += elf_coredump_extra_notes_size();
20442046

20452047
phdr4note = kmalloc(sizeof(*phdr4note), GFP_KERNEL);
2046-
if (!phdr4note)
2048+
if (!phdr4note) {
2049+
coredump_report_failure("Error allocating program headers note entry");
20472050
goto end_coredump;
2051+
}
20482052

20492053
fill_elf_note_phdr(phdr4note, sz, offset);
20502054
offset += sz;
@@ -2058,18 +2062,24 @@ static int elf_core_dump(struct coredump_params *cprm)
20582062

20592063
if (e_phnum == PN_XNUM) {
20602064
shdr4extnum = kmalloc(sizeof(*shdr4extnum), GFP_KERNEL);
2061-
if (!shdr4extnum)
2065+
if (!shdr4extnum) {
2066+
coredump_report_failure("Error allocating extra program headers");
20622067
goto end_coredump;
2068+
}
20632069
fill_extnum_info(&elf, shdr4extnum, e_shoff, segs);
20642070
}
20652071

20662072
offset = dataoff;
20672073

2068-
if (!dump_emit(cprm, &elf, sizeof(elf)))
2074+
if (!dump_emit(cprm, &elf, sizeof(elf))) {
2075+
coredump_report_failure("Error emitting the ELF headers");
20692076
goto end_coredump;
2077+
}
20702078

2071-
if (!dump_emit(cprm, phdr4note, sizeof(*phdr4note)))
2079+
if (!dump_emit(cprm, phdr4note, sizeof(*phdr4note))) {
2080+
coredump_report_failure("Error emitting the program header for notes");
20722081
goto end_coredump;
2082+
}
20732083

20742084
/* Write program headers for segments dump */
20752085
for (i = 0; i < cprm->vma_count; i++) {
@@ -2092,37 +2102,51 @@ static int elf_core_dump(struct coredump_params *cprm)
20922102
phdr.p_flags |= PF_X;
20932103
phdr.p_align = ELF_EXEC_PAGESIZE;
20942104

2095-
if (!dump_emit(cprm, &phdr, sizeof(phdr)))
2105+
if (!dump_emit(cprm, &phdr, sizeof(phdr))) {
2106+
coredump_report_failure("Error emitting program headers");
20962107
goto end_coredump;
2108+
}
20972109
}
20982110

2099-
if (!elf_core_write_extra_phdrs(cprm, offset))
2111+
if (!elf_core_write_extra_phdrs(cprm, offset)) {
2112+
coredump_report_failure("Error writing out extra program headers");
21002113
goto end_coredump;
2114+
}
21012115

21022116
/* write out the notes section */
2103-
if (!write_note_info(&info, cprm))
2117+
if (!write_note_info(&info, cprm)) {
2118+
coredump_report_failure("Error writing out notes");
21042119
goto end_coredump;
2120+
}
21052121

21062122
/* For cell spufs */
2107-
if (elf_coredump_extra_notes_write(cprm))
2123+
if (elf_coredump_extra_notes_write(cprm)) {
2124+
coredump_report_failure("Error writing out extra notes");
21082125
goto end_coredump;
2126+
}
21092127

21102128
/* Align to page */
21112129
dump_skip_to(cprm, dataoff);
21122130

21132131
for (i = 0; i < cprm->vma_count; i++) {
21142132
struct core_vma_metadata *meta = cprm->vma_meta + i;
21152133

2116-
if (!dump_user_range(cprm, meta->start, meta->dump_size))
2134+
if (!dump_user_range(cprm, meta->start, meta->dump_size)) {
2135+
coredump_report_failure("Error writing out the process memory");
21172136
goto end_coredump;
2137+
}
21182138
}
21192139

2120-
if (!elf_core_write_extra_data(cprm))
2140+
if (!elf_core_write_extra_data(cprm)) {
2141+
coredump_report_failure("Error writing out extra data");
21212142
goto end_coredump;
2143+
}
21222144

21232145
if (e_phnum == PN_XNUM) {
2124-
if (!dump_emit(cprm, shdr4extnum, sizeof(*shdr4extnum)))
2146+
if (!dump_emit(cprm, shdr4extnum, sizeof(*shdr4extnum))) {
2147+
coredump_report_failure("Error emitting extra program headers");
21252148
goto end_coredump;
2149+
}
21262150
}
21272151

21282152
end_coredump:

fs/coredump.c

Lines changed: 88 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -464,7 +464,17 @@ static bool dump_interrupted(void)
464464
* but then we need to teach dump_write() to restart and clear
465465
* TIF_SIGPENDING.
466466
*/
467-
return fatal_signal_pending(current) || freezing(current);
467+
if (fatal_signal_pending(current)) {
468+
coredump_report_failure("interrupted: fatal signal pending");
469+
return true;
470+
}
471+
472+
if (freezing(current)) {
473+
coredump_report_failure("interrupted: freezing");
474+
return true;
475+
}
476+
477+
return false;
468478
}
469479

470480
static void wait_for_dump_helpers(struct file *file)
@@ -519,15 +529,15 @@ static int umh_pipe_setup(struct subprocess_info *info, struct cred *new)
519529
return err;
520530
}
521531

522-
void do_coredump(const kernel_siginfo_t *siginfo)
532+
int do_coredump(const kernel_siginfo_t *siginfo)
523533
{
524534
struct core_state core_state;
525535
struct core_name cn;
526536
struct mm_struct *mm = current->mm;
527537
struct linux_binfmt * binfmt;
528538
const struct cred *old_cred;
529539
struct cred *cred;
530-
int retval = 0;
540+
int retval;
531541
int ispipe;
532542
size_t *argv = NULL;
533543
int argc = 0;
@@ -551,14 +561,20 @@ void do_coredump(const kernel_siginfo_t *siginfo)
551561
audit_core_dumps(siginfo->si_signo);
552562

553563
binfmt = mm->binfmt;
554-
if (!binfmt || !binfmt->core_dump)
564+
if (!binfmt || !binfmt->core_dump) {
565+
retval = -ENOEXEC;
555566
goto fail;
556-
if (!__get_dumpable(cprm.mm_flags))
567+
}
568+
if (!__get_dumpable(cprm.mm_flags)) {
569+
retval = -EACCES;
557570
goto fail;
571+
}
558572

559573
cred = prepare_creds();
560-
if (!cred)
574+
if (!cred) {
575+
retval = -EPERM;
561576
goto fail;
577+
}
562578
/*
563579
* We cannot trust fsuid as being the "true" uid of the process
564580
* nor do we know its entire history. We only know it was tainted
@@ -587,6 +603,7 @@ void do_coredump(const kernel_siginfo_t *siginfo)
587603

588604
if (ispipe < 0) {
589605
coredump_report_failure("format_corename failed, aborting core");
606+
retval = ispipe;
590607
goto fail_unlock;
591608
}
592609

@@ -607,20 +624,23 @@ void do_coredump(const kernel_siginfo_t *siginfo)
607624
* core_pattern process dies.
608625
*/
609626
coredump_report_failure("RLIMIT_CORE is set to 1, aborting core");
627+
retval = -EPERM;
610628
goto fail_unlock;
611629
}
612630
cprm.limit = RLIM_INFINITY;
613631

614632
dump_count = atomic_inc_return(&core_dump_count);
615633
if (core_pipe_limit && (core_pipe_limit < dump_count)) {
616634
coredump_report_failure("over core_pipe_limit, skipping core dump");
635+
retval = -E2BIG;
617636
goto fail_dropcount;
618637
}
619638

620639
helper_argv = kmalloc_array(argc + 1, sizeof(*helper_argv),
621640
GFP_KERNEL);
622641
if (!helper_argv) {
623642
coredump_report_failure("%s failed to allocate memory", __func__);
643+
retval = -ENOMEM;
624644
goto fail_dropcount;
625645
}
626646
for (argi = 0; argi < argc; argi++)
@@ -646,12 +666,16 @@ void do_coredump(const kernel_siginfo_t *siginfo)
646666
int open_flags = O_CREAT | O_WRONLY | O_NOFOLLOW |
647667
O_LARGEFILE | O_EXCL;
648668

649-
if (cprm.limit < binfmt->min_coredump)
669+
if (cprm.limit < binfmt->min_coredump) {
670+
coredump_report_failure("over coredump resource limit, skipping core dump");
671+
retval = -E2BIG;
650672
goto fail_unlock;
673+
}
651674

652675
if (need_suid_safe && cn.corename[0] != '/') {
653676
coredump_report_failure(
654677
"this process can only dump core to a fully qualified path, skipping core dump");
678+
retval = -EPERM;
655679
goto fail_unlock;
656680
}
657681

@@ -697,20 +721,28 @@ void do_coredump(const kernel_siginfo_t *siginfo)
697721
} else {
698722
cprm.file = filp_open(cn.corename, open_flags, 0600);
699723
}
700-
if (IS_ERR(cprm.file))
724+
if (IS_ERR(cprm.file)) {
725+
retval = PTR_ERR(cprm.file);
701726
goto fail_unlock;
727+
}
702728

703729
inode = file_inode(cprm.file);
704-
if (inode->i_nlink > 1)
730+
if (inode->i_nlink > 1) {
731+
retval = -EMLINK;
705732
goto close_fail;
706-
if (d_unhashed(cprm.file->f_path.dentry))
733+
}
734+
if (d_unhashed(cprm.file->f_path.dentry)) {
735+
retval = -EEXIST;
707736
goto close_fail;
737+
}
708738
/*
709739
* AK: actually i see no reason to not allow this for named
710740
* pipes etc, but keep the previous behaviour for now.
711741
*/
712-
if (!S_ISREG(inode->i_mode))
742+
if (!S_ISREG(inode->i_mode)) {
743+
retval = -EISDIR;
713744
goto close_fail;
745+
}
714746
/*
715747
* Don't dump core if the filesystem changed owner or mode
716748
* of the file during file creation. This is an issue when
@@ -722,17 +754,22 @@ void do_coredump(const kernel_siginfo_t *siginfo)
722754
current_fsuid())) {
723755
coredump_report_failure("Core dump to %s aborted: "
724756
"cannot preserve file owner", cn.corename);
757+
retval = -EPERM;
725758
goto close_fail;
726759
}
727760
if ((inode->i_mode & 0677) != 0600) {
728761
coredump_report_failure("Core dump to %s aborted: "
729762
"cannot preserve file permissions", cn.corename);
763+
retval = -EPERM;
730764
goto close_fail;
731765
}
732-
if (!(cprm.file->f_mode & FMODE_CAN_WRITE))
766+
if (!(cprm.file->f_mode & FMODE_CAN_WRITE)) {
767+
retval = -EACCES;
733768
goto close_fail;
734-
if (do_truncate(idmap, cprm.file->f_path.dentry,
735-
0, 0, cprm.file))
769+
}
770+
retval = do_truncate(idmap, cprm.file->f_path.dentry,
771+
0, 0, cprm.file);
772+
if (retval)
736773
goto close_fail;
737774
}
738775

@@ -748,10 +785,15 @@ void do_coredump(const kernel_siginfo_t *siginfo)
748785
*/
749786
if (!cprm.file) {
750787
coredump_report_failure("Core dump to |%s disabled", cn.corename);
788+
retval = -EPERM;
751789
goto close_fail;
752790
}
753-
if (!dump_vma_snapshot(&cprm))
791+
if (!dump_vma_snapshot(&cprm)) {
792+
coredump_report_failure("Can't get VMA snapshot for core dump |%s",
793+
cn.corename);
794+
retval = -EACCES;
754795
goto close_fail;
796+
}
755797

756798
file_start_write(cprm.file);
757799
core_dumped = binfmt->core_dump(&cprm);
@@ -767,9 +809,21 @@ void do_coredump(const kernel_siginfo_t *siginfo)
767809
}
768810
file_end_write(cprm.file);
769811
free_vma_snapshot(&cprm);
812+
} else {
813+
coredump_report_failure("Core dump to %s%s has been interrupted",
814+
ispipe ? "|" : "", cn.corename);
815+
retval = -EAGAIN;
816+
goto fail;
770817
}
818+
coredump_report(
819+
"written to %s%s: VMAs: %d, size %zu; core: %lld bytes, pos %lld",
820+
ispipe ? "|" : "", cn.corename,
821+
cprm.vma_count, cprm.vma_data_size, cprm.written, cprm.pos);
771822
if (ispipe && core_pipe_limit)
772823
wait_for_dump_helpers(cprm.file);
824+
825+
retval = 0;
826+
773827
close_fail:
774828
if (cprm.file)
775829
filp_close(cprm.file, NULL);
@@ -784,7 +838,7 @@ void do_coredump(const kernel_siginfo_t *siginfo)
784838
fail_creds:
785839
put_cred(cred);
786840
fail:
787-
return;
841+
return retval;
788842
}
789843

790844
/*
@@ -804,8 +858,16 @@ static int __dump_emit(struct coredump_params *cprm, const void *addr, int nr)
804858
if (dump_interrupted())
805859
return 0;
806860
n = __kernel_write(file, addr, nr, &pos);
807-
if (n != nr)
861+
if (n != nr) {
862+
if (n < 0)
863+
coredump_report_failure("failed when writing out, error %zd", n);
864+
else
865+
coredump_report_failure(
866+
"partially written out, only %zd(of %d) bytes written",
867+
n, nr);
868+
808869
return 0;
870+
}
809871
file->f_pos = pos;
810872
cprm->written += n;
811873
cprm->pos += n;
@@ -818,9 +880,16 @@ static int __dump_skip(struct coredump_params *cprm, size_t nr)
818880
static char zeroes[PAGE_SIZE];
819881
struct file *file = cprm->file;
820882
if (file->f_mode & FMODE_LSEEK) {
821-
if (dump_interrupted() ||
822-
vfs_llseek(file, nr, SEEK_CUR) < 0)
883+
int ret;
884+
885+
if (dump_interrupted())
823886
return 0;
887+
888+
ret = vfs_llseek(file, nr, SEEK_CUR);
889+
if (ret < 0) {
890+
coredump_report_failure("failed when seeking, error %d", ret);
891+
return 0;
892+
}
824893
cprm->pos += nr;
825894
return 1;
826895
} else {

include/linux/coredump.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ extern int dump_emit(struct coredump_params *cprm, const void *addr, int nr);
4242
extern int dump_align(struct coredump_params *cprm, int align);
4343
int dump_user_range(struct coredump_params *cprm, unsigned long start,
4444
unsigned long len);
45-
extern void do_coredump(const kernel_siginfo_t *siginfo);
45+
extern int do_coredump(const kernel_siginfo_t *siginfo);
4646

4747
/*
4848
* Logging for the coredump code, ratelimited.
@@ -62,7 +62,11 @@ extern void do_coredump(const kernel_siginfo_t *siginfo);
6262
#define coredump_report_failure(fmt, ...) __COREDUMP_PRINTK(KERN_WARNING, fmt, ##__VA_ARGS__)
6363

6464
#else
65-
static inline void do_coredump(const kernel_siginfo_t *siginfo) {}
65+
static inline int do_coredump(const kernel_siginfo_t *siginfo)
66+
{
67+
/* Coredump support is not available, can't fail. */
68+
return 0;
69+
}
6670

6771
#define coredump_report(...)
6872
#define coredump_report_failure(...)

0 commit comments

Comments
 (0)