Merge branch 'work.fdpic' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 7 Aug 2020 20:29:39 +0000 (13:29 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 7 Aug 2020 20:29:39 +0000 (13:29 -0700)
Pull fdpick coredump update from Al Viro:
 "Switches fdpic coredumps away from original aout dumping primitives to
  the same kind of regset use as regular elf coredumps do"

* 'work.fdpic' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
  [elf-fdpic] switch coredump to regsets
  [elf-fdpic] use elf_dump_thread_status() for the dumper thread as well
  [elf-fdpic] move allocation of elf_thread_status into elf_dump_thread_status()
  [elf-fdpic] coredump: don't bother with cyclic list for per-thread objects
  kill elf_fpxregs_t
  take fdpic-related parts of elf_prstatus out
  unexport linux/elfcore.h

1  2 
fs/binfmt_elf_fdpic.c
scripts/headers_install.sh

diff --combined fs/binfmt_elf_fdpic.c
  #include <linux/elfcore.h>
  #include <linux/coredump.h>
  #include <linux/dax.h>
+ #include <linux/regset.h>
  
  #include <linux/uaccess.h>
  #include <asm/param.h>
 -#include <asm/pgalloc.h>
  
  typedef char *elf_caddr_t;
  
@@@ -1188,6 -1190,32 +1189,32 @@@ static int elf_fdpic_map_file_by_direct
   */
  #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).
@@@ -1344,7 -1372,7 +1371,7 @@@ static inline void fill_note(struct mem
   * 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;
@@@ -1426,14 -1454,10 +1453,10 @@@ static int fill_psinfo(struct elf_prpsi
  /* Here is the structure in which status of each thread is captured. */
  struct elf_thread_status
  {
-       struct list_head list;
-       struct elf_prstatus prstatus;   /* NT_PRSTATUS */
+       struct elf_thread_status *next;
+       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];
+       struct memelfnote notes[2];
        int num_notes;
  };
  
   * 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;
+       const struct user_regset_view *view = task_user_regset_view(p);
+       struct elf_thread_status *t;
+       int i, ret;
  
-       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);
+       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]);
+       *sz += notesize(&t->notes[0]);
+       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;
+       }
  
-       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]);
        }
- #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;
+       return t;
  }
  
  static void fill_extnum_info(struct elfhdr *elf, struct elf_shdr *shdr4extnum,
@@@ -1552,23 -1582,15 +1581,15 @@@ static size_t elf_core_vma_data_size(un
   */
  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 *prstatus = NULL;   /* NT_PRSTATUS */
+       struct memelfnote psinfo_note, auxv_note;
        struct elf_prpsinfo *psinfo = NULL;     /* NT_PRPSINFO */
-       LIST_HEAD(thread_list);
-       struct list_head *t;
-       elf_fpregset_t *fpu = NULL;
- #ifdef ELF_CORE_COPY_XFPREGS
-       elf_fpxregset_t *xfpu = NULL;
- #endif
+       struct elf_thread_status *thread_list = NULL;
        int thread_status_size = 0;
        elf_addr_t *auxv;
        struct elf_phdr *phdr4note = NULL;
        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;
- #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) {
-               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;
-               list_add(&tmp->list, &thread_list);
-       }
-       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);
-               thread_status_size += sz;
+               tmp->next = thread_list;
+               thread_list = tmp;
        }
  
        /* 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();
         * 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(&notes[numnote++], "CORE", NT_AUXV,
-                 i * sizeof(elf_addr_t), auxv);
-       /* 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);
- #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
+       fill_note(&auxv_note, "CORE", NT_AUXV, i * sizeof(elf_addr_t), auxv);
+       thread_status_size += notesize(&auxv_note);
  
-       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);
                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 */
-       list_for_each(t, &thread_list) {
-               struct elf_thread_status *tmp =
-                               list_entry(t, struct elf_thread_status, list);
+       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;
        }
  
  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);
-       kfree(prstatus);
        kfree(psinfo);
-       kfree(notes);
-       kfree(fpu);
        kfree(shdr4extnum);
- #ifdef ELF_CORE_COPY_XFPREGS
-       kfree(xfpu);
- #endif
        return has_dumped;
- #undef NUM_NOTES
  }
  
  #endif                /* CONFIG_ELF_CORE */
@@@ -11,7 -11,7 +11,7 @@@ the
        echo "asm/inline/volatile keywords."
        echo
        echo "INFILE: header file to operate on"
 -      echo "OUTFILE: output file which the processed header is writen to"
 +      echo "OUTFILE: output file which the processed header is written to"
  
        exit 1
  fi
@@@ -86,10 -86,10 +86,9 @@@ arch/x86/include/uapi/asm/auxvec.h:CONF
  arch/x86/include/uapi/asm/mman.h:CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS
  include/uapi/asm-generic/fcntl.h:CONFIG_64BIT
  include/uapi/linux/atmdev.h:CONFIG_COMPAT
- include/uapi/linux/elfcore.h:CONFIG_BINFMT_ELF_FDPIC
  include/uapi/linux/eventpoll.h:CONFIG_PM_SLEEP
  include/uapi/linux/hw_breakpoint.h:CONFIG_HAVE_MIXED_BREAKPOINTS_REGS
  include/uapi/linux/pktcdvd.h:CONFIG_CDROM_PKTCDVD_WCACHE
 -include/uapi/linux/raw.h:CONFIG_MAX_RAW_DEVS
  "
  
  for c in $configs