Skip to content

Commit

Permalink
Merge branch 'coredump-vma-snapshot-fix-for-v5.18' of https://git.ker…
Browse files Browse the repository at this point in the history
…nel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace into for-next/execve

- Fix missing mmap_lock in file_files_note (Eric W. Biederman)
  • Loading branch information
Kees Cook committed Mar 9, 2022
2 parents 9e1a3ce + f833116 commit 2722ae9
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 84 deletions.
66 changes: 30 additions & 36 deletions fs/binfmt_elf.c
Original file line number Diff line number Diff line change
Expand Up @@ -1641,17 +1641,16 @@ static void fill_siginfo_note(struct memelfnote *note, user_siginfo_t *csigdata,
* long file_ofs
* followed by COUNT filenames in ASCII: "FILE1" NUL "FILE2" NUL...
*/
static int fill_files_note(struct memelfnote *note)
static int fill_files_note(struct memelfnote *note, struct coredump_params *cprm)
{
struct mm_struct *mm = current->mm;
struct vm_area_struct *vma;
unsigned count, size, names_ofs, remaining, n;
user_long_t *data;
user_long_t *start_end_ofs;
char *name_base, *name_curpos;
int i;

/* *Estimated* file count and total data size needed */
count = mm->map_count;
count = cprm->vma_count;
if (count > UINT_MAX / 64)
return -EINVAL;
size = count * 64;
Expand All @@ -1673,11 +1672,12 @@ static int fill_files_note(struct memelfnote *note)
name_base = name_curpos = ((char *)data) + names_ofs;
remaining = size - names_ofs;
count = 0;
for (vma = mm->mmap; vma != NULL; vma = vma->vm_next) {
for (i = 0; i < cprm->vma_count; i++) {
struct core_vma_metadata *m = &cprm->vma_meta[i];
struct file *file;
const char *filename;

file = vma->vm_file;
file = m->file;
if (!file)
continue;
filename = file_path(file, name_curpos, remaining);
Expand All @@ -1697,9 +1697,9 @@ static int fill_files_note(struct memelfnote *note)
memmove(name_curpos, filename, n);
name_curpos += n;

*start_end_ofs++ = vma->vm_start;
*start_end_ofs++ = vma->vm_end;
*start_end_ofs++ = vma->vm_pgoff;
*start_end_ofs++ = m->start;
*start_end_ofs++ = m->end;
*start_end_ofs++ = m->pgoff;
count++;
}

Expand All @@ -1710,7 +1710,7 @@ static int fill_files_note(struct memelfnote *note)
* Count usually is less than mm->map_count,
* we need to move filenames down.
*/
n = mm->map_count - count;
n = cprm->vma_count - count;
if (n != 0) {
unsigned shift_bytes = n * 3 * sizeof(data[0]);
memmove(name_base - shift_bytes, name_base,
Expand Down Expand Up @@ -1822,7 +1822,7 @@ static int fill_thread_core_info(struct elf_thread_core_info *t,

static int fill_note_info(struct elfhdr *elf, int phdrs,
struct elf_note_info *info,
const kernel_siginfo_t *siginfo, struct pt_regs *regs)
struct coredump_params *cprm)
{
struct task_struct *dump_task = current;
const struct user_regset_view *view = task_user_regset_view(dump_task);
Expand Down Expand Up @@ -1894,7 +1894,7 @@ static int fill_note_info(struct elfhdr *elf, int phdrs,
* Now fill in each thread's information.
*/
for (t = info->thread; t != NULL; t = t->next)
if (!fill_thread_core_info(t, view, siginfo->si_signo, &info->size))
if (!fill_thread_core_info(t, view, cprm->siginfo->si_signo, &info->size))
return 0;

/*
Expand All @@ -1903,13 +1903,13 @@ static int fill_note_info(struct elfhdr *elf, int phdrs,
fill_psinfo(psinfo, dump_task->group_leader, dump_task->mm);
info->size += notesize(&info->psinfo);

fill_siginfo_note(&info->signote, &info->csigdata, siginfo);
fill_siginfo_note(&info->signote, &info->csigdata, cprm->siginfo);
info->size += notesize(&info->signote);

fill_auxv_note(&info->auxv, current->mm);
info->size += notesize(&info->auxv);

if (fill_files_note(&info->files) == 0)
if (fill_files_note(&info->files, cprm) == 0)
info->size += notesize(&info->files);

return 1;
Expand Down Expand Up @@ -2051,7 +2051,7 @@ static int elf_note_info_init(struct elf_note_info *info)

static int fill_note_info(struct elfhdr *elf, int phdrs,
struct elf_note_info *info,
const kernel_siginfo_t *siginfo, struct pt_regs *regs)
struct coredump_params *cprm)
{
struct core_thread *ct;
struct elf_thread_status *ets;
Expand All @@ -2072,13 +2072,13 @@ static int fill_note_info(struct elfhdr *elf, int phdrs,
list_for_each_entry(ets, &info->thread_list, list) {
int sz;

sz = elf_dump_thread_status(siginfo->si_signo, ets);
sz = elf_dump_thread_status(cprm->siginfo->si_signo, ets);
info->thread_status_size += sz;
}
/* now collect the dump for the current */
memset(info->prstatus, 0, sizeof(*info->prstatus));
fill_prstatus(&info->prstatus->common, current, siginfo->si_signo);
elf_core_copy_regs(&info->prstatus->pr_reg, regs);
fill_prstatus(&info->prstatus->common, current, cprm->siginfo->si_signo);
elf_core_copy_regs(&info->prstatus->pr_reg, cprm->regs);

/* Set up header */
fill_elf_header(elf, phdrs, ELF_ARCH, ELF_CORE_EFLAGS);
Expand All @@ -2094,18 +2094,18 @@ static int fill_note_info(struct elfhdr *elf, int phdrs,
fill_note(info->notes + 1, "CORE", NT_PRPSINFO,
sizeof(*info->psinfo), info->psinfo);

fill_siginfo_note(info->notes + 2, &info->csigdata, siginfo);
fill_siginfo_note(info->notes + 2, &info->csigdata, cprm->siginfo);
fill_auxv_note(info->notes + 3, current->mm);
info->numnote = 4;

if (fill_files_note(info->notes + info->numnote) == 0) {
if (fill_files_note(info->notes + info->numnote, cprm) == 0) {
info->notes_files = info->notes + info->numnote;
info->numnote++;
}

/* Try to dump the FPU. */
info->prstatus->pr_fpvalid = elf_core_copy_task_fpregs(current, regs,
info->fpu);
info->prstatus->pr_fpvalid =
elf_core_copy_task_fpregs(current, cprm->regs, info->fpu);
if (info->prstatus->pr_fpvalid)
fill_note(info->notes + info->numnote++,
"CORE", NT_PRFPREG, sizeof(*info->fpu), info->fpu);
Expand Down Expand Up @@ -2191,25 +2191,20 @@ static void fill_extnum_info(struct elfhdr *elf, struct elf_shdr *shdr4extnum,
static int elf_core_dump(struct coredump_params *cprm)
{
int has_dumped = 0;
int vma_count, segs, i;
size_t vma_data_size;
int segs, i;
struct elfhdr elf;
loff_t offset = 0, dataoff;
struct elf_note_info info = { };
struct elf_phdr *phdr4note = NULL;
struct elf_shdr *shdr4extnum = NULL;
Elf_Half e_phnum;
elf_addr_t e_shoff;
struct core_vma_metadata *vma_meta;

if (dump_vma_snapshot(cprm, &vma_count, &vma_meta, &vma_data_size))
return 0;

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

/* for notes section */
segs++;
Expand All @@ -2223,7 +2218,7 @@ static int elf_core_dump(struct coredump_params *cprm)
* Collect all the non-memory information about the process for the
* notes. This also sets up the file header.
*/
if (!fill_note_info(&elf, e_phnum, &info, cprm->siginfo, cprm->regs))
if (!fill_note_info(&elf, e_phnum, &info, cprm))
goto end_coredump;

has_dumped = 1;
Expand All @@ -2248,7 +2243,7 @@ static int elf_core_dump(struct coredump_params *cprm)

dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE);

offset += vma_data_size;
offset += cprm->vma_data_size;
offset += elf_core_extra_data_size();
e_shoff = offset;

Expand All @@ -2268,8 +2263,8 @@ static int elf_core_dump(struct coredump_params *cprm)
goto end_coredump;

/* Write program headers for segments dump */
for (i = 0; i < vma_count; i++) {
struct core_vma_metadata *meta = vma_meta + i;
for (i = 0; i < cprm->vma_count; i++) {
struct core_vma_metadata *meta = cprm->vma_meta + i;
struct elf_phdr phdr;

phdr.p_type = PT_LOAD;
Expand Down Expand Up @@ -2306,8 +2301,8 @@ static int elf_core_dump(struct coredump_params *cprm)
/* Align to page */
dump_skip_to(cprm, dataoff);

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

if (!dump_user_range(cprm, meta->start, meta->dump_size))
goto end_coredump;
Expand All @@ -2324,7 +2319,6 @@ static int elf_core_dump(struct coredump_params *cprm)
end_coredump:
free_note_info(&info);
kfree(shdr4extnum);
kvfree(vma_meta);
kfree(phdr4note);
return has_dumped;
}
Expand Down
18 changes: 6 additions & 12 deletions fs/binfmt_elf_fdpic.c
Original file line number Diff line number Diff line change
Expand Up @@ -1465,7 +1465,7 @@ static bool elf_fdpic_dump_segments(struct coredump_params *cprm,
static int elf_fdpic_core_dump(struct coredump_params *cprm)
{
int has_dumped = 0;
int vma_count, segs;
int segs;
int i;
struct elfhdr *elf = NULL;
loff_t offset = 0, dataoff;
Expand All @@ -1480,8 +1480,6 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
elf_addr_t e_shoff;
struct core_thread *ct;
struct elf_thread_status *tmp;
struct core_vma_metadata *vma_meta = NULL;
size_t vma_data_size;

/* alloc memory for large data structures: too large to be on stack */
elf = kmalloc(sizeof(*elf), GFP_KERNEL);
Expand All @@ -1491,9 +1489,6 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
if (!psinfo)
goto end_coredump;

if (dump_vma_snapshot(cprm, &vma_count, &vma_meta, &vma_data_size))
goto end_coredump;

for (ct = current->signal->core_state->dumper.next;
ct; ct = ct->next) {
tmp = elf_dump_thread_status(cprm->siginfo->si_signo,
Expand All @@ -1513,7 +1508,7 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
tmp->next = thread_list;
thread_list = tmp;

segs = vma_count + elf_core_extra_phdrs();
segs = cprm->vma_count + elf_core_extra_phdrs();

/* for notes section */
segs++;
Expand Down Expand Up @@ -1558,7 +1553,7 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
/* Page-align dumped data */
dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE);

offset += vma_data_size;
offset += cprm->vma_data_size;
offset += elf_core_extra_data_size();
e_shoff = offset;

Expand All @@ -1578,8 +1573,8 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
goto end_coredump;

/* write program headers for segments dump */
for (i = 0; i < vma_count; i++) {
struct core_vma_metadata *meta = vma_meta + i;
for (i = 0; i < cprm->vma_count; i++) {
struct core_vma_metadata *meta = cprm->vma_meta + i;
struct elf_phdr phdr;
size_t sz;

Expand Down Expand Up @@ -1628,7 +1623,7 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)

dump_skip_to(cprm, dataoff);

if (!elf_fdpic_dump_segments(cprm, vma_meta, vma_count))
if (!elf_fdpic_dump_segments(cprm, cprm->vma_meta, cprm->vma_count))
goto end_coredump;

if (!elf_core_write_extra_data(cprm))
Expand All @@ -1652,7 +1647,6 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
thread_list = thread_list->next;
kfree(tmp);
}
kvfree(vma_meta);
kfree(phdr4note);
kfree(elf);
kfree(psinfo);
Expand Down
5 changes: 5 additions & 0 deletions fs/binfmt_flat.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include <linux/flat.h>
#include <linux/uaccess.h>
#include <linux/vmalloc.h>
#include <linux/coredump.h>

#include <asm/byteorder.h>
#include <asm/unaligned.h>
Expand Down Expand Up @@ -97,7 +98,9 @@ static int load_flat_shared_library(int id, struct lib_info *p);
#endif

static int load_flat_binary(struct linux_binprm *);
#ifdef CONFIG_COREDUMP
static int flat_core_dump(struct coredump_params *cprm);
#endif

static struct linux_binfmt flat_format = {
.module = THIS_MODULE,
Expand All @@ -114,12 +117,14 @@ static struct linux_binfmt flat_format = {
* Currently only a stub-function.
*/

#ifdef CONFIG_COREDUMP
static int flat_core_dump(struct coredump_params *cprm)
{
pr_warn("Process %s:%d received signr %d and should have core dumped\n",
current->comm, current->pid, cprm->siginfo->si_signo);
return 1;
}
#endif

/****************************************************************************/
/*
Expand Down
Loading

0 comments on commit 2722ae9

Please sign in to comment.