Skip to content

Commit 936c8be

Browse files
ebiedermgregkh
authored andcommitted
coredump: Snapshot the vmas in do_coredump
commit 95c5436 upstream. Move the call of dump_vma_snapshot and kvfree(vma_meta) out of the individual coredump routines into do_coredump itself. This makes the code less error prone and easier to maintain. Make the vma snapshot available to the coredump routines in struct coredump_params. This makes it easier to change and update what is captures in the vma snapshot and will be needed for fixing fill_file_notes. Reviewed-by: Jann Horn <jannh@google.com> Reviewed-by: Kees Cook <keescook@chromium.org> Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 5318cdf commit 936c8be

5 files changed

Lines changed: 39 additions & 46 deletions

File tree

fs/binfmt_elf.c

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2166,25 +2166,20 @@ static void fill_extnum_info(struct elfhdr *elf, struct elf_shdr *shdr4extnum,
21662166
static int elf_core_dump(struct coredump_params *cprm)
21672167
{
21682168
int has_dumped = 0;
2169-
int vma_count, segs, i;
2170-
size_t vma_data_size;
2169+
int segs, i;
21712170
struct elfhdr elf;
21722171
loff_t offset = 0, dataoff;
21732172
struct elf_note_info info = { };
21742173
struct elf_phdr *phdr4note = NULL;
21752174
struct elf_shdr *shdr4extnum = NULL;
21762175
Elf_Half e_phnum;
21772176
elf_addr_t e_shoff;
2178-
struct core_vma_metadata *vma_meta;
2179-
2180-
if (dump_vma_snapshot(cprm, &vma_count, &vma_meta, &vma_data_size))
2181-
return 0;
21822177

21832178
/*
21842179
* The number of segs are recored into ELF header as 16bit value.
21852180
* Please check DEFAULT_MAX_MAP_COUNT definition when you modify here.
21862181
*/
2187-
segs = vma_count + elf_core_extra_phdrs();
2182+
segs = cprm->vma_count + elf_core_extra_phdrs();
21882183

21892184
/* for notes section */
21902185
segs++;
@@ -2222,7 +2217,7 @@ static int elf_core_dump(struct coredump_params *cprm)
22222217

22232218
dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE);
22242219

2225-
offset += vma_data_size;
2220+
offset += cprm->vma_data_size;
22262221
offset += elf_core_extra_data_size();
22272222
e_shoff = offset;
22282223

@@ -2242,8 +2237,8 @@ static int elf_core_dump(struct coredump_params *cprm)
22422237
goto end_coredump;
22432238

22442239
/* Write program headers for segments dump */
2245-
for (i = 0; i < vma_count; i++) {
2246-
struct core_vma_metadata *meta = vma_meta + i;
2240+
for (i = 0; i < cprm->vma_count; i++) {
2241+
struct core_vma_metadata *meta = cprm->vma_meta + i;
22472242
struct elf_phdr phdr;
22482243

22492244
phdr.p_type = PT_LOAD;
@@ -2280,8 +2275,8 @@ static int elf_core_dump(struct coredump_params *cprm)
22802275
if (!dump_skip(cprm, dataoff - cprm->pos))
22812276
goto end_coredump;
22822277

2283-
for (i = 0; i < vma_count; i++) {
2284-
struct core_vma_metadata *meta = vma_meta + i;
2278+
for (i = 0; i < cprm->vma_count; i++) {
2279+
struct core_vma_metadata *meta = cprm->vma_meta + i;
22852280

22862281
if (!dump_user_range(cprm, meta->start, meta->dump_size))
22872282
goto end_coredump;
@@ -2299,7 +2294,6 @@ static int elf_core_dump(struct coredump_params *cprm)
22992294
end_coredump:
23002295
free_note_info(&info);
23012296
kfree(shdr4extnum);
2302-
kvfree(vma_meta);
23032297
kfree(phdr4note);
23042298
return has_dumped;
23052299
}

fs/binfmt_elf_fdpic.c

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1479,7 +1479,7 @@ static bool elf_fdpic_dump_segments(struct coredump_params *cprm,
14791479
static int elf_fdpic_core_dump(struct coredump_params *cprm)
14801480
{
14811481
int has_dumped = 0;
1482-
int vma_count, segs;
1482+
int segs;
14831483
int i;
14841484
struct elfhdr *elf = NULL;
14851485
loff_t offset = 0, dataoff;
@@ -1494,8 +1494,6 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
14941494
elf_addr_t e_shoff;
14951495
struct core_thread *ct;
14961496
struct elf_thread_status *tmp;
1497-
struct core_vma_metadata *vma_meta = NULL;
1498-
size_t vma_data_size;
14991497

15001498
/* alloc memory for large data structures: too large to be on stack */
15011499
elf = kmalloc(sizeof(*elf), GFP_KERNEL);
@@ -1505,9 +1503,6 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
15051503
if (!psinfo)
15061504
goto end_coredump;
15071505

1508-
if (dump_vma_snapshot(cprm, &vma_count, &vma_meta, &vma_data_size))
1509-
goto end_coredump;
1510-
15111506
for (ct = current->mm->core_state->dumper.next;
15121507
ct; ct = ct->next) {
15131508
tmp = elf_dump_thread_status(cprm->siginfo->si_signo,
@@ -1527,7 +1522,7 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
15271522
tmp->next = thread_list;
15281523
thread_list = tmp;
15291524

1530-
segs = vma_count + elf_core_extra_phdrs();
1525+
segs = cprm->vma_count + elf_core_extra_phdrs();
15311526

15321527
/* for notes section */
15331528
segs++;
@@ -1572,7 +1567,7 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
15721567
/* Page-align dumped data */
15731568
dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE);
15741569

1575-
offset += vma_data_size;
1570+
offset += cprm->vma_data_size;
15761571
offset += elf_core_extra_data_size();
15771572
e_shoff = offset;
15781573

@@ -1592,8 +1587,8 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
15921587
goto end_coredump;
15931588

15941589
/* write program headers for segments dump */
1595-
for (i = 0; i < vma_count; i++) {
1596-
struct core_vma_metadata *meta = vma_meta + i;
1590+
for (i = 0; i < cprm->vma_count; i++) {
1591+
struct core_vma_metadata *meta = cprm->vma_meta + i;
15971592
struct elf_phdr phdr;
15981593
size_t sz;
15991594

@@ -1643,7 +1638,7 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
16431638
if (!dump_skip(cprm, dataoff - cprm->pos))
16441639
goto end_coredump;
16451640

1646-
if (!elf_fdpic_dump_segments(cprm, vma_meta, vma_count))
1641+
if (!elf_fdpic_dump_segments(cprm, cprm->vma_meta, cprm->vma_count))
16471642
goto end_coredump;
16481643

16491644
if (!elf_core_write_extra_data(cprm))
@@ -1667,7 +1662,6 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
16671662
thread_list = thread_list->next;
16681663
kfree(tmp);
16691664
}
1670-
kvfree(vma_meta);
16711665
kfree(phdr4note);
16721666
kfree(elf);
16731667
kfree(psinfo);

fs/coredump.c

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@
5353

5454
#include <trace/events/sched.h>
5555

56+
static bool dump_vma_snapshot(struct coredump_params *cprm);
57+
5658
int core_uses_pid;
5759
unsigned int core_pipe_limit;
5860
char core_pattern[CORENAME_MAX_SIZE] = "core";
@@ -602,6 +604,7 @@ void do_coredump(const kernel_siginfo_t *siginfo)
602604
* by any locks.
603605
*/
604606
.mm_flags = mm->flags,
607+
.vma_meta = NULL,
605608
};
606609

607610
audit_core_dumps(siginfo->si_signo);
@@ -807,9 +810,13 @@ void do_coredump(const kernel_siginfo_t *siginfo)
807810
pr_info("Core dump to |%s disabled\n", cn.corename);
808811
goto close_fail;
809812
}
813+
if (!dump_vma_snapshot(&cprm))
814+
goto close_fail;
815+
810816
file_start_write(cprm.file);
811817
core_dumped = binfmt->core_dump(&cprm);
812818
file_end_write(cprm.file);
819+
kvfree(cprm.vma_meta);
813820
}
814821
if (ispipe && core_pipe_limit)
815822
wait_for_dump_helpers(cprm.file);
@@ -1085,35 +1092,33 @@ static struct vm_area_struct *next_vma(struct vm_area_struct *this_vma,
10851092
* Under the mmap_lock, take a snapshot of relevant information about the task's
10861093
* VMAs.
10871094
*/
1088-
int dump_vma_snapshot(struct coredump_params *cprm, int *vma_count,
1089-
struct core_vma_metadata **vma_meta,
1090-
size_t *vma_data_size_ptr)
1095+
static bool dump_vma_snapshot(struct coredump_params *cprm)
10911096
{
10921097
struct vm_area_struct *vma, *gate_vma;
10931098
struct mm_struct *mm = current->mm;
10941099
int i;
1095-
size_t vma_data_size = 0;
10961100

10971101
/*
10981102
* Once the stack expansion code is fixed to not change VMA bounds
10991103
* under mmap_lock in read mode, this can be changed to take the
11001104
* mmap_lock in read mode.
11011105
*/
11021106
if (mmap_write_lock_killable(mm))
1103-
return -EINTR;
1107+
return false;
11041108

1109+
cprm->vma_data_size = 0;
11051110
gate_vma = get_gate_vma(mm);
1106-
*vma_count = mm->map_count + (gate_vma ? 1 : 0);
1111+
cprm->vma_count = mm->map_count + (gate_vma ? 1 : 0);
11071112

1108-
*vma_meta = kvmalloc_array(*vma_count, sizeof(**vma_meta), GFP_KERNEL);
1109-
if (!*vma_meta) {
1113+
cprm->vma_meta = kvmalloc_array(cprm->vma_count, sizeof(*cprm->vma_meta), GFP_KERNEL);
1114+
if (!cprm->vma_meta) {
11101115
mmap_write_unlock(mm);
1111-
return -ENOMEM;
1116+
return false;
11121117
}
11131118

11141119
for (i = 0, vma = first_vma(current, gate_vma); vma != NULL;
11151120
vma = next_vma(vma, gate_vma), i++) {
1116-
struct core_vma_metadata *m = (*vma_meta) + i;
1121+
struct core_vma_metadata *m = cprm->vma_meta + i;
11171122

11181123
m->start = vma->vm_start;
11191124
m->end = vma->vm_end;
@@ -1123,13 +1128,14 @@ int dump_vma_snapshot(struct coredump_params *cprm, int *vma_count,
11231128

11241129
mmap_write_unlock(mm);
11251130

1126-
if (WARN_ON(i != *vma_count)) {
1127-
kvfree(*vma_meta);
1128-
return -EFAULT;
1131+
if (WARN_ON(i != cprm->vma_count)) {
1132+
kvfree(cprm->vma_meta);
1133+
return false;
11291134
}
11301135

1131-
for (i = 0; i < *vma_count; i++) {
1132-
struct core_vma_metadata *m = (*vma_meta) + i;
1136+
1137+
for (i = 0; i < cprm->vma_count; i++) {
1138+
struct core_vma_metadata *m = cprm->vma_meta + i;
11331139

11341140
if (m->dump_size == DUMP_SIZE_MAYBE_ELFHDR_PLACEHOLDER) {
11351141
char elfmag[SELFMAG];
@@ -1142,9 +1148,8 @@ int dump_vma_snapshot(struct coredump_params *cprm, int *vma_count,
11421148
}
11431149
}
11441150

1145-
vma_data_size += m->dump_size;
1151+
cprm->vma_data_size += m->dump_size;
11461152
}
11471153

1148-
*vma_data_size_ptr = vma_data_size;
1149-
return 0;
1154+
return true;
11501155
}

include/linux/binfmts.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,9 @@ struct coredump_params {
8282
unsigned long mm_flags;
8383
loff_t written;
8484
loff_t pos;
85+
int vma_count;
86+
size_t vma_data_size;
87+
struct core_vma_metadata *vma_meta;
8588
};
8689

8790
/*

include/linux/coredump.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,6 @@ extern int dump_align(struct coredump_params *cprm, int align);
2424
extern void dump_truncate(struct coredump_params *cprm);
2525
int dump_user_range(struct coredump_params *cprm, unsigned long start,
2626
unsigned long len);
27-
int dump_vma_snapshot(struct coredump_params *cprm, int *vma_count,
28-
struct core_vma_metadata **vma_meta,
29-
size_t *vma_data_size_ptr);
3027
#ifdef CONFIG_COREDUMP
3128
extern void do_coredump(const kernel_siginfo_t *siginfo);
3229
#else

0 commit comments

Comments
 (0)