From 16aead81018ca404efe9bd928786824e7168151f Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 14 Jun 2020 09:52:06 -0400 Subject: take fdpic-related parts of elf_prstatus out The only architecture where we might end up using both is arm, and there we definitely don't want fdpic-related fields in elf_prstatus - coredump layout of ELF binaries should not depend upon having the kernel built with the support of ELF_FDPIC ones. Just move the fdpic-modified variant into binfmt_elf_fdpic.c (and call it elf_prstatus_fdpic there) [name stolen from nico] Signed-off-by: Al Viro --- fs/binfmt_elf_fdpic.c | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) (limited to 'fs/binfmt_elf_fdpic.c') diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c index 0f45521b237c..6e13d8bea32d 100644 --- a/fs/binfmt_elf_fdpic.c +++ b/fs/binfmt_elf_fdpic.c @@ -1189,6 +1189,32 @@ static int elf_fdpic_map_file_by_direct_mmap(struct elf_fdpic_params *params, */ #ifdef CONFIG_ELF_CORE +struct elf_prstatus_fdpic +{ + struct elf_siginfo pr_info; /* Info associated with signal */ + short pr_cursig; /* Current signal */ + unsigned long pr_sigpend; /* Set of pending signals */ + unsigned long pr_sighold; /* Set of held signals */ + pid_t pr_pid; + pid_t pr_ppid; + pid_t pr_pgrp; + pid_t pr_sid; + struct __kernel_old_timeval pr_utime; /* User time */ + struct __kernel_old_timeval pr_stime; /* System time */ + struct __kernel_old_timeval pr_cutime; /* Cumulative user time */ + struct __kernel_old_timeval pr_cstime; /* Cumulative system time */ + elf_gregset_t pr_reg; /* GP registers */ + /* When using FDPIC, the loadmap addresses need to be communicated + * to GDB in order for GDB to do the necessary relocations. The + * fields (below) used to communicate this information are placed + * immediately after ``pr_reg'', so that the loadmap addresses may + * be viewed as part of the register set if so desired. + */ + unsigned long pr_exec_fdpic_loadmap; + unsigned long pr_interp_fdpic_loadmap; + int pr_fpvalid; /* True if math co-processor being used. */ +}; + /* * Decide whether a segment is worth dumping; default is yes to be * sure (missing info is worse than too much; etc). @@ -1345,7 +1371,7 @@ static inline void fill_note(struct memelfnote *note, const char *name, int type * fill up all the fields in prstatus from the given task struct, except * registers which need to be filled up separately. */ -static void fill_prstatus(struct elf_prstatus *prstatus, +static void fill_prstatus(struct elf_prstatus_fdpic *prstatus, struct task_struct *p, long signr) { prstatus->pr_info.si_signo = prstatus->pr_cursig = signr; @@ -1428,7 +1454,7 @@ static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p, struct elf_thread_status { struct list_head list; - struct elf_prstatus prstatus; /* NT_PRSTATUS */ + struct elf_prstatus_fdpic prstatus; /* NT_PRSTATUS */ elf_fpregset_t fpu; /* NT_PRFPREG */ struct task_struct *thread; #ifdef ELF_CORE_COPY_XFPREGS @@ -1562,7 +1588,7 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm) loff_t offset = 0, dataoff; int numnote; struct memelfnote *notes = NULL; - struct elf_prstatus *prstatus = NULL; /* NT_PRSTATUS */ + struct elf_prstatus_fdpic *prstatus = NULL; /* NT_PRSTATUS */ struct elf_prpsinfo *psinfo = NULL; /* NT_PRPSINFO */ LIST_HEAD(thread_list); struct list_head *t; -- cgit From 7a896028adcfbff4552e6748e8fc8d06036c132c Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 13 Jun 2020 00:23:31 -0400 Subject: kill elf_fpxregs_t all uses are conditional upon ELF_CORE_COPY_XFPREGS, which has not been defined on any architecture since 2010 Signed-off-by: Al Viro --- fs/binfmt_elf_fdpic.c | 28 ---------------------------- 1 file changed, 28 deletions(-) (limited to 'fs/binfmt_elf_fdpic.c') diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c index 6e13d8bea32d..a6ee92137529 100644 --- a/fs/binfmt_elf_fdpic.c +++ b/fs/binfmt_elf_fdpic.c @@ -1457,9 +1457,6 @@ struct elf_thread_status struct elf_prstatus_fdpic prstatus; /* NT_PRSTATUS */ elf_fpregset_t fpu; /* NT_PRFPREG */ struct task_struct *thread; -#ifdef ELF_CORE_COPY_XFPREGS - elf_fpxregset_t xfpu; /* ELF_CORE_XFPREG_TYPE */ -#endif struct memelfnote notes[3]; int num_notes; }; @@ -1491,15 +1488,6 @@ static int elf_dump_thread_status(long signr, struct elf_thread_status *t) t->num_notes++; sz += notesize(&t->notes[1]); } - -#ifdef ELF_CORE_COPY_XFPREGS - if (elf_core_copy_task_xfpregs(p, &t->xfpu)) { - fill_note(&t->notes[2], "LINUX", ELF_CORE_XFPREG_TYPE, - sizeof(t->xfpu), &t->xfpu); - t->num_notes++; - sz += notesize(&t->notes[2]); - } -#endif return sz; } @@ -1593,9 +1581,6 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm) LIST_HEAD(thread_list); struct list_head *t; elf_fpregset_t *fpu = NULL; -#ifdef ELF_CORE_COPY_XFPREGS - elf_fpxregset_t *xfpu = NULL; -#endif int thread_status_size = 0; elf_addr_t *auxv; struct elf_phdr *phdr4note = NULL; @@ -1634,11 +1619,6 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm) fpu = kmalloc(sizeof(*fpu), GFP_KERNEL); if (!fpu) goto end_coredump; -#ifdef ELF_CORE_COPY_XFPREGS - xfpu = kmalloc(sizeof(*xfpu), GFP_KERNEL); - if (!xfpu) - goto end_coredump; -#endif for (ct = current->mm->core_state->dumper.next; ct; ct = ct->next) { @@ -1703,11 +1683,6 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm) elf_core_copy_task_fpregs(current, cprm->regs, fpu))) fill_note(notes + numnote++, "CORE", NT_PRFPREG, sizeof(*fpu), fpu); -#ifdef ELF_CORE_COPY_XFPREGS - if (elf_core_copy_task_xfpregs(current, xfpu)) - fill_note(notes + numnote++, - "LINUX", ELF_CORE_XFPREG_TYPE, sizeof(*xfpu), xfpu); -#endif offset += sizeof(*elf); /* Elf header */ offset += segs * sizeof(struct elf_phdr); /* Program headers */ @@ -1828,9 +1803,6 @@ end_coredump: kfree(notes); kfree(fpu); kfree(shdr4extnum); -#ifdef ELF_CORE_COPY_XFPREGS - kfree(xfpu); -#endif return has_dumped; #undef NUM_NOTES } -- cgit From 5074c7f69f9e86a8f83955bc9ca4f2634261917e Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 15 Jun 2020 10:19:31 -0400 Subject: [elf-fdpic] coredump: don't bother with cyclic list for per-thread objects plain single-linked list is just fine here... Signed-off-by: Al Viro --- fs/binfmt_elf_fdpic.c | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) (limited to 'fs/binfmt_elf_fdpic.c') diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c index a6ee92137529..bcbf756fba39 100644 --- a/fs/binfmt_elf_fdpic.c +++ b/fs/binfmt_elf_fdpic.c @@ -1453,7 +1453,7 @@ static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p, /* Here is the structure in which status of each thread is captured. */ struct elf_thread_status { - struct list_head list; + struct elf_thread_status *next; struct elf_prstatus_fdpic prstatus; /* NT_PRSTATUS */ elf_fpregset_t fpu; /* NT_PRFPREG */ struct task_struct *thread; @@ -1578,8 +1578,7 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm) struct memelfnote *notes = NULL; struct elf_prstatus_fdpic *prstatus = NULL; /* NT_PRSTATUS */ struct elf_prpsinfo *psinfo = NULL; /* NT_PRPSINFO */ - LIST_HEAD(thread_list); - struct list_head *t; + struct elf_thread_status *thread_list = NULL; elf_fpregset_t *fpu = NULL; int thread_status_size = 0; elf_addr_t *auxv; @@ -1627,15 +1626,12 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm) goto end_coredump; tmp->thread = ct->task; - list_add(&tmp->list, &thread_list); + tmp->next = thread_list; + thread_list = tmp; } - list_for_each(t, &thread_list) { - struct elf_thread_status *tmp; - int sz; - - tmp = list_entry(t, struct elf_thread_status, list); - sz = elf_dump_thread_status(cprm->siginfo->si_signo, tmp); + for (tmp = thread_list; tmp; tmp = tmp->next) { + int sz = elf_dump_thread_status(cprm->siginfo->si_signo, tmp); thread_status_size += sz; } @@ -1760,10 +1756,7 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm) goto end_coredump; /* write out the thread status notes section */ - list_for_each(t, &thread_list) { - struct elf_thread_status *tmp = - list_entry(t, struct elf_thread_status, list); - + for (tmp = thread_list; tmp; tmp = tmp->next) { for (i = 0; i < tmp->num_notes; i++) if (!writenote(&tmp->notes[i], cprm)) goto end_coredump; @@ -1791,10 +1784,10 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm) } end_coredump: - while (!list_empty(&thread_list)) { - struct list_head *tmp = thread_list.next; - list_del(tmp); - kfree(list_entry(tmp, struct elf_thread_status, list)); + while (thread_list) { + tmp = thread_list; + thread_list = thread_list->next; + kfree(tmp); } kfree(phdr4note); kfree(elf); -- cgit From 38a62779ae8e7a3b5fcf0ed3ee0bd6620809891c Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 15 Jun 2020 10:41:08 -0400 Subject: [elf-fdpic] move allocation of elf_thread_status into elf_dump_thread_status() Signed-off-by: Al Viro --- fs/binfmt_elf_fdpic.c | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) (limited to 'fs/binfmt_elf_fdpic.c') diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c index bcbf756fba39..ba4f264dff3a 100644 --- a/fs/binfmt_elf_fdpic.c +++ b/fs/binfmt_elf_fdpic.c @@ -1466,12 +1466,13 @@ struct elf_thread_status * we need to keep a linked list of every thread's pr_status and then create * a single section for them in the final core file. */ -static int elf_dump_thread_status(long signr, struct elf_thread_status *t) +static struct elf_thread_status *elf_dump_thread_status(long signr, struct task_struct *p, int *sz) { - struct task_struct *p = t->thread; - int sz = 0; + struct elf_thread_status *t; - t->num_notes = 0; + t = kzalloc(sizeof(struct elf_thread_status), GFP_KERNEL); + if (!t) + return t; fill_prstatus(&t->prstatus, p, signr); elf_core_copy_task_regs(p, &t->prstatus.pr_reg); @@ -1479,16 +1480,16 @@ static int elf_dump_thread_status(long signr, struct elf_thread_status *t) fill_note(&t->notes[0], "CORE", NT_PRSTATUS, sizeof(t->prstatus), &t->prstatus); t->num_notes++; - sz += notesize(&t->notes[0]); + *sz += notesize(&t->notes[0]); t->prstatus.pr_fpvalid = elf_core_copy_task_fpregs(p, NULL, &t->fpu); if (t->prstatus.pr_fpvalid) { fill_note(&t->notes[1], "CORE", NT_PRFPREG, sizeof(t->fpu), &t->fpu); t->num_notes++; - sz += notesize(&t->notes[1]); + *sz += notesize(&t->notes[1]); } - return sz; + return t; } static void fill_extnum_info(struct elfhdr *elf, struct elf_shdr *shdr4extnum, @@ -1621,20 +1622,15 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm) for (ct = current->mm->core_state->dumper.next; ct; ct = ct->next) { - tmp = kzalloc(sizeof(*tmp), GFP_KERNEL); + tmp = elf_dump_thread_status(cprm->siginfo->si_signo, + ct->task, &thread_status_size); if (!tmp) goto end_coredump; - tmp->thread = ct->task; tmp->next = thread_list; thread_list = tmp; } - for (tmp = thread_list; tmp; tmp = tmp->next) { - int sz = elf_dump_thread_status(cprm->siginfo->si_signo, tmp); - thread_status_size += sz; - } - /* now collect the dump for the current */ fill_prstatus(prstatus, current, cprm->siginfo->si_signo); elf_core_copy_regs(&prstatus->pr_reg, cprm->regs); -- cgit From d2f581684a292ece5c10cd56ad51bf4f702b7beb Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 15 Jun 2020 11:03:28 -0400 Subject: [elf-fdpic] use elf_dump_thread_status() for the dumper thread as well the only reason to have it open-coded for the first (dumper) thread is that coredump has a couple of process-wide notes stuck right after the first (NT_PRSTATUS) note of the first thread. But we don't need to make the data collection side irregular for the first thread to handle that - it's only the logics ordering the calls of writenote() that needs to take care of that. Signed-off-by: Al Viro --- fs/binfmt_elf_fdpic.c | 81 ++++++++++++++++++--------------------------------- 1 file changed, 28 insertions(+), 53 deletions(-) (limited to 'fs/binfmt_elf_fdpic.c') diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c index ba4f264dff3a..34c45410d587 100644 --- a/fs/binfmt_elf_fdpic.c +++ b/fs/binfmt_elf_fdpic.c @@ -1482,7 +1482,8 @@ static struct elf_thread_status *elf_dump_thread_status(long signr, struct task_ t->num_notes++; *sz += notesize(&t->notes[0]); - t->prstatus.pr_fpvalid = elf_core_copy_task_fpregs(p, NULL, &t->fpu); + t->prstatus.pr_fpvalid = elf_core_copy_task_fpregs(p, task_pt_regs(p), + &t->fpu); if (t->prstatus.pr_fpvalid) { fill_note(&t->notes[1], "CORE", NT_PRFPREG, sizeof(t->fpu), &t->fpu); @@ -1568,19 +1569,15 @@ static size_t elf_core_vma_data_size(unsigned long mm_flags) */ static int elf_fdpic_core_dump(struct coredump_params *cprm) { -#define NUM_NOTES 6 int has_dumped = 0; int segs; int i; struct vm_area_struct *vma; struct elfhdr *elf = NULL; loff_t offset = 0, dataoff; - int numnote; - struct memelfnote *notes = NULL; - struct elf_prstatus_fdpic *prstatus = NULL; /* NT_PRSTATUS */ + struct memelfnote psinfo_note, auxv_note; struct elf_prpsinfo *psinfo = NULL; /* NT_PRPSINFO */ struct elf_thread_status *thread_list = NULL; - elf_fpregset_t *fpu = NULL; int thread_status_size = 0; elf_addr_t *auxv; struct elf_phdr *phdr4note = NULL; @@ -1606,19 +1603,9 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm) elf = kmalloc(sizeof(*elf), GFP_KERNEL); if (!elf) goto end_coredump; - prstatus = kzalloc(sizeof(*prstatus), GFP_KERNEL); - if (!prstatus) - goto end_coredump; psinfo = kmalloc(sizeof(*psinfo), GFP_KERNEL); if (!psinfo) goto end_coredump; - notes = kmalloc_array(NUM_NOTES, sizeof(struct memelfnote), - GFP_KERNEL); - if (!notes) - goto end_coredump; - fpu = kmalloc(sizeof(*fpu), GFP_KERNEL); - if (!fpu) - goto end_coredump; for (ct = current->mm->core_state->dumper.next; ct; ct = ct->next) { @@ -1632,8 +1619,12 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm) } /* now collect the dump for the current */ - fill_prstatus(prstatus, current, cprm->siginfo->si_signo); - elf_core_copy_regs(&prstatus->pr_reg, cprm->regs); + tmp = elf_dump_thread_status(cprm->siginfo->si_signo, + current, &thread_status_size); + if (!tmp) + goto end_coredump; + tmp->next = thread_list; + thread_list = tmp; segs = current->mm->map_count; segs += elf_core_extra_phdrs(); @@ -1655,46 +1646,28 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm) * with info from their /proc. */ - fill_note(notes + 0, "CORE", NT_PRSTATUS, sizeof(*prstatus), prstatus); fill_psinfo(psinfo, current->group_leader, current->mm); - fill_note(notes + 1, "CORE", NT_PRPSINFO, sizeof(*psinfo), psinfo); - - numnote = 2; + fill_note(&psinfo_note, "CORE", NT_PRPSINFO, sizeof(*psinfo), psinfo); + thread_status_size += notesize(&psinfo_note); auxv = (elf_addr_t *) current->mm->saved_auxv; - i = 0; do i += 2; while (auxv[i - 2] != AT_NULL); - fill_note(¬es[numnote++], "CORE", NT_AUXV, - i * sizeof(elf_addr_t), auxv); + fill_note(&auxv_note, "CORE", NT_AUXV, i * sizeof(elf_addr_t), auxv); + thread_status_size += notesize(&auxv_note); - /* Try to dump the FPU. */ - if ((prstatus->pr_fpvalid = - elf_core_copy_task_fpregs(current, cprm->regs, fpu))) - fill_note(notes + numnote++, - "CORE", NT_PRFPREG, sizeof(*fpu), fpu); - - offset += sizeof(*elf); /* Elf header */ + offset = sizeof(*elf); /* Elf header */ offset += segs * sizeof(struct elf_phdr); /* Program headers */ /* Write notes phdr entry */ - { - int sz = 0; - - for (i = 0; i < numnote; i++) - sz += notesize(notes + i); - - sz += thread_status_size; - - phdr4note = kmalloc(sizeof(*phdr4note), GFP_KERNEL); - if (!phdr4note) - goto end_coredump; + phdr4note = kmalloc(sizeof(*phdr4note), GFP_KERNEL); + if (!phdr4note) + goto end_coredump; - fill_elf_note_phdr(phdr4note, sz, offset); - offset += sz; - } + fill_elf_note_phdr(phdr4note, thread_status_size, offset); + offset += thread_status_size; /* Page-align dumped data */ dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE); @@ -1747,12 +1720,18 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm) goto end_coredump; /* write out the notes section */ - for (i = 0; i < numnote; i++) - if (!writenote(notes + i, cprm)) + if (!writenote(thread_list->notes, cprm)) + goto end_coredump; + if (!writenote(&psinfo_note, cprm)) + goto end_coredump; + if (!writenote(&auxv_note, cprm)) + goto end_coredump; + for (i = 1; i < thread_list->num_notes; i++) + if (!writenote(thread_list->notes + i, cprm)) goto end_coredump; /* write out the thread status notes section */ - for (tmp = thread_list; tmp; tmp = tmp->next) { + for (tmp = thread_list->next; tmp; tmp = tmp->next) { for (i = 0; i < tmp->num_notes; i++) if (!writenote(&tmp->notes[i], cprm)) goto end_coredump; @@ -1787,13 +1766,9 @@ end_coredump: } kfree(phdr4note); kfree(elf); - kfree(prstatus); kfree(psinfo); - kfree(notes); - kfree(fpu); kfree(shdr4extnum); return has_dumped; -#undef NUM_NOTES } #endif /* CONFIG_ELF_CORE */ -- cgit From 1697a322e28ba96d35953c5d824540d172546d36 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 15 Jun 2020 11:22:55 -0400 Subject: [elf-fdpic] switch coredump to regsets similar to how elf coredump is working on architectures that have regsets, and all architectures with elf-fdpic support *do* have that. Signed-off-by: Al Viro --- fs/binfmt_elf_fdpic.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) (limited to 'fs/binfmt_elf_fdpic.c') diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c index 34c45410d587..1af03c8d3c09 100644 --- a/fs/binfmt_elf_fdpic.c +++ b/fs/binfmt_elf_fdpic.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -1456,8 +1457,7 @@ struct elf_thread_status struct elf_thread_status *next; struct elf_prstatus_fdpic prstatus; /* NT_PRSTATUS */ elf_fpregset_t fpu; /* NT_PRFPREG */ - struct task_struct *thread; - struct memelfnote notes[3]; + struct memelfnote notes[2]; int num_notes; }; @@ -1468,22 +1468,35 @@ struct elf_thread_status */ static struct elf_thread_status *elf_dump_thread_status(long signr, struct task_struct *p, int *sz) { + const struct user_regset_view *view = task_user_regset_view(p); struct elf_thread_status *t; + int i, ret; t = kzalloc(sizeof(struct elf_thread_status), GFP_KERNEL); if (!t) return t; fill_prstatus(&t->prstatus, p, signr); - elf_core_copy_task_regs(p, &t->prstatus.pr_reg); + regset_get(p, &view->regsets[0], + sizeof(t->prstatus.pr_reg), &t->prstatus.pr_reg); fill_note(&t->notes[0], "CORE", NT_PRSTATUS, sizeof(t->prstatus), &t->prstatus); t->num_notes++; *sz += notesize(&t->notes[0]); - t->prstatus.pr_fpvalid = elf_core_copy_task_fpregs(p, task_pt_regs(p), - &t->fpu); + for (i = 1; i < view->n; ++i) { + const struct user_regset *regset = &view->regsets[i]; + if (regset->core_note_type != NT_PRFPREG) + continue; + if (regset->active && regset->active(p, regset) <= 0) + continue; + ret = regset_get(p, regset, sizeof(t->fpu), &t->fpu); + if (ret >= 0) + t->prstatus.pr_fpvalid = 1; + break; + } + if (t->prstatus.pr_fpvalid) { fill_note(&t->notes[1], "CORE", NT_PRFPREG, sizeof(t->fpu), &t->fpu); -- cgit