18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * linux/fs/binfmt_elf.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * These are the functions used to load ELF format executables as used 68c2ecf20Sopenharmony_ci * on SVr4 machines. Information on the format may be found in the book 78c2ecf20Sopenharmony_ci * "UNIX SYSTEM V RELEASE 4 Programmers Guide: Ansi C and Programming Support 88c2ecf20Sopenharmony_ci * Tools". 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Copyright 1993, 1994: Eric Youngdale (ericy@cais.com). 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <linux/module.h> 148c2ecf20Sopenharmony_ci#include <linux/kernel.h> 158c2ecf20Sopenharmony_ci#include <linux/fs.h> 168c2ecf20Sopenharmony_ci#include <linux/log2.h> 178c2ecf20Sopenharmony_ci#include <linux/mm.h> 188c2ecf20Sopenharmony_ci#include <linux/mman.h> 198c2ecf20Sopenharmony_ci#include <linux/errno.h> 208c2ecf20Sopenharmony_ci#include <linux/signal.h> 218c2ecf20Sopenharmony_ci#include <linux/binfmts.h> 228c2ecf20Sopenharmony_ci#include <linux/string.h> 238c2ecf20Sopenharmony_ci#include <linux/file.h> 248c2ecf20Sopenharmony_ci#include <linux/slab.h> 258c2ecf20Sopenharmony_ci#include <linux/personality.h> 268c2ecf20Sopenharmony_ci#include <linux/elfcore.h> 278c2ecf20Sopenharmony_ci#include <linux/init.h> 288c2ecf20Sopenharmony_ci#include <linux/highuid.h> 298c2ecf20Sopenharmony_ci#include <linux/compiler.h> 308c2ecf20Sopenharmony_ci#include <linux/highmem.h> 318c2ecf20Sopenharmony_ci#include <linux/hugetlb.h> 328c2ecf20Sopenharmony_ci#include <linux/pagemap.h> 338c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 348c2ecf20Sopenharmony_ci#include <linux/security.h> 358c2ecf20Sopenharmony_ci#include <linux/random.h> 368c2ecf20Sopenharmony_ci#include <linux/elf.h> 378c2ecf20Sopenharmony_ci#include <linux/elf-randomize.h> 388c2ecf20Sopenharmony_ci#include <linux/utsname.h> 398c2ecf20Sopenharmony_ci#include <linux/coredump.h> 408c2ecf20Sopenharmony_ci#include <linux/sched.h> 418c2ecf20Sopenharmony_ci#include <linux/sched/coredump.h> 428c2ecf20Sopenharmony_ci#include <linux/sched/task_stack.h> 438c2ecf20Sopenharmony_ci#include <linux/sched/cputime.h> 448c2ecf20Sopenharmony_ci#include <linux/sizes.h> 458c2ecf20Sopenharmony_ci#include <linux/types.h> 468c2ecf20Sopenharmony_ci#include <linux/cred.h> 478c2ecf20Sopenharmony_ci#include <linux/dax.h> 488c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 498c2ecf20Sopenharmony_ci#include <asm/param.h> 508c2ecf20Sopenharmony_ci#include <asm/page.h> 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci#ifndef ELF_COMPAT 538c2ecf20Sopenharmony_ci#define ELF_COMPAT 0 548c2ecf20Sopenharmony_ci#endif 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci#ifndef user_long_t 578c2ecf20Sopenharmony_ci#define user_long_t long 588c2ecf20Sopenharmony_ci#endif 598c2ecf20Sopenharmony_ci#ifndef user_siginfo_t 608c2ecf20Sopenharmony_ci#define user_siginfo_t siginfo_t 618c2ecf20Sopenharmony_ci#endif 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci/* That's for binfmt_elf_fdpic to deal with */ 648c2ecf20Sopenharmony_ci#ifndef elf_check_fdpic 658c2ecf20Sopenharmony_ci#define elf_check_fdpic(ex) false 668c2ecf20Sopenharmony_ci#endif 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic int load_elf_binary(struct linux_binprm *bprm); 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci#ifdef CONFIG_USELIB 718c2ecf20Sopenharmony_cistatic int load_elf_library(struct file *); 728c2ecf20Sopenharmony_ci#else 738c2ecf20Sopenharmony_ci#define load_elf_library NULL 748c2ecf20Sopenharmony_ci#endif 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci/* 778c2ecf20Sopenharmony_ci * If we don't support core dumping, then supply a NULL so we 788c2ecf20Sopenharmony_ci * don't even try. 798c2ecf20Sopenharmony_ci */ 808c2ecf20Sopenharmony_ci#ifdef CONFIG_ELF_CORE 818c2ecf20Sopenharmony_cistatic int elf_core_dump(struct coredump_params *cprm); 828c2ecf20Sopenharmony_ci#else 838c2ecf20Sopenharmony_ci#define elf_core_dump NULL 848c2ecf20Sopenharmony_ci#endif 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci#if ELF_EXEC_PAGESIZE > PAGE_SIZE 878c2ecf20Sopenharmony_ci#define ELF_MIN_ALIGN ELF_EXEC_PAGESIZE 888c2ecf20Sopenharmony_ci#else 898c2ecf20Sopenharmony_ci#define ELF_MIN_ALIGN PAGE_SIZE 908c2ecf20Sopenharmony_ci#endif 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci#ifndef ELF_CORE_EFLAGS 938c2ecf20Sopenharmony_ci#define ELF_CORE_EFLAGS 0 948c2ecf20Sopenharmony_ci#endif 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci#define ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(ELF_MIN_ALIGN-1)) 978c2ecf20Sopenharmony_ci#define ELF_PAGEOFFSET(_v) ((_v) & (ELF_MIN_ALIGN-1)) 988c2ecf20Sopenharmony_ci#define ELF_PAGEALIGN(_v) (((_v) + ELF_MIN_ALIGN - 1) & ~(ELF_MIN_ALIGN - 1)) 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cistatic struct linux_binfmt elf_format = { 1018c2ecf20Sopenharmony_ci .module = THIS_MODULE, 1028c2ecf20Sopenharmony_ci .load_binary = load_elf_binary, 1038c2ecf20Sopenharmony_ci .load_shlib = load_elf_library, 1048c2ecf20Sopenharmony_ci .core_dump = elf_core_dump, 1058c2ecf20Sopenharmony_ci .min_coredump = ELF_EXEC_PAGESIZE, 1068c2ecf20Sopenharmony_ci}; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci#define BAD_ADDR(x) (unlikely((unsigned long)(x) >= TASK_SIZE)) 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_cistatic int set_brk(unsigned long start, unsigned long end, int prot) 1118c2ecf20Sopenharmony_ci{ 1128c2ecf20Sopenharmony_ci start = ELF_PAGEALIGN(start); 1138c2ecf20Sopenharmony_ci end = ELF_PAGEALIGN(end); 1148c2ecf20Sopenharmony_ci if (end > start) { 1158c2ecf20Sopenharmony_ci /* 1168c2ecf20Sopenharmony_ci * Map the last of the bss segment. 1178c2ecf20Sopenharmony_ci * If the header is requesting these pages to be 1188c2ecf20Sopenharmony_ci * executable, honour that (ppc32 needs this). 1198c2ecf20Sopenharmony_ci */ 1208c2ecf20Sopenharmony_ci int error = vm_brk_flags(start, end - start, 1218c2ecf20Sopenharmony_ci prot & PROT_EXEC ? VM_EXEC : 0); 1228c2ecf20Sopenharmony_ci if (error) 1238c2ecf20Sopenharmony_ci return error; 1248c2ecf20Sopenharmony_ci } 1258c2ecf20Sopenharmony_ci current->mm->start_brk = current->mm->brk = end; 1268c2ecf20Sopenharmony_ci return 0; 1278c2ecf20Sopenharmony_ci} 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci/* We need to explicitly zero any fractional pages 1308c2ecf20Sopenharmony_ci after the data section (i.e. bss). This would 1318c2ecf20Sopenharmony_ci contain the junk from the file that should not 1328c2ecf20Sopenharmony_ci be in memory 1338c2ecf20Sopenharmony_ci */ 1348c2ecf20Sopenharmony_cistatic int padzero(unsigned long elf_bss) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci unsigned long nbyte; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci nbyte = ELF_PAGEOFFSET(elf_bss); 1398c2ecf20Sopenharmony_ci if (nbyte) { 1408c2ecf20Sopenharmony_ci nbyte = ELF_MIN_ALIGN - nbyte; 1418c2ecf20Sopenharmony_ci if (clear_user((void __user *) elf_bss, nbyte)) 1428c2ecf20Sopenharmony_ci return -EFAULT; 1438c2ecf20Sopenharmony_ci } 1448c2ecf20Sopenharmony_ci return 0; 1458c2ecf20Sopenharmony_ci} 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci/* Let's use some macros to make this stack manipulation a little clearer */ 1488c2ecf20Sopenharmony_ci#ifdef CONFIG_STACK_GROWSUP 1498c2ecf20Sopenharmony_ci#define STACK_ADD(sp, items) ((elf_addr_t __user *)(sp) + (items)) 1508c2ecf20Sopenharmony_ci#define STACK_ROUND(sp, items) \ 1518c2ecf20Sopenharmony_ci ((15 + (unsigned long) ((sp) + (items))) &~ 15UL) 1528c2ecf20Sopenharmony_ci#define STACK_ALLOC(sp, len) ({ \ 1538c2ecf20Sopenharmony_ci elf_addr_t __user *old_sp = (elf_addr_t __user *)sp; sp += len; \ 1548c2ecf20Sopenharmony_ci old_sp; }) 1558c2ecf20Sopenharmony_ci#else 1568c2ecf20Sopenharmony_ci#define STACK_ADD(sp, items) ((elf_addr_t __user *)(sp) - (items)) 1578c2ecf20Sopenharmony_ci#define STACK_ROUND(sp, items) \ 1588c2ecf20Sopenharmony_ci (((unsigned long) (sp - items)) &~ 15UL) 1598c2ecf20Sopenharmony_ci#define STACK_ALLOC(sp, len) ({ sp -= len ; sp; }) 1608c2ecf20Sopenharmony_ci#endif 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci#ifndef ELF_BASE_PLATFORM 1638c2ecf20Sopenharmony_ci/* 1648c2ecf20Sopenharmony_ci * AT_BASE_PLATFORM indicates the "real" hardware/microarchitecture. 1658c2ecf20Sopenharmony_ci * If the arch defines ELF_BASE_PLATFORM (in asm/elf.h), the value 1668c2ecf20Sopenharmony_ci * will be copied to the user stack in the same manner as AT_PLATFORM. 1678c2ecf20Sopenharmony_ci */ 1688c2ecf20Sopenharmony_ci#define ELF_BASE_PLATFORM NULL 1698c2ecf20Sopenharmony_ci#endif 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_cistatic int 1728c2ecf20Sopenharmony_cicreate_elf_tables(struct linux_binprm *bprm, const struct elfhdr *exec, 1738c2ecf20Sopenharmony_ci unsigned long interp_load_addr, 1748c2ecf20Sopenharmony_ci unsigned long e_entry, unsigned long phdr_addr) 1758c2ecf20Sopenharmony_ci{ 1768c2ecf20Sopenharmony_ci struct mm_struct *mm = current->mm; 1778c2ecf20Sopenharmony_ci unsigned long p = bprm->p; 1788c2ecf20Sopenharmony_ci int argc = bprm->argc; 1798c2ecf20Sopenharmony_ci int envc = bprm->envc; 1808c2ecf20Sopenharmony_ci elf_addr_t __user *sp; 1818c2ecf20Sopenharmony_ci elf_addr_t __user *u_platform; 1828c2ecf20Sopenharmony_ci elf_addr_t __user *u_base_platform; 1838c2ecf20Sopenharmony_ci elf_addr_t __user *u_rand_bytes; 1848c2ecf20Sopenharmony_ci const char *k_platform = ELF_PLATFORM; 1858c2ecf20Sopenharmony_ci const char *k_base_platform = ELF_BASE_PLATFORM; 1868c2ecf20Sopenharmony_ci unsigned char k_rand_bytes[16]; 1878c2ecf20Sopenharmony_ci int items; 1888c2ecf20Sopenharmony_ci elf_addr_t *elf_info; 1898c2ecf20Sopenharmony_ci int ei_index; 1908c2ecf20Sopenharmony_ci const struct cred *cred = current_cred(); 1918c2ecf20Sopenharmony_ci struct vm_area_struct *vma; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci /* 1948c2ecf20Sopenharmony_ci * In some cases (e.g. Hyper-Threading), we want to avoid L1 1958c2ecf20Sopenharmony_ci * evictions by the processes running on the same package. One 1968c2ecf20Sopenharmony_ci * thing we can do is to shuffle the initial stack for them. 1978c2ecf20Sopenharmony_ci */ 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci p = arch_align_stack(p); 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci /* 2028c2ecf20Sopenharmony_ci * If this architecture has a platform capability string, copy it 2038c2ecf20Sopenharmony_ci * to userspace. In some cases (Sparc), this info is impossible 2048c2ecf20Sopenharmony_ci * for userspace to get any other way, in others (i386) it is 2058c2ecf20Sopenharmony_ci * merely difficult. 2068c2ecf20Sopenharmony_ci */ 2078c2ecf20Sopenharmony_ci u_platform = NULL; 2088c2ecf20Sopenharmony_ci if (k_platform) { 2098c2ecf20Sopenharmony_ci size_t len = strlen(k_platform) + 1; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci u_platform = (elf_addr_t __user *)STACK_ALLOC(p, len); 2128c2ecf20Sopenharmony_ci if (copy_to_user(u_platform, k_platform, len)) 2138c2ecf20Sopenharmony_ci return -EFAULT; 2148c2ecf20Sopenharmony_ci } 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci /* 2178c2ecf20Sopenharmony_ci * If this architecture has a "base" platform capability 2188c2ecf20Sopenharmony_ci * string, copy it to userspace. 2198c2ecf20Sopenharmony_ci */ 2208c2ecf20Sopenharmony_ci u_base_platform = NULL; 2218c2ecf20Sopenharmony_ci if (k_base_platform) { 2228c2ecf20Sopenharmony_ci size_t len = strlen(k_base_platform) + 1; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci u_base_platform = (elf_addr_t __user *)STACK_ALLOC(p, len); 2258c2ecf20Sopenharmony_ci if (copy_to_user(u_base_platform, k_base_platform, len)) 2268c2ecf20Sopenharmony_ci return -EFAULT; 2278c2ecf20Sopenharmony_ci } 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci /* 2308c2ecf20Sopenharmony_ci * Generate 16 random bytes for userspace PRNG seeding. 2318c2ecf20Sopenharmony_ci */ 2328c2ecf20Sopenharmony_ci get_random_bytes(k_rand_bytes, sizeof(k_rand_bytes)); 2338c2ecf20Sopenharmony_ci u_rand_bytes = (elf_addr_t __user *) 2348c2ecf20Sopenharmony_ci STACK_ALLOC(p, sizeof(k_rand_bytes)); 2358c2ecf20Sopenharmony_ci if (copy_to_user(u_rand_bytes, k_rand_bytes, sizeof(k_rand_bytes))) 2368c2ecf20Sopenharmony_ci return -EFAULT; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci /* Create the ELF interpreter info */ 2398c2ecf20Sopenharmony_ci elf_info = (elf_addr_t *)mm->saved_auxv; 2408c2ecf20Sopenharmony_ci /* update AT_VECTOR_SIZE_BASE if the number of NEW_AUX_ENT() changes */ 2418c2ecf20Sopenharmony_ci#define NEW_AUX_ENT(id, val) \ 2428c2ecf20Sopenharmony_ci do { \ 2438c2ecf20Sopenharmony_ci *elf_info++ = id; \ 2448c2ecf20Sopenharmony_ci *elf_info++ = val; \ 2458c2ecf20Sopenharmony_ci } while (0) 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci#ifdef ARCH_DLINFO 2488c2ecf20Sopenharmony_ci /* 2498c2ecf20Sopenharmony_ci * ARCH_DLINFO must come first so PPC can do its special alignment of 2508c2ecf20Sopenharmony_ci * AUXV. 2518c2ecf20Sopenharmony_ci * update AT_VECTOR_SIZE_ARCH if the number of NEW_AUX_ENT() in 2528c2ecf20Sopenharmony_ci * ARCH_DLINFO changes 2538c2ecf20Sopenharmony_ci */ 2548c2ecf20Sopenharmony_ci ARCH_DLINFO; 2558c2ecf20Sopenharmony_ci#endif 2568c2ecf20Sopenharmony_ci NEW_AUX_ENT(AT_HWCAP, ELF_HWCAP); 2578c2ecf20Sopenharmony_ci NEW_AUX_ENT(AT_PAGESZ, ELF_EXEC_PAGESIZE); 2588c2ecf20Sopenharmony_ci NEW_AUX_ENT(AT_CLKTCK, CLOCKS_PER_SEC); 2598c2ecf20Sopenharmony_ci NEW_AUX_ENT(AT_PHDR, phdr_addr); 2608c2ecf20Sopenharmony_ci NEW_AUX_ENT(AT_PHENT, sizeof(struct elf_phdr)); 2618c2ecf20Sopenharmony_ci NEW_AUX_ENT(AT_PHNUM, exec->e_phnum); 2628c2ecf20Sopenharmony_ci NEW_AUX_ENT(AT_BASE, interp_load_addr); 2638c2ecf20Sopenharmony_ci NEW_AUX_ENT(AT_FLAGS, 0); 2648c2ecf20Sopenharmony_ci NEW_AUX_ENT(AT_ENTRY, e_entry); 2658c2ecf20Sopenharmony_ci NEW_AUX_ENT(AT_UID, from_kuid_munged(cred->user_ns, cred->uid)); 2668c2ecf20Sopenharmony_ci NEW_AUX_ENT(AT_EUID, from_kuid_munged(cred->user_ns, cred->euid)); 2678c2ecf20Sopenharmony_ci NEW_AUX_ENT(AT_GID, from_kgid_munged(cred->user_ns, cred->gid)); 2688c2ecf20Sopenharmony_ci NEW_AUX_ENT(AT_EGID, from_kgid_munged(cred->user_ns, cred->egid)); 2698c2ecf20Sopenharmony_ci NEW_AUX_ENT(AT_SECURE, bprm->secureexec); 2708c2ecf20Sopenharmony_ci NEW_AUX_ENT(AT_RANDOM, (elf_addr_t)(unsigned long)u_rand_bytes); 2718c2ecf20Sopenharmony_ci#ifdef ELF_HWCAP2 2728c2ecf20Sopenharmony_ci NEW_AUX_ENT(AT_HWCAP2, ELF_HWCAP2); 2738c2ecf20Sopenharmony_ci#endif 2748c2ecf20Sopenharmony_ci NEW_AUX_ENT(AT_EXECFN, bprm->exec); 2758c2ecf20Sopenharmony_ci if (k_platform) { 2768c2ecf20Sopenharmony_ci NEW_AUX_ENT(AT_PLATFORM, 2778c2ecf20Sopenharmony_ci (elf_addr_t)(unsigned long)u_platform); 2788c2ecf20Sopenharmony_ci } 2798c2ecf20Sopenharmony_ci if (k_base_platform) { 2808c2ecf20Sopenharmony_ci NEW_AUX_ENT(AT_BASE_PLATFORM, 2818c2ecf20Sopenharmony_ci (elf_addr_t)(unsigned long)u_base_platform); 2828c2ecf20Sopenharmony_ci } 2838c2ecf20Sopenharmony_ci if (bprm->have_execfd) { 2848c2ecf20Sopenharmony_ci NEW_AUX_ENT(AT_EXECFD, bprm->execfd); 2858c2ecf20Sopenharmony_ci } 2868c2ecf20Sopenharmony_ci#undef NEW_AUX_ENT 2878c2ecf20Sopenharmony_ci /* AT_NULL is zero; clear the rest too */ 2888c2ecf20Sopenharmony_ci memset(elf_info, 0, (char *)mm->saved_auxv + 2898c2ecf20Sopenharmony_ci sizeof(mm->saved_auxv) - (char *)elf_info); 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci /* And advance past the AT_NULL entry. */ 2928c2ecf20Sopenharmony_ci elf_info += 2; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci ei_index = elf_info - (elf_addr_t *)mm->saved_auxv; 2958c2ecf20Sopenharmony_ci sp = STACK_ADD(p, ei_index); 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci items = (argc + 1) + (envc + 1) + 1; 2988c2ecf20Sopenharmony_ci bprm->p = STACK_ROUND(sp, items); 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci /* Point sp at the lowest address on the stack */ 3018c2ecf20Sopenharmony_ci#ifdef CONFIG_STACK_GROWSUP 3028c2ecf20Sopenharmony_ci sp = (elf_addr_t __user *)bprm->p - items - ei_index; 3038c2ecf20Sopenharmony_ci bprm->exec = (unsigned long)sp; /* XXX: PARISC HACK */ 3048c2ecf20Sopenharmony_ci#else 3058c2ecf20Sopenharmony_ci sp = (elf_addr_t __user *)bprm->p; 3068c2ecf20Sopenharmony_ci#endif 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci /* 3108c2ecf20Sopenharmony_ci * Grow the stack manually; some architectures have a limit on how 3118c2ecf20Sopenharmony_ci * far ahead a user-space access may be in order to grow the stack. 3128c2ecf20Sopenharmony_ci */ 3138c2ecf20Sopenharmony_ci if (mmap_read_lock_killable(mm)) 3148c2ecf20Sopenharmony_ci return -EINTR; 3158c2ecf20Sopenharmony_ci vma = find_extend_vma(mm, bprm->p); 3168c2ecf20Sopenharmony_ci mmap_read_unlock(mm); 3178c2ecf20Sopenharmony_ci if (!vma) 3188c2ecf20Sopenharmony_ci return -EFAULT; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci /* Now, let's put argc (and argv, envp if appropriate) on the stack */ 3218c2ecf20Sopenharmony_ci if (put_user(argc, sp++)) 3228c2ecf20Sopenharmony_ci return -EFAULT; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci /* Populate list of argv pointers back to argv strings. */ 3258c2ecf20Sopenharmony_ci p = mm->arg_end = mm->arg_start; 3268c2ecf20Sopenharmony_ci while (argc-- > 0) { 3278c2ecf20Sopenharmony_ci size_t len; 3288c2ecf20Sopenharmony_ci if (put_user((elf_addr_t)p, sp++)) 3298c2ecf20Sopenharmony_ci return -EFAULT; 3308c2ecf20Sopenharmony_ci len = strnlen_user((void __user *)p, MAX_ARG_STRLEN); 3318c2ecf20Sopenharmony_ci if (!len || len > MAX_ARG_STRLEN) 3328c2ecf20Sopenharmony_ci return -EINVAL; 3338c2ecf20Sopenharmony_ci p += len; 3348c2ecf20Sopenharmony_ci } 3358c2ecf20Sopenharmony_ci if (put_user(0, sp++)) 3368c2ecf20Sopenharmony_ci return -EFAULT; 3378c2ecf20Sopenharmony_ci mm->arg_end = p; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci /* Populate list of envp pointers back to envp strings. */ 3408c2ecf20Sopenharmony_ci mm->env_end = mm->env_start = p; 3418c2ecf20Sopenharmony_ci while (envc-- > 0) { 3428c2ecf20Sopenharmony_ci size_t len; 3438c2ecf20Sopenharmony_ci if (put_user((elf_addr_t)p, sp++)) 3448c2ecf20Sopenharmony_ci return -EFAULT; 3458c2ecf20Sopenharmony_ci len = strnlen_user((void __user *)p, MAX_ARG_STRLEN); 3468c2ecf20Sopenharmony_ci if (!len || len > MAX_ARG_STRLEN) 3478c2ecf20Sopenharmony_ci return -EINVAL; 3488c2ecf20Sopenharmony_ci p += len; 3498c2ecf20Sopenharmony_ci } 3508c2ecf20Sopenharmony_ci if (put_user(0, sp++)) 3518c2ecf20Sopenharmony_ci return -EFAULT; 3528c2ecf20Sopenharmony_ci mm->env_end = p; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci /* Put the elf_info on the stack in the right place. */ 3558c2ecf20Sopenharmony_ci if (copy_to_user(sp, mm->saved_auxv, ei_index * sizeof(elf_addr_t))) 3568c2ecf20Sopenharmony_ci return -EFAULT; 3578c2ecf20Sopenharmony_ci return 0; 3588c2ecf20Sopenharmony_ci} 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_cistatic unsigned long elf_map(struct file *filep, unsigned long addr, 3618c2ecf20Sopenharmony_ci const struct elf_phdr *eppnt, int prot, int type, 3628c2ecf20Sopenharmony_ci unsigned long total_size) 3638c2ecf20Sopenharmony_ci{ 3648c2ecf20Sopenharmony_ci unsigned long map_addr; 3658c2ecf20Sopenharmony_ci unsigned long size = eppnt->p_filesz + ELF_PAGEOFFSET(eppnt->p_vaddr); 3668c2ecf20Sopenharmony_ci unsigned long off = eppnt->p_offset - ELF_PAGEOFFSET(eppnt->p_vaddr); 3678c2ecf20Sopenharmony_ci addr = ELF_PAGESTART(addr); 3688c2ecf20Sopenharmony_ci size = ELF_PAGEALIGN(size); 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci /* mmap() will return -EINVAL if given a zero size, but a 3718c2ecf20Sopenharmony_ci * segment with zero filesize is perfectly valid */ 3728c2ecf20Sopenharmony_ci if (!size) 3738c2ecf20Sopenharmony_ci return addr; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci /* 3768c2ecf20Sopenharmony_ci * total_size is the size of the ELF (interpreter) image. 3778c2ecf20Sopenharmony_ci * The _first_ mmap needs to know the full size, otherwise 3788c2ecf20Sopenharmony_ci * randomization might put this image into an overlapping 3798c2ecf20Sopenharmony_ci * position with the ELF binary image. (since size < total_size) 3808c2ecf20Sopenharmony_ci * So we first map the 'big' image - and unmap the remainder at 3818c2ecf20Sopenharmony_ci * the end. (which unmap is needed for ELF images with holes.) 3828c2ecf20Sopenharmony_ci */ 3838c2ecf20Sopenharmony_ci if (total_size) { 3848c2ecf20Sopenharmony_ci total_size = ELF_PAGEALIGN(total_size); 3858c2ecf20Sopenharmony_ci map_addr = vm_mmap(filep, addr, total_size, prot, type, off); 3868c2ecf20Sopenharmony_ci if (!BAD_ADDR(map_addr)) 3878c2ecf20Sopenharmony_ci vm_munmap(map_addr+size, total_size-size); 3888c2ecf20Sopenharmony_ci } else 3898c2ecf20Sopenharmony_ci map_addr = vm_mmap(filep, addr, size, prot, type, off); 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci if ((type & MAP_FIXED_NOREPLACE) && 3928c2ecf20Sopenharmony_ci PTR_ERR((void *)map_addr) == -EEXIST) 3938c2ecf20Sopenharmony_ci pr_info("%d (%s): Uhuuh, elf segment at %px requested but the memory is mapped already\n", 3948c2ecf20Sopenharmony_ci task_pid_nr(current), current->comm, (void *)addr); 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci return(map_addr); 3978c2ecf20Sopenharmony_ci} 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_cistatic unsigned long total_mapping_size(const struct elf_phdr *cmds, int nr) 4008c2ecf20Sopenharmony_ci{ 4018c2ecf20Sopenharmony_ci int i, first_idx = -1, last_idx = -1; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci for (i = 0; i < nr; i++) { 4048c2ecf20Sopenharmony_ci if (cmds[i].p_type == PT_LOAD) { 4058c2ecf20Sopenharmony_ci last_idx = i; 4068c2ecf20Sopenharmony_ci if (first_idx == -1) 4078c2ecf20Sopenharmony_ci first_idx = i; 4088c2ecf20Sopenharmony_ci } 4098c2ecf20Sopenharmony_ci } 4108c2ecf20Sopenharmony_ci if (first_idx == -1) 4118c2ecf20Sopenharmony_ci return 0; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci return cmds[last_idx].p_vaddr + cmds[last_idx].p_memsz - 4148c2ecf20Sopenharmony_ci ELF_PAGESTART(cmds[first_idx].p_vaddr); 4158c2ecf20Sopenharmony_ci} 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_cistatic int elf_read(struct file *file, void *buf, size_t len, loff_t pos) 4188c2ecf20Sopenharmony_ci{ 4198c2ecf20Sopenharmony_ci ssize_t rv; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci rv = kernel_read(file, buf, len, &pos); 4228c2ecf20Sopenharmony_ci if (unlikely(rv != len)) { 4238c2ecf20Sopenharmony_ci return (rv < 0) ? rv : -EIO; 4248c2ecf20Sopenharmony_ci } 4258c2ecf20Sopenharmony_ci return 0; 4268c2ecf20Sopenharmony_ci} 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_cistatic unsigned long maximum_alignment(struct elf_phdr *cmds, int nr) 4298c2ecf20Sopenharmony_ci{ 4308c2ecf20Sopenharmony_ci unsigned long alignment = 0; 4318c2ecf20Sopenharmony_ci int i; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci for (i = 0; i < nr; i++) { 4348c2ecf20Sopenharmony_ci if (cmds[i].p_type == PT_LOAD) { 4358c2ecf20Sopenharmony_ci unsigned long p_align = cmds[i].p_align; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci /* skip non-power of two alignments as invalid */ 4388c2ecf20Sopenharmony_ci if (!is_power_of_2(p_align)) 4398c2ecf20Sopenharmony_ci continue; 4408c2ecf20Sopenharmony_ci alignment = max(alignment, p_align); 4418c2ecf20Sopenharmony_ci } 4428c2ecf20Sopenharmony_ci } 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci /* ensure we align to at least one page */ 4458c2ecf20Sopenharmony_ci return ELF_PAGEALIGN(alignment); 4468c2ecf20Sopenharmony_ci} 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci/** 4498c2ecf20Sopenharmony_ci * load_elf_phdrs() - load ELF program headers 4508c2ecf20Sopenharmony_ci * @elf_ex: ELF header of the binary whose program headers should be loaded 4518c2ecf20Sopenharmony_ci * @elf_file: the opened ELF binary file 4528c2ecf20Sopenharmony_ci * 4538c2ecf20Sopenharmony_ci * Loads ELF program headers from the binary file elf_file, which has the ELF 4548c2ecf20Sopenharmony_ci * header pointed to by elf_ex, into a newly allocated array. The caller is 4558c2ecf20Sopenharmony_ci * responsible for freeing the allocated data. Returns an ERR_PTR upon failure. 4568c2ecf20Sopenharmony_ci */ 4578c2ecf20Sopenharmony_cistatic struct elf_phdr *load_elf_phdrs(const struct elfhdr *elf_ex, 4588c2ecf20Sopenharmony_ci struct file *elf_file) 4598c2ecf20Sopenharmony_ci{ 4608c2ecf20Sopenharmony_ci struct elf_phdr *elf_phdata = NULL; 4618c2ecf20Sopenharmony_ci int retval, err = -1; 4628c2ecf20Sopenharmony_ci unsigned int size; 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci /* 4658c2ecf20Sopenharmony_ci * If the size of this structure has changed, then punt, since 4668c2ecf20Sopenharmony_ci * we will be doing the wrong thing. 4678c2ecf20Sopenharmony_ci */ 4688c2ecf20Sopenharmony_ci if (elf_ex->e_phentsize != sizeof(struct elf_phdr)) 4698c2ecf20Sopenharmony_ci goto out; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci /* Sanity check the number of program headers... */ 4728c2ecf20Sopenharmony_ci /* ...and their total size. */ 4738c2ecf20Sopenharmony_ci size = sizeof(struct elf_phdr) * elf_ex->e_phnum; 4748c2ecf20Sopenharmony_ci if (size == 0 || size > 65536 || size > ELF_MIN_ALIGN) 4758c2ecf20Sopenharmony_ci goto out; 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci elf_phdata = kmalloc(size, GFP_KERNEL); 4788c2ecf20Sopenharmony_ci if (!elf_phdata) 4798c2ecf20Sopenharmony_ci goto out; 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci /* Read in the program headers */ 4828c2ecf20Sopenharmony_ci retval = elf_read(elf_file, elf_phdata, size, elf_ex->e_phoff); 4838c2ecf20Sopenharmony_ci if (retval < 0) { 4848c2ecf20Sopenharmony_ci err = retval; 4858c2ecf20Sopenharmony_ci goto out; 4868c2ecf20Sopenharmony_ci } 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci /* Success! */ 4898c2ecf20Sopenharmony_ci err = 0; 4908c2ecf20Sopenharmony_ciout: 4918c2ecf20Sopenharmony_ci if (err) { 4928c2ecf20Sopenharmony_ci kfree(elf_phdata); 4938c2ecf20Sopenharmony_ci elf_phdata = NULL; 4948c2ecf20Sopenharmony_ci } 4958c2ecf20Sopenharmony_ci return elf_phdata; 4968c2ecf20Sopenharmony_ci} 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci#ifndef CONFIG_ARCH_BINFMT_ELF_STATE 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci/** 5018c2ecf20Sopenharmony_ci * struct arch_elf_state - arch-specific ELF loading state 5028c2ecf20Sopenharmony_ci * 5038c2ecf20Sopenharmony_ci * This structure is used to preserve architecture specific data during 5048c2ecf20Sopenharmony_ci * the loading of an ELF file, throughout the checking of architecture 5058c2ecf20Sopenharmony_ci * specific ELF headers & through to the point where the ELF load is 5068c2ecf20Sopenharmony_ci * known to be proceeding (ie. SET_PERSONALITY). 5078c2ecf20Sopenharmony_ci * 5088c2ecf20Sopenharmony_ci * This implementation is a dummy for architectures which require no 5098c2ecf20Sopenharmony_ci * specific state. 5108c2ecf20Sopenharmony_ci */ 5118c2ecf20Sopenharmony_cistruct arch_elf_state { 5128c2ecf20Sopenharmony_ci}; 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci#define INIT_ARCH_ELF_STATE {} 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci/** 5178c2ecf20Sopenharmony_ci * arch_elf_pt_proc() - check a PT_LOPROC..PT_HIPROC ELF program header 5188c2ecf20Sopenharmony_ci * @ehdr: The main ELF header 5198c2ecf20Sopenharmony_ci * @phdr: The program header to check 5208c2ecf20Sopenharmony_ci * @elf: The open ELF file 5218c2ecf20Sopenharmony_ci * @is_interp: True if the phdr is from the interpreter of the ELF being 5228c2ecf20Sopenharmony_ci * loaded, else false. 5238c2ecf20Sopenharmony_ci * @state: Architecture-specific state preserved throughout the process 5248c2ecf20Sopenharmony_ci * of loading the ELF. 5258c2ecf20Sopenharmony_ci * 5268c2ecf20Sopenharmony_ci * Inspects the program header phdr to validate its correctness and/or 5278c2ecf20Sopenharmony_ci * suitability for the system. Called once per ELF program header in the 5288c2ecf20Sopenharmony_ci * range PT_LOPROC to PT_HIPROC, for both the ELF being loaded and its 5298c2ecf20Sopenharmony_ci * interpreter. 5308c2ecf20Sopenharmony_ci * 5318c2ecf20Sopenharmony_ci * Return: Zero to proceed with the ELF load, non-zero to fail the ELF load 5328c2ecf20Sopenharmony_ci * with that return code. 5338c2ecf20Sopenharmony_ci */ 5348c2ecf20Sopenharmony_cistatic inline int arch_elf_pt_proc(struct elfhdr *ehdr, 5358c2ecf20Sopenharmony_ci struct elf_phdr *phdr, 5368c2ecf20Sopenharmony_ci struct file *elf, bool is_interp, 5378c2ecf20Sopenharmony_ci struct arch_elf_state *state) 5388c2ecf20Sopenharmony_ci{ 5398c2ecf20Sopenharmony_ci /* Dummy implementation, always proceed */ 5408c2ecf20Sopenharmony_ci return 0; 5418c2ecf20Sopenharmony_ci} 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci/** 5448c2ecf20Sopenharmony_ci * arch_check_elf() - check an ELF executable 5458c2ecf20Sopenharmony_ci * @ehdr: The main ELF header 5468c2ecf20Sopenharmony_ci * @has_interp: True if the ELF has an interpreter, else false. 5478c2ecf20Sopenharmony_ci * @interp_ehdr: The interpreter's ELF header 5488c2ecf20Sopenharmony_ci * @state: Architecture-specific state preserved throughout the process 5498c2ecf20Sopenharmony_ci * of loading the ELF. 5508c2ecf20Sopenharmony_ci * 5518c2ecf20Sopenharmony_ci * Provides a final opportunity for architecture code to reject the loading 5528c2ecf20Sopenharmony_ci * of the ELF & cause an exec syscall to return an error. This is called after 5538c2ecf20Sopenharmony_ci * all program headers to be checked by arch_elf_pt_proc have been. 5548c2ecf20Sopenharmony_ci * 5558c2ecf20Sopenharmony_ci * Return: Zero to proceed with the ELF load, non-zero to fail the ELF load 5568c2ecf20Sopenharmony_ci * with that return code. 5578c2ecf20Sopenharmony_ci */ 5588c2ecf20Sopenharmony_cistatic inline int arch_check_elf(struct elfhdr *ehdr, bool has_interp, 5598c2ecf20Sopenharmony_ci struct elfhdr *interp_ehdr, 5608c2ecf20Sopenharmony_ci struct arch_elf_state *state) 5618c2ecf20Sopenharmony_ci{ 5628c2ecf20Sopenharmony_ci /* Dummy implementation, always proceed */ 5638c2ecf20Sopenharmony_ci return 0; 5648c2ecf20Sopenharmony_ci} 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci#endif /* !CONFIG_ARCH_BINFMT_ELF_STATE */ 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_cistatic inline int make_prot(u32 p_flags, struct arch_elf_state *arch_state, 5698c2ecf20Sopenharmony_ci bool has_interp, bool is_interp) 5708c2ecf20Sopenharmony_ci{ 5718c2ecf20Sopenharmony_ci int prot = 0; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci if (p_flags & PF_R) 5748c2ecf20Sopenharmony_ci prot |= PROT_READ; 5758c2ecf20Sopenharmony_ci if (p_flags & PF_W) 5768c2ecf20Sopenharmony_ci prot |= PROT_WRITE; 5778c2ecf20Sopenharmony_ci if (p_flags & PF_X) 5788c2ecf20Sopenharmony_ci prot |= PROT_EXEC; 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci return arch_elf_adjust_prot(prot, arch_state, has_interp, is_interp); 5818c2ecf20Sopenharmony_ci} 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci/* This is much more generalized than the library routine read function, 5848c2ecf20Sopenharmony_ci so we keep this separate. Technically the library read function 5858c2ecf20Sopenharmony_ci is only provided so that we can read a.out libraries that have 5868c2ecf20Sopenharmony_ci an ELF header */ 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_cistatic unsigned long load_elf_interp(struct elfhdr *interp_elf_ex, 5898c2ecf20Sopenharmony_ci struct file *interpreter, 5908c2ecf20Sopenharmony_ci unsigned long no_base, struct elf_phdr *interp_elf_phdata, 5918c2ecf20Sopenharmony_ci struct arch_elf_state *arch_state) 5928c2ecf20Sopenharmony_ci{ 5938c2ecf20Sopenharmony_ci struct elf_phdr *eppnt; 5948c2ecf20Sopenharmony_ci unsigned long load_addr = 0; 5958c2ecf20Sopenharmony_ci int load_addr_set = 0; 5968c2ecf20Sopenharmony_ci unsigned long last_bss = 0, elf_bss = 0; 5978c2ecf20Sopenharmony_ci int bss_prot = 0; 5988c2ecf20Sopenharmony_ci unsigned long error = ~0UL; 5998c2ecf20Sopenharmony_ci unsigned long total_size; 6008c2ecf20Sopenharmony_ci int i; 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci /* First of all, some simple consistency checks */ 6038c2ecf20Sopenharmony_ci if (interp_elf_ex->e_type != ET_EXEC && 6048c2ecf20Sopenharmony_ci interp_elf_ex->e_type != ET_DYN) 6058c2ecf20Sopenharmony_ci goto out; 6068c2ecf20Sopenharmony_ci if (!elf_check_arch(interp_elf_ex) || 6078c2ecf20Sopenharmony_ci elf_check_fdpic(interp_elf_ex)) 6088c2ecf20Sopenharmony_ci goto out; 6098c2ecf20Sopenharmony_ci if (!interpreter->f_op->mmap) 6108c2ecf20Sopenharmony_ci goto out; 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci total_size = total_mapping_size(interp_elf_phdata, 6138c2ecf20Sopenharmony_ci interp_elf_ex->e_phnum); 6148c2ecf20Sopenharmony_ci if (!total_size) { 6158c2ecf20Sopenharmony_ci error = -EINVAL; 6168c2ecf20Sopenharmony_ci goto out; 6178c2ecf20Sopenharmony_ci } 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci eppnt = interp_elf_phdata; 6208c2ecf20Sopenharmony_ci for (i = 0; i < interp_elf_ex->e_phnum; i++, eppnt++) { 6218c2ecf20Sopenharmony_ci if (eppnt->p_type == PT_LOAD) { 6228c2ecf20Sopenharmony_ci int elf_type = MAP_PRIVATE | MAP_DENYWRITE; 6238c2ecf20Sopenharmony_ci int elf_prot = make_prot(eppnt->p_flags, arch_state, 6248c2ecf20Sopenharmony_ci true, true); 6258c2ecf20Sopenharmony_ci unsigned long vaddr = 0; 6268c2ecf20Sopenharmony_ci unsigned long k, map_addr; 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci vaddr = eppnt->p_vaddr; 6298c2ecf20Sopenharmony_ci if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) 6308c2ecf20Sopenharmony_ci elf_type |= MAP_FIXED; 6318c2ecf20Sopenharmony_ci else if (no_base && interp_elf_ex->e_type == ET_DYN) 6328c2ecf20Sopenharmony_ci load_addr = -vaddr; 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci map_addr = elf_map(interpreter, load_addr + vaddr, 6358c2ecf20Sopenharmony_ci eppnt, elf_prot, elf_type, total_size); 6368c2ecf20Sopenharmony_ci total_size = 0; 6378c2ecf20Sopenharmony_ci error = map_addr; 6388c2ecf20Sopenharmony_ci if (BAD_ADDR(map_addr)) 6398c2ecf20Sopenharmony_ci goto out; 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci if (!load_addr_set && 6428c2ecf20Sopenharmony_ci interp_elf_ex->e_type == ET_DYN) { 6438c2ecf20Sopenharmony_ci load_addr = map_addr - ELF_PAGESTART(vaddr); 6448c2ecf20Sopenharmony_ci load_addr_set = 1; 6458c2ecf20Sopenharmony_ci } 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci /* 6488c2ecf20Sopenharmony_ci * Check to see if the section's size will overflow the 6498c2ecf20Sopenharmony_ci * allowed task size. Note that p_filesz must always be 6508c2ecf20Sopenharmony_ci * <= p_memsize so it's only necessary to check p_memsz. 6518c2ecf20Sopenharmony_ci */ 6528c2ecf20Sopenharmony_ci k = load_addr + eppnt->p_vaddr; 6538c2ecf20Sopenharmony_ci if (BAD_ADDR(k) || 6548c2ecf20Sopenharmony_ci eppnt->p_filesz > eppnt->p_memsz || 6558c2ecf20Sopenharmony_ci eppnt->p_memsz > TASK_SIZE || 6568c2ecf20Sopenharmony_ci TASK_SIZE - eppnt->p_memsz < k) { 6578c2ecf20Sopenharmony_ci error = -ENOMEM; 6588c2ecf20Sopenharmony_ci goto out; 6598c2ecf20Sopenharmony_ci } 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci /* 6628c2ecf20Sopenharmony_ci * Find the end of the file mapping for this phdr, and 6638c2ecf20Sopenharmony_ci * keep track of the largest address we see for this. 6648c2ecf20Sopenharmony_ci */ 6658c2ecf20Sopenharmony_ci k = load_addr + eppnt->p_vaddr + eppnt->p_filesz; 6668c2ecf20Sopenharmony_ci if (k > elf_bss) 6678c2ecf20Sopenharmony_ci elf_bss = k; 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci /* 6708c2ecf20Sopenharmony_ci * Do the same thing for the memory mapping - between 6718c2ecf20Sopenharmony_ci * elf_bss and last_bss is the bss section. 6728c2ecf20Sopenharmony_ci */ 6738c2ecf20Sopenharmony_ci k = load_addr + eppnt->p_vaddr + eppnt->p_memsz; 6748c2ecf20Sopenharmony_ci if (k > last_bss) { 6758c2ecf20Sopenharmony_ci last_bss = k; 6768c2ecf20Sopenharmony_ci bss_prot = elf_prot; 6778c2ecf20Sopenharmony_ci } 6788c2ecf20Sopenharmony_ci } 6798c2ecf20Sopenharmony_ci } 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci /* 6828c2ecf20Sopenharmony_ci * Now fill out the bss section: first pad the last page from 6838c2ecf20Sopenharmony_ci * the file up to the page boundary, and zero it from elf_bss 6848c2ecf20Sopenharmony_ci * up to the end of the page. 6858c2ecf20Sopenharmony_ci */ 6868c2ecf20Sopenharmony_ci if (padzero(elf_bss)) { 6878c2ecf20Sopenharmony_ci error = -EFAULT; 6888c2ecf20Sopenharmony_ci goto out; 6898c2ecf20Sopenharmony_ci } 6908c2ecf20Sopenharmony_ci /* 6918c2ecf20Sopenharmony_ci * Next, align both the file and mem bss up to the page size, 6928c2ecf20Sopenharmony_ci * since this is where elf_bss was just zeroed up to, and where 6938c2ecf20Sopenharmony_ci * last_bss will end after the vm_brk_flags() below. 6948c2ecf20Sopenharmony_ci */ 6958c2ecf20Sopenharmony_ci elf_bss = ELF_PAGEALIGN(elf_bss); 6968c2ecf20Sopenharmony_ci last_bss = ELF_PAGEALIGN(last_bss); 6978c2ecf20Sopenharmony_ci /* Finally, if there is still more bss to allocate, do it. */ 6988c2ecf20Sopenharmony_ci if (last_bss > elf_bss) { 6998c2ecf20Sopenharmony_ci error = vm_brk_flags(elf_bss, last_bss - elf_bss, 7008c2ecf20Sopenharmony_ci bss_prot & PROT_EXEC ? VM_EXEC : 0); 7018c2ecf20Sopenharmony_ci if (error) 7028c2ecf20Sopenharmony_ci goto out; 7038c2ecf20Sopenharmony_ci } 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci error = load_addr; 7068c2ecf20Sopenharmony_ciout: 7078c2ecf20Sopenharmony_ci return error; 7088c2ecf20Sopenharmony_ci} 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci/* 7118c2ecf20Sopenharmony_ci * These are the functions used to load ELF style executables and shared 7128c2ecf20Sopenharmony_ci * libraries. There is no binary dependent code anywhere else. 7138c2ecf20Sopenharmony_ci */ 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_cistatic int parse_elf_property(const char *data, size_t *off, size_t datasz, 7168c2ecf20Sopenharmony_ci struct arch_elf_state *arch, 7178c2ecf20Sopenharmony_ci bool have_prev_type, u32 *prev_type) 7188c2ecf20Sopenharmony_ci{ 7198c2ecf20Sopenharmony_ci size_t o, step; 7208c2ecf20Sopenharmony_ci const struct gnu_property *pr; 7218c2ecf20Sopenharmony_ci int ret; 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci if (*off == datasz) 7248c2ecf20Sopenharmony_ci return -ENOENT; 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(*off > datasz || *off % ELF_GNU_PROPERTY_ALIGN)) 7278c2ecf20Sopenharmony_ci return -EIO; 7288c2ecf20Sopenharmony_ci o = *off; 7298c2ecf20Sopenharmony_ci datasz -= *off; 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci if (datasz < sizeof(*pr)) 7328c2ecf20Sopenharmony_ci return -ENOEXEC; 7338c2ecf20Sopenharmony_ci pr = (const struct gnu_property *)(data + o); 7348c2ecf20Sopenharmony_ci o += sizeof(*pr); 7358c2ecf20Sopenharmony_ci datasz -= sizeof(*pr); 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci if (pr->pr_datasz > datasz) 7388c2ecf20Sopenharmony_ci return -ENOEXEC; 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci WARN_ON_ONCE(o % ELF_GNU_PROPERTY_ALIGN); 7418c2ecf20Sopenharmony_ci step = round_up(pr->pr_datasz, ELF_GNU_PROPERTY_ALIGN); 7428c2ecf20Sopenharmony_ci if (step > datasz) 7438c2ecf20Sopenharmony_ci return -ENOEXEC; 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci /* Properties are supposed to be unique and sorted on pr_type: */ 7468c2ecf20Sopenharmony_ci if (have_prev_type && pr->pr_type <= *prev_type) 7478c2ecf20Sopenharmony_ci return -ENOEXEC; 7488c2ecf20Sopenharmony_ci *prev_type = pr->pr_type; 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci ret = arch_parse_elf_property(pr->pr_type, data + o, 7518c2ecf20Sopenharmony_ci pr->pr_datasz, ELF_COMPAT, arch); 7528c2ecf20Sopenharmony_ci if (ret) 7538c2ecf20Sopenharmony_ci return ret; 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci *off = o + step; 7568c2ecf20Sopenharmony_ci return 0; 7578c2ecf20Sopenharmony_ci} 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci#define NOTE_DATA_SZ SZ_1K 7608c2ecf20Sopenharmony_ci#define GNU_PROPERTY_TYPE_0_NAME "GNU" 7618c2ecf20Sopenharmony_ci#define NOTE_NAME_SZ (sizeof(GNU_PROPERTY_TYPE_0_NAME)) 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_cistatic int parse_elf_properties(struct file *f, const struct elf_phdr *phdr, 7648c2ecf20Sopenharmony_ci struct arch_elf_state *arch) 7658c2ecf20Sopenharmony_ci{ 7668c2ecf20Sopenharmony_ci union { 7678c2ecf20Sopenharmony_ci struct elf_note nhdr; 7688c2ecf20Sopenharmony_ci char data[NOTE_DATA_SZ]; 7698c2ecf20Sopenharmony_ci } note; 7708c2ecf20Sopenharmony_ci loff_t pos; 7718c2ecf20Sopenharmony_ci ssize_t n; 7728c2ecf20Sopenharmony_ci size_t off, datasz; 7738c2ecf20Sopenharmony_ci int ret; 7748c2ecf20Sopenharmony_ci bool have_prev_type; 7758c2ecf20Sopenharmony_ci u32 prev_type; 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci if (!IS_ENABLED(CONFIG_ARCH_USE_GNU_PROPERTY) || !phdr) 7788c2ecf20Sopenharmony_ci return 0; 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci /* load_elf_binary() shouldn't call us unless this is true... */ 7818c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(phdr->p_type != PT_GNU_PROPERTY)) 7828c2ecf20Sopenharmony_ci return -ENOEXEC; 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci /* If the properties are crazy large, that's too bad (for now): */ 7858c2ecf20Sopenharmony_ci if (phdr->p_filesz > sizeof(note)) 7868c2ecf20Sopenharmony_ci return -ENOEXEC; 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci pos = phdr->p_offset; 7898c2ecf20Sopenharmony_ci n = kernel_read(f, ¬e, phdr->p_filesz, &pos); 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(note) < sizeof(note.nhdr) + NOTE_NAME_SZ); 7928c2ecf20Sopenharmony_ci if (n < 0 || n < sizeof(note.nhdr) + NOTE_NAME_SZ) 7938c2ecf20Sopenharmony_ci return -EIO; 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci if (note.nhdr.n_type != NT_GNU_PROPERTY_TYPE_0 || 7968c2ecf20Sopenharmony_ci note.nhdr.n_namesz != NOTE_NAME_SZ || 7978c2ecf20Sopenharmony_ci strncmp(note.data + sizeof(note.nhdr), 7988c2ecf20Sopenharmony_ci GNU_PROPERTY_TYPE_0_NAME, n - sizeof(note.nhdr))) 7998c2ecf20Sopenharmony_ci return -ENOEXEC; 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci off = round_up(sizeof(note.nhdr) + NOTE_NAME_SZ, 8028c2ecf20Sopenharmony_ci ELF_GNU_PROPERTY_ALIGN); 8038c2ecf20Sopenharmony_ci if (off > n) 8048c2ecf20Sopenharmony_ci return -ENOEXEC; 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci if (note.nhdr.n_descsz > n - off) 8078c2ecf20Sopenharmony_ci return -ENOEXEC; 8088c2ecf20Sopenharmony_ci datasz = off + note.nhdr.n_descsz; 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci have_prev_type = false; 8118c2ecf20Sopenharmony_ci do { 8128c2ecf20Sopenharmony_ci ret = parse_elf_property(note.data, &off, datasz, arch, 8138c2ecf20Sopenharmony_ci have_prev_type, &prev_type); 8148c2ecf20Sopenharmony_ci have_prev_type = true; 8158c2ecf20Sopenharmony_ci } while (!ret); 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci return ret == -ENOENT ? 0 : ret; 8188c2ecf20Sopenharmony_ci} 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_cistatic int load_elf_binary(struct linux_binprm *bprm) 8218c2ecf20Sopenharmony_ci{ 8228c2ecf20Sopenharmony_ci struct file *interpreter = NULL; /* to shut gcc up */ 8238c2ecf20Sopenharmony_ci unsigned long load_addr, load_bias = 0, phdr_addr = 0; 8248c2ecf20Sopenharmony_ci int load_addr_set = 0; 8258c2ecf20Sopenharmony_ci unsigned long error; 8268c2ecf20Sopenharmony_ci struct elf_phdr *elf_ppnt, *elf_phdata, *interp_elf_phdata = NULL; 8278c2ecf20Sopenharmony_ci struct elf_phdr *elf_property_phdata = NULL; 8288c2ecf20Sopenharmony_ci unsigned long elf_bss, elf_brk; 8298c2ecf20Sopenharmony_ci int bss_prot = 0; 8308c2ecf20Sopenharmony_ci int retval, i; 8318c2ecf20Sopenharmony_ci unsigned long elf_entry; 8328c2ecf20Sopenharmony_ci unsigned long e_entry; 8338c2ecf20Sopenharmony_ci unsigned long interp_load_addr = 0; 8348c2ecf20Sopenharmony_ci unsigned long start_code, end_code, start_data, end_data; 8358c2ecf20Sopenharmony_ci unsigned long reloc_func_desc __maybe_unused = 0; 8368c2ecf20Sopenharmony_ci int executable_stack = EXSTACK_DEFAULT; 8378c2ecf20Sopenharmony_ci struct elfhdr *elf_ex = (struct elfhdr *)bprm->buf; 8388c2ecf20Sopenharmony_ci struct elfhdr *interp_elf_ex = NULL; 8398c2ecf20Sopenharmony_ci struct arch_elf_state arch_state = INIT_ARCH_ELF_STATE; 8408c2ecf20Sopenharmony_ci struct mm_struct *mm; 8418c2ecf20Sopenharmony_ci struct pt_regs *regs; 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci retval = -ENOEXEC; 8448c2ecf20Sopenharmony_ci /* First of all, some simple consistency checks */ 8458c2ecf20Sopenharmony_ci if (memcmp(elf_ex->e_ident, ELFMAG, SELFMAG) != 0) 8468c2ecf20Sopenharmony_ci goto out; 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci if (elf_ex->e_type != ET_EXEC && elf_ex->e_type != ET_DYN) 8498c2ecf20Sopenharmony_ci goto out; 8508c2ecf20Sopenharmony_ci if (!elf_check_arch(elf_ex)) 8518c2ecf20Sopenharmony_ci goto out; 8528c2ecf20Sopenharmony_ci if (elf_check_fdpic(elf_ex)) 8538c2ecf20Sopenharmony_ci goto out; 8548c2ecf20Sopenharmony_ci if (!bprm->file->f_op->mmap) 8558c2ecf20Sopenharmony_ci goto out; 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci elf_phdata = load_elf_phdrs(elf_ex, bprm->file); 8588c2ecf20Sopenharmony_ci if (!elf_phdata) 8598c2ecf20Sopenharmony_ci goto out; 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci elf_ppnt = elf_phdata; 8628c2ecf20Sopenharmony_ci for (i = 0; i < elf_ex->e_phnum; i++, elf_ppnt++) { 8638c2ecf20Sopenharmony_ci char *elf_interpreter; 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci if (elf_ppnt->p_type == PT_GNU_PROPERTY) { 8668c2ecf20Sopenharmony_ci elf_property_phdata = elf_ppnt; 8678c2ecf20Sopenharmony_ci continue; 8688c2ecf20Sopenharmony_ci } 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci if (elf_ppnt->p_type != PT_INTERP) 8718c2ecf20Sopenharmony_ci continue; 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci /* 8748c2ecf20Sopenharmony_ci * This is the program interpreter used for shared libraries - 8758c2ecf20Sopenharmony_ci * for now assume that this is an a.out format binary. 8768c2ecf20Sopenharmony_ci */ 8778c2ecf20Sopenharmony_ci retval = -ENOEXEC; 8788c2ecf20Sopenharmony_ci if (elf_ppnt->p_filesz > PATH_MAX || elf_ppnt->p_filesz < 2) 8798c2ecf20Sopenharmony_ci goto out_free_ph; 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci retval = -ENOMEM; 8828c2ecf20Sopenharmony_ci elf_interpreter = kmalloc(elf_ppnt->p_filesz, GFP_KERNEL); 8838c2ecf20Sopenharmony_ci if (!elf_interpreter) 8848c2ecf20Sopenharmony_ci goto out_free_ph; 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci retval = elf_read(bprm->file, elf_interpreter, elf_ppnt->p_filesz, 8878c2ecf20Sopenharmony_ci elf_ppnt->p_offset); 8888c2ecf20Sopenharmony_ci if (retval < 0) 8898c2ecf20Sopenharmony_ci goto out_free_interp; 8908c2ecf20Sopenharmony_ci /* make sure path is NULL terminated */ 8918c2ecf20Sopenharmony_ci retval = -ENOEXEC; 8928c2ecf20Sopenharmony_ci if (elf_interpreter[elf_ppnt->p_filesz - 1] != '\0') 8938c2ecf20Sopenharmony_ci goto out_free_interp; 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci interpreter = open_exec(elf_interpreter); 8968c2ecf20Sopenharmony_ci kfree(elf_interpreter); 8978c2ecf20Sopenharmony_ci retval = PTR_ERR(interpreter); 8988c2ecf20Sopenharmony_ci if (IS_ERR(interpreter)) 8998c2ecf20Sopenharmony_ci goto out_free_ph; 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci /* 9028c2ecf20Sopenharmony_ci * If the binary is not readable then enforce mm->dumpable = 0 9038c2ecf20Sopenharmony_ci * regardless of the interpreter's permissions. 9048c2ecf20Sopenharmony_ci */ 9058c2ecf20Sopenharmony_ci would_dump(bprm, interpreter); 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci interp_elf_ex = kmalloc(sizeof(*interp_elf_ex), GFP_KERNEL); 9088c2ecf20Sopenharmony_ci if (!interp_elf_ex) { 9098c2ecf20Sopenharmony_ci retval = -ENOMEM; 9108c2ecf20Sopenharmony_ci goto out_free_file; 9118c2ecf20Sopenharmony_ci } 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci /* Get the exec headers */ 9148c2ecf20Sopenharmony_ci retval = elf_read(interpreter, interp_elf_ex, 9158c2ecf20Sopenharmony_ci sizeof(*interp_elf_ex), 0); 9168c2ecf20Sopenharmony_ci if (retval < 0) 9178c2ecf20Sopenharmony_ci goto out_free_dentry; 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci break; 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ciout_free_interp: 9228c2ecf20Sopenharmony_ci kfree(elf_interpreter); 9238c2ecf20Sopenharmony_ci goto out_free_ph; 9248c2ecf20Sopenharmony_ci } 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci elf_ppnt = elf_phdata; 9278c2ecf20Sopenharmony_ci for (i = 0; i < elf_ex->e_phnum; i++, elf_ppnt++) 9288c2ecf20Sopenharmony_ci switch (elf_ppnt->p_type) { 9298c2ecf20Sopenharmony_ci case PT_GNU_STACK: 9308c2ecf20Sopenharmony_ci if (elf_ppnt->p_flags & PF_X) 9318c2ecf20Sopenharmony_ci executable_stack = EXSTACK_ENABLE_X; 9328c2ecf20Sopenharmony_ci else 9338c2ecf20Sopenharmony_ci executable_stack = EXSTACK_DISABLE_X; 9348c2ecf20Sopenharmony_ci break; 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci case PT_LOPROC ... PT_HIPROC: 9378c2ecf20Sopenharmony_ci retval = arch_elf_pt_proc(elf_ex, elf_ppnt, 9388c2ecf20Sopenharmony_ci bprm->file, false, 9398c2ecf20Sopenharmony_ci &arch_state); 9408c2ecf20Sopenharmony_ci if (retval) 9418c2ecf20Sopenharmony_ci goto out_free_dentry; 9428c2ecf20Sopenharmony_ci break; 9438c2ecf20Sopenharmony_ci } 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci /* Some simple consistency checks for the interpreter */ 9468c2ecf20Sopenharmony_ci if (interpreter) { 9478c2ecf20Sopenharmony_ci retval = -ELIBBAD; 9488c2ecf20Sopenharmony_ci /* Not an ELF interpreter */ 9498c2ecf20Sopenharmony_ci if (memcmp(interp_elf_ex->e_ident, ELFMAG, SELFMAG) != 0) 9508c2ecf20Sopenharmony_ci goto out_free_dentry; 9518c2ecf20Sopenharmony_ci /* Verify the interpreter has a valid arch */ 9528c2ecf20Sopenharmony_ci if (!elf_check_arch(interp_elf_ex) || 9538c2ecf20Sopenharmony_ci elf_check_fdpic(interp_elf_ex)) 9548c2ecf20Sopenharmony_ci goto out_free_dentry; 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci /* Load the interpreter program headers */ 9578c2ecf20Sopenharmony_ci interp_elf_phdata = load_elf_phdrs(interp_elf_ex, 9588c2ecf20Sopenharmony_ci interpreter); 9598c2ecf20Sopenharmony_ci if (!interp_elf_phdata) 9608c2ecf20Sopenharmony_ci goto out_free_dentry; 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci /* Pass PT_LOPROC..PT_HIPROC headers to arch code */ 9638c2ecf20Sopenharmony_ci elf_property_phdata = NULL; 9648c2ecf20Sopenharmony_ci elf_ppnt = interp_elf_phdata; 9658c2ecf20Sopenharmony_ci for (i = 0; i < interp_elf_ex->e_phnum; i++, elf_ppnt++) 9668c2ecf20Sopenharmony_ci switch (elf_ppnt->p_type) { 9678c2ecf20Sopenharmony_ci case PT_GNU_PROPERTY: 9688c2ecf20Sopenharmony_ci elf_property_phdata = elf_ppnt; 9698c2ecf20Sopenharmony_ci break; 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ci case PT_LOPROC ... PT_HIPROC: 9728c2ecf20Sopenharmony_ci retval = arch_elf_pt_proc(interp_elf_ex, 9738c2ecf20Sopenharmony_ci elf_ppnt, interpreter, 9748c2ecf20Sopenharmony_ci true, &arch_state); 9758c2ecf20Sopenharmony_ci if (retval) 9768c2ecf20Sopenharmony_ci goto out_free_dentry; 9778c2ecf20Sopenharmony_ci break; 9788c2ecf20Sopenharmony_ci } 9798c2ecf20Sopenharmony_ci } 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci retval = parse_elf_properties(interpreter ?: bprm->file, 9828c2ecf20Sopenharmony_ci elf_property_phdata, &arch_state); 9838c2ecf20Sopenharmony_ci if (retval) 9848c2ecf20Sopenharmony_ci goto out_free_dentry; 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci /* 9878c2ecf20Sopenharmony_ci * Allow arch code to reject the ELF at this point, whilst it's 9888c2ecf20Sopenharmony_ci * still possible to return an error to the code that invoked 9898c2ecf20Sopenharmony_ci * the exec syscall. 9908c2ecf20Sopenharmony_ci */ 9918c2ecf20Sopenharmony_ci retval = arch_check_elf(elf_ex, 9928c2ecf20Sopenharmony_ci !!interpreter, interp_elf_ex, 9938c2ecf20Sopenharmony_ci &arch_state); 9948c2ecf20Sopenharmony_ci if (retval) 9958c2ecf20Sopenharmony_ci goto out_free_dentry; 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ci /* Flush all traces of the currently running executable */ 9988c2ecf20Sopenharmony_ci retval = begin_new_exec(bprm); 9998c2ecf20Sopenharmony_ci if (retval) 10008c2ecf20Sopenharmony_ci goto out_free_dentry; 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci /* Do this immediately, since STACK_TOP as used in setup_arg_pages 10038c2ecf20Sopenharmony_ci may depend on the personality. */ 10048c2ecf20Sopenharmony_ci SET_PERSONALITY2(*elf_ex, &arch_state); 10058c2ecf20Sopenharmony_ci if (elf_read_implies_exec(*elf_ex, executable_stack)) 10068c2ecf20Sopenharmony_ci current->personality |= READ_IMPLIES_EXEC; 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space) 10098c2ecf20Sopenharmony_ci current->flags |= PF_RANDOMIZE; 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci setup_new_exec(bprm); 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_ci /* Do this so that we can load the interpreter, if need be. We will 10148c2ecf20Sopenharmony_ci change some of these later */ 10158c2ecf20Sopenharmony_ci retval = setup_arg_pages(bprm, randomize_stack_top(STACK_TOP), 10168c2ecf20Sopenharmony_ci executable_stack); 10178c2ecf20Sopenharmony_ci if (retval < 0) 10188c2ecf20Sopenharmony_ci goto out_free_dentry; 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ci elf_bss = 0; 10218c2ecf20Sopenharmony_ci elf_brk = 0; 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_ci start_code = ~0UL; 10248c2ecf20Sopenharmony_ci end_code = 0; 10258c2ecf20Sopenharmony_ci start_data = 0; 10268c2ecf20Sopenharmony_ci end_data = 0; 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci /* Now we do a little grungy work by mmapping the ELF image into 10298c2ecf20Sopenharmony_ci the correct location in memory. */ 10308c2ecf20Sopenharmony_ci for(i = 0, elf_ppnt = elf_phdata; 10318c2ecf20Sopenharmony_ci i < elf_ex->e_phnum; i++, elf_ppnt++) { 10328c2ecf20Sopenharmony_ci int elf_prot, elf_flags; 10338c2ecf20Sopenharmony_ci unsigned long k, vaddr; 10348c2ecf20Sopenharmony_ci unsigned long total_size = 0; 10358c2ecf20Sopenharmony_ci unsigned long alignment; 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci if (elf_ppnt->p_type == PT_OHOS_RANDOMDATA) { 10388c2ecf20Sopenharmony_ci void *temp_buf = NULL; 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_ci if (elf_ppnt->p_memsz > PT_OHOS_RANDOMDATA_SIZE_LIMIT) { 10418c2ecf20Sopenharmony_ci retval = -EINVAL; 10428c2ecf20Sopenharmony_ci goto out_free_dentry; 10438c2ecf20Sopenharmony_ci } 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci temp_buf = vmalloc(elf_ppnt->p_memsz); 10468c2ecf20Sopenharmony_ci if (!temp_buf) { 10478c2ecf20Sopenharmony_ci retval = -ENOMEM; 10488c2ecf20Sopenharmony_ci goto out_free_dentry; 10498c2ecf20Sopenharmony_ci } 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci get_random_bytes(temp_buf, (int)elf_ppnt->p_memsz); 10528c2ecf20Sopenharmony_ci if (copy_to_user((void *)(elf_ppnt->p_vaddr + load_bias), temp_buf, (unsigned long)elf_ppnt->p_memsz)) { 10538c2ecf20Sopenharmony_ci retval = -EFAULT; 10548c2ecf20Sopenharmony_ci vfree(temp_buf); 10558c2ecf20Sopenharmony_ci goto out_free_dentry; 10568c2ecf20Sopenharmony_ci } 10578c2ecf20Sopenharmony_ci vfree(temp_buf); 10588c2ecf20Sopenharmony_ci continue; 10598c2ecf20Sopenharmony_ci } 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ci if (elf_ppnt->p_type != PT_LOAD) 10628c2ecf20Sopenharmony_ci continue; 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci if (unlikely (elf_brk > elf_bss)) { 10658c2ecf20Sopenharmony_ci unsigned long nbyte; 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_ci /* There was a PT_LOAD segment with p_memsz > p_filesz 10688c2ecf20Sopenharmony_ci before this one. Map anonymous pages, if needed, 10698c2ecf20Sopenharmony_ci and clear the area. */ 10708c2ecf20Sopenharmony_ci retval = set_brk(elf_bss + load_bias, 10718c2ecf20Sopenharmony_ci elf_brk + load_bias, 10728c2ecf20Sopenharmony_ci bss_prot); 10738c2ecf20Sopenharmony_ci if (retval) 10748c2ecf20Sopenharmony_ci goto out_free_dentry; 10758c2ecf20Sopenharmony_ci nbyte = ELF_PAGEOFFSET(elf_bss); 10768c2ecf20Sopenharmony_ci if (nbyte) { 10778c2ecf20Sopenharmony_ci nbyte = ELF_MIN_ALIGN - nbyte; 10788c2ecf20Sopenharmony_ci if (nbyte > elf_brk - elf_bss) 10798c2ecf20Sopenharmony_ci nbyte = elf_brk - elf_bss; 10808c2ecf20Sopenharmony_ci if (clear_user((void __user *)elf_bss + 10818c2ecf20Sopenharmony_ci load_bias, nbyte)) { 10828c2ecf20Sopenharmony_ci /* 10838c2ecf20Sopenharmony_ci * This bss-zeroing can fail if the ELF 10848c2ecf20Sopenharmony_ci * file specifies odd protections. So 10858c2ecf20Sopenharmony_ci * we don't check the return value 10868c2ecf20Sopenharmony_ci */ 10878c2ecf20Sopenharmony_ci } 10888c2ecf20Sopenharmony_ci } 10898c2ecf20Sopenharmony_ci } 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci elf_prot = make_prot(elf_ppnt->p_flags, &arch_state, 10928c2ecf20Sopenharmony_ci !!interpreter, false); 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci elf_flags = MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE; 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci vaddr = elf_ppnt->p_vaddr; 10978c2ecf20Sopenharmony_ci /* 10988c2ecf20Sopenharmony_ci * If we are loading ET_EXEC or we have already performed 10998c2ecf20Sopenharmony_ci * the ET_DYN load_addr calculations, proceed normally. 11008c2ecf20Sopenharmony_ci */ 11018c2ecf20Sopenharmony_ci if (elf_ex->e_type == ET_EXEC || load_addr_set) { 11028c2ecf20Sopenharmony_ci elf_flags |= MAP_FIXED; 11038c2ecf20Sopenharmony_ci } else if (elf_ex->e_type == ET_DYN) { 11048c2ecf20Sopenharmony_ci /* 11058c2ecf20Sopenharmony_ci * This logic is run once for the first LOAD Program 11068c2ecf20Sopenharmony_ci * Header for ET_DYN binaries to calculate the 11078c2ecf20Sopenharmony_ci * randomization (load_bias) for all the LOAD 11088c2ecf20Sopenharmony_ci * Program Headers, and to calculate the entire 11098c2ecf20Sopenharmony_ci * size of the ELF mapping (total_size). (Note that 11108c2ecf20Sopenharmony_ci * load_addr_set is set to true later once the 11118c2ecf20Sopenharmony_ci * initial mapping is performed.) 11128c2ecf20Sopenharmony_ci * 11138c2ecf20Sopenharmony_ci * There are effectively two types of ET_DYN 11148c2ecf20Sopenharmony_ci * binaries: programs (i.e. PIE: ET_DYN with INTERP) 11158c2ecf20Sopenharmony_ci * and loaders (ET_DYN without INTERP, since they 11168c2ecf20Sopenharmony_ci * _are_ the ELF interpreter). The loaders must 11178c2ecf20Sopenharmony_ci * be loaded away from programs since the program 11188c2ecf20Sopenharmony_ci * may otherwise collide with the loader (especially 11198c2ecf20Sopenharmony_ci * for ET_EXEC which does not have a randomized 11208c2ecf20Sopenharmony_ci * position). For example to handle invocations of 11218c2ecf20Sopenharmony_ci * "./ld.so someprog" to test out a new version of 11228c2ecf20Sopenharmony_ci * the loader, the subsequent program that the 11238c2ecf20Sopenharmony_ci * loader loads must avoid the loader itself, so 11248c2ecf20Sopenharmony_ci * they cannot share the same load range. Sufficient 11258c2ecf20Sopenharmony_ci * room for the brk must be allocated with the 11268c2ecf20Sopenharmony_ci * loader as well, since brk must be available with 11278c2ecf20Sopenharmony_ci * the loader. 11288c2ecf20Sopenharmony_ci * 11298c2ecf20Sopenharmony_ci * Therefore, programs are loaded offset from 11308c2ecf20Sopenharmony_ci * ELF_ET_DYN_BASE and loaders are loaded into the 11318c2ecf20Sopenharmony_ci * independently randomized mmap region (0 load_bias 11328c2ecf20Sopenharmony_ci * without MAP_FIXED). 11338c2ecf20Sopenharmony_ci */ 11348c2ecf20Sopenharmony_ci if (interpreter) { 11358c2ecf20Sopenharmony_ci load_bias = ELF_ET_DYN_BASE; 11368c2ecf20Sopenharmony_ci if (current->flags & PF_RANDOMIZE) 11378c2ecf20Sopenharmony_ci load_bias += arch_mmap_rnd(); 11388c2ecf20Sopenharmony_ci alignment = maximum_alignment(elf_phdata, elf_ex->e_phnum); 11398c2ecf20Sopenharmony_ci if (alignment) 11408c2ecf20Sopenharmony_ci load_bias &= ~(alignment - 1); 11418c2ecf20Sopenharmony_ci elf_flags |= MAP_FIXED; 11428c2ecf20Sopenharmony_ci } else 11438c2ecf20Sopenharmony_ci load_bias = 0; 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci /* 11468c2ecf20Sopenharmony_ci * Since load_bias is used for all subsequent loading 11478c2ecf20Sopenharmony_ci * calculations, we must lower it by the first vaddr 11488c2ecf20Sopenharmony_ci * so that the remaining calculations based on the 11498c2ecf20Sopenharmony_ci * ELF vaddrs will be correctly offset. The result 11508c2ecf20Sopenharmony_ci * is then page aligned. 11518c2ecf20Sopenharmony_ci */ 11528c2ecf20Sopenharmony_ci load_bias = ELF_PAGESTART(load_bias - vaddr); 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ci total_size = total_mapping_size(elf_phdata, 11558c2ecf20Sopenharmony_ci elf_ex->e_phnum); 11568c2ecf20Sopenharmony_ci if (!total_size) { 11578c2ecf20Sopenharmony_ci retval = -EINVAL; 11588c2ecf20Sopenharmony_ci goto out_free_dentry; 11598c2ecf20Sopenharmony_ci } 11608c2ecf20Sopenharmony_ci } 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt, 11638c2ecf20Sopenharmony_ci elf_prot, elf_flags, total_size); 11648c2ecf20Sopenharmony_ci if (BAD_ADDR(error)) { 11658c2ecf20Sopenharmony_ci retval = IS_ERR((void *)error) ? 11668c2ecf20Sopenharmony_ci PTR_ERR((void*)error) : -EINVAL; 11678c2ecf20Sopenharmony_ci goto out_free_dentry; 11688c2ecf20Sopenharmony_ci } 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci if (!load_addr_set) { 11718c2ecf20Sopenharmony_ci load_addr_set = 1; 11728c2ecf20Sopenharmony_ci load_addr = (elf_ppnt->p_vaddr - elf_ppnt->p_offset); 11738c2ecf20Sopenharmony_ci if (elf_ex->e_type == ET_DYN) { 11748c2ecf20Sopenharmony_ci load_bias += error - 11758c2ecf20Sopenharmony_ci ELF_PAGESTART(load_bias + vaddr); 11768c2ecf20Sopenharmony_ci load_addr += load_bias; 11778c2ecf20Sopenharmony_ci reloc_func_desc = load_bias; 11788c2ecf20Sopenharmony_ci } 11798c2ecf20Sopenharmony_ci } 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_ci /* 11828c2ecf20Sopenharmony_ci * Figure out which segment in the file contains the Program 11838c2ecf20Sopenharmony_ci * Header table, and map to the associated memory address. 11848c2ecf20Sopenharmony_ci */ 11858c2ecf20Sopenharmony_ci if (elf_ppnt->p_offset <= elf_ex->e_phoff && 11868c2ecf20Sopenharmony_ci elf_ex->e_phoff < elf_ppnt->p_offset + elf_ppnt->p_filesz) { 11878c2ecf20Sopenharmony_ci phdr_addr = elf_ex->e_phoff - elf_ppnt->p_offset + 11888c2ecf20Sopenharmony_ci elf_ppnt->p_vaddr; 11898c2ecf20Sopenharmony_ci } 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_ci k = elf_ppnt->p_vaddr; 11928c2ecf20Sopenharmony_ci if ((elf_ppnt->p_flags & PF_X) && k < start_code) 11938c2ecf20Sopenharmony_ci start_code = k; 11948c2ecf20Sopenharmony_ci if (start_data < k) 11958c2ecf20Sopenharmony_ci start_data = k; 11968c2ecf20Sopenharmony_ci 11978c2ecf20Sopenharmony_ci /* 11988c2ecf20Sopenharmony_ci * Check to see if the section's size will overflow the 11998c2ecf20Sopenharmony_ci * allowed task size. Note that p_filesz must always be 12008c2ecf20Sopenharmony_ci * <= p_memsz so it is only necessary to check p_memsz. 12018c2ecf20Sopenharmony_ci */ 12028c2ecf20Sopenharmony_ci if (BAD_ADDR(k) || elf_ppnt->p_filesz > elf_ppnt->p_memsz || 12038c2ecf20Sopenharmony_ci elf_ppnt->p_memsz > TASK_SIZE || 12048c2ecf20Sopenharmony_ci TASK_SIZE - elf_ppnt->p_memsz < k) { 12058c2ecf20Sopenharmony_ci /* set_brk can never work. Avoid overflows. */ 12068c2ecf20Sopenharmony_ci retval = -EINVAL; 12078c2ecf20Sopenharmony_ci goto out_free_dentry; 12088c2ecf20Sopenharmony_ci } 12098c2ecf20Sopenharmony_ci 12108c2ecf20Sopenharmony_ci k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz; 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_ci if (k > elf_bss) 12138c2ecf20Sopenharmony_ci elf_bss = k; 12148c2ecf20Sopenharmony_ci if ((elf_ppnt->p_flags & PF_X) && end_code < k) 12158c2ecf20Sopenharmony_ci end_code = k; 12168c2ecf20Sopenharmony_ci if (end_data < k) 12178c2ecf20Sopenharmony_ci end_data = k; 12188c2ecf20Sopenharmony_ci k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz; 12198c2ecf20Sopenharmony_ci if (k > elf_brk) { 12208c2ecf20Sopenharmony_ci bss_prot = elf_prot; 12218c2ecf20Sopenharmony_ci elf_brk = k; 12228c2ecf20Sopenharmony_ci } 12238c2ecf20Sopenharmony_ci } 12248c2ecf20Sopenharmony_ci 12258c2ecf20Sopenharmony_ci e_entry = elf_ex->e_entry + load_bias; 12268c2ecf20Sopenharmony_ci phdr_addr += load_bias; 12278c2ecf20Sopenharmony_ci elf_bss += load_bias; 12288c2ecf20Sopenharmony_ci elf_brk += load_bias; 12298c2ecf20Sopenharmony_ci start_code += load_bias; 12308c2ecf20Sopenharmony_ci end_code += load_bias; 12318c2ecf20Sopenharmony_ci start_data += load_bias; 12328c2ecf20Sopenharmony_ci end_data += load_bias; 12338c2ecf20Sopenharmony_ci 12348c2ecf20Sopenharmony_ci /* Calling set_brk effectively mmaps the pages that we need 12358c2ecf20Sopenharmony_ci * for the bss and break sections. We must do this before 12368c2ecf20Sopenharmony_ci * mapping in the interpreter, to make sure it doesn't wind 12378c2ecf20Sopenharmony_ci * up getting placed where the bss needs to go. 12388c2ecf20Sopenharmony_ci */ 12398c2ecf20Sopenharmony_ci retval = set_brk(elf_bss, elf_brk, bss_prot); 12408c2ecf20Sopenharmony_ci if (retval) 12418c2ecf20Sopenharmony_ci goto out_free_dentry; 12428c2ecf20Sopenharmony_ci if (likely(elf_bss != elf_brk) && unlikely(padzero(elf_bss))) { 12438c2ecf20Sopenharmony_ci retval = -EFAULT; /* Nobody gets to see this, but.. */ 12448c2ecf20Sopenharmony_ci goto out_free_dentry; 12458c2ecf20Sopenharmony_ci } 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_ci if (interpreter) { 12488c2ecf20Sopenharmony_ci elf_entry = load_elf_interp(interp_elf_ex, 12498c2ecf20Sopenharmony_ci interpreter, 12508c2ecf20Sopenharmony_ci load_bias, interp_elf_phdata, 12518c2ecf20Sopenharmony_ci &arch_state); 12528c2ecf20Sopenharmony_ci if (!IS_ERR((void *)elf_entry)) { 12538c2ecf20Sopenharmony_ci /* 12548c2ecf20Sopenharmony_ci * load_elf_interp() returns relocation 12558c2ecf20Sopenharmony_ci * adjustment 12568c2ecf20Sopenharmony_ci */ 12578c2ecf20Sopenharmony_ci interp_load_addr = elf_entry; 12588c2ecf20Sopenharmony_ci elf_entry += interp_elf_ex->e_entry; 12598c2ecf20Sopenharmony_ci } 12608c2ecf20Sopenharmony_ci if (BAD_ADDR(elf_entry)) { 12618c2ecf20Sopenharmony_ci retval = IS_ERR((void *)elf_entry) ? 12628c2ecf20Sopenharmony_ci (int)elf_entry : -EINVAL; 12638c2ecf20Sopenharmony_ci goto out_free_dentry; 12648c2ecf20Sopenharmony_ci } 12658c2ecf20Sopenharmony_ci reloc_func_desc = interp_load_addr; 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci allow_write_access(interpreter); 12688c2ecf20Sopenharmony_ci fput(interpreter); 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_ci kfree(interp_elf_ex); 12718c2ecf20Sopenharmony_ci kfree(interp_elf_phdata); 12728c2ecf20Sopenharmony_ci } else { 12738c2ecf20Sopenharmony_ci elf_entry = e_entry; 12748c2ecf20Sopenharmony_ci if (BAD_ADDR(elf_entry)) { 12758c2ecf20Sopenharmony_ci retval = -EINVAL; 12768c2ecf20Sopenharmony_ci goto out_free_dentry; 12778c2ecf20Sopenharmony_ci } 12788c2ecf20Sopenharmony_ci } 12798c2ecf20Sopenharmony_ci 12808c2ecf20Sopenharmony_ci kfree(elf_phdata); 12818c2ecf20Sopenharmony_ci 12828c2ecf20Sopenharmony_ci set_binfmt(&elf_format); 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_ci#ifdef ARCH_HAS_SETUP_ADDITIONAL_PAGES 12858c2ecf20Sopenharmony_ci retval = arch_setup_additional_pages(bprm, !!interpreter); 12868c2ecf20Sopenharmony_ci if (retval < 0) 12878c2ecf20Sopenharmony_ci goto out; 12888c2ecf20Sopenharmony_ci#endif /* ARCH_HAS_SETUP_ADDITIONAL_PAGES */ 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_ci retval = create_elf_tables(bprm, elf_ex, interp_load_addr, 12918c2ecf20Sopenharmony_ci e_entry, phdr_addr); 12928c2ecf20Sopenharmony_ci if (retval < 0) 12938c2ecf20Sopenharmony_ci goto out; 12948c2ecf20Sopenharmony_ci 12958c2ecf20Sopenharmony_ci mm = current->mm; 12968c2ecf20Sopenharmony_ci mm->end_code = end_code; 12978c2ecf20Sopenharmony_ci mm->start_code = start_code; 12988c2ecf20Sopenharmony_ci mm->start_data = start_data; 12998c2ecf20Sopenharmony_ci mm->end_data = end_data; 13008c2ecf20Sopenharmony_ci mm->start_stack = bprm->p; 13018c2ecf20Sopenharmony_ci 13028c2ecf20Sopenharmony_ci if ((current->flags & PF_RANDOMIZE) && (randomize_va_space > 1)) { 13038c2ecf20Sopenharmony_ci /* 13048c2ecf20Sopenharmony_ci * For architectures with ELF randomization, when executing 13058c2ecf20Sopenharmony_ci * a loader directly (i.e. no interpreter listed in ELF 13068c2ecf20Sopenharmony_ci * headers), move the brk area out of the mmap region 13078c2ecf20Sopenharmony_ci * (since it grows up, and may collide early with the stack 13088c2ecf20Sopenharmony_ci * growing down), and into the unused ELF_ET_DYN_BASE region. 13098c2ecf20Sopenharmony_ci */ 13108c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_ARCH_HAS_ELF_RANDOMIZE) && 13118c2ecf20Sopenharmony_ci elf_ex->e_type == ET_DYN && !interpreter) { 13128c2ecf20Sopenharmony_ci mm->brk = mm->start_brk = ELF_ET_DYN_BASE; 13138c2ecf20Sopenharmony_ci } 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_ci mm->brk = mm->start_brk = arch_randomize_brk(mm); 13168c2ecf20Sopenharmony_ci#ifdef compat_brk_randomized 13178c2ecf20Sopenharmony_ci current->brk_randomized = 1; 13188c2ecf20Sopenharmony_ci#endif 13198c2ecf20Sopenharmony_ci } 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_ci if (current->personality & MMAP_PAGE_ZERO) { 13228c2ecf20Sopenharmony_ci /* Why this, you ask??? Well SVr4 maps page 0 as read-only, 13238c2ecf20Sopenharmony_ci and some applications "depend" upon this behavior. 13248c2ecf20Sopenharmony_ci Since we do not have the power to recompile these, we 13258c2ecf20Sopenharmony_ci emulate the SVr4 behavior. Sigh. */ 13268c2ecf20Sopenharmony_ci error = vm_mmap(NULL, 0, PAGE_SIZE, PROT_READ | PROT_EXEC, 13278c2ecf20Sopenharmony_ci MAP_FIXED | MAP_PRIVATE, 0); 13288c2ecf20Sopenharmony_ci } 13298c2ecf20Sopenharmony_ci 13308c2ecf20Sopenharmony_ci regs = current_pt_regs(); 13318c2ecf20Sopenharmony_ci#ifdef ELF_PLAT_INIT 13328c2ecf20Sopenharmony_ci /* 13338c2ecf20Sopenharmony_ci * The ABI may specify that certain registers be set up in special 13348c2ecf20Sopenharmony_ci * ways (on i386 %edx is the address of a DT_FINI function, for 13358c2ecf20Sopenharmony_ci * example. In addition, it may also specify (eg, PowerPC64 ELF) 13368c2ecf20Sopenharmony_ci * that the e_entry field is the address of the function descriptor 13378c2ecf20Sopenharmony_ci * for the startup routine, rather than the address of the startup 13388c2ecf20Sopenharmony_ci * routine itself. This macro performs whatever initialization to 13398c2ecf20Sopenharmony_ci * the regs structure is required as well as any relocations to the 13408c2ecf20Sopenharmony_ci * function descriptor entries when executing dynamically links apps. 13418c2ecf20Sopenharmony_ci */ 13428c2ecf20Sopenharmony_ci ELF_PLAT_INIT(regs, reloc_func_desc); 13438c2ecf20Sopenharmony_ci#endif 13448c2ecf20Sopenharmony_ci 13458c2ecf20Sopenharmony_ci finalize_exec(bprm); 13468c2ecf20Sopenharmony_ci start_thread(regs, elf_entry, bprm->p); 13478c2ecf20Sopenharmony_ci retval = 0; 13488c2ecf20Sopenharmony_ciout: 13498c2ecf20Sopenharmony_ci return retval; 13508c2ecf20Sopenharmony_ci 13518c2ecf20Sopenharmony_ci /* error cleanup */ 13528c2ecf20Sopenharmony_ciout_free_dentry: 13538c2ecf20Sopenharmony_ci kfree(interp_elf_ex); 13548c2ecf20Sopenharmony_ci kfree(interp_elf_phdata); 13558c2ecf20Sopenharmony_ciout_free_file: 13568c2ecf20Sopenharmony_ci allow_write_access(interpreter); 13578c2ecf20Sopenharmony_ci if (interpreter) 13588c2ecf20Sopenharmony_ci fput(interpreter); 13598c2ecf20Sopenharmony_ciout_free_ph: 13608c2ecf20Sopenharmony_ci kfree(elf_phdata); 13618c2ecf20Sopenharmony_ci goto out; 13628c2ecf20Sopenharmony_ci} 13638c2ecf20Sopenharmony_ci 13648c2ecf20Sopenharmony_ci#ifdef CONFIG_USELIB 13658c2ecf20Sopenharmony_ci/* This is really simpleminded and specialized - we are loading an 13668c2ecf20Sopenharmony_ci a.out library that is given an ELF header. */ 13678c2ecf20Sopenharmony_cistatic int load_elf_library(struct file *file) 13688c2ecf20Sopenharmony_ci{ 13698c2ecf20Sopenharmony_ci struct elf_phdr *elf_phdata; 13708c2ecf20Sopenharmony_ci struct elf_phdr *eppnt; 13718c2ecf20Sopenharmony_ci unsigned long elf_bss, bss, len; 13728c2ecf20Sopenharmony_ci int retval, error, i, j; 13738c2ecf20Sopenharmony_ci struct elfhdr elf_ex; 13748c2ecf20Sopenharmony_ci 13758c2ecf20Sopenharmony_ci error = -ENOEXEC; 13768c2ecf20Sopenharmony_ci retval = elf_read(file, &elf_ex, sizeof(elf_ex), 0); 13778c2ecf20Sopenharmony_ci if (retval < 0) 13788c2ecf20Sopenharmony_ci goto out; 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_ci if (memcmp(elf_ex.e_ident, ELFMAG, SELFMAG) != 0) 13818c2ecf20Sopenharmony_ci goto out; 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_ci /* First of all, some simple consistency checks */ 13848c2ecf20Sopenharmony_ci if (elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 || 13858c2ecf20Sopenharmony_ci !elf_check_arch(&elf_ex) || !file->f_op->mmap) 13868c2ecf20Sopenharmony_ci goto out; 13878c2ecf20Sopenharmony_ci if (elf_check_fdpic(&elf_ex)) 13888c2ecf20Sopenharmony_ci goto out; 13898c2ecf20Sopenharmony_ci 13908c2ecf20Sopenharmony_ci /* Now read in all of the header information */ 13918c2ecf20Sopenharmony_ci 13928c2ecf20Sopenharmony_ci j = sizeof(struct elf_phdr) * elf_ex.e_phnum; 13938c2ecf20Sopenharmony_ci /* j < ELF_MIN_ALIGN because elf_ex.e_phnum <= 2 */ 13948c2ecf20Sopenharmony_ci 13958c2ecf20Sopenharmony_ci error = -ENOMEM; 13968c2ecf20Sopenharmony_ci elf_phdata = kmalloc(j, GFP_KERNEL); 13978c2ecf20Sopenharmony_ci if (!elf_phdata) 13988c2ecf20Sopenharmony_ci goto out; 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_ci eppnt = elf_phdata; 14018c2ecf20Sopenharmony_ci error = -ENOEXEC; 14028c2ecf20Sopenharmony_ci retval = elf_read(file, eppnt, j, elf_ex.e_phoff); 14038c2ecf20Sopenharmony_ci if (retval < 0) 14048c2ecf20Sopenharmony_ci goto out_free_ph; 14058c2ecf20Sopenharmony_ci 14068c2ecf20Sopenharmony_ci for (j = 0, i = 0; i<elf_ex.e_phnum; i++) 14078c2ecf20Sopenharmony_ci if ((eppnt + i)->p_type == PT_LOAD) 14088c2ecf20Sopenharmony_ci j++; 14098c2ecf20Sopenharmony_ci if (j != 1) 14108c2ecf20Sopenharmony_ci goto out_free_ph; 14118c2ecf20Sopenharmony_ci 14128c2ecf20Sopenharmony_ci while (eppnt->p_type != PT_LOAD) 14138c2ecf20Sopenharmony_ci eppnt++; 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_ci /* Now use mmap to map the library into memory. */ 14168c2ecf20Sopenharmony_ci error = vm_mmap(file, 14178c2ecf20Sopenharmony_ci ELF_PAGESTART(eppnt->p_vaddr), 14188c2ecf20Sopenharmony_ci (eppnt->p_filesz + 14198c2ecf20Sopenharmony_ci ELF_PAGEOFFSET(eppnt->p_vaddr)), 14208c2ecf20Sopenharmony_ci PROT_READ | PROT_WRITE | PROT_EXEC, 14218c2ecf20Sopenharmony_ci MAP_FIXED_NOREPLACE | MAP_PRIVATE | MAP_DENYWRITE, 14228c2ecf20Sopenharmony_ci (eppnt->p_offset - 14238c2ecf20Sopenharmony_ci ELF_PAGEOFFSET(eppnt->p_vaddr))); 14248c2ecf20Sopenharmony_ci if (error != ELF_PAGESTART(eppnt->p_vaddr)) 14258c2ecf20Sopenharmony_ci goto out_free_ph; 14268c2ecf20Sopenharmony_ci 14278c2ecf20Sopenharmony_ci elf_bss = eppnt->p_vaddr + eppnt->p_filesz; 14288c2ecf20Sopenharmony_ci if (padzero(elf_bss)) { 14298c2ecf20Sopenharmony_ci error = -EFAULT; 14308c2ecf20Sopenharmony_ci goto out_free_ph; 14318c2ecf20Sopenharmony_ci } 14328c2ecf20Sopenharmony_ci 14338c2ecf20Sopenharmony_ci len = ELF_PAGEALIGN(eppnt->p_filesz + eppnt->p_vaddr); 14348c2ecf20Sopenharmony_ci bss = ELF_PAGEALIGN(eppnt->p_memsz + eppnt->p_vaddr); 14358c2ecf20Sopenharmony_ci if (bss > len) { 14368c2ecf20Sopenharmony_ci error = vm_brk(len, bss - len); 14378c2ecf20Sopenharmony_ci if (error) 14388c2ecf20Sopenharmony_ci goto out_free_ph; 14398c2ecf20Sopenharmony_ci } 14408c2ecf20Sopenharmony_ci error = 0; 14418c2ecf20Sopenharmony_ci 14428c2ecf20Sopenharmony_ciout_free_ph: 14438c2ecf20Sopenharmony_ci kfree(elf_phdata); 14448c2ecf20Sopenharmony_ciout: 14458c2ecf20Sopenharmony_ci return error; 14468c2ecf20Sopenharmony_ci} 14478c2ecf20Sopenharmony_ci#endif /* #ifdef CONFIG_USELIB */ 14488c2ecf20Sopenharmony_ci 14498c2ecf20Sopenharmony_ci#ifdef CONFIG_ELF_CORE 14508c2ecf20Sopenharmony_ci/* 14518c2ecf20Sopenharmony_ci * ELF core dumper 14528c2ecf20Sopenharmony_ci * 14538c2ecf20Sopenharmony_ci * Modelled on fs/exec.c:aout_core_dump() 14548c2ecf20Sopenharmony_ci * Jeremy Fitzhardinge <jeremy@sw.oz.au> 14558c2ecf20Sopenharmony_ci */ 14568c2ecf20Sopenharmony_ci 14578c2ecf20Sopenharmony_ci/* An ELF note in memory */ 14588c2ecf20Sopenharmony_cistruct memelfnote 14598c2ecf20Sopenharmony_ci{ 14608c2ecf20Sopenharmony_ci const char *name; 14618c2ecf20Sopenharmony_ci int type; 14628c2ecf20Sopenharmony_ci unsigned int datasz; 14638c2ecf20Sopenharmony_ci void *data; 14648c2ecf20Sopenharmony_ci}; 14658c2ecf20Sopenharmony_ci 14668c2ecf20Sopenharmony_cistatic int notesize(struct memelfnote *en) 14678c2ecf20Sopenharmony_ci{ 14688c2ecf20Sopenharmony_ci int sz; 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_ci sz = sizeof(struct elf_note); 14718c2ecf20Sopenharmony_ci sz += roundup(strlen(en->name) + 1, 4); 14728c2ecf20Sopenharmony_ci sz += roundup(en->datasz, 4); 14738c2ecf20Sopenharmony_ci 14748c2ecf20Sopenharmony_ci return sz; 14758c2ecf20Sopenharmony_ci} 14768c2ecf20Sopenharmony_ci 14778c2ecf20Sopenharmony_cistatic int writenote(struct memelfnote *men, struct coredump_params *cprm) 14788c2ecf20Sopenharmony_ci{ 14798c2ecf20Sopenharmony_ci struct elf_note en; 14808c2ecf20Sopenharmony_ci en.n_namesz = strlen(men->name) + 1; 14818c2ecf20Sopenharmony_ci en.n_descsz = men->datasz; 14828c2ecf20Sopenharmony_ci en.n_type = men->type; 14838c2ecf20Sopenharmony_ci 14848c2ecf20Sopenharmony_ci return dump_emit(cprm, &en, sizeof(en)) && 14858c2ecf20Sopenharmony_ci dump_emit(cprm, men->name, en.n_namesz) && dump_align(cprm, 4) && 14868c2ecf20Sopenharmony_ci dump_emit(cprm, men->data, men->datasz) && dump_align(cprm, 4); 14878c2ecf20Sopenharmony_ci} 14888c2ecf20Sopenharmony_ci 14898c2ecf20Sopenharmony_cistatic void fill_elf_header(struct elfhdr *elf, int segs, 14908c2ecf20Sopenharmony_ci u16 machine, u32 flags) 14918c2ecf20Sopenharmony_ci{ 14928c2ecf20Sopenharmony_ci memset(elf, 0, sizeof(*elf)); 14938c2ecf20Sopenharmony_ci 14948c2ecf20Sopenharmony_ci memcpy(elf->e_ident, ELFMAG, SELFMAG); 14958c2ecf20Sopenharmony_ci elf->e_ident[EI_CLASS] = ELF_CLASS; 14968c2ecf20Sopenharmony_ci elf->e_ident[EI_DATA] = ELF_DATA; 14978c2ecf20Sopenharmony_ci elf->e_ident[EI_VERSION] = EV_CURRENT; 14988c2ecf20Sopenharmony_ci elf->e_ident[EI_OSABI] = ELF_OSABI; 14998c2ecf20Sopenharmony_ci 15008c2ecf20Sopenharmony_ci elf->e_type = ET_CORE; 15018c2ecf20Sopenharmony_ci elf->e_machine = machine; 15028c2ecf20Sopenharmony_ci elf->e_version = EV_CURRENT; 15038c2ecf20Sopenharmony_ci elf->e_phoff = sizeof(struct elfhdr); 15048c2ecf20Sopenharmony_ci elf->e_flags = flags; 15058c2ecf20Sopenharmony_ci elf->e_ehsize = sizeof(struct elfhdr); 15068c2ecf20Sopenharmony_ci elf->e_phentsize = sizeof(struct elf_phdr); 15078c2ecf20Sopenharmony_ci elf->e_phnum = segs; 15088c2ecf20Sopenharmony_ci} 15098c2ecf20Sopenharmony_ci 15108c2ecf20Sopenharmony_cistatic void fill_elf_note_phdr(struct elf_phdr *phdr, int sz, loff_t offset) 15118c2ecf20Sopenharmony_ci{ 15128c2ecf20Sopenharmony_ci phdr->p_type = PT_NOTE; 15138c2ecf20Sopenharmony_ci phdr->p_offset = offset; 15148c2ecf20Sopenharmony_ci phdr->p_vaddr = 0; 15158c2ecf20Sopenharmony_ci phdr->p_paddr = 0; 15168c2ecf20Sopenharmony_ci phdr->p_filesz = sz; 15178c2ecf20Sopenharmony_ci phdr->p_memsz = 0; 15188c2ecf20Sopenharmony_ci phdr->p_flags = 0; 15198c2ecf20Sopenharmony_ci phdr->p_align = 0; 15208c2ecf20Sopenharmony_ci} 15218c2ecf20Sopenharmony_ci 15228c2ecf20Sopenharmony_cistatic void fill_note(struct memelfnote *note, const char *name, int type, 15238c2ecf20Sopenharmony_ci unsigned int sz, void *data) 15248c2ecf20Sopenharmony_ci{ 15258c2ecf20Sopenharmony_ci note->name = name; 15268c2ecf20Sopenharmony_ci note->type = type; 15278c2ecf20Sopenharmony_ci note->datasz = sz; 15288c2ecf20Sopenharmony_ci note->data = data; 15298c2ecf20Sopenharmony_ci} 15308c2ecf20Sopenharmony_ci 15318c2ecf20Sopenharmony_ci/* 15328c2ecf20Sopenharmony_ci * fill up all the fields in prstatus from the given task struct, except 15338c2ecf20Sopenharmony_ci * registers which need to be filled up separately. 15348c2ecf20Sopenharmony_ci */ 15358c2ecf20Sopenharmony_cistatic void fill_prstatus(struct elf_prstatus *prstatus, 15368c2ecf20Sopenharmony_ci struct task_struct *p, long signr) 15378c2ecf20Sopenharmony_ci{ 15388c2ecf20Sopenharmony_ci prstatus->pr_info.si_signo = prstatus->pr_cursig = signr; 15398c2ecf20Sopenharmony_ci prstatus->pr_sigpend = p->pending.signal.sig[0]; 15408c2ecf20Sopenharmony_ci prstatus->pr_sighold = p->blocked.sig[0]; 15418c2ecf20Sopenharmony_ci rcu_read_lock(); 15428c2ecf20Sopenharmony_ci prstatus->pr_ppid = task_pid_vnr(rcu_dereference(p->real_parent)); 15438c2ecf20Sopenharmony_ci rcu_read_unlock(); 15448c2ecf20Sopenharmony_ci prstatus->pr_pid = task_pid_vnr(p); 15458c2ecf20Sopenharmony_ci prstatus->pr_pgrp = task_pgrp_vnr(p); 15468c2ecf20Sopenharmony_ci prstatus->pr_sid = task_session_vnr(p); 15478c2ecf20Sopenharmony_ci if (thread_group_leader(p)) { 15488c2ecf20Sopenharmony_ci struct task_cputime cputime; 15498c2ecf20Sopenharmony_ci 15508c2ecf20Sopenharmony_ci /* 15518c2ecf20Sopenharmony_ci * This is the record for the group leader. It shows the 15528c2ecf20Sopenharmony_ci * group-wide total, not its individual thread total. 15538c2ecf20Sopenharmony_ci */ 15548c2ecf20Sopenharmony_ci thread_group_cputime(p, &cputime); 15558c2ecf20Sopenharmony_ci prstatus->pr_utime = ns_to_kernel_old_timeval(cputime.utime); 15568c2ecf20Sopenharmony_ci prstatus->pr_stime = ns_to_kernel_old_timeval(cputime.stime); 15578c2ecf20Sopenharmony_ci } else { 15588c2ecf20Sopenharmony_ci u64 utime, stime; 15598c2ecf20Sopenharmony_ci 15608c2ecf20Sopenharmony_ci task_cputime(p, &utime, &stime); 15618c2ecf20Sopenharmony_ci prstatus->pr_utime = ns_to_kernel_old_timeval(utime); 15628c2ecf20Sopenharmony_ci prstatus->pr_stime = ns_to_kernel_old_timeval(stime); 15638c2ecf20Sopenharmony_ci } 15648c2ecf20Sopenharmony_ci 15658c2ecf20Sopenharmony_ci prstatus->pr_cutime = ns_to_kernel_old_timeval(p->signal->cutime); 15668c2ecf20Sopenharmony_ci prstatus->pr_cstime = ns_to_kernel_old_timeval(p->signal->cstime); 15678c2ecf20Sopenharmony_ci} 15688c2ecf20Sopenharmony_ci 15698c2ecf20Sopenharmony_cistatic int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p, 15708c2ecf20Sopenharmony_ci struct mm_struct *mm) 15718c2ecf20Sopenharmony_ci{ 15728c2ecf20Sopenharmony_ci const struct cred *cred; 15738c2ecf20Sopenharmony_ci unsigned int i, len; 15748c2ecf20Sopenharmony_ci 15758c2ecf20Sopenharmony_ci /* first copy the parameters from user space */ 15768c2ecf20Sopenharmony_ci memset(psinfo, 0, sizeof(struct elf_prpsinfo)); 15778c2ecf20Sopenharmony_ci 15788c2ecf20Sopenharmony_ci len = mm->arg_end - mm->arg_start; 15798c2ecf20Sopenharmony_ci if (len >= ELF_PRARGSZ) 15808c2ecf20Sopenharmony_ci len = ELF_PRARGSZ-1; 15818c2ecf20Sopenharmony_ci if (copy_from_user(&psinfo->pr_psargs, 15828c2ecf20Sopenharmony_ci (const char __user *)mm->arg_start, len)) 15838c2ecf20Sopenharmony_ci return -EFAULT; 15848c2ecf20Sopenharmony_ci for(i = 0; i < len; i++) 15858c2ecf20Sopenharmony_ci if (psinfo->pr_psargs[i] == 0) 15868c2ecf20Sopenharmony_ci psinfo->pr_psargs[i] = ' '; 15878c2ecf20Sopenharmony_ci psinfo->pr_psargs[len] = 0; 15888c2ecf20Sopenharmony_ci 15898c2ecf20Sopenharmony_ci rcu_read_lock(); 15908c2ecf20Sopenharmony_ci psinfo->pr_ppid = task_pid_vnr(rcu_dereference(p->real_parent)); 15918c2ecf20Sopenharmony_ci rcu_read_unlock(); 15928c2ecf20Sopenharmony_ci psinfo->pr_pid = task_pid_vnr(p); 15938c2ecf20Sopenharmony_ci psinfo->pr_pgrp = task_pgrp_vnr(p); 15948c2ecf20Sopenharmony_ci psinfo->pr_sid = task_session_vnr(p); 15958c2ecf20Sopenharmony_ci 15968c2ecf20Sopenharmony_ci i = p->state ? ffz(~p->state) + 1 : 0; 15978c2ecf20Sopenharmony_ci psinfo->pr_state = i; 15988c2ecf20Sopenharmony_ci psinfo->pr_sname = (i > 5) ? '.' : "RSDTZW"[i]; 15998c2ecf20Sopenharmony_ci psinfo->pr_zomb = psinfo->pr_sname == 'Z'; 16008c2ecf20Sopenharmony_ci psinfo->pr_nice = task_nice(p); 16018c2ecf20Sopenharmony_ci psinfo->pr_flag = p->flags; 16028c2ecf20Sopenharmony_ci rcu_read_lock(); 16038c2ecf20Sopenharmony_ci cred = __task_cred(p); 16048c2ecf20Sopenharmony_ci SET_UID(psinfo->pr_uid, from_kuid_munged(cred->user_ns, cred->uid)); 16058c2ecf20Sopenharmony_ci SET_GID(psinfo->pr_gid, from_kgid_munged(cred->user_ns, cred->gid)); 16068c2ecf20Sopenharmony_ci rcu_read_unlock(); 16078c2ecf20Sopenharmony_ci strncpy(psinfo->pr_fname, p->comm, sizeof(psinfo->pr_fname)); 16088c2ecf20Sopenharmony_ci 16098c2ecf20Sopenharmony_ci return 0; 16108c2ecf20Sopenharmony_ci} 16118c2ecf20Sopenharmony_ci 16128c2ecf20Sopenharmony_cistatic void fill_auxv_note(struct memelfnote *note, struct mm_struct *mm) 16138c2ecf20Sopenharmony_ci{ 16148c2ecf20Sopenharmony_ci elf_addr_t *auxv = (elf_addr_t *) mm->saved_auxv; 16158c2ecf20Sopenharmony_ci int i = 0; 16168c2ecf20Sopenharmony_ci do 16178c2ecf20Sopenharmony_ci i += 2; 16188c2ecf20Sopenharmony_ci while (auxv[i - 2] != AT_NULL); 16198c2ecf20Sopenharmony_ci fill_note(note, "CORE", NT_AUXV, i * sizeof(elf_addr_t), auxv); 16208c2ecf20Sopenharmony_ci} 16218c2ecf20Sopenharmony_ci 16228c2ecf20Sopenharmony_cistatic void fill_siginfo_note(struct memelfnote *note, user_siginfo_t *csigdata, 16238c2ecf20Sopenharmony_ci const kernel_siginfo_t *siginfo) 16248c2ecf20Sopenharmony_ci{ 16258c2ecf20Sopenharmony_ci copy_siginfo_to_external(csigdata, siginfo); 16268c2ecf20Sopenharmony_ci fill_note(note, "CORE", NT_SIGINFO, sizeof(*csigdata), csigdata); 16278c2ecf20Sopenharmony_ci} 16288c2ecf20Sopenharmony_ci 16298c2ecf20Sopenharmony_ci#define MAX_FILE_NOTE_SIZE (4*1024*1024) 16308c2ecf20Sopenharmony_ci/* 16318c2ecf20Sopenharmony_ci * Format of NT_FILE note: 16328c2ecf20Sopenharmony_ci * 16338c2ecf20Sopenharmony_ci * long count -- how many files are mapped 16348c2ecf20Sopenharmony_ci * long page_size -- units for file_ofs 16358c2ecf20Sopenharmony_ci * array of [COUNT] elements of 16368c2ecf20Sopenharmony_ci * long start 16378c2ecf20Sopenharmony_ci * long end 16388c2ecf20Sopenharmony_ci * long file_ofs 16398c2ecf20Sopenharmony_ci * followed by COUNT filenames in ASCII: "FILE1" NUL "FILE2" NUL... 16408c2ecf20Sopenharmony_ci */ 16418c2ecf20Sopenharmony_cistatic int fill_files_note(struct memelfnote *note, struct coredump_params *cprm) 16428c2ecf20Sopenharmony_ci{ 16438c2ecf20Sopenharmony_ci unsigned count, size, names_ofs, remaining, n; 16448c2ecf20Sopenharmony_ci user_long_t *data; 16458c2ecf20Sopenharmony_ci user_long_t *start_end_ofs; 16468c2ecf20Sopenharmony_ci char *name_base, *name_curpos; 16478c2ecf20Sopenharmony_ci int i; 16488c2ecf20Sopenharmony_ci 16498c2ecf20Sopenharmony_ci /* *Estimated* file count and total data size needed */ 16508c2ecf20Sopenharmony_ci count = cprm->vma_count; 16518c2ecf20Sopenharmony_ci if (count > UINT_MAX / 64) 16528c2ecf20Sopenharmony_ci return -EINVAL; 16538c2ecf20Sopenharmony_ci size = count * 64; 16548c2ecf20Sopenharmony_ci 16558c2ecf20Sopenharmony_ci names_ofs = (2 + 3 * count) * sizeof(data[0]); 16568c2ecf20Sopenharmony_ci alloc: 16578c2ecf20Sopenharmony_ci if (size >= MAX_FILE_NOTE_SIZE) /* paranoia check */ 16588c2ecf20Sopenharmony_ci return -EINVAL; 16598c2ecf20Sopenharmony_ci size = round_up(size, PAGE_SIZE); 16608c2ecf20Sopenharmony_ci /* 16618c2ecf20Sopenharmony_ci * "size" can be 0 here legitimately. 16628c2ecf20Sopenharmony_ci * Let it ENOMEM and omit NT_FILE section which will be empty anyway. 16638c2ecf20Sopenharmony_ci */ 16648c2ecf20Sopenharmony_ci data = kvmalloc(size, GFP_KERNEL); 16658c2ecf20Sopenharmony_ci if (ZERO_OR_NULL_PTR(data)) 16668c2ecf20Sopenharmony_ci return -ENOMEM; 16678c2ecf20Sopenharmony_ci 16688c2ecf20Sopenharmony_ci start_end_ofs = data + 2; 16698c2ecf20Sopenharmony_ci name_base = name_curpos = ((char *)data) + names_ofs; 16708c2ecf20Sopenharmony_ci remaining = size - names_ofs; 16718c2ecf20Sopenharmony_ci count = 0; 16728c2ecf20Sopenharmony_ci for (i = 0; i < cprm->vma_count; i++) { 16738c2ecf20Sopenharmony_ci struct core_vma_metadata *m = &cprm->vma_meta[i]; 16748c2ecf20Sopenharmony_ci struct file *file; 16758c2ecf20Sopenharmony_ci const char *filename; 16768c2ecf20Sopenharmony_ci 16778c2ecf20Sopenharmony_ci file = m->file; 16788c2ecf20Sopenharmony_ci if (!file) 16798c2ecf20Sopenharmony_ci continue; 16808c2ecf20Sopenharmony_ci filename = file_path(file, name_curpos, remaining); 16818c2ecf20Sopenharmony_ci if (IS_ERR(filename)) { 16828c2ecf20Sopenharmony_ci if (PTR_ERR(filename) == -ENAMETOOLONG) { 16838c2ecf20Sopenharmony_ci kvfree(data); 16848c2ecf20Sopenharmony_ci size = size * 5 / 4; 16858c2ecf20Sopenharmony_ci goto alloc; 16868c2ecf20Sopenharmony_ci } 16878c2ecf20Sopenharmony_ci continue; 16888c2ecf20Sopenharmony_ci } 16898c2ecf20Sopenharmony_ci 16908c2ecf20Sopenharmony_ci /* file_path() fills at the end, move name down */ 16918c2ecf20Sopenharmony_ci /* n = strlen(filename) + 1: */ 16928c2ecf20Sopenharmony_ci n = (name_curpos + remaining) - filename; 16938c2ecf20Sopenharmony_ci remaining = filename - name_curpos; 16948c2ecf20Sopenharmony_ci memmove(name_curpos, filename, n); 16958c2ecf20Sopenharmony_ci name_curpos += n; 16968c2ecf20Sopenharmony_ci 16978c2ecf20Sopenharmony_ci *start_end_ofs++ = m->start; 16988c2ecf20Sopenharmony_ci *start_end_ofs++ = m->end; 16998c2ecf20Sopenharmony_ci *start_end_ofs++ = m->pgoff; 17008c2ecf20Sopenharmony_ci count++; 17018c2ecf20Sopenharmony_ci } 17028c2ecf20Sopenharmony_ci 17038c2ecf20Sopenharmony_ci /* Now we know exact count of files, can store it */ 17048c2ecf20Sopenharmony_ci data[0] = count; 17058c2ecf20Sopenharmony_ci data[1] = PAGE_SIZE; 17068c2ecf20Sopenharmony_ci /* 17078c2ecf20Sopenharmony_ci * Count usually is less than mm->map_count, 17088c2ecf20Sopenharmony_ci * we need to move filenames down. 17098c2ecf20Sopenharmony_ci */ 17108c2ecf20Sopenharmony_ci n = cprm->vma_count - count; 17118c2ecf20Sopenharmony_ci if (n != 0) { 17128c2ecf20Sopenharmony_ci unsigned shift_bytes = n * 3 * sizeof(data[0]); 17138c2ecf20Sopenharmony_ci memmove(name_base - shift_bytes, name_base, 17148c2ecf20Sopenharmony_ci name_curpos - name_base); 17158c2ecf20Sopenharmony_ci name_curpos -= shift_bytes; 17168c2ecf20Sopenharmony_ci } 17178c2ecf20Sopenharmony_ci 17188c2ecf20Sopenharmony_ci size = name_curpos - (char *)data; 17198c2ecf20Sopenharmony_ci fill_note(note, "CORE", NT_FILE, size, data); 17208c2ecf20Sopenharmony_ci return 0; 17218c2ecf20Sopenharmony_ci} 17228c2ecf20Sopenharmony_ci 17238c2ecf20Sopenharmony_ci#ifdef CORE_DUMP_USE_REGSET 17248c2ecf20Sopenharmony_ci#include <linux/regset.h> 17258c2ecf20Sopenharmony_ci 17268c2ecf20Sopenharmony_cistruct elf_thread_core_info { 17278c2ecf20Sopenharmony_ci struct elf_thread_core_info *next; 17288c2ecf20Sopenharmony_ci struct task_struct *task; 17298c2ecf20Sopenharmony_ci struct elf_prstatus prstatus; 17308c2ecf20Sopenharmony_ci struct memelfnote notes[]; 17318c2ecf20Sopenharmony_ci}; 17328c2ecf20Sopenharmony_ci 17338c2ecf20Sopenharmony_cistruct elf_note_info { 17348c2ecf20Sopenharmony_ci struct elf_thread_core_info *thread; 17358c2ecf20Sopenharmony_ci struct memelfnote psinfo; 17368c2ecf20Sopenharmony_ci struct memelfnote signote; 17378c2ecf20Sopenharmony_ci struct memelfnote auxv; 17388c2ecf20Sopenharmony_ci struct memelfnote files; 17398c2ecf20Sopenharmony_ci user_siginfo_t csigdata; 17408c2ecf20Sopenharmony_ci size_t size; 17418c2ecf20Sopenharmony_ci int thread_notes; 17428c2ecf20Sopenharmony_ci}; 17438c2ecf20Sopenharmony_ci 17448c2ecf20Sopenharmony_ci/* 17458c2ecf20Sopenharmony_ci * When a regset has a writeback hook, we call it on each thread before 17468c2ecf20Sopenharmony_ci * dumping user memory. On register window machines, this makes sure the 17478c2ecf20Sopenharmony_ci * user memory backing the register data is up to date before we read it. 17488c2ecf20Sopenharmony_ci */ 17498c2ecf20Sopenharmony_cistatic void do_thread_regset_writeback(struct task_struct *task, 17508c2ecf20Sopenharmony_ci const struct user_regset *regset) 17518c2ecf20Sopenharmony_ci{ 17528c2ecf20Sopenharmony_ci if (regset->writeback) 17538c2ecf20Sopenharmony_ci regset->writeback(task, regset, 1); 17548c2ecf20Sopenharmony_ci} 17558c2ecf20Sopenharmony_ci 17568c2ecf20Sopenharmony_ci#ifndef PRSTATUS_SIZE 17578c2ecf20Sopenharmony_ci#define PRSTATUS_SIZE(S, R) sizeof(S) 17588c2ecf20Sopenharmony_ci#endif 17598c2ecf20Sopenharmony_ci 17608c2ecf20Sopenharmony_ci#ifndef SET_PR_FPVALID 17618c2ecf20Sopenharmony_ci#define SET_PR_FPVALID(S, V, R) ((S)->pr_fpvalid = (V)) 17628c2ecf20Sopenharmony_ci#endif 17638c2ecf20Sopenharmony_ci 17648c2ecf20Sopenharmony_cistatic int fill_thread_core_info(struct elf_thread_core_info *t, 17658c2ecf20Sopenharmony_ci const struct user_regset_view *view, 17668c2ecf20Sopenharmony_ci long signr, size_t *total) 17678c2ecf20Sopenharmony_ci{ 17688c2ecf20Sopenharmony_ci unsigned int i; 17698c2ecf20Sopenharmony_ci int regset0_size; 17708c2ecf20Sopenharmony_ci 17718c2ecf20Sopenharmony_ci /* 17728c2ecf20Sopenharmony_ci * NT_PRSTATUS is the one special case, because the regset data 17738c2ecf20Sopenharmony_ci * goes into the pr_reg field inside the note contents, rather 17748c2ecf20Sopenharmony_ci * than being the whole note contents. We fill the reset in here. 17758c2ecf20Sopenharmony_ci * We assume that regset 0 is NT_PRSTATUS. 17768c2ecf20Sopenharmony_ci */ 17778c2ecf20Sopenharmony_ci fill_prstatus(&t->prstatus, t->task, signr); 17788c2ecf20Sopenharmony_ci regset0_size = regset_get(t->task, &view->regsets[0], 17798c2ecf20Sopenharmony_ci sizeof(t->prstatus.pr_reg), &t->prstatus.pr_reg); 17808c2ecf20Sopenharmony_ci if (regset0_size < 0) 17818c2ecf20Sopenharmony_ci return 0; 17828c2ecf20Sopenharmony_ci 17838c2ecf20Sopenharmony_ci fill_note(&t->notes[0], "CORE", NT_PRSTATUS, 17848c2ecf20Sopenharmony_ci PRSTATUS_SIZE(t->prstatus, regset0_size), &t->prstatus); 17858c2ecf20Sopenharmony_ci *total += notesize(&t->notes[0]); 17868c2ecf20Sopenharmony_ci 17878c2ecf20Sopenharmony_ci do_thread_regset_writeback(t->task, &view->regsets[0]); 17888c2ecf20Sopenharmony_ci 17898c2ecf20Sopenharmony_ci /* 17908c2ecf20Sopenharmony_ci * Each other regset might generate a note too. For each regset 17918c2ecf20Sopenharmony_ci * that has no core_note_type or is inactive, we leave t->notes[i] 17928c2ecf20Sopenharmony_ci * all zero and we'll know to skip writing it later. 17938c2ecf20Sopenharmony_ci */ 17948c2ecf20Sopenharmony_ci for (i = 1; i < view->n; ++i) { 17958c2ecf20Sopenharmony_ci const struct user_regset *regset = &view->regsets[i]; 17968c2ecf20Sopenharmony_ci int note_type = regset->core_note_type; 17978c2ecf20Sopenharmony_ci bool is_fpreg = note_type == NT_PRFPREG; 17988c2ecf20Sopenharmony_ci void *data; 17998c2ecf20Sopenharmony_ci int ret; 18008c2ecf20Sopenharmony_ci 18018c2ecf20Sopenharmony_ci do_thread_regset_writeback(t->task, regset); 18028c2ecf20Sopenharmony_ci if (!note_type) // not for coredumps 18038c2ecf20Sopenharmony_ci continue; 18048c2ecf20Sopenharmony_ci if (regset->active && regset->active(t->task, regset) <= 0) 18058c2ecf20Sopenharmony_ci continue; 18068c2ecf20Sopenharmony_ci 18078c2ecf20Sopenharmony_ci ret = regset_get_alloc(t->task, regset, ~0U, &data); 18088c2ecf20Sopenharmony_ci if (ret < 0) 18098c2ecf20Sopenharmony_ci continue; 18108c2ecf20Sopenharmony_ci 18118c2ecf20Sopenharmony_ci if (is_fpreg) 18128c2ecf20Sopenharmony_ci SET_PR_FPVALID(&t->prstatus, 1, regset0_size); 18138c2ecf20Sopenharmony_ci 18148c2ecf20Sopenharmony_ci fill_note(&t->notes[i], is_fpreg ? "CORE" : "LINUX", 18158c2ecf20Sopenharmony_ci note_type, ret, data); 18168c2ecf20Sopenharmony_ci 18178c2ecf20Sopenharmony_ci *total += notesize(&t->notes[i]); 18188c2ecf20Sopenharmony_ci } 18198c2ecf20Sopenharmony_ci 18208c2ecf20Sopenharmony_ci return 1; 18218c2ecf20Sopenharmony_ci} 18228c2ecf20Sopenharmony_ci 18238c2ecf20Sopenharmony_cistatic int fill_note_info(struct elfhdr *elf, int phdrs, 18248c2ecf20Sopenharmony_ci struct elf_note_info *info, 18258c2ecf20Sopenharmony_ci struct coredump_params *cprm) 18268c2ecf20Sopenharmony_ci{ 18278c2ecf20Sopenharmony_ci struct task_struct *dump_task = current; 18288c2ecf20Sopenharmony_ci const struct user_regset_view *view = task_user_regset_view(dump_task); 18298c2ecf20Sopenharmony_ci struct elf_thread_core_info *t; 18308c2ecf20Sopenharmony_ci struct elf_prpsinfo *psinfo; 18318c2ecf20Sopenharmony_ci struct core_thread *ct; 18328c2ecf20Sopenharmony_ci unsigned int i; 18338c2ecf20Sopenharmony_ci 18348c2ecf20Sopenharmony_ci info->size = 0; 18358c2ecf20Sopenharmony_ci info->thread = NULL; 18368c2ecf20Sopenharmony_ci 18378c2ecf20Sopenharmony_ci psinfo = kmalloc(sizeof(*psinfo), GFP_KERNEL); 18388c2ecf20Sopenharmony_ci if (psinfo == NULL) { 18398c2ecf20Sopenharmony_ci info->psinfo.data = NULL; /* So we don't free this wrongly */ 18408c2ecf20Sopenharmony_ci return 0; 18418c2ecf20Sopenharmony_ci } 18428c2ecf20Sopenharmony_ci 18438c2ecf20Sopenharmony_ci fill_note(&info->psinfo, "CORE", NT_PRPSINFO, sizeof(*psinfo), psinfo); 18448c2ecf20Sopenharmony_ci 18458c2ecf20Sopenharmony_ci /* 18468c2ecf20Sopenharmony_ci * Figure out how many notes we're going to need for each thread. 18478c2ecf20Sopenharmony_ci */ 18488c2ecf20Sopenharmony_ci info->thread_notes = 0; 18498c2ecf20Sopenharmony_ci for (i = 0; i < view->n; ++i) 18508c2ecf20Sopenharmony_ci if (view->regsets[i].core_note_type != 0) 18518c2ecf20Sopenharmony_ci ++info->thread_notes; 18528c2ecf20Sopenharmony_ci 18538c2ecf20Sopenharmony_ci /* 18548c2ecf20Sopenharmony_ci * Sanity check. We rely on regset 0 being in NT_PRSTATUS, 18558c2ecf20Sopenharmony_ci * since it is our one special case. 18568c2ecf20Sopenharmony_ci */ 18578c2ecf20Sopenharmony_ci if (unlikely(info->thread_notes == 0) || 18588c2ecf20Sopenharmony_ci unlikely(view->regsets[0].core_note_type != NT_PRSTATUS)) { 18598c2ecf20Sopenharmony_ci WARN_ON(1); 18608c2ecf20Sopenharmony_ci return 0; 18618c2ecf20Sopenharmony_ci } 18628c2ecf20Sopenharmony_ci 18638c2ecf20Sopenharmony_ci /* 18648c2ecf20Sopenharmony_ci * Initialize the ELF file header. 18658c2ecf20Sopenharmony_ci */ 18668c2ecf20Sopenharmony_ci fill_elf_header(elf, phdrs, 18678c2ecf20Sopenharmony_ci view->e_machine, view->e_flags); 18688c2ecf20Sopenharmony_ci 18698c2ecf20Sopenharmony_ci /* 18708c2ecf20Sopenharmony_ci * Allocate a structure for each thread. 18718c2ecf20Sopenharmony_ci */ 18728c2ecf20Sopenharmony_ci for (ct = &dump_task->mm->core_state->dumper; ct; ct = ct->next) { 18738c2ecf20Sopenharmony_ci t = kzalloc(offsetof(struct elf_thread_core_info, 18748c2ecf20Sopenharmony_ci notes[info->thread_notes]), 18758c2ecf20Sopenharmony_ci GFP_KERNEL); 18768c2ecf20Sopenharmony_ci if (unlikely(!t)) 18778c2ecf20Sopenharmony_ci return 0; 18788c2ecf20Sopenharmony_ci 18798c2ecf20Sopenharmony_ci t->task = ct->task; 18808c2ecf20Sopenharmony_ci if (ct->task == dump_task || !info->thread) { 18818c2ecf20Sopenharmony_ci t->next = info->thread; 18828c2ecf20Sopenharmony_ci info->thread = t; 18838c2ecf20Sopenharmony_ci } else { 18848c2ecf20Sopenharmony_ci /* 18858c2ecf20Sopenharmony_ci * Make sure to keep the original task at 18868c2ecf20Sopenharmony_ci * the head of the list. 18878c2ecf20Sopenharmony_ci */ 18888c2ecf20Sopenharmony_ci t->next = info->thread->next; 18898c2ecf20Sopenharmony_ci info->thread->next = t; 18908c2ecf20Sopenharmony_ci } 18918c2ecf20Sopenharmony_ci } 18928c2ecf20Sopenharmony_ci 18938c2ecf20Sopenharmony_ci /* 18948c2ecf20Sopenharmony_ci * Now fill in each thread's information. 18958c2ecf20Sopenharmony_ci */ 18968c2ecf20Sopenharmony_ci for (t = info->thread; t != NULL; t = t->next) 18978c2ecf20Sopenharmony_ci if (!fill_thread_core_info(t, view, cprm->siginfo->si_signo, &info->size)) 18988c2ecf20Sopenharmony_ci return 0; 18998c2ecf20Sopenharmony_ci 19008c2ecf20Sopenharmony_ci /* 19018c2ecf20Sopenharmony_ci * Fill in the two process-wide notes. 19028c2ecf20Sopenharmony_ci */ 19038c2ecf20Sopenharmony_ci fill_psinfo(psinfo, dump_task->group_leader, dump_task->mm); 19048c2ecf20Sopenharmony_ci info->size += notesize(&info->psinfo); 19058c2ecf20Sopenharmony_ci 19068c2ecf20Sopenharmony_ci fill_siginfo_note(&info->signote, &info->csigdata, cprm->siginfo); 19078c2ecf20Sopenharmony_ci info->size += notesize(&info->signote); 19088c2ecf20Sopenharmony_ci 19098c2ecf20Sopenharmony_ci fill_auxv_note(&info->auxv, current->mm); 19108c2ecf20Sopenharmony_ci info->size += notesize(&info->auxv); 19118c2ecf20Sopenharmony_ci 19128c2ecf20Sopenharmony_ci if (fill_files_note(&info->files, cprm) == 0) 19138c2ecf20Sopenharmony_ci info->size += notesize(&info->files); 19148c2ecf20Sopenharmony_ci 19158c2ecf20Sopenharmony_ci return 1; 19168c2ecf20Sopenharmony_ci} 19178c2ecf20Sopenharmony_ci 19188c2ecf20Sopenharmony_cistatic size_t get_note_info_size(struct elf_note_info *info) 19198c2ecf20Sopenharmony_ci{ 19208c2ecf20Sopenharmony_ci return info->size; 19218c2ecf20Sopenharmony_ci} 19228c2ecf20Sopenharmony_ci 19238c2ecf20Sopenharmony_ci/* 19248c2ecf20Sopenharmony_ci * Write all the notes for each thread. When writing the first thread, the 19258c2ecf20Sopenharmony_ci * process-wide notes are interleaved after the first thread-specific note. 19268c2ecf20Sopenharmony_ci */ 19278c2ecf20Sopenharmony_cistatic int write_note_info(struct elf_note_info *info, 19288c2ecf20Sopenharmony_ci struct coredump_params *cprm) 19298c2ecf20Sopenharmony_ci{ 19308c2ecf20Sopenharmony_ci bool first = true; 19318c2ecf20Sopenharmony_ci struct elf_thread_core_info *t = info->thread; 19328c2ecf20Sopenharmony_ci 19338c2ecf20Sopenharmony_ci do { 19348c2ecf20Sopenharmony_ci int i; 19358c2ecf20Sopenharmony_ci 19368c2ecf20Sopenharmony_ci if (!writenote(&t->notes[0], cprm)) 19378c2ecf20Sopenharmony_ci return 0; 19388c2ecf20Sopenharmony_ci 19398c2ecf20Sopenharmony_ci if (first && !writenote(&info->psinfo, cprm)) 19408c2ecf20Sopenharmony_ci return 0; 19418c2ecf20Sopenharmony_ci if (first && !writenote(&info->signote, cprm)) 19428c2ecf20Sopenharmony_ci return 0; 19438c2ecf20Sopenharmony_ci if (first && !writenote(&info->auxv, cprm)) 19448c2ecf20Sopenharmony_ci return 0; 19458c2ecf20Sopenharmony_ci if (first && info->files.data && 19468c2ecf20Sopenharmony_ci !writenote(&info->files, cprm)) 19478c2ecf20Sopenharmony_ci return 0; 19488c2ecf20Sopenharmony_ci 19498c2ecf20Sopenharmony_ci for (i = 1; i < info->thread_notes; ++i) 19508c2ecf20Sopenharmony_ci if (t->notes[i].data && 19518c2ecf20Sopenharmony_ci !writenote(&t->notes[i], cprm)) 19528c2ecf20Sopenharmony_ci return 0; 19538c2ecf20Sopenharmony_ci 19548c2ecf20Sopenharmony_ci first = false; 19558c2ecf20Sopenharmony_ci t = t->next; 19568c2ecf20Sopenharmony_ci } while (t); 19578c2ecf20Sopenharmony_ci 19588c2ecf20Sopenharmony_ci return 1; 19598c2ecf20Sopenharmony_ci} 19608c2ecf20Sopenharmony_ci 19618c2ecf20Sopenharmony_cistatic void free_note_info(struct elf_note_info *info) 19628c2ecf20Sopenharmony_ci{ 19638c2ecf20Sopenharmony_ci struct elf_thread_core_info *threads = info->thread; 19648c2ecf20Sopenharmony_ci while (threads) { 19658c2ecf20Sopenharmony_ci unsigned int i; 19668c2ecf20Sopenharmony_ci struct elf_thread_core_info *t = threads; 19678c2ecf20Sopenharmony_ci threads = t->next; 19688c2ecf20Sopenharmony_ci WARN_ON(t->notes[0].data && t->notes[0].data != &t->prstatus); 19698c2ecf20Sopenharmony_ci for (i = 1; i < info->thread_notes; ++i) 19708c2ecf20Sopenharmony_ci kfree(t->notes[i].data); 19718c2ecf20Sopenharmony_ci kfree(t); 19728c2ecf20Sopenharmony_ci } 19738c2ecf20Sopenharmony_ci kfree(info->psinfo.data); 19748c2ecf20Sopenharmony_ci kvfree(info->files.data); 19758c2ecf20Sopenharmony_ci} 19768c2ecf20Sopenharmony_ci 19778c2ecf20Sopenharmony_ci#else 19788c2ecf20Sopenharmony_ci 19798c2ecf20Sopenharmony_ci/* Here is the structure in which status of each thread is captured. */ 19808c2ecf20Sopenharmony_cistruct elf_thread_status 19818c2ecf20Sopenharmony_ci{ 19828c2ecf20Sopenharmony_ci struct list_head list; 19838c2ecf20Sopenharmony_ci struct elf_prstatus prstatus; /* NT_PRSTATUS */ 19848c2ecf20Sopenharmony_ci elf_fpregset_t fpu; /* NT_PRFPREG */ 19858c2ecf20Sopenharmony_ci struct task_struct *thread; 19868c2ecf20Sopenharmony_ci struct memelfnote notes[3]; 19878c2ecf20Sopenharmony_ci int num_notes; 19888c2ecf20Sopenharmony_ci}; 19898c2ecf20Sopenharmony_ci 19908c2ecf20Sopenharmony_ci/* 19918c2ecf20Sopenharmony_ci * In order to add the specific thread information for the elf file format, 19928c2ecf20Sopenharmony_ci * we need to keep a linked list of every threads pr_status and then create 19938c2ecf20Sopenharmony_ci * a single section for them in the final core file. 19948c2ecf20Sopenharmony_ci */ 19958c2ecf20Sopenharmony_cistatic int elf_dump_thread_status(long signr, struct elf_thread_status *t) 19968c2ecf20Sopenharmony_ci{ 19978c2ecf20Sopenharmony_ci int sz = 0; 19988c2ecf20Sopenharmony_ci struct task_struct *p = t->thread; 19998c2ecf20Sopenharmony_ci t->num_notes = 0; 20008c2ecf20Sopenharmony_ci 20018c2ecf20Sopenharmony_ci fill_prstatus(&t->prstatus, p, signr); 20028c2ecf20Sopenharmony_ci elf_core_copy_task_regs(p, &t->prstatus.pr_reg); 20038c2ecf20Sopenharmony_ci 20048c2ecf20Sopenharmony_ci fill_note(&t->notes[0], "CORE", NT_PRSTATUS, sizeof(t->prstatus), 20058c2ecf20Sopenharmony_ci &(t->prstatus)); 20068c2ecf20Sopenharmony_ci t->num_notes++; 20078c2ecf20Sopenharmony_ci sz += notesize(&t->notes[0]); 20088c2ecf20Sopenharmony_ci 20098c2ecf20Sopenharmony_ci if ((t->prstatus.pr_fpvalid = elf_core_copy_task_fpregs(p, NULL, 20108c2ecf20Sopenharmony_ci &t->fpu))) { 20118c2ecf20Sopenharmony_ci fill_note(&t->notes[1], "CORE", NT_PRFPREG, sizeof(t->fpu), 20128c2ecf20Sopenharmony_ci &(t->fpu)); 20138c2ecf20Sopenharmony_ci t->num_notes++; 20148c2ecf20Sopenharmony_ci sz += notesize(&t->notes[1]); 20158c2ecf20Sopenharmony_ci } 20168c2ecf20Sopenharmony_ci return sz; 20178c2ecf20Sopenharmony_ci} 20188c2ecf20Sopenharmony_ci 20198c2ecf20Sopenharmony_cistruct elf_note_info { 20208c2ecf20Sopenharmony_ci struct memelfnote *notes; 20218c2ecf20Sopenharmony_ci struct memelfnote *notes_files; 20228c2ecf20Sopenharmony_ci struct elf_prstatus *prstatus; /* NT_PRSTATUS */ 20238c2ecf20Sopenharmony_ci struct elf_prpsinfo *psinfo; /* NT_PRPSINFO */ 20248c2ecf20Sopenharmony_ci struct list_head thread_list; 20258c2ecf20Sopenharmony_ci elf_fpregset_t *fpu; 20268c2ecf20Sopenharmony_ci user_siginfo_t csigdata; 20278c2ecf20Sopenharmony_ci int thread_status_size; 20288c2ecf20Sopenharmony_ci int numnote; 20298c2ecf20Sopenharmony_ci}; 20308c2ecf20Sopenharmony_ci 20318c2ecf20Sopenharmony_cistatic int elf_note_info_init(struct elf_note_info *info) 20328c2ecf20Sopenharmony_ci{ 20338c2ecf20Sopenharmony_ci memset(info, 0, sizeof(*info)); 20348c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&info->thread_list); 20358c2ecf20Sopenharmony_ci 20368c2ecf20Sopenharmony_ci /* Allocate space for ELF notes */ 20378c2ecf20Sopenharmony_ci info->notes = kmalloc_array(8, sizeof(struct memelfnote), GFP_KERNEL); 20388c2ecf20Sopenharmony_ci if (!info->notes) 20398c2ecf20Sopenharmony_ci return 0; 20408c2ecf20Sopenharmony_ci info->psinfo = kmalloc(sizeof(*info->psinfo), GFP_KERNEL); 20418c2ecf20Sopenharmony_ci if (!info->psinfo) 20428c2ecf20Sopenharmony_ci return 0; 20438c2ecf20Sopenharmony_ci info->prstatus = kmalloc(sizeof(*info->prstatus), GFP_KERNEL); 20448c2ecf20Sopenharmony_ci if (!info->prstatus) 20458c2ecf20Sopenharmony_ci return 0; 20468c2ecf20Sopenharmony_ci info->fpu = kmalloc(sizeof(*info->fpu), GFP_KERNEL); 20478c2ecf20Sopenharmony_ci if (!info->fpu) 20488c2ecf20Sopenharmony_ci return 0; 20498c2ecf20Sopenharmony_ci return 1; 20508c2ecf20Sopenharmony_ci} 20518c2ecf20Sopenharmony_ci 20528c2ecf20Sopenharmony_cistatic int fill_note_info(struct elfhdr *elf, int phdrs, 20538c2ecf20Sopenharmony_ci struct elf_note_info *info, 20548c2ecf20Sopenharmony_ci struct coredump_params *cprm) 20558c2ecf20Sopenharmony_ci{ 20568c2ecf20Sopenharmony_ci struct core_thread *ct; 20578c2ecf20Sopenharmony_ci struct elf_thread_status *ets; 20588c2ecf20Sopenharmony_ci 20598c2ecf20Sopenharmony_ci if (!elf_note_info_init(info)) 20608c2ecf20Sopenharmony_ci return 0; 20618c2ecf20Sopenharmony_ci 20628c2ecf20Sopenharmony_ci for (ct = current->mm->core_state->dumper.next; 20638c2ecf20Sopenharmony_ci ct; ct = ct->next) { 20648c2ecf20Sopenharmony_ci ets = kzalloc(sizeof(*ets), GFP_KERNEL); 20658c2ecf20Sopenharmony_ci if (!ets) 20668c2ecf20Sopenharmony_ci return 0; 20678c2ecf20Sopenharmony_ci 20688c2ecf20Sopenharmony_ci ets->thread = ct->task; 20698c2ecf20Sopenharmony_ci list_add(&ets->list, &info->thread_list); 20708c2ecf20Sopenharmony_ci } 20718c2ecf20Sopenharmony_ci 20728c2ecf20Sopenharmony_ci list_for_each_entry(ets, &info->thread_list, list) { 20738c2ecf20Sopenharmony_ci int sz; 20748c2ecf20Sopenharmony_ci 20758c2ecf20Sopenharmony_ci sz = elf_dump_thread_status(cprm->siginfo->si_signo, ets); 20768c2ecf20Sopenharmony_ci info->thread_status_size += sz; 20778c2ecf20Sopenharmony_ci } 20788c2ecf20Sopenharmony_ci /* now collect the dump for the current */ 20798c2ecf20Sopenharmony_ci memset(info->prstatus, 0, sizeof(*info->prstatus)); 20808c2ecf20Sopenharmony_ci fill_prstatus(info->prstatus, current, cprm->siginfo->si_signo); 20818c2ecf20Sopenharmony_ci elf_core_copy_regs(&info->prstatus->pr_reg, cprm->regs); 20828c2ecf20Sopenharmony_ci 20838c2ecf20Sopenharmony_ci /* Set up header */ 20848c2ecf20Sopenharmony_ci fill_elf_header(elf, phdrs, ELF_ARCH, ELF_CORE_EFLAGS); 20858c2ecf20Sopenharmony_ci 20868c2ecf20Sopenharmony_ci /* 20878c2ecf20Sopenharmony_ci * Set up the notes in similar form to SVR4 core dumps made 20888c2ecf20Sopenharmony_ci * with info from their /proc. 20898c2ecf20Sopenharmony_ci */ 20908c2ecf20Sopenharmony_ci 20918c2ecf20Sopenharmony_ci fill_note(info->notes + 0, "CORE", NT_PRSTATUS, 20928c2ecf20Sopenharmony_ci sizeof(*info->prstatus), info->prstatus); 20938c2ecf20Sopenharmony_ci fill_psinfo(info->psinfo, current->group_leader, current->mm); 20948c2ecf20Sopenharmony_ci fill_note(info->notes + 1, "CORE", NT_PRPSINFO, 20958c2ecf20Sopenharmony_ci sizeof(*info->psinfo), info->psinfo); 20968c2ecf20Sopenharmony_ci 20978c2ecf20Sopenharmony_ci fill_siginfo_note(info->notes + 2, &info->csigdata, cprm->siginfo); 20988c2ecf20Sopenharmony_ci fill_auxv_note(info->notes + 3, current->mm); 20998c2ecf20Sopenharmony_ci info->numnote = 4; 21008c2ecf20Sopenharmony_ci 21018c2ecf20Sopenharmony_ci if (fill_files_note(info->notes + info->numnote, cprm) == 0) { 21028c2ecf20Sopenharmony_ci info->notes_files = info->notes + info->numnote; 21038c2ecf20Sopenharmony_ci info->numnote++; 21048c2ecf20Sopenharmony_ci } 21058c2ecf20Sopenharmony_ci 21068c2ecf20Sopenharmony_ci /* Try to dump the FPU. */ 21078c2ecf20Sopenharmony_ci info->prstatus->pr_fpvalid = 21088c2ecf20Sopenharmony_ci elf_core_copy_task_fpregs(current, cprm->regs, info->fpu); 21098c2ecf20Sopenharmony_ci if (info->prstatus->pr_fpvalid) 21108c2ecf20Sopenharmony_ci fill_note(info->notes + info->numnote++, 21118c2ecf20Sopenharmony_ci "CORE", NT_PRFPREG, sizeof(*info->fpu), info->fpu); 21128c2ecf20Sopenharmony_ci return 1; 21138c2ecf20Sopenharmony_ci} 21148c2ecf20Sopenharmony_ci 21158c2ecf20Sopenharmony_cistatic size_t get_note_info_size(struct elf_note_info *info) 21168c2ecf20Sopenharmony_ci{ 21178c2ecf20Sopenharmony_ci int sz = 0; 21188c2ecf20Sopenharmony_ci int i; 21198c2ecf20Sopenharmony_ci 21208c2ecf20Sopenharmony_ci for (i = 0; i < info->numnote; i++) 21218c2ecf20Sopenharmony_ci sz += notesize(info->notes + i); 21228c2ecf20Sopenharmony_ci 21238c2ecf20Sopenharmony_ci sz += info->thread_status_size; 21248c2ecf20Sopenharmony_ci 21258c2ecf20Sopenharmony_ci return sz; 21268c2ecf20Sopenharmony_ci} 21278c2ecf20Sopenharmony_ci 21288c2ecf20Sopenharmony_cistatic int write_note_info(struct elf_note_info *info, 21298c2ecf20Sopenharmony_ci struct coredump_params *cprm) 21308c2ecf20Sopenharmony_ci{ 21318c2ecf20Sopenharmony_ci struct elf_thread_status *ets; 21328c2ecf20Sopenharmony_ci int i; 21338c2ecf20Sopenharmony_ci 21348c2ecf20Sopenharmony_ci for (i = 0; i < info->numnote; i++) 21358c2ecf20Sopenharmony_ci if (!writenote(info->notes + i, cprm)) 21368c2ecf20Sopenharmony_ci return 0; 21378c2ecf20Sopenharmony_ci 21388c2ecf20Sopenharmony_ci /* write out the thread status notes section */ 21398c2ecf20Sopenharmony_ci list_for_each_entry(ets, &info->thread_list, list) { 21408c2ecf20Sopenharmony_ci for (i = 0; i < ets->num_notes; i++) 21418c2ecf20Sopenharmony_ci if (!writenote(&ets->notes[i], cprm)) 21428c2ecf20Sopenharmony_ci return 0; 21438c2ecf20Sopenharmony_ci } 21448c2ecf20Sopenharmony_ci 21458c2ecf20Sopenharmony_ci return 1; 21468c2ecf20Sopenharmony_ci} 21478c2ecf20Sopenharmony_ci 21488c2ecf20Sopenharmony_cistatic void free_note_info(struct elf_note_info *info) 21498c2ecf20Sopenharmony_ci{ 21508c2ecf20Sopenharmony_ci while (!list_empty(&info->thread_list)) { 21518c2ecf20Sopenharmony_ci struct list_head *tmp = info->thread_list.next; 21528c2ecf20Sopenharmony_ci list_del(tmp); 21538c2ecf20Sopenharmony_ci kfree(list_entry(tmp, struct elf_thread_status, list)); 21548c2ecf20Sopenharmony_ci } 21558c2ecf20Sopenharmony_ci 21568c2ecf20Sopenharmony_ci /* Free data possibly allocated by fill_files_note(): */ 21578c2ecf20Sopenharmony_ci if (info->notes_files) 21588c2ecf20Sopenharmony_ci kvfree(info->notes_files->data); 21598c2ecf20Sopenharmony_ci 21608c2ecf20Sopenharmony_ci kfree(info->prstatus); 21618c2ecf20Sopenharmony_ci kfree(info->psinfo); 21628c2ecf20Sopenharmony_ci kfree(info->notes); 21638c2ecf20Sopenharmony_ci kfree(info->fpu); 21648c2ecf20Sopenharmony_ci} 21658c2ecf20Sopenharmony_ci 21668c2ecf20Sopenharmony_ci#endif 21678c2ecf20Sopenharmony_ci 21688c2ecf20Sopenharmony_cistatic void fill_extnum_info(struct elfhdr *elf, struct elf_shdr *shdr4extnum, 21698c2ecf20Sopenharmony_ci elf_addr_t e_shoff, int segs) 21708c2ecf20Sopenharmony_ci{ 21718c2ecf20Sopenharmony_ci elf->e_shoff = e_shoff; 21728c2ecf20Sopenharmony_ci elf->e_shentsize = sizeof(*shdr4extnum); 21738c2ecf20Sopenharmony_ci elf->e_shnum = 1; 21748c2ecf20Sopenharmony_ci elf->e_shstrndx = SHN_UNDEF; 21758c2ecf20Sopenharmony_ci 21768c2ecf20Sopenharmony_ci memset(shdr4extnum, 0, sizeof(*shdr4extnum)); 21778c2ecf20Sopenharmony_ci 21788c2ecf20Sopenharmony_ci shdr4extnum->sh_type = SHT_NULL; 21798c2ecf20Sopenharmony_ci shdr4extnum->sh_size = elf->e_shnum; 21808c2ecf20Sopenharmony_ci shdr4extnum->sh_link = elf->e_shstrndx; 21818c2ecf20Sopenharmony_ci shdr4extnum->sh_info = segs; 21828c2ecf20Sopenharmony_ci} 21838c2ecf20Sopenharmony_ci 21848c2ecf20Sopenharmony_ci/* 21858c2ecf20Sopenharmony_ci * Actual dumper 21868c2ecf20Sopenharmony_ci * 21878c2ecf20Sopenharmony_ci * This is a two-pass process; first we find the offsets of the bits, 21888c2ecf20Sopenharmony_ci * and then they are actually written out. If we run out of core limit 21898c2ecf20Sopenharmony_ci * we just truncate. 21908c2ecf20Sopenharmony_ci */ 21918c2ecf20Sopenharmony_cistatic int elf_core_dump(struct coredump_params *cprm) 21928c2ecf20Sopenharmony_ci{ 21938c2ecf20Sopenharmony_ci int has_dumped = 0; 21948c2ecf20Sopenharmony_ci int segs, i; 21958c2ecf20Sopenharmony_ci struct elfhdr elf; 21968c2ecf20Sopenharmony_ci loff_t offset = 0, dataoff; 21978c2ecf20Sopenharmony_ci struct elf_note_info info = { }; 21988c2ecf20Sopenharmony_ci struct elf_phdr *phdr4note = NULL; 21998c2ecf20Sopenharmony_ci struct elf_shdr *shdr4extnum = NULL; 22008c2ecf20Sopenharmony_ci Elf_Half e_phnum; 22018c2ecf20Sopenharmony_ci elf_addr_t e_shoff; 22028c2ecf20Sopenharmony_ci 22038c2ecf20Sopenharmony_ci /* 22048c2ecf20Sopenharmony_ci * The number of segs are recored into ELF header as 16bit value. 22058c2ecf20Sopenharmony_ci * Please check DEFAULT_MAX_MAP_COUNT definition when you modify here. 22068c2ecf20Sopenharmony_ci */ 22078c2ecf20Sopenharmony_ci segs = cprm->vma_count + elf_core_extra_phdrs(); 22088c2ecf20Sopenharmony_ci 22098c2ecf20Sopenharmony_ci /* for notes section */ 22108c2ecf20Sopenharmony_ci segs++; 22118c2ecf20Sopenharmony_ci 22128c2ecf20Sopenharmony_ci /* If segs > PN_XNUM(0xffff), then e_phnum overflows. To avoid 22138c2ecf20Sopenharmony_ci * this, kernel supports extended numbering. Have a look at 22148c2ecf20Sopenharmony_ci * include/linux/elf.h for further information. */ 22158c2ecf20Sopenharmony_ci e_phnum = segs > PN_XNUM ? PN_XNUM : segs; 22168c2ecf20Sopenharmony_ci 22178c2ecf20Sopenharmony_ci /* 22188c2ecf20Sopenharmony_ci * Collect all the non-memory information about the process for the 22198c2ecf20Sopenharmony_ci * notes. This also sets up the file header. 22208c2ecf20Sopenharmony_ci */ 22218c2ecf20Sopenharmony_ci if (!fill_note_info(&elf, e_phnum, &info, cprm)) 22228c2ecf20Sopenharmony_ci goto end_coredump; 22238c2ecf20Sopenharmony_ci 22248c2ecf20Sopenharmony_ci has_dumped = 1; 22258c2ecf20Sopenharmony_ci 22268c2ecf20Sopenharmony_ci offset += sizeof(elf); /* Elf header */ 22278c2ecf20Sopenharmony_ci offset += segs * sizeof(struct elf_phdr); /* Program headers */ 22288c2ecf20Sopenharmony_ci 22298c2ecf20Sopenharmony_ci /* Write notes phdr entry */ 22308c2ecf20Sopenharmony_ci { 22318c2ecf20Sopenharmony_ci size_t sz = get_note_info_size(&info); 22328c2ecf20Sopenharmony_ci 22338c2ecf20Sopenharmony_ci sz += elf_coredump_extra_notes_size(); 22348c2ecf20Sopenharmony_ci 22358c2ecf20Sopenharmony_ci phdr4note = kmalloc(sizeof(*phdr4note), GFP_KERNEL); 22368c2ecf20Sopenharmony_ci if (!phdr4note) 22378c2ecf20Sopenharmony_ci goto end_coredump; 22388c2ecf20Sopenharmony_ci 22398c2ecf20Sopenharmony_ci fill_elf_note_phdr(phdr4note, sz, offset); 22408c2ecf20Sopenharmony_ci offset += sz; 22418c2ecf20Sopenharmony_ci } 22428c2ecf20Sopenharmony_ci 22438c2ecf20Sopenharmony_ci dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE); 22448c2ecf20Sopenharmony_ci 22458c2ecf20Sopenharmony_ci offset += cprm->vma_data_size; 22468c2ecf20Sopenharmony_ci offset += elf_core_extra_data_size(); 22478c2ecf20Sopenharmony_ci e_shoff = offset; 22488c2ecf20Sopenharmony_ci 22498c2ecf20Sopenharmony_ci if (e_phnum == PN_XNUM) { 22508c2ecf20Sopenharmony_ci shdr4extnum = kmalloc(sizeof(*shdr4extnum), GFP_KERNEL); 22518c2ecf20Sopenharmony_ci if (!shdr4extnum) 22528c2ecf20Sopenharmony_ci goto end_coredump; 22538c2ecf20Sopenharmony_ci fill_extnum_info(&elf, shdr4extnum, e_shoff, segs); 22548c2ecf20Sopenharmony_ci } 22558c2ecf20Sopenharmony_ci 22568c2ecf20Sopenharmony_ci offset = dataoff; 22578c2ecf20Sopenharmony_ci 22588c2ecf20Sopenharmony_ci if (!dump_emit(cprm, &elf, sizeof(elf))) 22598c2ecf20Sopenharmony_ci goto end_coredump; 22608c2ecf20Sopenharmony_ci 22618c2ecf20Sopenharmony_ci if (!dump_emit(cprm, phdr4note, sizeof(*phdr4note))) 22628c2ecf20Sopenharmony_ci goto end_coredump; 22638c2ecf20Sopenharmony_ci 22648c2ecf20Sopenharmony_ci /* Write program headers for segments dump */ 22658c2ecf20Sopenharmony_ci for (i = 0; i < cprm->vma_count; i++) { 22668c2ecf20Sopenharmony_ci struct core_vma_metadata *meta = cprm->vma_meta + i; 22678c2ecf20Sopenharmony_ci struct elf_phdr phdr; 22688c2ecf20Sopenharmony_ci 22698c2ecf20Sopenharmony_ci phdr.p_type = PT_LOAD; 22708c2ecf20Sopenharmony_ci phdr.p_offset = offset; 22718c2ecf20Sopenharmony_ci phdr.p_vaddr = meta->start; 22728c2ecf20Sopenharmony_ci phdr.p_paddr = 0; 22738c2ecf20Sopenharmony_ci phdr.p_filesz = meta->dump_size; 22748c2ecf20Sopenharmony_ci phdr.p_memsz = meta->end - meta->start; 22758c2ecf20Sopenharmony_ci offset += phdr.p_filesz; 22768c2ecf20Sopenharmony_ci phdr.p_flags = 0; 22778c2ecf20Sopenharmony_ci if (meta->flags & VM_READ) 22788c2ecf20Sopenharmony_ci phdr.p_flags |= PF_R; 22798c2ecf20Sopenharmony_ci if (meta->flags & VM_WRITE) 22808c2ecf20Sopenharmony_ci phdr.p_flags |= PF_W; 22818c2ecf20Sopenharmony_ci if (meta->flags & VM_EXEC) 22828c2ecf20Sopenharmony_ci phdr.p_flags |= PF_X; 22838c2ecf20Sopenharmony_ci phdr.p_align = ELF_EXEC_PAGESIZE; 22848c2ecf20Sopenharmony_ci 22858c2ecf20Sopenharmony_ci if (!dump_emit(cprm, &phdr, sizeof(phdr))) 22868c2ecf20Sopenharmony_ci goto end_coredump; 22878c2ecf20Sopenharmony_ci } 22888c2ecf20Sopenharmony_ci 22898c2ecf20Sopenharmony_ci if (!elf_core_write_extra_phdrs(cprm, offset)) 22908c2ecf20Sopenharmony_ci goto end_coredump; 22918c2ecf20Sopenharmony_ci 22928c2ecf20Sopenharmony_ci /* write out the notes section */ 22938c2ecf20Sopenharmony_ci if (!write_note_info(&info, cprm)) 22948c2ecf20Sopenharmony_ci goto end_coredump; 22958c2ecf20Sopenharmony_ci 22968c2ecf20Sopenharmony_ci if (elf_coredump_extra_notes_write(cprm)) 22978c2ecf20Sopenharmony_ci goto end_coredump; 22988c2ecf20Sopenharmony_ci 22998c2ecf20Sopenharmony_ci /* Align to page */ 23008c2ecf20Sopenharmony_ci if (!dump_skip(cprm, dataoff - cprm->pos)) 23018c2ecf20Sopenharmony_ci goto end_coredump; 23028c2ecf20Sopenharmony_ci 23038c2ecf20Sopenharmony_ci for (i = 0; i < cprm->vma_count; i++) { 23048c2ecf20Sopenharmony_ci struct core_vma_metadata *meta = cprm->vma_meta + i; 23058c2ecf20Sopenharmony_ci 23068c2ecf20Sopenharmony_ci if (!dump_user_range(cprm, meta->start, meta->dump_size)) 23078c2ecf20Sopenharmony_ci goto end_coredump; 23088c2ecf20Sopenharmony_ci } 23098c2ecf20Sopenharmony_ci dump_truncate(cprm); 23108c2ecf20Sopenharmony_ci 23118c2ecf20Sopenharmony_ci if (!elf_core_write_extra_data(cprm)) 23128c2ecf20Sopenharmony_ci goto end_coredump; 23138c2ecf20Sopenharmony_ci 23148c2ecf20Sopenharmony_ci if (e_phnum == PN_XNUM) { 23158c2ecf20Sopenharmony_ci if (!dump_emit(cprm, shdr4extnum, sizeof(*shdr4extnum))) 23168c2ecf20Sopenharmony_ci goto end_coredump; 23178c2ecf20Sopenharmony_ci } 23188c2ecf20Sopenharmony_ci 23198c2ecf20Sopenharmony_ciend_coredump: 23208c2ecf20Sopenharmony_ci free_note_info(&info); 23218c2ecf20Sopenharmony_ci kfree(shdr4extnum); 23228c2ecf20Sopenharmony_ci kfree(phdr4note); 23238c2ecf20Sopenharmony_ci return has_dumped; 23248c2ecf20Sopenharmony_ci} 23258c2ecf20Sopenharmony_ci 23268c2ecf20Sopenharmony_ci#endif /* CONFIG_ELF_CORE */ 23278c2ecf20Sopenharmony_ci 23288c2ecf20Sopenharmony_cistatic int __init init_elf_binfmt(void) 23298c2ecf20Sopenharmony_ci{ 23308c2ecf20Sopenharmony_ci register_binfmt(&elf_format); 23318c2ecf20Sopenharmony_ci return 0; 23328c2ecf20Sopenharmony_ci} 23338c2ecf20Sopenharmony_ci 23348c2ecf20Sopenharmony_cistatic void __exit exit_elf_binfmt(void) 23358c2ecf20Sopenharmony_ci{ 23368c2ecf20Sopenharmony_ci /* Remove the COFF and ELF loaders. */ 23378c2ecf20Sopenharmony_ci unregister_binfmt(&elf_format); 23388c2ecf20Sopenharmony_ci} 23398c2ecf20Sopenharmony_ci 23408c2ecf20Sopenharmony_cicore_initcall(init_elf_binfmt); 23418c2ecf20Sopenharmony_cimodule_exit(exit_elf_binfmt); 23428c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 2343