]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blobdiff - fs/binfmt_elf.c
btrfs: zoned: fix missing endianness conversion in sb_write_pointer
[mirror_ubuntu-jammy-kernel.git] / fs / binfmt_elf.c
index a813b70f594e69ee043781a61de130a636ef9c6a..30379c33ad20c7371efba60bd32274cacc1a1405 100644 (file)
@@ -170,8 +170,8 @@ static int padzero(unsigned long elf_bss)
 
 static int
 create_elf_tables(struct linux_binprm *bprm, const struct elfhdr *exec,
-               unsigned long load_addr, unsigned long interp_load_addr,
-               unsigned long e_entry)
+               unsigned long interp_load_addr,
+               unsigned long e_entry, unsigned long phdr_addr)
 {
        struct mm_struct *mm = current->mm;
        unsigned long p = bprm->p;
@@ -257,7 +257,7 @@ create_elf_tables(struct linux_binprm *bprm, const struct elfhdr *exec,
        NEW_AUX_ENT(AT_HWCAP, ELF_HWCAP);
        NEW_AUX_ENT(AT_PAGESZ, ELF_EXEC_PAGESIZE);
        NEW_AUX_ENT(AT_CLKTCK, CLOCKS_PER_SEC);
-       NEW_AUX_ENT(AT_PHDR, load_addr + exec->e_phoff);
+       NEW_AUX_ENT(AT_PHDR, phdr_addr);
        NEW_AUX_ENT(AT_PHENT, sizeof(struct elf_phdr));
        NEW_AUX_ENT(AT_PHNUM, exec->e_phnum);
        NEW_AUX_ENT(AT_BASE, interp_load_addr);
@@ -823,7 +823,7 @@ static int parse_elf_properties(struct file *f, const struct elf_phdr *phdr,
 static int load_elf_binary(struct linux_binprm *bprm)
 {
        struct file *interpreter = NULL; /* to shut gcc up */
-       unsigned long load_addr = 0, load_bias = 0;
+       unsigned long load_addr, load_bias = 0, phdr_addr = 0;
        int load_addr_set = 0;
        unsigned long error;
        struct elf_phdr *elf_ppnt, *elf_phdata, *interp_elf_phdata = NULL;
@@ -910,7 +910,7 @@ static int load_elf_binary(struct linux_binprm *bprm)
                interp_elf_ex = kmalloc(sizeof(*interp_elf_ex), GFP_KERNEL);
                if (!interp_elf_ex) {
                        retval = -ENOMEM;
-                       goto out_free_ph;
+                       goto out_free_file;
                }
 
                /* Get the exec headers */
@@ -1156,6 +1156,17 @@ out_free_interp:
                                reloc_func_desc = load_bias;
                        }
                }
+
+               /*
+                * Figure out which segment in the file contains the Program
+                * Header table, and map to the associated memory address.
+                */
+               if (elf_ppnt->p_offset <= elf_ex->e_phoff &&
+                   elf_ex->e_phoff < elf_ppnt->p_offset + elf_ppnt->p_filesz) {
+                       phdr_addr = elf_ex->e_phoff - elf_ppnt->p_offset +
+                                   elf_ppnt->p_vaddr;
+               }
+
                k = elf_ppnt->p_vaddr;
                if ((elf_ppnt->p_flags & PF_X) && k < start_code)
                        start_code = k;
@@ -1191,6 +1202,7 @@ out_free_interp:
        }
 
        e_entry = elf_ex->e_entry + load_bias;
+       phdr_addr += load_bias;
        elf_bss += load_bias;
        elf_brk += load_bias;
        start_code += load_bias;
@@ -1254,8 +1266,8 @@ out_free_interp:
                goto out;
 #endif /* ARCH_HAS_SETUP_ADDITIONAL_PAGES */
 
-       retval = create_elf_tables(bprm, elf_ex,
-                         load_addr, interp_load_addr, e_entry);
+       retval = create_elf_tables(bprm, elf_ex, interp_load_addr,
+                                  e_entry, phdr_addr);
        if (retval < 0)
                goto out;
 
@@ -1319,6 +1331,7 @@ out:
 out_free_dentry:
        kfree(interp_elf_ex);
        kfree(interp_elf_phdata);
+out_free_file:
        allow_write_access(interpreter);
        if (interpreter)
                fput(interpreter);
@@ -1606,17 +1619,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;
@@ -1638,11 +1650,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);
@@ -1662,9 +1675,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++;
        }
 
@@ -1675,7 +1688,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,
@@ -1787,7 +1800,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);
@@ -1859,7 +1872,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;
 
        /*
@@ -1868,13 +1881,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;
@@ -2016,7 +2029,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;
@@ -2037,13 +2050,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);
@@ -2059,18 +2072,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);
@@ -2156,8 +2169,7 @@ 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 = { };
@@ -2165,16 +2177,12 @@ static int elf_core_dump(struct coredump_params *cprm)
        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++;
@@ -2188,7 +2196,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;
@@ -2213,7 +2221,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;
 
@@ -2233,8 +2241,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;
@@ -2271,8 +2279,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;
@@ -2289,7 +2297,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;
 }