162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * linux/fs/binfmt_elf.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * These are the functions used to load ELF format executables as used 662306a36Sopenharmony_ci * on SVr4 machines. Information on the format may be found in the book 762306a36Sopenharmony_ci * "UNIX SYSTEM V RELEASE 4 Programmers Guide: Ansi C and Programming Support 862306a36Sopenharmony_ci * Tools". 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * Copyright 1993, 1994: Eric Youngdale (ericy@cais.com). 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <linux/module.h> 1462306a36Sopenharmony_ci#include <linux/kernel.h> 1562306a36Sopenharmony_ci#include <linux/fs.h> 1662306a36Sopenharmony_ci#include <linux/log2.h> 1762306a36Sopenharmony_ci#include <linux/mm.h> 1862306a36Sopenharmony_ci#include <linux/mman.h> 1962306a36Sopenharmony_ci#include <linux/errno.h> 2062306a36Sopenharmony_ci#include <linux/signal.h> 2162306a36Sopenharmony_ci#include <linux/binfmts.h> 2262306a36Sopenharmony_ci#include <linux/string.h> 2362306a36Sopenharmony_ci#include <linux/file.h> 2462306a36Sopenharmony_ci#include <linux/slab.h> 2562306a36Sopenharmony_ci#include <linux/personality.h> 2662306a36Sopenharmony_ci#include <linux/elfcore.h> 2762306a36Sopenharmony_ci#include <linux/init.h> 2862306a36Sopenharmony_ci#include <linux/highuid.h> 2962306a36Sopenharmony_ci#include <linux/compiler.h> 3062306a36Sopenharmony_ci#include <linux/highmem.h> 3162306a36Sopenharmony_ci#include <linux/hugetlb.h> 3262306a36Sopenharmony_ci#include <linux/pagemap.h> 3362306a36Sopenharmony_ci#include <linux/vmalloc.h> 3462306a36Sopenharmony_ci#include <linux/security.h> 3562306a36Sopenharmony_ci#include <linux/random.h> 3662306a36Sopenharmony_ci#include <linux/elf.h> 3762306a36Sopenharmony_ci#include <linux/elf-randomize.h> 3862306a36Sopenharmony_ci#include <linux/utsname.h> 3962306a36Sopenharmony_ci#include <linux/coredump.h> 4062306a36Sopenharmony_ci#include <linux/sched.h> 4162306a36Sopenharmony_ci#include <linux/sched/coredump.h> 4262306a36Sopenharmony_ci#include <linux/sched/task_stack.h> 4362306a36Sopenharmony_ci#include <linux/sched/cputime.h> 4462306a36Sopenharmony_ci#include <linux/sizes.h> 4562306a36Sopenharmony_ci#include <linux/types.h> 4662306a36Sopenharmony_ci#include <linux/cred.h> 4762306a36Sopenharmony_ci#include <linux/dax.h> 4862306a36Sopenharmony_ci#include <linux/uaccess.h> 4962306a36Sopenharmony_ci#include <linux/rseq.h> 5062306a36Sopenharmony_ci#include <asm/param.h> 5162306a36Sopenharmony_ci#include <asm/page.h> 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci#ifndef ELF_COMPAT 5462306a36Sopenharmony_ci#define ELF_COMPAT 0 5562306a36Sopenharmony_ci#endif 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci#ifndef user_long_t 5862306a36Sopenharmony_ci#define user_long_t long 5962306a36Sopenharmony_ci#endif 6062306a36Sopenharmony_ci#ifndef user_siginfo_t 6162306a36Sopenharmony_ci#define user_siginfo_t siginfo_t 6262306a36Sopenharmony_ci#endif 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci/* That's for binfmt_elf_fdpic to deal with */ 6562306a36Sopenharmony_ci#ifndef elf_check_fdpic 6662306a36Sopenharmony_ci#define elf_check_fdpic(ex) false 6762306a36Sopenharmony_ci#endif 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_cistatic int load_elf_binary(struct linux_binprm *bprm); 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci#ifdef CONFIG_USELIB 7262306a36Sopenharmony_cistatic int load_elf_library(struct file *); 7362306a36Sopenharmony_ci#else 7462306a36Sopenharmony_ci#define load_elf_library NULL 7562306a36Sopenharmony_ci#endif 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci/* 7862306a36Sopenharmony_ci * If we don't support core dumping, then supply a NULL so we 7962306a36Sopenharmony_ci * don't even try. 8062306a36Sopenharmony_ci */ 8162306a36Sopenharmony_ci#ifdef CONFIG_ELF_CORE 8262306a36Sopenharmony_cistatic int elf_core_dump(struct coredump_params *cprm); 8362306a36Sopenharmony_ci#else 8462306a36Sopenharmony_ci#define elf_core_dump NULL 8562306a36Sopenharmony_ci#endif 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci#if ELF_EXEC_PAGESIZE > PAGE_SIZE 8862306a36Sopenharmony_ci#define ELF_MIN_ALIGN ELF_EXEC_PAGESIZE 8962306a36Sopenharmony_ci#else 9062306a36Sopenharmony_ci#define ELF_MIN_ALIGN PAGE_SIZE 9162306a36Sopenharmony_ci#endif 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci#ifndef ELF_CORE_EFLAGS 9462306a36Sopenharmony_ci#define ELF_CORE_EFLAGS 0 9562306a36Sopenharmony_ci#endif 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci#define ELF_PAGESTART(_v) ((_v) & ~(int)(ELF_MIN_ALIGN-1)) 9862306a36Sopenharmony_ci#define ELF_PAGEOFFSET(_v) ((_v) & (ELF_MIN_ALIGN-1)) 9962306a36Sopenharmony_ci#define ELF_PAGEALIGN(_v) (((_v) + ELF_MIN_ALIGN - 1) & ~(ELF_MIN_ALIGN - 1)) 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_cistatic struct linux_binfmt elf_format = { 10262306a36Sopenharmony_ci .module = THIS_MODULE, 10362306a36Sopenharmony_ci .load_binary = load_elf_binary, 10462306a36Sopenharmony_ci .load_shlib = load_elf_library, 10562306a36Sopenharmony_ci#ifdef CONFIG_COREDUMP 10662306a36Sopenharmony_ci .core_dump = elf_core_dump, 10762306a36Sopenharmony_ci .min_coredump = ELF_EXEC_PAGESIZE, 10862306a36Sopenharmony_ci#endif 10962306a36Sopenharmony_ci}; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci#define BAD_ADDR(x) (unlikely((unsigned long)(x) >= TASK_SIZE)) 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_cistatic int set_brk(unsigned long start, unsigned long end, int prot) 11462306a36Sopenharmony_ci{ 11562306a36Sopenharmony_ci start = ELF_PAGEALIGN(start); 11662306a36Sopenharmony_ci end = ELF_PAGEALIGN(end); 11762306a36Sopenharmony_ci if (end > start) { 11862306a36Sopenharmony_ci /* 11962306a36Sopenharmony_ci * Map the last of the bss segment. 12062306a36Sopenharmony_ci * If the header is requesting these pages to be 12162306a36Sopenharmony_ci * executable, honour that (ppc32 needs this). 12262306a36Sopenharmony_ci */ 12362306a36Sopenharmony_ci int error = vm_brk_flags(start, end - start, 12462306a36Sopenharmony_ci prot & PROT_EXEC ? VM_EXEC : 0); 12562306a36Sopenharmony_ci if (error) 12662306a36Sopenharmony_ci return error; 12762306a36Sopenharmony_ci } 12862306a36Sopenharmony_ci current->mm->start_brk = current->mm->brk = end; 12962306a36Sopenharmony_ci return 0; 13062306a36Sopenharmony_ci} 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci/* We need to explicitly zero any fractional pages 13362306a36Sopenharmony_ci after the data section (i.e. bss). This would 13462306a36Sopenharmony_ci contain the junk from the file that should not 13562306a36Sopenharmony_ci be in memory 13662306a36Sopenharmony_ci */ 13762306a36Sopenharmony_cistatic int padzero(unsigned long elf_bss) 13862306a36Sopenharmony_ci{ 13962306a36Sopenharmony_ci unsigned long nbyte; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci nbyte = ELF_PAGEOFFSET(elf_bss); 14262306a36Sopenharmony_ci if (nbyte) { 14362306a36Sopenharmony_ci nbyte = ELF_MIN_ALIGN - nbyte; 14462306a36Sopenharmony_ci if (clear_user((void __user *) elf_bss, nbyte)) 14562306a36Sopenharmony_ci return -EFAULT; 14662306a36Sopenharmony_ci } 14762306a36Sopenharmony_ci return 0; 14862306a36Sopenharmony_ci} 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci/* Let's use some macros to make this stack manipulation a little clearer */ 15162306a36Sopenharmony_ci#ifdef CONFIG_STACK_GROWSUP 15262306a36Sopenharmony_ci#define STACK_ADD(sp, items) ((elf_addr_t __user *)(sp) + (items)) 15362306a36Sopenharmony_ci#define STACK_ROUND(sp, items) \ 15462306a36Sopenharmony_ci ((15 + (unsigned long) ((sp) + (items))) &~ 15UL) 15562306a36Sopenharmony_ci#define STACK_ALLOC(sp, len) ({ \ 15662306a36Sopenharmony_ci elf_addr_t __user *old_sp = (elf_addr_t __user *)sp; sp += len; \ 15762306a36Sopenharmony_ci old_sp; }) 15862306a36Sopenharmony_ci#else 15962306a36Sopenharmony_ci#define STACK_ADD(sp, items) ((elf_addr_t __user *)(sp) - (items)) 16062306a36Sopenharmony_ci#define STACK_ROUND(sp, items) \ 16162306a36Sopenharmony_ci (((unsigned long) (sp - items)) &~ 15UL) 16262306a36Sopenharmony_ci#define STACK_ALLOC(sp, len) (sp -= len) 16362306a36Sopenharmony_ci#endif 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci#ifndef ELF_BASE_PLATFORM 16662306a36Sopenharmony_ci/* 16762306a36Sopenharmony_ci * AT_BASE_PLATFORM indicates the "real" hardware/microarchitecture. 16862306a36Sopenharmony_ci * If the arch defines ELF_BASE_PLATFORM (in asm/elf.h), the value 16962306a36Sopenharmony_ci * will be copied to the user stack in the same manner as AT_PLATFORM. 17062306a36Sopenharmony_ci */ 17162306a36Sopenharmony_ci#define ELF_BASE_PLATFORM NULL 17262306a36Sopenharmony_ci#endif 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_cistatic int 17562306a36Sopenharmony_cicreate_elf_tables(struct linux_binprm *bprm, const struct elfhdr *exec, 17662306a36Sopenharmony_ci unsigned long interp_load_addr, 17762306a36Sopenharmony_ci unsigned long e_entry, unsigned long phdr_addr) 17862306a36Sopenharmony_ci{ 17962306a36Sopenharmony_ci struct mm_struct *mm = current->mm; 18062306a36Sopenharmony_ci unsigned long p = bprm->p; 18162306a36Sopenharmony_ci int argc = bprm->argc; 18262306a36Sopenharmony_ci int envc = bprm->envc; 18362306a36Sopenharmony_ci elf_addr_t __user *sp; 18462306a36Sopenharmony_ci elf_addr_t __user *u_platform; 18562306a36Sopenharmony_ci elf_addr_t __user *u_base_platform; 18662306a36Sopenharmony_ci elf_addr_t __user *u_rand_bytes; 18762306a36Sopenharmony_ci const char *k_platform = ELF_PLATFORM; 18862306a36Sopenharmony_ci const char *k_base_platform = ELF_BASE_PLATFORM; 18962306a36Sopenharmony_ci unsigned char k_rand_bytes[16]; 19062306a36Sopenharmony_ci int items; 19162306a36Sopenharmony_ci elf_addr_t *elf_info; 19262306a36Sopenharmony_ci elf_addr_t flags = 0; 19362306a36Sopenharmony_ci int ei_index; 19462306a36Sopenharmony_ci const struct cred *cred = current_cred(); 19562306a36Sopenharmony_ci struct vm_area_struct *vma; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci /* 19862306a36Sopenharmony_ci * In some cases (e.g. Hyper-Threading), we want to avoid L1 19962306a36Sopenharmony_ci * evictions by the processes running on the same package. One 20062306a36Sopenharmony_ci * thing we can do is to shuffle the initial stack for them. 20162306a36Sopenharmony_ci */ 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci p = arch_align_stack(p); 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci /* 20662306a36Sopenharmony_ci * If this architecture has a platform capability string, copy it 20762306a36Sopenharmony_ci * to userspace. In some cases (Sparc), this info is impossible 20862306a36Sopenharmony_ci * for userspace to get any other way, in others (i386) it is 20962306a36Sopenharmony_ci * merely difficult. 21062306a36Sopenharmony_ci */ 21162306a36Sopenharmony_ci u_platform = NULL; 21262306a36Sopenharmony_ci if (k_platform) { 21362306a36Sopenharmony_ci size_t len = strlen(k_platform) + 1; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci u_platform = (elf_addr_t __user *)STACK_ALLOC(p, len); 21662306a36Sopenharmony_ci if (copy_to_user(u_platform, k_platform, len)) 21762306a36Sopenharmony_ci return -EFAULT; 21862306a36Sopenharmony_ci } 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci /* 22162306a36Sopenharmony_ci * If this architecture has a "base" platform capability 22262306a36Sopenharmony_ci * string, copy it to userspace. 22362306a36Sopenharmony_ci */ 22462306a36Sopenharmony_ci u_base_platform = NULL; 22562306a36Sopenharmony_ci if (k_base_platform) { 22662306a36Sopenharmony_ci size_t len = strlen(k_base_platform) + 1; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci u_base_platform = (elf_addr_t __user *)STACK_ALLOC(p, len); 22962306a36Sopenharmony_ci if (copy_to_user(u_base_platform, k_base_platform, len)) 23062306a36Sopenharmony_ci return -EFAULT; 23162306a36Sopenharmony_ci } 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci /* 23462306a36Sopenharmony_ci * Generate 16 random bytes for userspace PRNG seeding. 23562306a36Sopenharmony_ci */ 23662306a36Sopenharmony_ci get_random_bytes(k_rand_bytes, sizeof(k_rand_bytes)); 23762306a36Sopenharmony_ci u_rand_bytes = (elf_addr_t __user *) 23862306a36Sopenharmony_ci STACK_ALLOC(p, sizeof(k_rand_bytes)); 23962306a36Sopenharmony_ci if (copy_to_user(u_rand_bytes, k_rand_bytes, sizeof(k_rand_bytes))) 24062306a36Sopenharmony_ci return -EFAULT; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci /* Create the ELF interpreter info */ 24362306a36Sopenharmony_ci elf_info = (elf_addr_t *)mm->saved_auxv; 24462306a36Sopenharmony_ci /* update AT_VECTOR_SIZE_BASE if the number of NEW_AUX_ENT() changes */ 24562306a36Sopenharmony_ci#define NEW_AUX_ENT(id, val) \ 24662306a36Sopenharmony_ci do { \ 24762306a36Sopenharmony_ci *elf_info++ = id; \ 24862306a36Sopenharmony_ci *elf_info++ = val; \ 24962306a36Sopenharmony_ci } while (0) 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci#ifdef ARCH_DLINFO 25262306a36Sopenharmony_ci /* 25362306a36Sopenharmony_ci * ARCH_DLINFO must come first so PPC can do its special alignment of 25462306a36Sopenharmony_ci * AUXV. 25562306a36Sopenharmony_ci * update AT_VECTOR_SIZE_ARCH if the number of NEW_AUX_ENT() in 25662306a36Sopenharmony_ci * ARCH_DLINFO changes 25762306a36Sopenharmony_ci */ 25862306a36Sopenharmony_ci ARCH_DLINFO; 25962306a36Sopenharmony_ci#endif 26062306a36Sopenharmony_ci NEW_AUX_ENT(AT_HWCAP, ELF_HWCAP); 26162306a36Sopenharmony_ci NEW_AUX_ENT(AT_PAGESZ, ELF_EXEC_PAGESIZE); 26262306a36Sopenharmony_ci NEW_AUX_ENT(AT_CLKTCK, CLOCKS_PER_SEC); 26362306a36Sopenharmony_ci NEW_AUX_ENT(AT_PHDR, phdr_addr); 26462306a36Sopenharmony_ci NEW_AUX_ENT(AT_PHENT, sizeof(struct elf_phdr)); 26562306a36Sopenharmony_ci NEW_AUX_ENT(AT_PHNUM, exec->e_phnum); 26662306a36Sopenharmony_ci NEW_AUX_ENT(AT_BASE, interp_load_addr); 26762306a36Sopenharmony_ci if (bprm->interp_flags & BINPRM_FLAGS_PRESERVE_ARGV0) 26862306a36Sopenharmony_ci flags |= AT_FLAGS_PRESERVE_ARGV0; 26962306a36Sopenharmony_ci NEW_AUX_ENT(AT_FLAGS, flags); 27062306a36Sopenharmony_ci NEW_AUX_ENT(AT_ENTRY, e_entry); 27162306a36Sopenharmony_ci NEW_AUX_ENT(AT_UID, from_kuid_munged(cred->user_ns, cred->uid)); 27262306a36Sopenharmony_ci NEW_AUX_ENT(AT_EUID, from_kuid_munged(cred->user_ns, cred->euid)); 27362306a36Sopenharmony_ci NEW_AUX_ENT(AT_GID, from_kgid_munged(cred->user_ns, cred->gid)); 27462306a36Sopenharmony_ci NEW_AUX_ENT(AT_EGID, from_kgid_munged(cred->user_ns, cred->egid)); 27562306a36Sopenharmony_ci NEW_AUX_ENT(AT_SECURE, bprm->secureexec); 27662306a36Sopenharmony_ci NEW_AUX_ENT(AT_RANDOM, (elf_addr_t)(unsigned long)u_rand_bytes); 27762306a36Sopenharmony_ci#ifdef ELF_HWCAP2 27862306a36Sopenharmony_ci NEW_AUX_ENT(AT_HWCAP2, ELF_HWCAP2); 27962306a36Sopenharmony_ci#endif 28062306a36Sopenharmony_ci NEW_AUX_ENT(AT_EXECFN, bprm->exec); 28162306a36Sopenharmony_ci if (k_platform) { 28262306a36Sopenharmony_ci NEW_AUX_ENT(AT_PLATFORM, 28362306a36Sopenharmony_ci (elf_addr_t)(unsigned long)u_platform); 28462306a36Sopenharmony_ci } 28562306a36Sopenharmony_ci if (k_base_platform) { 28662306a36Sopenharmony_ci NEW_AUX_ENT(AT_BASE_PLATFORM, 28762306a36Sopenharmony_ci (elf_addr_t)(unsigned long)u_base_platform); 28862306a36Sopenharmony_ci } 28962306a36Sopenharmony_ci if (bprm->have_execfd) { 29062306a36Sopenharmony_ci NEW_AUX_ENT(AT_EXECFD, bprm->execfd); 29162306a36Sopenharmony_ci } 29262306a36Sopenharmony_ci#ifdef CONFIG_RSEQ 29362306a36Sopenharmony_ci NEW_AUX_ENT(AT_RSEQ_FEATURE_SIZE, offsetof(struct rseq, end)); 29462306a36Sopenharmony_ci NEW_AUX_ENT(AT_RSEQ_ALIGN, __alignof__(struct rseq)); 29562306a36Sopenharmony_ci#endif 29662306a36Sopenharmony_ci#undef NEW_AUX_ENT 29762306a36Sopenharmony_ci /* AT_NULL is zero; clear the rest too */ 29862306a36Sopenharmony_ci memset(elf_info, 0, (char *)mm->saved_auxv + 29962306a36Sopenharmony_ci sizeof(mm->saved_auxv) - (char *)elf_info); 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci /* And advance past the AT_NULL entry. */ 30262306a36Sopenharmony_ci elf_info += 2; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci ei_index = elf_info - (elf_addr_t *)mm->saved_auxv; 30562306a36Sopenharmony_ci sp = STACK_ADD(p, ei_index); 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci items = (argc + 1) + (envc + 1) + 1; 30862306a36Sopenharmony_ci bprm->p = STACK_ROUND(sp, items); 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci /* Point sp at the lowest address on the stack */ 31162306a36Sopenharmony_ci#ifdef CONFIG_STACK_GROWSUP 31262306a36Sopenharmony_ci sp = (elf_addr_t __user *)bprm->p - items - ei_index; 31362306a36Sopenharmony_ci bprm->exec = (unsigned long)sp; /* XXX: PARISC HACK */ 31462306a36Sopenharmony_ci#else 31562306a36Sopenharmony_ci sp = (elf_addr_t __user *)bprm->p; 31662306a36Sopenharmony_ci#endif 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci /* 32062306a36Sopenharmony_ci * Grow the stack manually; some architectures have a limit on how 32162306a36Sopenharmony_ci * far ahead a user-space access may be in order to grow the stack. 32262306a36Sopenharmony_ci */ 32362306a36Sopenharmony_ci if (mmap_write_lock_killable(mm)) 32462306a36Sopenharmony_ci return -EINTR; 32562306a36Sopenharmony_ci vma = find_extend_vma_locked(mm, bprm->p); 32662306a36Sopenharmony_ci mmap_write_unlock(mm); 32762306a36Sopenharmony_ci if (!vma) 32862306a36Sopenharmony_ci return -EFAULT; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci /* Now, let's put argc (and argv, envp if appropriate) on the stack */ 33162306a36Sopenharmony_ci if (put_user(argc, sp++)) 33262306a36Sopenharmony_ci return -EFAULT; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci /* Populate list of argv pointers back to argv strings. */ 33562306a36Sopenharmony_ci p = mm->arg_end = mm->arg_start; 33662306a36Sopenharmony_ci while (argc-- > 0) { 33762306a36Sopenharmony_ci size_t len; 33862306a36Sopenharmony_ci if (put_user((elf_addr_t)p, sp++)) 33962306a36Sopenharmony_ci return -EFAULT; 34062306a36Sopenharmony_ci len = strnlen_user((void __user *)p, MAX_ARG_STRLEN); 34162306a36Sopenharmony_ci if (!len || len > MAX_ARG_STRLEN) 34262306a36Sopenharmony_ci return -EINVAL; 34362306a36Sopenharmony_ci p += len; 34462306a36Sopenharmony_ci } 34562306a36Sopenharmony_ci if (put_user(0, sp++)) 34662306a36Sopenharmony_ci return -EFAULT; 34762306a36Sopenharmony_ci mm->arg_end = p; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci /* Populate list of envp pointers back to envp strings. */ 35062306a36Sopenharmony_ci mm->env_end = mm->env_start = p; 35162306a36Sopenharmony_ci while (envc-- > 0) { 35262306a36Sopenharmony_ci size_t len; 35362306a36Sopenharmony_ci if (put_user((elf_addr_t)p, sp++)) 35462306a36Sopenharmony_ci return -EFAULT; 35562306a36Sopenharmony_ci len = strnlen_user((void __user *)p, MAX_ARG_STRLEN); 35662306a36Sopenharmony_ci if (!len || len > MAX_ARG_STRLEN) 35762306a36Sopenharmony_ci return -EINVAL; 35862306a36Sopenharmony_ci p += len; 35962306a36Sopenharmony_ci } 36062306a36Sopenharmony_ci if (put_user(0, sp++)) 36162306a36Sopenharmony_ci return -EFAULT; 36262306a36Sopenharmony_ci mm->env_end = p; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci /* Put the elf_info on the stack in the right place. */ 36562306a36Sopenharmony_ci if (copy_to_user(sp, mm->saved_auxv, ei_index * sizeof(elf_addr_t))) 36662306a36Sopenharmony_ci return -EFAULT; 36762306a36Sopenharmony_ci return 0; 36862306a36Sopenharmony_ci} 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_cistatic unsigned long elf_map(struct file *filep, unsigned long addr, 37162306a36Sopenharmony_ci const struct elf_phdr *eppnt, int prot, int type, 37262306a36Sopenharmony_ci unsigned long total_size) 37362306a36Sopenharmony_ci{ 37462306a36Sopenharmony_ci unsigned long map_addr; 37562306a36Sopenharmony_ci unsigned long size = eppnt->p_filesz + ELF_PAGEOFFSET(eppnt->p_vaddr); 37662306a36Sopenharmony_ci unsigned long off = eppnt->p_offset - ELF_PAGEOFFSET(eppnt->p_vaddr); 37762306a36Sopenharmony_ci addr = ELF_PAGESTART(addr); 37862306a36Sopenharmony_ci size = ELF_PAGEALIGN(size); 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci /* mmap() will return -EINVAL if given a zero size, but a 38162306a36Sopenharmony_ci * segment with zero filesize is perfectly valid */ 38262306a36Sopenharmony_ci if (!size) 38362306a36Sopenharmony_ci return addr; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci /* 38662306a36Sopenharmony_ci * total_size is the size of the ELF (interpreter) image. 38762306a36Sopenharmony_ci * The _first_ mmap needs to know the full size, otherwise 38862306a36Sopenharmony_ci * randomization might put this image into an overlapping 38962306a36Sopenharmony_ci * position with the ELF binary image. (since size < total_size) 39062306a36Sopenharmony_ci * So we first map the 'big' image - and unmap the remainder at 39162306a36Sopenharmony_ci * the end. (which unmap is needed for ELF images with holes.) 39262306a36Sopenharmony_ci */ 39362306a36Sopenharmony_ci if (total_size) { 39462306a36Sopenharmony_ci total_size = ELF_PAGEALIGN(total_size); 39562306a36Sopenharmony_ci map_addr = vm_mmap(filep, addr, total_size, prot, type, off); 39662306a36Sopenharmony_ci if (!BAD_ADDR(map_addr)) 39762306a36Sopenharmony_ci vm_munmap(map_addr+size, total_size-size); 39862306a36Sopenharmony_ci } else 39962306a36Sopenharmony_ci map_addr = vm_mmap(filep, addr, size, prot, type, off); 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci if ((type & MAP_FIXED_NOREPLACE) && 40262306a36Sopenharmony_ci PTR_ERR((void *)map_addr) == -EEXIST) 40362306a36Sopenharmony_ci pr_info("%d (%s): Uhuuh, elf segment at %px requested but the memory is mapped already\n", 40462306a36Sopenharmony_ci task_pid_nr(current), current->comm, (void *)addr); 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci return(map_addr); 40762306a36Sopenharmony_ci} 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_cistatic unsigned long total_mapping_size(const struct elf_phdr *phdr, int nr) 41062306a36Sopenharmony_ci{ 41162306a36Sopenharmony_ci elf_addr_t min_addr = -1; 41262306a36Sopenharmony_ci elf_addr_t max_addr = 0; 41362306a36Sopenharmony_ci bool pt_load = false; 41462306a36Sopenharmony_ci int i; 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci for (i = 0; i < nr; i++) { 41762306a36Sopenharmony_ci if (phdr[i].p_type == PT_LOAD) { 41862306a36Sopenharmony_ci min_addr = min(min_addr, ELF_PAGESTART(phdr[i].p_vaddr)); 41962306a36Sopenharmony_ci max_addr = max(max_addr, phdr[i].p_vaddr + phdr[i].p_memsz); 42062306a36Sopenharmony_ci pt_load = true; 42162306a36Sopenharmony_ci } 42262306a36Sopenharmony_ci } 42362306a36Sopenharmony_ci return pt_load ? (max_addr - min_addr) : 0; 42462306a36Sopenharmony_ci} 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_cistatic int elf_read(struct file *file, void *buf, size_t len, loff_t pos) 42762306a36Sopenharmony_ci{ 42862306a36Sopenharmony_ci ssize_t rv; 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci rv = kernel_read(file, buf, len, &pos); 43162306a36Sopenharmony_ci if (unlikely(rv != len)) { 43262306a36Sopenharmony_ci return (rv < 0) ? rv : -EIO; 43362306a36Sopenharmony_ci } 43462306a36Sopenharmony_ci return 0; 43562306a36Sopenharmony_ci} 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_cistatic unsigned long maximum_alignment(struct elf_phdr *cmds, int nr) 43862306a36Sopenharmony_ci{ 43962306a36Sopenharmony_ci unsigned long alignment = 0; 44062306a36Sopenharmony_ci int i; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci for (i = 0; i < nr; i++) { 44362306a36Sopenharmony_ci if (cmds[i].p_type == PT_LOAD) { 44462306a36Sopenharmony_ci unsigned long p_align = cmds[i].p_align; 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci /* skip non-power of two alignments as invalid */ 44762306a36Sopenharmony_ci if (!is_power_of_2(p_align)) 44862306a36Sopenharmony_ci continue; 44962306a36Sopenharmony_ci alignment = max(alignment, p_align); 45062306a36Sopenharmony_ci } 45162306a36Sopenharmony_ci } 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci /* ensure we align to at least one page */ 45462306a36Sopenharmony_ci return ELF_PAGEALIGN(alignment); 45562306a36Sopenharmony_ci} 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci/** 45862306a36Sopenharmony_ci * load_elf_phdrs() - load ELF program headers 45962306a36Sopenharmony_ci * @elf_ex: ELF header of the binary whose program headers should be loaded 46062306a36Sopenharmony_ci * @elf_file: the opened ELF binary file 46162306a36Sopenharmony_ci * 46262306a36Sopenharmony_ci * Loads ELF program headers from the binary file elf_file, which has the ELF 46362306a36Sopenharmony_ci * header pointed to by elf_ex, into a newly allocated array. The caller is 46462306a36Sopenharmony_ci * responsible for freeing the allocated data. Returns NULL upon failure. 46562306a36Sopenharmony_ci */ 46662306a36Sopenharmony_cistatic struct elf_phdr *load_elf_phdrs(const struct elfhdr *elf_ex, 46762306a36Sopenharmony_ci struct file *elf_file) 46862306a36Sopenharmony_ci{ 46962306a36Sopenharmony_ci struct elf_phdr *elf_phdata = NULL; 47062306a36Sopenharmony_ci int retval = -1; 47162306a36Sopenharmony_ci unsigned int size; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci /* 47462306a36Sopenharmony_ci * If the size of this structure has changed, then punt, since 47562306a36Sopenharmony_ci * we will be doing the wrong thing. 47662306a36Sopenharmony_ci */ 47762306a36Sopenharmony_ci if (elf_ex->e_phentsize != sizeof(struct elf_phdr)) 47862306a36Sopenharmony_ci goto out; 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci /* Sanity check the number of program headers... */ 48162306a36Sopenharmony_ci /* ...and their total size. */ 48262306a36Sopenharmony_ci size = sizeof(struct elf_phdr) * elf_ex->e_phnum; 48362306a36Sopenharmony_ci if (size == 0 || size > 65536 || size > ELF_MIN_ALIGN) 48462306a36Sopenharmony_ci goto out; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci elf_phdata = kmalloc(size, GFP_KERNEL); 48762306a36Sopenharmony_ci if (!elf_phdata) 48862306a36Sopenharmony_ci goto out; 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci /* Read in the program headers */ 49162306a36Sopenharmony_ci retval = elf_read(elf_file, elf_phdata, size, elf_ex->e_phoff); 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ciout: 49462306a36Sopenharmony_ci if (retval) { 49562306a36Sopenharmony_ci kfree(elf_phdata); 49662306a36Sopenharmony_ci elf_phdata = NULL; 49762306a36Sopenharmony_ci } 49862306a36Sopenharmony_ci return elf_phdata; 49962306a36Sopenharmony_ci} 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci#ifndef CONFIG_ARCH_BINFMT_ELF_STATE 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci/** 50462306a36Sopenharmony_ci * struct arch_elf_state - arch-specific ELF loading state 50562306a36Sopenharmony_ci * 50662306a36Sopenharmony_ci * This structure is used to preserve architecture specific data during 50762306a36Sopenharmony_ci * the loading of an ELF file, throughout the checking of architecture 50862306a36Sopenharmony_ci * specific ELF headers & through to the point where the ELF load is 50962306a36Sopenharmony_ci * known to be proceeding (ie. SET_PERSONALITY). 51062306a36Sopenharmony_ci * 51162306a36Sopenharmony_ci * This implementation is a dummy for architectures which require no 51262306a36Sopenharmony_ci * specific state. 51362306a36Sopenharmony_ci */ 51462306a36Sopenharmony_cistruct arch_elf_state { 51562306a36Sopenharmony_ci}; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci#define INIT_ARCH_ELF_STATE {} 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci/** 52062306a36Sopenharmony_ci * arch_elf_pt_proc() - check a PT_LOPROC..PT_HIPROC ELF program header 52162306a36Sopenharmony_ci * @ehdr: The main ELF header 52262306a36Sopenharmony_ci * @phdr: The program header to check 52362306a36Sopenharmony_ci * @elf: The open ELF file 52462306a36Sopenharmony_ci * @is_interp: True if the phdr is from the interpreter of the ELF being 52562306a36Sopenharmony_ci * loaded, else false. 52662306a36Sopenharmony_ci * @state: Architecture-specific state preserved throughout the process 52762306a36Sopenharmony_ci * of loading the ELF. 52862306a36Sopenharmony_ci * 52962306a36Sopenharmony_ci * Inspects the program header phdr to validate its correctness and/or 53062306a36Sopenharmony_ci * suitability for the system. Called once per ELF program header in the 53162306a36Sopenharmony_ci * range PT_LOPROC to PT_HIPROC, for both the ELF being loaded and its 53262306a36Sopenharmony_ci * interpreter. 53362306a36Sopenharmony_ci * 53462306a36Sopenharmony_ci * Return: Zero to proceed with the ELF load, non-zero to fail the ELF load 53562306a36Sopenharmony_ci * with that return code. 53662306a36Sopenharmony_ci */ 53762306a36Sopenharmony_cistatic inline int arch_elf_pt_proc(struct elfhdr *ehdr, 53862306a36Sopenharmony_ci struct elf_phdr *phdr, 53962306a36Sopenharmony_ci struct file *elf, bool is_interp, 54062306a36Sopenharmony_ci struct arch_elf_state *state) 54162306a36Sopenharmony_ci{ 54262306a36Sopenharmony_ci /* Dummy implementation, always proceed */ 54362306a36Sopenharmony_ci return 0; 54462306a36Sopenharmony_ci} 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci/** 54762306a36Sopenharmony_ci * arch_check_elf() - check an ELF executable 54862306a36Sopenharmony_ci * @ehdr: The main ELF header 54962306a36Sopenharmony_ci * @has_interp: True if the ELF has an interpreter, else false. 55062306a36Sopenharmony_ci * @interp_ehdr: The interpreter's ELF header 55162306a36Sopenharmony_ci * @state: Architecture-specific state preserved throughout the process 55262306a36Sopenharmony_ci * of loading the ELF. 55362306a36Sopenharmony_ci * 55462306a36Sopenharmony_ci * Provides a final opportunity for architecture code to reject the loading 55562306a36Sopenharmony_ci * of the ELF & cause an exec syscall to return an error. This is called after 55662306a36Sopenharmony_ci * all program headers to be checked by arch_elf_pt_proc have been. 55762306a36Sopenharmony_ci * 55862306a36Sopenharmony_ci * Return: Zero to proceed with the ELF load, non-zero to fail the ELF load 55962306a36Sopenharmony_ci * with that return code. 56062306a36Sopenharmony_ci */ 56162306a36Sopenharmony_cistatic inline int arch_check_elf(struct elfhdr *ehdr, bool has_interp, 56262306a36Sopenharmony_ci struct elfhdr *interp_ehdr, 56362306a36Sopenharmony_ci struct arch_elf_state *state) 56462306a36Sopenharmony_ci{ 56562306a36Sopenharmony_ci /* Dummy implementation, always proceed */ 56662306a36Sopenharmony_ci return 0; 56762306a36Sopenharmony_ci} 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci#endif /* !CONFIG_ARCH_BINFMT_ELF_STATE */ 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_cistatic inline int make_prot(u32 p_flags, struct arch_elf_state *arch_state, 57262306a36Sopenharmony_ci bool has_interp, bool is_interp) 57362306a36Sopenharmony_ci{ 57462306a36Sopenharmony_ci int prot = 0; 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci if (p_flags & PF_R) 57762306a36Sopenharmony_ci prot |= PROT_READ; 57862306a36Sopenharmony_ci if (p_flags & PF_W) 57962306a36Sopenharmony_ci prot |= PROT_WRITE; 58062306a36Sopenharmony_ci if (p_flags & PF_X) 58162306a36Sopenharmony_ci prot |= PROT_EXEC; 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci return arch_elf_adjust_prot(prot, arch_state, has_interp, is_interp); 58462306a36Sopenharmony_ci} 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci/* This is much more generalized than the library routine read function, 58762306a36Sopenharmony_ci so we keep this separate. Technically the library read function 58862306a36Sopenharmony_ci is only provided so that we can read a.out libraries that have 58962306a36Sopenharmony_ci an ELF header */ 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_cistatic unsigned long load_elf_interp(struct elfhdr *interp_elf_ex, 59262306a36Sopenharmony_ci struct file *interpreter, 59362306a36Sopenharmony_ci unsigned long no_base, struct elf_phdr *interp_elf_phdata, 59462306a36Sopenharmony_ci struct arch_elf_state *arch_state) 59562306a36Sopenharmony_ci{ 59662306a36Sopenharmony_ci struct elf_phdr *eppnt; 59762306a36Sopenharmony_ci unsigned long load_addr = 0; 59862306a36Sopenharmony_ci int load_addr_set = 0; 59962306a36Sopenharmony_ci unsigned long last_bss = 0, elf_bss = 0; 60062306a36Sopenharmony_ci int bss_prot = 0; 60162306a36Sopenharmony_ci unsigned long error = ~0UL; 60262306a36Sopenharmony_ci unsigned long total_size; 60362306a36Sopenharmony_ci int i; 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci /* First of all, some simple consistency checks */ 60662306a36Sopenharmony_ci if (interp_elf_ex->e_type != ET_EXEC && 60762306a36Sopenharmony_ci interp_elf_ex->e_type != ET_DYN) 60862306a36Sopenharmony_ci goto out; 60962306a36Sopenharmony_ci if (!elf_check_arch(interp_elf_ex) || 61062306a36Sopenharmony_ci elf_check_fdpic(interp_elf_ex)) 61162306a36Sopenharmony_ci goto out; 61262306a36Sopenharmony_ci if (!interpreter->f_op->mmap) 61362306a36Sopenharmony_ci goto out; 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci total_size = total_mapping_size(interp_elf_phdata, 61662306a36Sopenharmony_ci interp_elf_ex->e_phnum); 61762306a36Sopenharmony_ci if (!total_size) { 61862306a36Sopenharmony_ci error = -EINVAL; 61962306a36Sopenharmony_ci goto out; 62062306a36Sopenharmony_ci } 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci eppnt = interp_elf_phdata; 62362306a36Sopenharmony_ci for (i = 0; i < interp_elf_ex->e_phnum; i++, eppnt++) { 62462306a36Sopenharmony_ci if (eppnt->p_type == PT_LOAD) { 62562306a36Sopenharmony_ci int elf_type = MAP_PRIVATE; 62662306a36Sopenharmony_ci int elf_prot = make_prot(eppnt->p_flags, arch_state, 62762306a36Sopenharmony_ci true, true); 62862306a36Sopenharmony_ci unsigned long vaddr = 0; 62962306a36Sopenharmony_ci unsigned long k, map_addr; 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci vaddr = eppnt->p_vaddr; 63262306a36Sopenharmony_ci if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) 63362306a36Sopenharmony_ci elf_type |= MAP_FIXED; 63462306a36Sopenharmony_ci else if (no_base && interp_elf_ex->e_type == ET_DYN) 63562306a36Sopenharmony_ci load_addr = -vaddr; 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci map_addr = elf_map(interpreter, load_addr + vaddr, 63862306a36Sopenharmony_ci eppnt, elf_prot, elf_type, total_size); 63962306a36Sopenharmony_ci total_size = 0; 64062306a36Sopenharmony_ci error = map_addr; 64162306a36Sopenharmony_ci if (BAD_ADDR(map_addr)) 64262306a36Sopenharmony_ci goto out; 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci if (!load_addr_set && 64562306a36Sopenharmony_ci interp_elf_ex->e_type == ET_DYN) { 64662306a36Sopenharmony_ci load_addr = map_addr - ELF_PAGESTART(vaddr); 64762306a36Sopenharmony_ci load_addr_set = 1; 64862306a36Sopenharmony_ci } 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci /* 65162306a36Sopenharmony_ci * Check to see if the section's size will overflow the 65262306a36Sopenharmony_ci * allowed task size. Note that p_filesz must always be 65362306a36Sopenharmony_ci * <= p_memsize so it's only necessary to check p_memsz. 65462306a36Sopenharmony_ci */ 65562306a36Sopenharmony_ci k = load_addr + eppnt->p_vaddr; 65662306a36Sopenharmony_ci if (BAD_ADDR(k) || 65762306a36Sopenharmony_ci eppnt->p_filesz > eppnt->p_memsz || 65862306a36Sopenharmony_ci eppnt->p_memsz > TASK_SIZE || 65962306a36Sopenharmony_ci TASK_SIZE - eppnt->p_memsz < k) { 66062306a36Sopenharmony_ci error = -ENOMEM; 66162306a36Sopenharmony_ci goto out; 66262306a36Sopenharmony_ci } 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci /* 66562306a36Sopenharmony_ci * Find the end of the file mapping for this phdr, and 66662306a36Sopenharmony_ci * keep track of the largest address we see for this. 66762306a36Sopenharmony_ci */ 66862306a36Sopenharmony_ci k = load_addr + eppnt->p_vaddr + eppnt->p_filesz; 66962306a36Sopenharmony_ci if (k > elf_bss) 67062306a36Sopenharmony_ci elf_bss = k; 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci /* 67362306a36Sopenharmony_ci * Do the same thing for the memory mapping - between 67462306a36Sopenharmony_ci * elf_bss and last_bss is the bss section. 67562306a36Sopenharmony_ci */ 67662306a36Sopenharmony_ci k = load_addr + eppnt->p_vaddr + eppnt->p_memsz; 67762306a36Sopenharmony_ci if (k > last_bss) { 67862306a36Sopenharmony_ci last_bss = k; 67962306a36Sopenharmony_ci bss_prot = elf_prot; 68062306a36Sopenharmony_ci } 68162306a36Sopenharmony_ci } 68262306a36Sopenharmony_ci } 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci /* 68562306a36Sopenharmony_ci * Now fill out the bss section: first pad the last page from 68662306a36Sopenharmony_ci * the file up to the page boundary, and zero it from elf_bss 68762306a36Sopenharmony_ci * up to the end of the page. 68862306a36Sopenharmony_ci */ 68962306a36Sopenharmony_ci if (padzero(elf_bss)) { 69062306a36Sopenharmony_ci error = -EFAULT; 69162306a36Sopenharmony_ci goto out; 69262306a36Sopenharmony_ci } 69362306a36Sopenharmony_ci /* 69462306a36Sopenharmony_ci * Next, align both the file and mem bss up to the page size, 69562306a36Sopenharmony_ci * since this is where elf_bss was just zeroed up to, and where 69662306a36Sopenharmony_ci * last_bss will end after the vm_brk_flags() below. 69762306a36Sopenharmony_ci */ 69862306a36Sopenharmony_ci elf_bss = ELF_PAGEALIGN(elf_bss); 69962306a36Sopenharmony_ci last_bss = ELF_PAGEALIGN(last_bss); 70062306a36Sopenharmony_ci /* Finally, if there is still more bss to allocate, do it. */ 70162306a36Sopenharmony_ci if (last_bss > elf_bss) { 70262306a36Sopenharmony_ci error = vm_brk_flags(elf_bss, last_bss - elf_bss, 70362306a36Sopenharmony_ci bss_prot & PROT_EXEC ? VM_EXEC : 0); 70462306a36Sopenharmony_ci if (error) 70562306a36Sopenharmony_ci goto out; 70662306a36Sopenharmony_ci } 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci error = load_addr; 70962306a36Sopenharmony_ciout: 71062306a36Sopenharmony_ci return error; 71162306a36Sopenharmony_ci} 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci/* 71462306a36Sopenharmony_ci * These are the functions used to load ELF style executables and shared 71562306a36Sopenharmony_ci * libraries. There is no binary dependent code anywhere else. 71662306a36Sopenharmony_ci */ 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_cistatic int parse_elf_property(const char *data, size_t *off, size_t datasz, 71962306a36Sopenharmony_ci struct arch_elf_state *arch, 72062306a36Sopenharmony_ci bool have_prev_type, u32 *prev_type) 72162306a36Sopenharmony_ci{ 72262306a36Sopenharmony_ci size_t o, step; 72362306a36Sopenharmony_ci const struct gnu_property *pr; 72462306a36Sopenharmony_ci int ret; 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci if (*off == datasz) 72762306a36Sopenharmony_ci return -ENOENT; 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci if (WARN_ON_ONCE(*off > datasz || *off % ELF_GNU_PROPERTY_ALIGN)) 73062306a36Sopenharmony_ci return -EIO; 73162306a36Sopenharmony_ci o = *off; 73262306a36Sopenharmony_ci datasz -= *off; 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci if (datasz < sizeof(*pr)) 73562306a36Sopenharmony_ci return -ENOEXEC; 73662306a36Sopenharmony_ci pr = (const struct gnu_property *)(data + o); 73762306a36Sopenharmony_ci o += sizeof(*pr); 73862306a36Sopenharmony_ci datasz -= sizeof(*pr); 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci if (pr->pr_datasz > datasz) 74162306a36Sopenharmony_ci return -ENOEXEC; 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci WARN_ON_ONCE(o % ELF_GNU_PROPERTY_ALIGN); 74462306a36Sopenharmony_ci step = round_up(pr->pr_datasz, ELF_GNU_PROPERTY_ALIGN); 74562306a36Sopenharmony_ci if (step > datasz) 74662306a36Sopenharmony_ci return -ENOEXEC; 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci /* Properties are supposed to be unique and sorted on pr_type: */ 74962306a36Sopenharmony_ci if (have_prev_type && pr->pr_type <= *prev_type) 75062306a36Sopenharmony_ci return -ENOEXEC; 75162306a36Sopenharmony_ci *prev_type = pr->pr_type; 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci ret = arch_parse_elf_property(pr->pr_type, data + o, 75462306a36Sopenharmony_ci pr->pr_datasz, ELF_COMPAT, arch); 75562306a36Sopenharmony_ci if (ret) 75662306a36Sopenharmony_ci return ret; 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci *off = o + step; 75962306a36Sopenharmony_ci return 0; 76062306a36Sopenharmony_ci} 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci#define NOTE_DATA_SZ SZ_1K 76362306a36Sopenharmony_ci#define GNU_PROPERTY_TYPE_0_NAME "GNU" 76462306a36Sopenharmony_ci#define NOTE_NAME_SZ (sizeof(GNU_PROPERTY_TYPE_0_NAME)) 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_cistatic int parse_elf_properties(struct file *f, const struct elf_phdr *phdr, 76762306a36Sopenharmony_ci struct arch_elf_state *arch) 76862306a36Sopenharmony_ci{ 76962306a36Sopenharmony_ci union { 77062306a36Sopenharmony_ci struct elf_note nhdr; 77162306a36Sopenharmony_ci char data[NOTE_DATA_SZ]; 77262306a36Sopenharmony_ci } note; 77362306a36Sopenharmony_ci loff_t pos; 77462306a36Sopenharmony_ci ssize_t n; 77562306a36Sopenharmony_ci size_t off, datasz; 77662306a36Sopenharmony_ci int ret; 77762306a36Sopenharmony_ci bool have_prev_type; 77862306a36Sopenharmony_ci u32 prev_type; 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci if (!IS_ENABLED(CONFIG_ARCH_USE_GNU_PROPERTY) || !phdr) 78162306a36Sopenharmony_ci return 0; 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci /* load_elf_binary() shouldn't call us unless this is true... */ 78462306a36Sopenharmony_ci if (WARN_ON_ONCE(phdr->p_type != PT_GNU_PROPERTY)) 78562306a36Sopenharmony_ci return -ENOEXEC; 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci /* If the properties are crazy large, that's too bad (for now): */ 78862306a36Sopenharmony_ci if (phdr->p_filesz > sizeof(note)) 78962306a36Sopenharmony_ci return -ENOEXEC; 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci pos = phdr->p_offset; 79262306a36Sopenharmony_ci n = kernel_read(f, ¬e, phdr->p_filesz, &pos); 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(note) < sizeof(note.nhdr) + NOTE_NAME_SZ); 79562306a36Sopenharmony_ci if (n < 0 || n < sizeof(note.nhdr) + NOTE_NAME_SZ) 79662306a36Sopenharmony_ci return -EIO; 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci if (note.nhdr.n_type != NT_GNU_PROPERTY_TYPE_0 || 79962306a36Sopenharmony_ci note.nhdr.n_namesz != NOTE_NAME_SZ || 80062306a36Sopenharmony_ci strncmp(note.data + sizeof(note.nhdr), 80162306a36Sopenharmony_ci GNU_PROPERTY_TYPE_0_NAME, n - sizeof(note.nhdr))) 80262306a36Sopenharmony_ci return -ENOEXEC; 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci off = round_up(sizeof(note.nhdr) + NOTE_NAME_SZ, 80562306a36Sopenharmony_ci ELF_GNU_PROPERTY_ALIGN); 80662306a36Sopenharmony_ci if (off > n) 80762306a36Sopenharmony_ci return -ENOEXEC; 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci if (note.nhdr.n_descsz > n - off) 81062306a36Sopenharmony_ci return -ENOEXEC; 81162306a36Sopenharmony_ci datasz = off + note.nhdr.n_descsz; 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci have_prev_type = false; 81462306a36Sopenharmony_ci do { 81562306a36Sopenharmony_ci ret = parse_elf_property(note.data, &off, datasz, arch, 81662306a36Sopenharmony_ci have_prev_type, &prev_type); 81762306a36Sopenharmony_ci have_prev_type = true; 81862306a36Sopenharmony_ci } while (!ret); 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci return ret == -ENOENT ? 0 : ret; 82162306a36Sopenharmony_ci} 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_cistatic int load_elf_binary(struct linux_binprm *bprm) 82462306a36Sopenharmony_ci{ 82562306a36Sopenharmony_ci struct file *interpreter = NULL; /* to shut gcc up */ 82662306a36Sopenharmony_ci unsigned long load_bias = 0, phdr_addr = 0; 82762306a36Sopenharmony_ci int first_pt_load = 1; 82862306a36Sopenharmony_ci unsigned long error; 82962306a36Sopenharmony_ci struct elf_phdr *elf_ppnt, *elf_phdata, *interp_elf_phdata = NULL; 83062306a36Sopenharmony_ci struct elf_phdr *elf_property_phdata = NULL; 83162306a36Sopenharmony_ci unsigned long elf_bss, elf_brk; 83262306a36Sopenharmony_ci int bss_prot = 0; 83362306a36Sopenharmony_ci int retval, i; 83462306a36Sopenharmony_ci unsigned long elf_entry; 83562306a36Sopenharmony_ci unsigned long e_entry; 83662306a36Sopenharmony_ci unsigned long interp_load_addr = 0; 83762306a36Sopenharmony_ci unsigned long start_code, end_code, start_data, end_data; 83862306a36Sopenharmony_ci unsigned long reloc_func_desc __maybe_unused = 0; 83962306a36Sopenharmony_ci int executable_stack = EXSTACK_DEFAULT; 84062306a36Sopenharmony_ci struct elfhdr *elf_ex = (struct elfhdr *)bprm->buf; 84162306a36Sopenharmony_ci struct elfhdr *interp_elf_ex = NULL; 84262306a36Sopenharmony_ci struct arch_elf_state arch_state = INIT_ARCH_ELF_STATE; 84362306a36Sopenharmony_ci struct mm_struct *mm; 84462306a36Sopenharmony_ci struct pt_regs *regs; 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci retval = -ENOEXEC; 84762306a36Sopenharmony_ci /* First of all, some simple consistency checks */ 84862306a36Sopenharmony_ci if (memcmp(elf_ex->e_ident, ELFMAG, SELFMAG) != 0) 84962306a36Sopenharmony_ci goto out; 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci if (elf_ex->e_type != ET_EXEC && elf_ex->e_type != ET_DYN) 85262306a36Sopenharmony_ci goto out; 85362306a36Sopenharmony_ci if (!elf_check_arch(elf_ex)) 85462306a36Sopenharmony_ci goto out; 85562306a36Sopenharmony_ci if (elf_check_fdpic(elf_ex)) 85662306a36Sopenharmony_ci goto out; 85762306a36Sopenharmony_ci if (!bprm->file->f_op->mmap) 85862306a36Sopenharmony_ci goto out; 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci elf_phdata = load_elf_phdrs(elf_ex, bprm->file); 86162306a36Sopenharmony_ci if (!elf_phdata) 86262306a36Sopenharmony_ci goto out; 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci elf_ppnt = elf_phdata; 86562306a36Sopenharmony_ci for (i = 0; i < elf_ex->e_phnum; i++, elf_ppnt++) { 86662306a36Sopenharmony_ci char *elf_interpreter; 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci if (elf_ppnt->p_type == PT_GNU_PROPERTY) { 86962306a36Sopenharmony_ci elf_property_phdata = elf_ppnt; 87062306a36Sopenharmony_ci continue; 87162306a36Sopenharmony_ci } 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci if (elf_ppnt->p_type != PT_INTERP) 87462306a36Sopenharmony_ci continue; 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci /* 87762306a36Sopenharmony_ci * This is the program interpreter used for shared libraries - 87862306a36Sopenharmony_ci * for now assume that this is an a.out format binary. 87962306a36Sopenharmony_ci */ 88062306a36Sopenharmony_ci retval = -ENOEXEC; 88162306a36Sopenharmony_ci if (elf_ppnt->p_filesz > PATH_MAX || elf_ppnt->p_filesz < 2) 88262306a36Sopenharmony_ci goto out_free_ph; 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci retval = -ENOMEM; 88562306a36Sopenharmony_ci elf_interpreter = kmalloc(elf_ppnt->p_filesz, GFP_KERNEL); 88662306a36Sopenharmony_ci if (!elf_interpreter) 88762306a36Sopenharmony_ci goto out_free_ph; 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci retval = elf_read(bprm->file, elf_interpreter, elf_ppnt->p_filesz, 89062306a36Sopenharmony_ci elf_ppnt->p_offset); 89162306a36Sopenharmony_ci if (retval < 0) 89262306a36Sopenharmony_ci goto out_free_interp; 89362306a36Sopenharmony_ci /* make sure path is NULL terminated */ 89462306a36Sopenharmony_ci retval = -ENOEXEC; 89562306a36Sopenharmony_ci if (elf_interpreter[elf_ppnt->p_filesz - 1] != '\0') 89662306a36Sopenharmony_ci goto out_free_interp; 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci interpreter = open_exec(elf_interpreter); 89962306a36Sopenharmony_ci kfree(elf_interpreter); 90062306a36Sopenharmony_ci retval = PTR_ERR(interpreter); 90162306a36Sopenharmony_ci if (IS_ERR(interpreter)) 90262306a36Sopenharmony_ci goto out_free_ph; 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci /* 90562306a36Sopenharmony_ci * If the binary is not readable then enforce mm->dumpable = 0 90662306a36Sopenharmony_ci * regardless of the interpreter's permissions. 90762306a36Sopenharmony_ci */ 90862306a36Sopenharmony_ci would_dump(bprm, interpreter); 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci interp_elf_ex = kmalloc(sizeof(*interp_elf_ex), GFP_KERNEL); 91162306a36Sopenharmony_ci if (!interp_elf_ex) { 91262306a36Sopenharmony_ci retval = -ENOMEM; 91362306a36Sopenharmony_ci goto out_free_file; 91462306a36Sopenharmony_ci } 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci /* Get the exec headers */ 91762306a36Sopenharmony_ci retval = elf_read(interpreter, interp_elf_ex, 91862306a36Sopenharmony_ci sizeof(*interp_elf_ex), 0); 91962306a36Sopenharmony_ci if (retval < 0) 92062306a36Sopenharmony_ci goto out_free_dentry; 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci break; 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ciout_free_interp: 92562306a36Sopenharmony_ci kfree(elf_interpreter); 92662306a36Sopenharmony_ci goto out_free_ph; 92762306a36Sopenharmony_ci } 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci elf_ppnt = elf_phdata; 93062306a36Sopenharmony_ci for (i = 0; i < elf_ex->e_phnum; i++, elf_ppnt++) 93162306a36Sopenharmony_ci switch (elf_ppnt->p_type) { 93262306a36Sopenharmony_ci case PT_GNU_STACK: 93362306a36Sopenharmony_ci if (elf_ppnt->p_flags & PF_X) 93462306a36Sopenharmony_ci executable_stack = EXSTACK_ENABLE_X; 93562306a36Sopenharmony_ci else 93662306a36Sopenharmony_ci executable_stack = EXSTACK_DISABLE_X; 93762306a36Sopenharmony_ci break; 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci case PT_LOPROC ... PT_HIPROC: 94062306a36Sopenharmony_ci retval = arch_elf_pt_proc(elf_ex, elf_ppnt, 94162306a36Sopenharmony_ci bprm->file, false, 94262306a36Sopenharmony_ci &arch_state); 94362306a36Sopenharmony_ci if (retval) 94462306a36Sopenharmony_ci goto out_free_dentry; 94562306a36Sopenharmony_ci break; 94662306a36Sopenharmony_ci } 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ci /* Some simple consistency checks for the interpreter */ 94962306a36Sopenharmony_ci if (interpreter) { 95062306a36Sopenharmony_ci retval = -ELIBBAD; 95162306a36Sopenharmony_ci /* Not an ELF interpreter */ 95262306a36Sopenharmony_ci if (memcmp(interp_elf_ex->e_ident, ELFMAG, SELFMAG) != 0) 95362306a36Sopenharmony_ci goto out_free_dentry; 95462306a36Sopenharmony_ci /* Verify the interpreter has a valid arch */ 95562306a36Sopenharmony_ci if (!elf_check_arch(interp_elf_ex) || 95662306a36Sopenharmony_ci elf_check_fdpic(interp_elf_ex)) 95762306a36Sopenharmony_ci goto out_free_dentry; 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci /* Load the interpreter program headers */ 96062306a36Sopenharmony_ci interp_elf_phdata = load_elf_phdrs(interp_elf_ex, 96162306a36Sopenharmony_ci interpreter); 96262306a36Sopenharmony_ci if (!interp_elf_phdata) 96362306a36Sopenharmony_ci goto out_free_dentry; 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci /* Pass PT_LOPROC..PT_HIPROC headers to arch code */ 96662306a36Sopenharmony_ci elf_property_phdata = NULL; 96762306a36Sopenharmony_ci elf_ppnt = interp_elf_phdata; 96862306a36Sopenharmony_ci for (i = 0; i < interp_elf_ex->e_phnum; i++, elf_ppnt++) 96962306a36Sopenharmony_ci switch (elf_ppnt->p_type) { 97062306a36Sopenharmony_ci case PT_GNU_PROPERTY: 97162306a36Sopenharmony_ci elf_property_phdata = elf_ppnt; 97262306a36Sopenharmony_ci break; 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_ci case PT_LOPROC ... PT_HIPROC: 97562306a36Sopenharmony_ci retval = arch_elf_pt_proc(interp_elf_ex, 97662306a36Sopenharmony_ci elf_ppnt, interpreter, 97762306a36Sopenharmony_ci true, &arch_state); 97862306a36Sopenharmony_ci if (retval) 97962306a36Sopenharmony_ci goto out_free_dentry; 98062306a36Sopenharmony_ci break; 98162306a36Sopenharmony_ci } 98262306a36Sopenharmony_ci } 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci retval = parse_elf_properties(interpreter ?: bprm->file, 98562306a36Sopenharmony_ci elf_property_phdata, &arch_state); 98662306a36Sopenharmony_ci if (retval) 98762306a36Sopenharmony_ci goto out_free_dentry; 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci /* 99062306a36Sopenharmony_ci * Allow arch code to reject the ELF at this point, whilst it's 99162306a36Sopenharmony_ci * still possible to return an error to the code that invoked 99262306a36Sopenharmony_ci * the exec syscall. 99362306a36Sopenharmony_ci */ 99462306a36Sopenharmony_ci retval = arch_check_elf(elf_ex, 99562306a36Sopenharmony_ci !!interpreter, interp_elf_ex, 99662306a36Sopenharmony_ci &arch_state); 99762306a36Sopenharmony_ci if (retval) 99862306a36Sopenharmony_ci goto out_free_dentry; 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci /* Flush all traces of the currently running executable */ 100162306a36Sopenharmony_ci retval = begin_new_exec(bprm); 100262306a36Sopenharmony_ci if (retval) 100362306a36Sopenharmony_ci goto out_free_dentry; 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ci /* Do this immediately, since STACK_TOP as used in setup_arg_pages 100662306a36Sopenharmony_ci may depend on the personality. */ 100762306a36Sopenharmony_ci SET_PERSONALITY2(*elf_ex, &arch_state); 100862306a36Sopenharmony_ci if (elf_read_implies_exec(*elf_ex, executable_stack)) 100962306a36Sopenharmony_ci current->personality |= READ_IMPLIES_EXEC; 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space) 101262306a36Sopenharmony_ci current->flags |= PF_RANDOMIZE; 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci setup_new_exec(bprm); 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci /* Do this so that we can load the interpreter, if need be. We will 101762306a36Sopenharmony_ci change some of these later */ 101862306a36Sopenharmony_ci retval = setup_arg_pages(bprm, randomize_stack_top(STACK_TOP), 101962306a36Sopenharmony_ci executable_stack); 102062306a36Sopenharmony_ci if (retval < 0) 102162306a36Sopenharmony_ci goto out_free_dentry; 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci elf_bss = 0; 102462306a36Sopenharmony_ci elf_brk = 0; 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_ci start_code = ~0UL; 102762306a36Sopenharmony_ci end_code = 0; 102862306a36Sopenharmony_ci start_data = 0; 102962306a36Sopenharmony_ci end_data = 0; 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_ci /* Now we do a little grungy work by mmapping the ELF image into 103262306a36Sopenharmony_ci the correct location in memory. */ 103362306a36Sopenharmony_ci for(i = 0, elf_ppnt = elf_phdata; 103462306a36Sopenharmony_ci i < elf_ex->e_phnum; i++, elf_ppnt++) { 103562306a36Sopenharmony_ci int elf_prot, elf_flags; 103662306a36Sopenharmony_ci unsigned long k, vaddr; 103762306a36Sopenharmony_ci unsigned long total_size = 0; 103862306a36Sopenharmony_ci unsigned long alignment; 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_ci if (elf_ppnt->p_type != PT_LOAD) 104162306a36Sopenharmony_ci continue; 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_ci if (unlikely (elf_brk > elf_bss)) { 104462306a36Sopenharmony_ci unsigned long nbyte; 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci /* There was a PT_LOAD segment with p_memsz > p_filesz 104762306a36Sopenharmony_ci before this one. Map anonymous pages, if needed, 104862306a36Sopenharmony_ci and clear the area. */ 104962306a36Sopenharmony_ci retval = set_brk(elf_bss + load_bias, 105062306a36Sopenharmony_ci elf_brk + load_bias, 105162306a36Sopenharmony_ci bss_prot); 105262306a36Sopenharmony_ci if (retval) 105362306a36Sopenharmony_ci goto out_free_dentry; 105462306a36Sopenharmony_ci nbyte = ELF_PAGEOFFSET(elf_bss); 105562306a36Sopenharmony_ci if (nbyte) { 105662306a36Sopenharmony_ci nbyte = ELF_MIN_ALIGN - nbyte; 105762306a36Sopenharmony_ci if (nbyte > elf_brk - elf_bss) 105862306a36Sopenharmony_ci nbyte = elf_brk - elf_bss; 105962306a36Sopenharmony_ci if (clear_user((void __user *)elf_bss + 106062306a36Sopenharmony_ci load_bias, nbyte)) { 106162306a36Sopenharmony_ci /* 106262306a36Sopenharmony_ci * This bss-zeroing can fail if the ELF 106362306a36Sopenharmony_ci * file specifies odd protections. So 106462306a36Sopenharmony_ci * we don't check the return value 106562306a36Sopenharmony_ci */ 106662306a36Sopenharmony_ci } 106762306a36Sopenharmony_ci } 106862306a36Sopenharmony_ci } 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ci elf_prot = make_prot(elf_ppnt->p_flags, &arch_state, 107162306a36Sopenharmony_ci !!interpreter, false); 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci elf_flags = MAP_PRIVATE; 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci vaddr = elf_ppnt->p_vaddr; 107662306a36Sopenharmony_ci /* 107762306a36Sopenharmony_ci * The first time through the loop, first_pt_load is true: 107862306a36Sopenharmony_ci * layout will be calculated. Once set, use MAP_FIXED since 107962306a36Sopenharmony_ci * we know we've already safely mapped the entire region with 108062306a36Sopenharmony_ci * MAP_FIXED_NOREPLACE in the once-per-binary logic following. 108162306a36Sopenharmony_ci */ 108262306a36Sopenharmony_ci if (!first_pt_load) { 108362306a36Sopenharmony_ci elf_flags |= MAP_FIXED; 108462306a36Sopenharmony_ci } else if (elf_ex->e_type == ET_EXEC) { 108562306a36Sopenharmony_ci /* 108662306a36Sopenharmony_ci * This logic is run once for the first LOAD Program 108762306a36Sopenharmony_ci * Header for ET_EXEC binaries. No special handling 108862306a36Sopenharmony_ci * is needed. 108962306a36Sopenharmony_ci */ 109062306a36Sopenharmony_ci elf_flags |= MAP_FIXED_NOREPLACE; 109162306a36Sopenharmony_ci } else if (elf_ex->e_type == ET_DYN) { 109262306a36Sopenharmony_ci /* 109362306a36Sopenharmony_ci * This logic is run once for the first LOAD Program 109462306a36Sopenharmony_ci * Header for ET_DYN binaries to calculate the 109562306a36Sopenharmony_ci * randomization (load_bias) for all the LOAD 109662306a36Sopenharmony_ci * Program Headers. 109762306a36Sopenharmony_ci * 109862306a36Sopenharmony_ci * There are effectively two types of ET_DYN 109962306a36Sopenharmony_ci * binaries: programs (i.e. PIE: ET_DYN with INTERP) 110062306a36Sopenharmony_ci * and loaders (ET_DYN without INTERP, since they 110162306a36Sopenharmony_ci * _are_ the ELF interpreter). The loaders must 110262306a36Sopenharmony_ci * be loaded away from programs since the program 110362306a36Sopenharmony_ci * may otherwise collide with the loader (especially 110462306a36Sopenharmony_ci * for ET_EXEC which does not have a randomized 110562306a36Sopenharmony_ci * position). For example to handle invocations of 110662306a36Sopenharmony_ci * "./ld.so someprog" to test out a new version of 110762306a36Sopenharmony_ci * the loader, the subsequent program that the 110862306a36Sopenharmony_ci * loader loads must avoid the loader itself, so 110962306a36Sopenharmony_ci * they cannot share the same load range. Sufficient 111062306a36Sopenharmony_ci * room for the brk must be allocated with the 111162306a36Sopenharmony_ci * loader as well, since brk must be available with 111262306a36Sopenharmony_ci * the loader. 111362306a36Sopenharmony_ci * 111462306a36Sopenharmony_ci * Therefore, programs are loaded offset from 111562306a36Sopenharmony_ci * ELF_ET_DYN_BASE and loaders are loaded into the 111662306a36Sopenharmony_ci * independently randomized mmap region (0 load_bias 111762306a36Sopenharmony_ci * without MAP_FIXED nor MAP_FIXED_NOREPLACE). 111862306a36Sopenharmony_ci */ 111962306a36Sopenharmony_ci if (interpreter) { 112062306a36Sopenharmony_ci load_bias = ELF_ET_DYN_BASE; 112162306a36Sopenharmony_ci if (current->flags & PF_RANDOMIZE) 112262306a36Sopenharmony_ci load_bias += arch_mmap_rnd(); 112362306a36Sopenharmony_ci alignment = maximum_alignment(elf_phdata, elf_ex->e_phnum); 112462306a36Sopenharmony_ci if (alignment) 112562306a36Sopenharmony_ci load_bias &= ~(alignment - 1); 112662306a36Sopenharmony_ci elf_flags |= MAP_FIXED_NOREPLACE; 112762306a36Sopenharmony_ci } else 112862306a36Sopenharmony_ci load_bias = 0; 112962306a36Sopenharmony_ci 113062306a36Sopenharmony_ci /* 113162306a36Sopenharmony_ci * Since load_bias is used for all subsequent loading 113262306a36Sopenharmony_ci * calculations, we must lower it by the first vaddr 113362306a36Sopenharmony_ci * so that the remaining calculations based on the 113462306a36Sopenharmony_ci * ELF vaddrs will be correctly offset. The result 113562306a36Sopenharmony_ci * is then page aligned. 113662306a36Sopenharmony_ci */ 113762306a36Sopenharmony_ci load_bias = ELF_PAGESTART(load_bias - vaddr); 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_ci /* 114062306a36Sopenharmony_ci * Calculate the entire size of the ELF mapping 114162306a36Sopenharmony_ci * (total_size), used for the initial mapping, 114262306a36Sopenharmony_ci * due to load_addr_set which is set to true later 114362306a36Sopenharmony_ci * once the initial mapping is performed. 114462306a36Sopenharmony_ci * 114562306a36Sopenharmony_ci * Note that this is only sensible when the LOAD 114662306a36Sopenharmony_ci * segments are contiguous (or overlapping). If 114762306a36Sopenharmony_ci * used for LOADs that are far apart, this would 114862306a36Sopenharmony_ci * cause the holes between LOADs to be mapped, 114962306a36Sopenharmony_ci * running the risk of having the mapping fail, 115062306a36Sopenharmony_ci * as it would be larger than the ELF file itself. 115162306a36Sopenharmony_ci * 115262306a36Sopenharmony_ci * As a result, only ET_DYN does this, since 115362306a36Sopenharmony_ci * some ET_EXEC (e.g. ia64) may have large virtual 115462306a36Sopenharmony_ci * memory holes between LOADs. 115562306a36Sopenharmony_ci * 115662306a36Sopenharmony_ci */ 115762306a36Sopenharmony_ci total_size = total_mapping_size(elf_phdata, 115862306a36Sopenharmony_ci elf_ex->e_phnum); 115962306a36Sopenharmony_ci if (!total_size) { 116062306a36Sopenharmony_ci retval = -EINVAL; 116162306a36Sopenharmony_ci goto out_free_dentry; 116262306a36Sopenharmony_ci } 116362306a36Sopenharmony_ci } 116462306a36Sopenharmony_ci 116562306a36Sopenharmony_ci error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt, 116662306a36Sopenharmony_ci elf_prot, elf_flags, total_size); 116762306a36Sopenharmony_ci if (BAD_ADDR(error)) { 116862306a36Sopenharmony_ci retval = IS_ERR_VALUE(error) ? 116962306a36Sopenharmony_ci PTR_ERR((void*)error) : -EINVAL; 117062306a36Sopenharmony_ci goto out_free_dentry; 117162306a36Sopenharmony_ci } 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci if (first_pt_load) { 117462306a36Sopenharmony_ci first_pt_load = 0; 117562306a36Sopenharmony_ci if (elf_ex->e_type == ET_DYN) { 117662306a36Sopenharmony_ci load_bias += error - 117762306a36Sopenharmony_ci ELF_PAGESTART(load_bias + vaddr); 117862306a36Sopenharmony_ci reloc_func_desc = load_bias; 117962306a36Sopenharmony_ci } 118062306a36Sopenharmony_ci } 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_ci /* 118362306a36Sopenharmony_ci * Figure out which segment in the file contains the Program 118462306a36Sopenharmony_ci * Header table, and map to the associated memory address. 118562306a36Sopenharmony_ci */ 118662306a36Sopenharmony_ci if (elf_ppnt->p_offset <= elf_ex->e_phoff && 118762306a36Sopenharmony_ci elf_ex->e_phoff < elf_ppnt->p_offset + elf_ppnt->p_filesz) { 118862306a36Sopenharmony_ci phdr_addr = elf_ex->e_phoff - elf_ppnt->p_offset + 118962306a36Sopenharmony_ci elf_ppnt->p_vaddr; 119062306a36Sopenharmony_ci } 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_ci k = elf_ppnt->p_vaddr; 119362306a36Sopenharmony_ci if ((elf_ppnt->p_flags & PF_X) && k < start_code) 119462306a36Sopenharmony_ci start_code = k; 119562306a36Sopenharmony_ci if (start_data < k) 119662306a36Sopenharmony_ci start_data = k; 119762306a36Sopenharmony_ci 119862306a36Sopenharmony_ci /* 119962306a36Sopenharmony_ci * Check to see if the section's size will overflow the 120062306a36Sopenharmony_ci * allowed task size. Note that p_filesz must always be 120162306a36Sopenharmony_ci * <= p_memsz so it is only necessary to check p_memsz. 120262306a36Sopenharmony_ci */ 120362306a36Sopenharmony_ci if (BAD_ADDR(k) || elf_ppnt->p_filesz > elf_ppnt->p_memsz || 120462306a36Sopenharmony_ci elf_ppnt->p_memsz > TASK_SIZE || 120562306a36Sopenharmony_ci TASK_SIZE - elf_ppnt->p_memsz < k) { 120662306a36Sopenharmony_ci /* set_brk can never work. Avoid overflows. */ 120762306a36Sopenharmony_ci retval = -EINVAL; 120862306a36Sopenharmony_ci goto out_free_dentry; 120962306a36Sopenharmony_ci } 121062306a36Sopenharmony_ci 121162306a36Sopenharmony_ci k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz; 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_ci if (k > elf_bss) 121462306a36Sopenharmony_ci elf_bss = k; 121562306a36Sopenharmony_ci if ((elf_ppnt->p_flags & PF_X) && end_code < k) 121662306a36Sopenharmony_ci end_code = k; 121762306a36Sopenharmony_ci if (end_data < k) 121862306a36Sopenharmony_ci end_data = k; 121962306a36Sopenharmony_ci k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz; 122062306a36Sopenharmony_ci if (k > elf_brk) { 122162306a36Sopenharmony_ci bss_prot = elf_prot; 122262306a36Sopenharmony_ci elf_brk = k; 122362306a36Sopenharmony_ci } 122462306a36Sopenharmony_ci } 122562306a36Sopenharmony_ci 122662306a36Sopenharmony_ci e_entry = elf_ex->e_entry + load_bias; 122762306a36Sopenharmony_ci phdr_addr += load_bias; 122862306a36Sopenharmony_ci elf_bss += load_bias; 122962306a36Sopenharmony_ci elf_brk += load_bias; 123062306a36Sopenharmony_ci start_code += load_bias; 123162306a36Sopenharmony_ci end_code += load_bias; 123262306a36Sopenharmony_ci start_data += load_bias; 123362306a36Sopenharmony_ci end_data += load_bias; 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_ci /* Calling set_brk effectively mmaps the pages that we need 123662306a36Sopenharmony_ci * for the bss and break sections. We must do this before 123762306a36Sopenharmony_ci * mapping in the interpreter, to make sure it doesn't wind 123862306a36Sopenharmony_ci * up getting placed where the bss needs to go. 123962306a36Sopenharmony_ci */ 124062306a36Sopenharmony_ci retval = set_brk(elf_bss, elf_brk, bss_prot); 124162306a36Sopenharmony_ci if (retval) 124262306a36Sopenharmony_ci goto out_free_dentry; 124362306a36Sopenharmony_ci if (likely(elf_bss != elf_brk) && unlikely(padzero(elf_bss))) { 124462306a36Sopenharmony_ci retval = -EFAULT; /* Nobody gets to see this, but.. */ 124562306a36Sopenharmony_ci goto out_free_dentry; 124662306a36Sopenharmony_ci } 124762306a36Sopenharmony_ci 124862306a36Sopenharmony_ci if (interpreter) { 124962306a36Sopenharmony_ci elf_entry = load_elf_interp(interp_elf_ex, 125062306a36Sopenharmony_ci interpreter, 125162306a36Sopenharmony_ci load_bias, interp_elf_phdata, 125262306a36Sopenharmony_ci &arch_state); 125362306a36Sopenharmony_ci if (!IS_ERR_VALUE(elf_entry)) { 125462306a36Sopenharmony_ci /* 125562306a36Sopenharmony_ci * load_elf_interp() returns relocation 125662306a36Sopenharmony_ci * adjustment 125762306a36Sopenharmony_ci */ 125862306a36Sopenharmony_ci interp_load_addr = elf_entry; 125962306a36Sopenharmony_ci elf_entry += interp_elf_ex->e_entry; 126062306a36Sopenharmony_ci } 126162306a36Sopenharmony_ci if (BAD_ADDR(elf_entry)) { 126262306a36Sopenharmony_ci retval = IS_ERR_VALUE(elf_entry) ? 126362306a36Sopenharmony_ci (int)elf_entry : -EINVAL; 126462306a36Sopenharmony_ci goto out_free_dentry; 126562306a36Sopenharmony_ci } 126662306a36Sopenharmony_ci reloc_func_desc = interp_load_addr; 126762306a36Sopenharmony_ci 126862306a36Sopenharmony_ci allow_write_access(interpreter); 126962306a36Sopenharmony_ci fput(interpreter); 127062306a36Sopenharmony_ci 127162306a36Sopenharmony_ci kfree(interp_elf_ex); 127262306a36Sopenharmony_ci kfree(interp_elf_phdata); 127362306a36Sopenharmony_ci } else { 127462306a36Sopenharmony_ci elf_entry = e_entry; 127562306a36Sopenharmony_ci if (BAD_ADDR(elf_entry)) { 127662306a36Sopenharmony_ci retval = -EINVAL; 127762306a36Sopenharmony_ci goto out_free_dentry; 127862306a36Sopenharmony_ci } 127962306a36Sopenharmony_ci } 128062306a36Sopenharmony_ci 128162306a36Sopenharmony_ci kfree(elf_phdata); 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_ci set_binfmt(&elf_format); 128462306a36Sopenharmony_ci 128562306a36Sopenharmony_ci#ifdef ARCH_HAS_SETUP_ADDITIONAL_PAGES 128662306a36Sopenharmony_ci retval = ARCH_SETUP_ADDITIONAL_PAGES(bprm, elf_ex, !!interpreter); 128762306a36Sopenharmony_ci if (retval < 0) 128862306a36Sopenharmony_ci goto out; 128962306a36Sopenharmony_ci#endif /* ARCH_HAS_SETUP_ADDITIONAL_PAGES */ 129062306a36Sopenharmony_ci 129162306a36Sopenharmony_ci retval = create_elf_tables(bprm, elf_ex, interp_load_addr, 129262306a36Sopenharmony_ci e_entry, phdr_addr); 129362306a36Sopenharmony_ci if (retval < 0) 129462306a36Sopenharmony_ci goto out; 129562306a36Sopenharmony_ci 129662306a36Sopenharmony_ci mm = current->mm; 129762306a36Sopenharmony_ci mm->end_code = end_code; 129862306a36Sopenharmony_ci mm->start_code = start_code; 129962306a36Sopenharmony_ci mm->start_data = start_data; 130062306a36Sopenharmony_ci mm->end_data = end_data; 130162306a36Sopenharmony_ci mm->start_stack = bprm->p; 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_ci if ((current->flags & PF_RANDOMIZE) && (randomize_va_space > 1)) { 130462306a36Sopenharmony_ci /* 130562306a36Sopenharmony_ci * For architectures with ELF randomization, when executing 130662306a36Sopenharmony_ci * a loader directly (i.e. no interpreter listed in ELF 130762306a36Sopenharmony_ci * headers), move the brk area out of the mmap region 130862306a36Sopenharmony_ci * (since it grows up, and may collide early with the stack 130962306a36Sopenharmony_ci * growing down), and into the unused ELF_ET_DYN_BASE region. 131062306a36Sopenharmony_ci */ 131162306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_ARCH_HAS_ELF_RANDOMIZE) && 131262306a36Sopenharmony_ci elf_ex->e_type == ET_DYN && !interpreter) { 131362306a36Sopenharmony_ci mm->brk = mm->start_brk = ELF_ET_DYN_BASE; 131462306a36Sopenharmony_ci } 131562306a36Sopenharmony_ci 131662306a36Sopenharmony_ci mm->brk = mm->start_brk = arch_randomize_brk(mm); 131762306a36Sopenharmony_ci#ifdef compat_brk_randomized 131862306a36Sopenharmony_ci current->brk_randomized = 1; 131962306a36Sopenharmony_ci#endif 132062306a36Sopenharmony_ci } 132162306a36Sopenharmony_ci 132262306a36Sopenharmony_ci if (current->personality & MMAP_PAGE_ZERO) { 132362306a36Sopenharmony_ci /* Why this, you ask??? Well SVr4 maps page 0 as read-only, 132462306a36Sopenharmony_ci and some applications "depend" upon this behavior. 132562306a36Sopenharmony_ci Since we do not have the power to recompile these, we 132662306a36Sopenharmony_ci emulate the SVr4 behavior. Sigh. */ 132762306a36Sopenharmony_ci error = vm_mmap(NULL, 0, PAGE_SIZE, PROT_READ | PROT_EXEC, 132862306a36Sopenharmony_ci MAP_FIXED | MAP_PRIVATE, 0); 132962306a36Sopenharmony_ci } 133062306a36Sopenharmony_ci 133162306a36Sopenharmony_ci regs = current_pt_regs(); 133262306a36Sopenharmony_ci#ifdef ELF_PLAT_INIT 133362306a36Sopenharmony_ci /* 133462306a36Sopenharmony_ci * The ABI may specify that certain registers be set up in special 133562306a36Sopenharmony_ci * ways (on i386 %edx is the address of a DT_FINI function, for 133662306a36Sopenharmony_ci * example. In addition, it may also specify (eg, PowerPC64 ELF) 133762306a36Sopenharmony_ci * that the e_entry field is the address of the function descriptor 133862306a36Sopenharmony_ci * for the startup routine, rather than the address of the startup 133962306a36Sopenharmony_ci * routine itself. This macro performs whatever initialization to 134062306a36Sopenharmony_ci * the regs structure is required as well as any relocations to the 134162306a36Sopenharmony_ci * function descriptor entries when executing dynamically links apps. 134262306a36Sopenharmony_ci */ 134362306a36Sopenharmony_ci ELF_PLAT_INIT(regs, reloc_func_desc); 134462306a36Sopenharmony_ci#endif 134562306a36Sopenharmony_ci 134662306a36Sopenharmony_ci finalize_exec(bprm); 134762306a36Sopenharmony_ci START_THREAD(elf_ex, regs, elf_entry, bprm->p); 134862306a36Sopenharmony_ci retval = 0; 134962306a36Sopenharmony_ciout: 135062306a36Sopenharmony_ci return retval; 135162306a36Sopenharmony_ci 135262306a36Sopenharmony_ci /* error cleanup */ 135362306a36Sopenharmony_ciout_free_dentry: 135462306a36Sopenharmony_ci kfree(interp_elf_ex); 135562306a36Sopenharmony_ci kfree(interp_elf_phdata); 135662306a36Sopenharmony_ciout_free_file: 135762306a36Sopenharmony_ci allow_write_access(interpreter); 135862306a36Sopenharmony_ci if (interpreter) 135962306a36Sopenharmony_ci fput(interpreter); 136062306a36Sopenharmony_ciout_free_ph: 136162306a36Sopenharmony_ci kfree(elf_phdata); 136262306a36Sopenharmony_ci goto out; 136362306a36Sopenharmony_ci} 136462306a36Sopenharmony_ci 136562306a36Sopenharmony_ci#ifdef CONFIG_USELIB 136662306a36Sopenharmony_ci/* This is really simpleminded and specialized - we are loading an 136762306a36Sopenharmony_ci a.out library that is given an ELF header. */ 136862306a36Sopenharmony_cistatic int load_elf_library(struct file *file) 136962306a36Sopenharmony_ci{ 137062306a36Sopenharmony_ci struct elf_phdr *elf_phdata; 137162306a36Sopenharmony_ci struct elf_phdr *eppnt; 137262306a36Sopenharmony_ci unsigned long elf_bss, bss, len; 137362306a36Sopenharmony_ci int retval, error, i, j; 137462306a36Sopenharmony_ci struct elfhdr elf_ex; 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_ci error = -ENOEXEC; 137762306a36Sopenharmony_ci retval = elf_read(file, &elf_ex, sizeof(elf_ex), 0); 137862306a36Sopenharmony_ci if (retval < 0) 137962306a36Sopenharmony_ci goto out; 138062306a36Sopenharmony_ci 138162306a36Sopenharmony_ci if (memcmp(elf_ex.e_ident, ELFMAG, SELFMAG) != 0) 138262306a36Sopenharmony_ci goto out; 138362306a36Sopenharmony_ci 138462306a36Sopenharmony_ci /* First of all, some simple consistency checks */ 138562306a36Sopenharmony_ci if (elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 || 138662306a36Sopenharmony_ci !elf_check_arch(&elf_ex) || !file->f_op->mmap) 138762306a36Sopenharmony_ci goto out; 138862306a36Sopenharmony_ci if (elf_check_fdpic(&elf_ex)) 138962306a36Sopenharmony_ci goto out; 139062306a36Sopenharmony_ci 139162306a36Sopenharmony_ci /* Now read in all of the header information */ 139262306a36Sopenharmony_ci 139362306a36Sopenharmony_ci j = sizeof(struct elf_phdr) * elf_ex.e_phnum; 139462306a36Sopenharmony_ci /* j < ELF_MIN_ALIGN because elf_ex.e_phnum <= 2 */ 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_ci error = -ENOMEM; 139762306a36Sopenharmony_ci elf_phdata = kmalloc(j, GFP_KERNEL); 139862306a36Sopenharmony_ci if (!elf_phdata) 139962306a36Sopenharmony_ci goto out; 140062306a36Sopenharmony_ci 140162306a36Sopenharmony_ci eppnt = elf_phdata; 140262306a36Sopenharmony_ci error = -ENOEXEC; 140362306a36Sopenharmony_ci retval = elf_read(file, eppnt, j, elf_ex.e_phoff); 140462306a36Sopenharmony_ci if (retval < 0) 140562306a36Sopenharmony_ci goto out_free_ph; 140662306a36Sopenharmony_ci 140762306a36Sopenharmony_ci for (j = 0, i = 0; i<elf_ex.e_phnum; i++) 140862306a36Sopenharmony_ci if ((eppnt + i)->p_type == PT_LOAD) 140962306a36Sopenharmony_ci j++; 141062306a36Sopenharmony_ci if (j != 1) 141162306a36Sopenharmony_ci goto out_free_ph; 141262306a36Sopenharmony_ci 141362306a36Sopenharmony_ci while (eppnt->p_type != PT_LOAD) 141462306a36Sopenharmony_ci eppnt++; 141562306a36Sopenharmony_ci 141662306a36Sopenharmony_ci /* Now use mmap to map the library into memory. */ 141762306a36Sopenharmony_ci error = vm_mmap(file, 141862306a36Sopenharmony_ci ELF_PAGESTART(eppnt->p_vaddr), 141962306a36Sopenharmony_ci (eppnt->p_filesz + 142062306a36Sopenharmony_ci ELF_PAGEOFFSET(eppnt->p_vaddr)), 142162306a36Sopenharmony_ci PROT_READ | PROT_WRITE | PROT_EXEC, 142262306a36Sopenharmony_ci MAP_FIXED_NOREPLACE | MAP_PRIVATE, 142362306a36Sopenharmony_ci (eppnt->p_offset - 142462306a36Sopenharmony_ci ELF_PAGEOFFSET(eppnt->p_vaddr))); 142562306a36Sopenharmony_ci if (error != ELF_PAGESTART(eppnt->p_vaddr)) 142662306a36Sopenharmony_ci goto out_free_ph; 142762306a36Sopenharmony_ci 142862306a36Sopenharmony_ci elf_bss = eppnt->p_vaddr + eppnt->p_filesz; 142962306a36Sopenharmony_ci if (padzero(elf_bss)) { 143062306a36Sopenharmony_ci error = -EFAULT; 143162306a36Sopenharmony_ci goto out_free_ph; 143262306a36Sopenharmony_ci } 143362306a36Sopenharmony_ci 143462306a36Sopenharmony_ci len = ELF_PAGEALIGN(eppnt->p_filesz + eppnt->p_vaddr); 143562306a36Sopenharmony_ci bss = ELF_PAGEALIGN(eppnt->p_memsz + eppnt->p_vaddr); 143662306a36Sopenharmony_ci if (bss > len) { 143762306a36Sopenharmony_ci error = vm_brk(len, bss - len); 143862306a36Sopenharmony_ci if (error) 143962306a36Sopenharmony_ci goto out_free_ph; 144062306a36Sopenharmony_ci } 144162306a36Sopenharmony_ci error = 0; 144262306a36Sopenharmony_ci 144362306a36Sopenharmony_ciout_free_ph: 144462306a36Sopenharmony_ci kfree(elf_phdata); 144562306a36Sopenharmony_ciout: 144662306a36Sopenharmony_ci return error; 144762306a36Sopenharmony_ci} 144862306a36Sopenharmony_ci#endif /* #ifdef CONFIG_USELIB */ 144962306a36Sopenharmony_ci 145062306a36Sopenharmony_ci#ifdef CONFIG_ELF_CORE 145162306a36Sopenharmony_ci/* 145262306a36Sopenharmony_ci * ELF core dumper 145362306a36Sopenharmony_ci * 145462306a36Sopenharmony_ci * Modelled on fs/exec.c:aout_core_dump() 145562306a36Sopenharmony_ci * Jeremy Fitzhardinge <jeremy@sw.oz.au> 145662306a36Sopenharmony_ci */ 145762306a36Sopenharmony_ci 145862306a36Sopenharmony_ci/* An ELF note in memory */ 145962306a36Sopenharmony_cistruct memelfnote 146062306a36Sopenharmony_ci{ 146162306a36Sopenharmony_ci const char *name; 146262306a36Sopenharmony_ci int type; 146362306a36Sopenharmony_ci unsigned int datasz; 146462306a36Sopenharmony_ci void *data; 146562306a36Sopenharmony_ci}; 146662306a36Sopenharmony_ci 146762306a36Sopenharmony_cistatic int notesize(struct memelfnote *en) 146862306a36Sopenharmony_ci{ 146962306a36Sopenharmony_ci int sz; 147062306a36Sopenharmony_ci 147162306a36Sopenharmony_ci sz = sizeof(struct elf_note); 147262306a36Sopenharmony_ci sz += roundup(strlen(en->name) + 1, 4); 147362306a36Sopenharmony_ci sz += roundup(en->datasz, 4); 147462306a36Sopenharmony_ci 147562306a36Sopenharmony_ci return sz; 147662306a36Sopenharmony_ci} 147762306a36Sopenharmony_ci 147862306a36Sopenharmony_cistatic int writenote(struct memelfnote *men, struct coredump_params *cprm) 147962306a36Sopenharmony_ci{ 148062306a36Sopenharmony_ci struct elf_note en; 148162306a36Sopenharmony_ci en.n_namesz = strlen(men->name) + 1; 148262306a36Sopenharmony_ci en.n_descsz = men->datasz; 148362306a36Sopenharmony_ci en.n_type = men->type; 148462306a36Sopenharmony_ci 148562306a36Sopenharmony_ci return dump_emit(cprm, &en, sizeof(en)) && 148662306a36Sopenharmony_ci dump_emit(cprm, men->name, en.n_namesz) && dump_align(cprm, 4) && 148762306a36Sopenharmony_ci dump_emit(cprm, men->data, men->datasz) && dump_align(cprm, 4); 148862306a36Sopenharmony_ci} 148962306a36Sopenharmony_ci 149062306a36Sopenharmony_cistatic void fill_elf_header(struct elfhdr *elf, int segs, 149162306a36Sopenharmony_ci u16 machine, u32 flags) 149262306a36Sopenharmony_ci{ 149362306a36Sopenharmony_ci memset(elf, 0, sizeof(*elf)); 149462306a36Sopenharmony_ci 149562306a36Sopenharmony_ci memcpy(elf->e_ident, ELFMAG, SELFMAG); 149662306a36Sopenharmony_ci elf->e_ident[EI_CLASS] = ELF_CLASS; 149762306a36Sopenharmony_ci elf->e_ident[EI_DATA] = ELF_DATA; 149862306a36Sopenharmony_ci elf->e_ident[EI_VERSION] = EV_CURRENT; 149962306a36Sopenharmony_ci elf->e_ident[EI_OSABI] = ELF_OSABI; 150062306a36Sopenharmony_ci 150162306a36Sopenharmony_ci elf->e_type = ET_CORE; 150262306a36Sopenharmony_ci elf->e_machine = machine; 150362306a36Sopenharmony_ci elf->e_version = EV_CURRENT; 150462306a36Sopenharmony_ci elf->e_phoff = sizeof(struct elfhdr); 150562306a36Sopenharmony_ci elf->e_flags = flags; 150662306a36Sopenharmony_ci elf->e_ehsize = sizeof(struct elfhdr); 150762306a36Sopenharmony_ci elf->e_phentsize = sizeof(struct elf_phdr); 150862306a36Sopenharmony_ci elf->e_phnum = segs; 150962306a36Sopenharmony_ci} 151062306a36Sopenharmony_ci 151162306a36Sopenharmony_cistatic void fill_elf_note_phdr(struct elf_phdr *phdr, int sz, loff_t offset) 151262306a36Sopenharmony_ci{ 151362306a36Sopenharmony_ci phdr->p_type = PT_NOTE; 151462306a36Sopenharmony_ci phdr->p_offset = offset; 151562306a36Sopenharmony_ci phdr->p_vaddr = 0; 151662306a36Sopenharmony_ci phdr->p_paddr = 0; 151762306a36Sopenharmony_ci phdr->p_filesz = sz; 151862306a36Sopenharmony_ci phdr->p_memsz = 0; 151962306a36Sopenharmony_ci phdr->p_flags = 0; 152062306a36Sopenharmony_ci phdr->p_align = 4; 152162306a36Sopenharmony_ci} 152262306a36Sopenharmony_ci 152362306a36Sopenharmony_cistatic void fill_note(struct memelfnote *note, const char *name, int type, 152462306a36Sopenharmony_ci unsigned int sz, void *data) 152562306a36Sopenharmony_ci{ 152662306a36Sopenharmony_ci note->name = name; 152762306a36Sopenharmony_ci note->type = type; 152862306a36Sopenharmony_ci note->datasz = sz; 152962306a36Sopenharmony_ci note->data = data; 153062306a36Sopenharmony_ci} 153162306a36Sopenharmony_ci 153262306a36Sopenharmony_ci/* 153362306a36Sopenharmony_ci * fill up all the fields in prstatus from the given task struct, except 153462306a36Sopenharmony_ci * registers which need to be filled up separately. 153562306a36Sopenharmony_ci */ 153662306a36Sopenharmony_cistatic void fill_prstatus(struct elf_prstatus_common *prstatus, 153762306a36Sopenharmony_ci struct task_struct *p, long signr) 153862306a36Sopenharmony_ci{ 153962306a36Sopenharmony_ci prstatus->pr_info.si_signo = prstatus->pr_cursig = signr; 154062306a36Sopenharmony_ci prstatus->pr_sigpend = p->pending.signal.sig[0]; 154162306a36Sopenharmony_ci prstatus->pr_sighold = p->blocked.sig[0]; 154262306a36Sopenharmony_ci rcu_read_lock(); 154362306a36Sopenharmony_ci prstatus->pr_ppid = task_pid_vnr(rcu_dereference(p->real_parent)); 154462306a36Sopenharmony_ci rcu_read_unlock(); 154562306a36Sopenharmony_ci prstatus->pr_pid = task_pid_vnr(p); 154662306a36Sopenharmony_ci prstatus->pr_pgrp = task_pgrp_vnr(p); 154762306a36Sopenharmony_ci prstatus->pr_sid = task_session_vnr(p); 154862306a36Sopenharmony_ci if (thread_group_leader(p)) { 154962306a36Sopenharmony_ci struct task_cputime cputime; 155062306a36Sopenharmony_ci 155162306a36Sopenharmony_ci /* 155262306a36Sopenharmony_ci * This is the record for the group leader. It shows the 155362306a36Sopenharmony_ci * group-wide total, not its individual thread total. 155462306a36Sopenharmony_ci */ 155562306a36Sopenharmony_ci thread_group_cputime(p, &cputime); 155662306a36Sopenharmony_ci prstatus->pr_utime = ns_to_kernel_old_timeval(cputime.utime); 155762306a36Sopenharmony_ci prstatus->pr_stime = ns_to_kernel_old_timeval(cputime.stime); 155862306a36Sopenharmony_ci } else { 155962306a36Sopenharmony_ci u64 utime, stime; 156062306a36Sopenharmony_ci 156162306a36Sopenharmony_ci task_cputime(p, &utime, &stime); 156262306a36Sopenharmony_ci prstatus->pr_utime = ns_to_kernel_old_timeval(utime); 156362306a36Sopenharmony_ci prstatus->pr_stime = ns_to_kernel_old_timeval(stime); 156462306a36Sopenharmony_ci } 156562306a36Sopenharmony_ci 156662306a36Sopenharmony_ci prstatus->pr_cutime = ns_to_kernel_old_timeval(p->signal->cutime); 156762306a36Sopenharmony_ci prstatus->pr_cstime = ns_to_kernel_old_timeval(p->signal->cstime); 156862306a36Sopenharmony_ci} 156962306a36Sopenharmony_ci 157062306a36Sopenharmony_cistatic int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p, 157162306a36Sopenharmony_ci struct mm_struct *mm) 157262306a36Sopenharmony_ci{ 157362306a36Sopenharmony_ci const struct cred *cred; 157462306a36Sopenharmony_ci unsigned int i, len; 157562306a36Sopenharmony_ci unsigned int state; 157662306a36Sopenharmony_ci 157762306a36Sopenharmony_ci /* first copy the parameters from user space */ 157862306a36Sopenharmony_ci memset(psinfo, 0, sizeof(struct elf_prpsinfo)); 157962306a36Sopenharmony_ci 158062306a36Sopenharmony_ci len = mm->arg_end - mm->arg_start; 158162306a36Sopenharmony_ci if (len >= ELF_PRARGSZ) 158262306a36Sopenharmony_ci len = ELF_PRARGSZ-1; 158362306a36Sopenharmony_ci if (copy_from_user(&psinfo->pr_psargs, 158462306a36Sopenharmony_ci (const char __user *)mm->arg_start, len)) 158562306a36Sopenharmony_ci return -EFAULT; 158662306a36Sopenharmony_ci for(i = 0; i < len; i++) 158762306a36Sopenharmony_ci if (psinfo->pr_psargs[i] == 0) 158862306a36Sopenharmony_ci psinfo->pr_psargs[i] = ' '; 158962306a36Sopenharmony_ci psinfo->pr_psargs[len] = 0; 159062306a36Sopenharmony_ci 159162306a36Sopenharmony_ci rcu_read_lock(); 159262306a36Sopenharmony_ci psinfo->pr_ppid = task_pid_vnr(rcu_dereference(p->real_parent)); 159362306a36Sopenharmony_ci rcu_read_unlock(); 159462306a36Sopenharmony_ci psinfo->pr_pid = task_pid_vnr(p); 159562306a36Sopenharmony_ci psinfo->pr_pgrp = task_pgrp_vnr(p); 159662306a36Sopenharmony_ci psinfo->pr_sid = task_session_vnr(p); 159762306a36Sopenharmony_ci 159862306a36Sopenharmony_ci state = READ_ONCE(p->__state); 159962306a36Sopenharmony_ci i = state ? ffz(~state) + 1 : 0; 160062306a36Sopenharmony_ci psinfo->pr_state = i; 160162306a36Sopenharmony_ci psinfo->pr_sname = (i > 5) ? '.' : "RSDTZW"[i]; 160262306a36Sopenharmony_ci psinfo->pr_zomb = psinfo->pr_sname == 'Z'; 160362306a36Sopenharmony_ci psinfo->pr_nice = task_nice(p); 160462306a36Sopenharmony_ci psinfo->pr_flag = p->flags; 160562306a36Sopenharmony_ci rcu_read_lock(); 160662306a36Sopenharmony_ci cred = __task_cred(p); 160762306a36Sopenharmony_ci SET_UID(psinfo->pr_uid, from_kuid_munged(cred->user_ns, cred->uid)); 160862306a36Sopenharmony_ci SET_GID(psinfo->pr_gid, from_kgid_munged(cred->user_ns, cred->gid)); 160962306a36Sopenharmony_ci rcu_read_unlock(); 161062306a36Sopenharmony_ci get_task_comm(psinfo->pr_fname, p); 161162306a36Sopenharmony_ci 161262306a36Sopenharmony_ci return 0; 161362306a36Sopenharmony_ci} 161462306a36Sopenharmony_ci 161562306a36Sopenharmony_cistatic void fill_auxv_note(struct memelfnote *note, struct mm_struct *mm) 161662306a36Sopenharmony_ci{ 161762306a36Sopenharmony_ci elf_addr_t *auxv = (elf_addr_t *) mm->saved_auxv; 161862306a36Sopenharmony_ci int i = 0; 161962306a36Sopenharmony_ci do 162062306a36Sopenharmony_ci i += 2; 162162306a36Sopenharmony_ci while (auxv[i - 2] != AT_NULL); 162262306a36Sopenharmony_ci fill_note(note, "CORE", NT_AUXV, i * sizeof(elf_addr_t), auxv); 162362306a36Sopenharmony_ci} 162462306a36Sopenharmony_ci 162562306a36Sopenharmony_cistatic void fill_siginfo_note(struct memelfnote *note, user_siginfo_t *csigdata, 162662306a36Sopenharmony_ci const kernel_siginfo_t *siginfo) 162762306a36Sopenharmony_ci{ 162862306a36Sopenharmony_ci copy_siginfo_to_external(csigdata, siginfo); 162962306a36Sopenharmony_ci fill_note(note, "CORE", NT_SIGINFO, sizeof(*csigdata), csigdata); 163062306a36Sopenharmony_ci} 163162306a36Sopenharmony_ci 163262306a36Sopenharmony_ci#define MAX_FILE_NOTE_SIZE (4*1024*1024) 163362306a36Sopenharmony_ci/* 163462306a36Sopenharmony_ci * Format of NT_FILE note: 163562306a36Sopenharmony_ci * 163662306a36Sopenharmony_ci * long count -- how many files are mapped 163762306a36Sopenharmony_ci * long page_size -- units for file_ofs 163862306a36Sopenharmony_ci * array of [COUNT] elements of 163962306a36Sopenharmony_ci * long start 164062306a36Sopenharmony_ci * long end 164162306a36Sopenharmony_ci * long file_ofs 164262306a36Sopenharmony_ci * followed by COUNT filenames in ASCII: "FILE1" NUL "FILE2" NUL... 164362306a36Sopenharmony_ci */ 164462306a36Sopenharmony_cistatic int fill_files_note(struct memelfnote *note, struct coredump_params *cprm) 164562306a36Sopenharmony_ci{ 164662306a36Sopenharmony_ci unsigned count, size, names_ofs, remaining, n; 164762306a36Sopenharmony_ci user_long_t *data; 164862306a36Sopenharmony_ci user_long_t *start_end_ofs; 164962306a36Sopenharmony_ci char *name_base, *name_curpos; 165062306a36Sopenharmony_ci int i; 165162306a36Sopenharmony_ci 165262306a36Sopenharmony_ci /* *Estimated* file count and total data size needed */ 165362306a36Sopenharmony_ci count = cprm->vma_count; 165462306a36Sopenharmony_ci if (count > UINT_MAX / 64) 165562306a36Sopenharmony_ci return -EINVAL; 165662306a36Sopenharmony_ci size = count * 64; 165762306a36Sopenharmony_ci 165862306a36Sopenharmony_ci names_ofs = (2 + 3 * count) * sizeof(data[0]); 165962306a36Sopenharmony_ci alloc: 166062306a36Sopenharmony_ci if (size >= MAX_FILE_NOTE_SIZE) /* paranoia check */ 166162306a36Sopenharmony_ci return -EINVAL; 166262306a36Sopenharmony_ci size = round_up(size, PAGE_SIZE); 166362306a36Sopenharmony_ci /* 166462306a36Sopenharmony_ci * "size" can be 0 here legitimately. 166562306a36Sopenharmony_ci * Let it ENOMEM and omit NT_FILE section which will be empty anyway. 166662306a36Sopenharmony_ci */ 166762306a36Sopenharmony_ci data = kvmalloc(size, GFP_KERNEL); 166862306a36Sopenharmony_ci if (ZERO_OR_NULL_PTR(data)) 166962306a36Sopenharmony_ci return -ENOMEM; 167062306a36Sopenharmony_ci 167162306a36Sopenharmony_ci start_end_ofs = data + 2; 167262306a36Sopenharmony_ci name_base = name_curpos = ((char *)data) + names_ofs; 167362306a36Sopenharmony_ci remaining = size - names_ofs; 167462306a36Sopenharmony_ci count = 0; 167562306a36Sopenharmony_ci for (i = 0; i < cprm->vma_count; i++) { 167662306a36Sopenharmony_ci struct core_vma_metadata *m = &cprm->vma_meta[i]; 167762306a36Sopenharmony_ci struct file *file; 167862306a36Sopenharmony_ci const char *filename; 167962306a36Sopenharmony_ci 168062306a36Sopenharmony_ci file = m->file; 168162306a36Sopenharmony_ci if (!file) 168262306a36Sopenharmony_ci continue; 168362306a36Sopenharmony_ci filename = file_path(file, name_curpos, remaining); 168462306a36Sopenharmony_ci if (IS_ERR(filename)) { 168562306a36Sopenharmony_ci if (PTR_ERR(filename) == -ENAMETOOLONG) { 168662306a36Sopenharmony_ci kvfree(data); 168762306a36Sopenharmony_ci size = size * 5 / 4; 168862306a36Sopenharmony_ci goto alloc; 168962306a36Sopenharmony_ci } 169062306a36Sopenharmony_ci continue; 169162306a36Sopenharmony_ci } 169262306a36Sopenharmony_ci 169362306a36Sopenharmony_ci /* file_path() fills at the end, move name down */ 169462306a36Sopenharmony_ci /* n = strlen(filename) + 1: */ 169562306a36Sopenharmony_ci n = (name_curpos + remaining) - filename; 169662306a36Sopenharmony_ci remaining = filename - name_curpos; 169762306a36Sopenharmony_ci memmove(name_curpos, filename, n); 169862306a36Sopenharmony_ci name_curpos += n; 169962306a36Sopenharmony_ci 170062306a36Sopenharmony_ci *start_end_ofs++ = m->start; 170162306a36Sopenharmony_ci *start_end_ofs++ = m->end; 170262306a36Sopenharmony_ci *start_end_ofs++ = m->pgoff; 170362306a36Sopenharmony_ci count++; 170462306a36Sopenharmony_ci } 170562306a36Sopenharmony_ci 170662306a36Sopenharmony_ci /* Now we know exact count of files, can store it */ 170762306a36Sopenharmony_ci data[0] = count; 170862306a36Sopenharmony_ci data[1] = PAGE_SIZE; 170962306a36Sopenharmony_ci /* 171062306a36Sopenharmony_ci * Count usually is less than mm->map_count, 171162306a36Sopenharmony_ci * we need to move filenames down. 171262306a36Sopenharmony_ci */ 171362306a36Sopenharmony_ci n = cprm->vma_count - count; 171462306a36Sopenharmony_ci if (n != 0) { 171562306a36Sopenharmony_ci unsigned shift_bytes = n * 3 * sizeof(data[0]); 171662306a36Sopenharmony_ci memmove(name_base - shift_bytes, name_base, 171762306a36Sopenharmony_ci name_curpos - name_base); 171862306a36Sopenharmony_ci name_curpos -= shift_bytes; 171962306a36Sopenharmony_ci } 172062306a36Sopenharmony_ci 172162306a36Sopenharmony_ci size = name_curpos - (char *)data; 172262306a36Sopenharmony_ci fill_note(note, "CORE", NT_FILE, size, data); 172362306a36Sopenharmony_ci return 0; 172462306a36Sopenharmony_ci} 172562306a36Sopenharmony_ci 172662306a36Sopenharmony_ci#include <linux/regset.h> 172762306a36Sopenharmony_ci 172862306a36Sopenharmony_cistruct elf_thread_core_info { 172962306a36Sopenharmony_ci struct elf_thread_core_info *next; 173062306a36Sopenharmony_ci struct task_struct *task; 173162306a36Sopenharmony_ci struct elf_prstatus prstatus; 173262306a36Sopenharmony_ci struct memelfnote notes[]; 173362306a36Sopenharmony_ci}; 173462306a36Sopenharmony_ci 173562306a36Sopenharmony_cistruct elf_note_info { 173662306a36Sopenharmony_ci struct elf_thread_core_info *thread; 173762306a36Sopenharmony_ci struct memelfnote psinfo; 173862306a36Sopenharmony_ci struct memelfnote signote; 173962306a36Sopenharmony_ci struct memelfnote auxv; 174062306a36Sopenharmony_ci struct memelfnote files; 174162306a36Sopenharmony_ci user_siginfo_t csigdata; 174262306a36Sopenharmony_ci size_t size; 174362306a36Sopenharmony_ci int thread_notes; 174462306a36Sopenharmony_ci}; 174562306a36Sopenharmony_ci 174662306a36Sopenharmony_ci#ifdef CORE_DUMP_USE_REGSET 174762306a36Sopenharmony_ci/* 174862306a36Sopenharmony_ci * When a regset has a writeback hook, we call it on each thread before 174962306a36Sopenharmony_ci * dumping user memory. On register window machines, this makes sure the 175062306a36Sopenharmony_ci * user memory backing the register data is up to date before we read it. 175162306a36Sopenharmony_ci */ 175262306a36Sopenharmony_cistatic void do_thread_regset_writeback(struct task_struct *task, 175362306a36Sopenharmony_ci const struct user_regset *regset) 175462306a36Sopenharmony_ci{ 175562306a36Sopenharmony_ci if (regset->writeback) 175662306a36Sopenharmony_ci regset->writeback(task, regset, 1); 175762306a36Sopenharmony_ci} 175862306a36Sopenharmony_ci 175962306a36Sopenharmony_ci#ifndef PRSTATUS_SIZE 176062306a36Sopenharmony_ci#define PRSTATUS_SIZE sizeof(struct elf_prstatus) 176162306a36Sopenharmony_ci#endif 176262306a36Sopenharmony_ci 176362306a36Sopenharmony_ci#ifndef SET_PR_FPVALID 176462306a36Sopenharmony_ci#define SET_PR_FPVALID(S) ((S)->pr_fpvalid = 1) 176562306a36Sopenharmony_ci#endif 176662306a36Sopenharmony_ci 176762306a36Sopenharmony_cistatic int fill_thread_core_info(struct elf_thread_core_info *t, 176862306a36Sopenharmony_ci const struct user_regset_view *view, 176962306a36Sopenharmony_ci long signr, struct elf_note_info *info) 177062306a36Sopenharmony_ci{ 177162306a36Sopenharmony_ci unsigned int note_iter, view_iter; 177262306a36Sopenharmony_ci 177362306a36Sopenharmony_ci /* 177462306a36Sopenharmony_ci * NT_PRSTATUS is the one special case, because the regset data 177562306a36Sopenharmony_ci * goes into the pr_reg field inside the note contents, rather 177662306a36Sopenharmony_ci * than being the whole note contents. We fill the regset in here. 177762306a36Sopenharmony_ci * We assume that regset 0 is NT_PRSTATUS. 177862306a36Sopenharmony_ci */ 177962306a36Sopenharmony_ci fill_prstatus(&t->prstatus.common, t->task, signr); 178062306a36Sopenharmony_ci regset_get(t->task, &view->regsets[0], 178162306a36Sopenharmony_ci sizeof(t->prstatus.pr_reg), &t->prstatus.pr_reg); 178262306a36Sopenharmony_ci 178362306a36Sopenharmony_ci fill_note(&t->notes[0], "CORE", NT_PRSTATUS, 178462306a36Sopenharmony_ci PRSTATUS_SIZE, &t->prstatus); 178562306a36Sopenharmony_ci info->size += notesize(&t->notes[0]); 178662306a36Sopenharmony_ci 178762306a36Sopenharmony_ci do_thread_regset_writeback(t->task, &view->regsets[0]); 178862306a36Sopenharmony_ci 178962306a36Sopenharmony_ci /* 179062306a36Sopenharmony_ci * Each other regset might generate a note too. For each regset 179162306a36Sopenharmony_ci * that has no core_note_type or is inactive, skip it. 179262306a36Sopenharmony_ci */ 179362306a36Sopenharmony_ci note_iter = 1; 179462306a36Sopenharmony_ci for (view_iter = 1; view_iter < view->n; ++view_iter) { 179562306a36Sopenharmony_ci const struct user_regset *regset = &view->regsets[view_iter]; 179662306a36Sopenharmony_ci int note_type = regset->core_note_type; 179762306a36Sopenharmony_ci bool is_fpreg = note_type == NT_PRFPREG; 179862306a36Sopenharmony_ci void *data; 179962306a36Sopenharmony_ci int ret; 180062306a36Sopenharmony_ci 180162306a36Sopenharmony_ci do_thread_regset_writeback(t->task, regset); 180262306a36Sopenharmony_ci if (!note_type) // not for coredumps 180362306a36Sopenharmony_ci continue; 180462306a36Sopenharmony_ci if (regset->active && regset->active(t->task, regset) <= 0) 180562306a36Sopenharmony_ci continue; 180662306a36Sopenharmony_ci 180762306a36Sopenharmony_ci ret = regset_get_alloc(t->task, regset, ~0U, &data); 180862306a36Sopenharmony_ci if (ret < 0) 180962306a36Sopenharmony_ci continue; 181062306a36Sopenharmony_ci 181162306a36Sopenharmony_ci if (WARN_ON_ONCE(note_iter >= info->thread_notes)) 181262306a36Sopenharmony_ci break; 181362306a36Sopenharmony_ci 181462306a36Sopenharmony_ci if (is_fpreg) 181562306a36Sopenharmony_ci SET_PR_FPVALID(&t->prstatus); 181662306a36Sopenharmony_ci 181762306a36Sopenharmony_ci fill_note(&t->notes[note_iter], is_fpreg ? "CORE" : "LINUX", 181862306a36Sopenharmony_ci note_type, ret, data); 181962306a36Sopenharmony_ci 182062306a36Sopenharmony_ci info->size += notesize(&t->notes[note_iter]); 182162306a36Sopenharmony_ci note_iter++; 182262306a36Sopenharmony_ci } 182362306a36Sopenharmony_ci 182462306a36Sopenharmony_ci return 1; 182562306a36Sopenharmony_ci} 182662306a36Sopenharmony_ci#else 182762306a36Sopenharmony_cistatic int fill_thread_core_info(struct elf_thread_core_info *t, 182862306a36Sopenharmony_ci const struct user_regset_view *view, 182962306a36Sopenharmony_ci long signr, struct elf_note_info *info) 183062306a36Sopenharmony_ci{ 183162306a36Sopenharmony_ci struct task_struct *p = t->task; 183262306a36Sopenharmony_ci elf_fpregset_t *fpu; 183362306a36Sopenharmony_ci 183462306a36Sopenharmony_ci fill_prstatus(&t->prstatus.common, p, signr); 183562306a36Sopenharmony_ci elf_core_copy_task_regs(p, &t->prstatus.pr_reg); 183662306a36Sopenharmony_ci 183762306a36Sopenharmony_ci fill_note(&t->notes[0], "CORE", NT_PRSTATUS, sizeof(t->prstatus), 183862306a36Sopenharmony_ci &(t->prstatus)); 183962306a36Sopenharmony_ci info->size += notesize(&t->notes[0]); 184062306a36Sopenharmony_ci 184162306a36Sopenharmony_ci fpu = kzalloc(sizeof(elf_fpregset_t), GFP_KERNEL); 184262306a36Sopenharmony_ci if (!fpu || !elf_core_copy_task_fpregs(p, fpu)) { 184362306a36Sopenharmony_ci kfree(fpu); 184462306a36Sopenharmony_ci return 1; 184562306a36Sopenharmony_ci } 184662306a36Sopenharmony_ci 184762306a36Sopenharmony_ci t->prstatus.pr_fpvalid = 1; 184862306a36Sopenharmony_ci fill_note(&t->notes[1], "CORE", NT_PRFPREG, sizeof(*fpu), fpu); 184962306a36Sopenharmony_ci info->size += notesize(&t->notes[1]); 185062306a36Sopenharmony_ci 185162306a36Sopenharmony_ci return 1; 185262306a36Sopenharmony_ci} 185362306a36Sopenharmony_ci#endif 185462306a36Sopenharmony_ci 185562306a36Sopenharmony_cistatic int fill_note_info(struct elfhdr *elf, int phdrs, 185662306a36Sopenharmony_ci struct elf_note_info *info, 185762306a36Sopenharmony_ci struct coredump_params *cprm) 185862306a36Sopenharmony_ci{ 185962306a36Sopenharmony_ci struct task_struct *dump_task = current; 186062306a36Sopenharmony_ci const struct user_regset_view *view; 186162306a36Sopenharmony_ci struct elf_thread_core_info *t; 186262306a36Sopenharmony_ci struct elf_prpsinfo *psinfo; 186362306a36Sopenharmony_ci struct core_thread *ct; 186462306a36Sopenharmony_ci 186562306a36Sopenharmony_ci psinfo = kmalloc(sizeof(*psinfo), GFP_KERNEL); 186662306a36Sopenharmony_ci if (!psinfo) 186762306a36Sopenharmony_ci return 0; 186862306a36Sopenharmony_ci fill_note(&info->psinfo, "CORE", NT_PRPSINFO, sizeof(*psinfo), psinfo); 186962306a36Sopenharmony_ci 187062306a36Sopenharmony_ci#ifdef CORE_DUMP_USE_REGSET 187162306a36Sopenharmony_ci view = task_user_regset_view(dump_task); 187262306a36Sopenharmony_ci 187362306a36Sopenharmony_ci /* 187462306a36Sopenharmony_ci * Figure out how many notes we're going to need for each thread. 187562306a36Sopenharmony_ci */ 187662306a36Sopenharmony_ci info->thread_notes = 0; 187762306a36Sopenharmony_ci for (int i = 0; i < view->n; ++i) 187862306a36Sopenharmony_ci if (view->regsets[i].core_note_type != 0) 187962306a36Sopenharmony_ci ++info->thread_notes; 188062306a36Sopenharmony_ci 188162306a36Sopenharmony_ci /* 188262306a36Sopenharmony_ci * Sanity check. We rely on regset 0 being in NT_PRSTATUS, 188362306a36Sopenharmony_ci * since it is our one special case. 188462306a36Sopenharmony_ci */ 188562306a36Sopenharmony_ci if (unlikely(info->thread_notes == 0) || 188662306a36Sopenharmony_ci unlikely(view->regsets[0].core_note_type != NT_PRSTATUS)) { 188762306a36Sopenharmony_ci WARN_ON(1); 188862306a36Sopenharmony_ci return 0; 188962306a36Sopenharmony_ci } 189062306a36Sopenharmony_ci 189162306a36Sopenharmony_ci /* 189262306a36Sopenharmony_ci * Initialize the ELF file header. 189362306a36Sopenharmony_ci */ 189462306a36Sopenharmony_ci fill_elf_header(elf, phdrs, 189562306a36Sopenharmony_ci view->e_machine, view->e_flags); 189662306a36Sopenharmony_ci#else 189762306a36Sopenharmony_ci view = NULL; 189862306a36Sopenharmony_ci info->thread_notes = 2; 189962306a36Sopenharmony_ci fill_elf_header(elf, phdrs, ELF_ARCH, ELF_CORE_EFLAGS); 190062306a36Sopenharmony_ci#endif 190162306a36Sopenharmony_ci 190262306a36Sopenharmony_ci /* 190362306a36Sopenharmony_ci * Allocate a structure for each thread. 190462306a36Sopenharmony_ci */ 190562306a36Sopenharmony_ci info->thread = kzalloc(offsetof(struct elf_thread_core_info, 190662306a36Sopenharmony_ci notes[info->thread_notes]), 190762306a36Sopenharmony_ci GFP_KERNEL); 190862306a36Sopenharmony_ci if (unlikely(!info->thread)) 190962306a36Sopenharmony_ci return 0; 191062306a36Sopenharmony_ci 191162306a36Sopenharmony_ci info->thread->task = dump_task; 191262306a36Sopenharmony_ci for (ct = dump_task->signal->core_state->dumper.next; ct; ct = ct->next) { 191362306a36Sopenharmony_ci t = kzalloc(offsetof(struct elf_thread_core_info, 191462306a36Sopenharmony_ci notes[info->thread_notes]), 191562306a36Sopenharmony_ci GFP_KERNEL); 191662306a36Sopenharmony_ci if (unlikely(!t)) 191762306a36Sopenharmony_ci return 0; 191862306a36Sopenharmony_ci 191962306a36Sopenharmony_ci t->task = ct->task; 192062306a36Sopenharmony_ci t->next = info->thread->next; 192162306a36Sopenharmony_ci info->thread->next = t; 192262306a36Sopenharmony_ci } 192362306a36Sopenharmony_ci 192462306a36Sopenharmony_ci /* 192562306a36Sopenharmony_ci * Now fill in each thread's information. 192662306a36Sopenharmony_ci */ 192762306a36Sopenharmony_ci for (t = info->thread; t != NULL; t = t->next) 192862306a36Sopenharmony_ci if (!fill_thread_core_info(t, view, cprm->siginfo->si_signo, info)) 192962306a36Sopenharmony_ci return 0; 193062306a36Sopenharmony_ci 193162306a36Sopenharmony_ci /* 193262306a36Sopenharmony_ci * Fill in the two process-wide notes. 193362306a36Sopenharmony_ci */ 193462306a36Sopenharmony_ci fill_psinfo(psinfo, dump_task->group_leader, dump_task->mm); 193562306a36Sopenharmony_ci info->size += notesize(&info->psinfo); 193662306a36Sopenharmony_ci 193762306a36Sopenharmony_ci fill_siginfo_note(&info->signote, &info->csigdata, cprm->siginfo); 193862306a36Sopenharmony_ci info->size += notesize(&info->signote); 193962306a36Sopenharmony_ci 194062306a36Sopenharmony_ci fill_auxv_note(&info->auxv, current->mm); 194162306a36Sopenharmony_ci info->size += notesize(&info->auxv); 194262306a36Sopenharmony_ci 194362306a36Sopenharmony_ci if (fill_files_note(&info->files, cprm) == 0) 194462306a36Sopenharmony_ci info->size += notesize(&info->files); 194562306a36Sopenharmony_ci 194662306a36Sopenharmony_ci return 1; 194762306a36Sopenharmony_ci} 194862306a36Sopenharmony_ci 194962306a36Sopenharmony_ci/* 195062306a36Sopenharmony_ci * Write all the notes for each thread. When writing the first thread, the 195162306a36Sopenharmony_ci * process-wide notes are interleaved after the first thread-specific note. 195262306a36Sopenharmony_ci */ 195362306a36Sopenharmony_cistatic int write_note_info(struct elf_note_info *info, 195462306a36Sopenharmony_ci struct coredump_params *cprm) 195562306a36Sopenharmony_ci{ 195662306a36Sopenharmony_ci bool first = true; 195762306a36Sopenharmony_ci struct elf_thread_core_info *t = info->thread; 195862306a36Sopenharmony_ci 195962306a36Sopenharmony_ci do { 196062306a36Sopenharmony_ci int i; 196162306a36Sopenharmony_ci 196262306a36Sopenharmony_ci if (!writenote(&t->notes[0], cprm)) 196362306a36Sopenharmony_ci return 0; 196462306a36Sopenharmony_ci 196562306a36Sopenharmony_ci if (first && !writenote(&info->psinfo, cprm)) 196662306a36Sopenharmony_ci return 0; 196762306a36Sopenharmony_ci if (first && !writenote(&info->signote, cprm)) 196862306a36Sopenharmony_ci return 0; 196962306a36Sopenharmony_ci if (first && !writenote(&info->auxv, cprm)) 197062306a36Sopenharmony_ci return 0; 197162306a36Sopenharmony_ci if (first && info->files.data && 197262306a36Sopenharmony_ci !writenote(&info->files, cprm)) 197362306a36Sopenharmony_ci return 0; 197462306a36Sopenharmony_ci 197562306a36Sopenharmony_ci for (i = 1; i < info->thread_notes; ++i) 197662306a36Sopenharmony_ci if (t->notes[i].data && 197762306a36Sopenharmony_ci !writenote(&t->notes[i], cprm)) 197862306a36Sopenharmony_ci return 0; 197962306a36Sopenharmony_ci 198062306a36Sopenharmony_ci first = false; 198162306a36Sopenharmony_ci t = t->next; 198262306a36Sopenharmony_ci } while (t); 198362306a36Sopenharmony_ci 198462306a36Sopenharmony_ci return 1; 198562306a36Sopenharmony_ci} 198662306a36Sopenharmony_ci 198762306a36Sopenharmony_cistatic void free_note_info(struct elf_note_info *info) 198862306a36Sopenharmony_ci{ 198962306a36Sopenharmony_ci struct elf_thread_core_info *threads = info->thread; 199062306a36Sopenharmony_ci while (threads) { 199162306a36Sopenharmony_ci unsigned int i; 199262306a36Sopenharmony_ci struct elf_thread_core_info *t = threads; 199362306a36Sopenharmony_ci threads = t->next; 199462306a36Sopenharmony_ci WARN_ON(t->notes[0].data && t->notes[0].data != &t->prstatus); 199562306a36Sopenharmony_ci for (i = 1; i < info->thread_notes; ++i) 199662306a36Sopenharmony_ci kfree(t->notes[i].data); 199762306a36Sopenharmony_ci kfree(t); 199862306a36Sopenharmony_ci } 199962306a36Sopenharmony_ci kfree(info->psinfo.data); 200062306a36Sopenharmony_ci kvfree(info->files.data); 200162306a36Sopenharmony_ci} 200262306a36Sopenharmony_ci 200362306a36Sopenharmony_cistatic void fill_extnum_info(struct elfhdr *elf, struct elf_shdr *shdr4extnum, 200462306a36Sopenharmony_ci elf_addr_t e_shoff, int segs) 200562306a36Sopenharmony_ci{ 200662306a36Sopenharmony_ci elf->e_shoff = e_shoff; 200762306a36Sopenharmony_ci elf->e_shentsize = sizeof(*shdr4extnum); 200862306a36Sopenharmony_ci elf->e_shnum = 1; 200962306a36Sopenharmony_ci elf->e_shstrndx = SHN_UNDEF; 201062306a36Sopenharmony_ci 201162306a36Sopenharmony_ci memset(shdr4extnum, 0, sizeof(*shdr4extnum)); 201262306a36Sopenharmony_ci 201362306a36Sopenharmony_ci shdr4extnum->sh_type = SHT_NULL; 201462306a36Sopenharmony_ci shdr4extnum->sh_size = elf->e_shnum; 201562306a36Sopenharmony_ci shdr4extnum->sh_link = elf->e_shstrndx; 201662306a36Sopenharmony_ci shdr4extnum->sh_info = segs; 201762306a36Sopenharmony_ci} 201862306a36Sopenharmony_ci 201962306a36Sopenharmony_ci/* 202062306a36Sopenharmony_ci * Actual dumper 202162306a36Sopenharmony_ci * 202262306a36Sopenharmony_ci * This is a two-pass process; first we find the offsets of the bits, 202362306a36Sopenharmony_ci * and then they are actually written out. If we run out of core limit 202462306a36Sopenharmony_ci * we just truncate. 202562306a36Sopenharmony_ci */ 202662306a36Sopenharmony_cistatic int elf_core_dump(struct coredump_params *cprm) 202762306a36Sopenharmony_ci{ 202862306a36Sopenharmony_ci int has_dumped = 0; 202962306a36Sopenharmony_ci int segs, i; 203062306a36Sopenharmony_ci struct elfhdr elf; 203162306a36Sopenharmony_ci loff_t offset = 0, dataoff; 203262306a36Sopenharmony_ci struct elf_note_info info = { }; 203362306a36Sopenharmony_ci struct elf_phdr *phdr4note = NULL; 203462306a36Sopenharmony_ci struct elf_shdr *shdr4extnum = NULL; 203562306a36Sopenharmony_ci Elf_Half e_phnum; 203662306a36Sopenharmony_ci elf_addr_t e_shoff; 203762306a36Sopenharmony_ci 203862306a36Sopenharmony_ci /* 203962306a36Sopenharmony_ci * The number of segs are recored into ELF header as 16bit value. 204062306a36Sopenharmony_ci * Please check DEFAULT_MAX_MAP_COUNT definition when you modify here. 204162306a36Sopenharmony_ci */ 204262306a36Sopenharmony_ci segs = cprm->vma_count + elf_core_extra_phdrs(cprm); 204362306a36Sopenharmony_ci 204462306a36Sopenharmony_ci /* for notes section */ 204562306a36Sopenharmony_ci segs++; 204662306a36Sopenharmony_ci 204762306a36Sopenharmony_ci /* If segs > PN_XNUM(0xffff), then e_phnum overflows. To avoid 204862306a36Sopenharmony_ci * this, kernel supports extended numbering. Have a look at 204962306a36Sopenharmony_ci * include/linux/elf.h for further information. */ 205062306a36Sopenharmony_ci e_phnum = segs > PN_XNUM ? PN_XNUM : segs; 205162306a36Sopenharmony_ci 205262306a36Sopenharmony_ci /* 205362306a36Sopenharmony_ci * Collect all the non-memory information about the process for the 205462306a36Sopenharmony_ci * notes. This also sets up the file header. 205562306a36Sopenharmony_ci */ 205662306a36Sopenharmony_ci if (!fill_note_info(&elf, e_phnum, &info, cprm)) 205762306a36Sopenharmony_ci goto end_coredump; 205862306a36Sopenharmony_ci 205962306a36Sopenharmony_ci has_dumped = 1; 206062306a36Sopenharmony_ci 206162306a36Sopenharmony_ci offset += sizeof(elf); /* ELF header */ 206262306a36Sopenharmony_ci offset += segs * sizeof(struct elf_phdr); /* Program headers */ 206362306a36Sopenharmony_ci 206462306a36Sopenharmony_ci /* Write notes phdr entry */ 206562306a36Sopenharmony_ci { 206662306a36Sopenharmony_ci size_t sz = info.size; 206762306a36Sopenharmony_ci 206862306a36Sopenharmony_ci /* For cell spufs */ 206962306a36Sopenharmony_ci sz += elf_coredump_extra_notes_size(); 207062306a36Sopenharmony_ci 207162306a36Sopenharmony_ci phdr4note = kmalloc(sizeof(*phdr4note), GFP_KERNEL); 207262306a36Sopenharmony_ci if (!phdr4note) 207362306a36Sopenharmony_ci goto end_coredump; 207462306a36Sopenharmony_ci 207562306a36Sopenharmony_ci fill_elf_note_phdr(phdr4note, sz, offset); 207662306a36Sopenharmony_ci offset += sz; 207762306a36Sopenharmony_ci } 207862306a36Sopenharmony_ci 207962306a36Sopenharmony_ci dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE); 208062306a36Sopenharmony_ci 208162306a36Sopenharmony_ci offset += cprm->vma_data_size; 208262306a36Sopenharmony_ci offset += elf_core_extra_data_size(cprm); 208362306a36Sopenharmony_ci e_shoff = offset; 208462306a36Sopenharmony_ci 208562306a36Sopenharmony_ci if (e_phnum == PN_XNUM) { 208662306a36Sopenharmony_ci shdr4extnum = kmalloc(sizeof(*shdr4extnum), GFP_KERNEL); 208762306a36Sopenharmony_ci if (!shdr4extnum) 208862306a36Sopenharmony_ci goto end_coredump; 208962306a36Sopenharmony_ci fill_extnum_info(&elf, shdr4extnum, e_shoff, segs); 209062306a36Sopenharmony_ci } 209162306a36Sopenharmony_ci 209262306a36Sopenharmony_ci offset = dataoff; 209362306a36Sopenharmony_ci 209462306a36Sopenharmony_ci if (!dump_emit(cprm, &elf, sizeof(elf))) 209562306a36Sopenharmony_ci goto end_coredump; 209662306a36Sopenharmony_ci 209762306a36Sopenharmony_ci if (!dump_emit(cprm, phdr4note, sizeof(*phdr4note))) 209862306a36Sopenharmony_ci goto end_coredump; 209962306a36Sopenharmony_ci 210062306a36Sopenharmony_ci /* Write program headers for segments dump */ 210162306a36Sopenharmony_ci for (i = 0; i < cprm->vma_count; i++) { 210262306a36Sopenharmony_ci struct core_vma_metadata *meta = cprm->vma_meta + i; 210362306a36Sopenharmony_ci struct elf_phdr phdr; 210462306a36Sopenharmony_ci 210562306a36Sopenharmony_ci phdr.p_type = PT_LOAD; 210662306a36Sopenharmony_ci phdr.p_offset = offset; 210762306a36Sopenharmony_ci phdr.p_vaddr = meta->start; 210862306a36Sopenharmony_ci phdr.p_paddr = 0; 210962306a36Sopenharmony_ci phdr.p_filesz = meta->dump_size; 211062306a36Sopenharmony_ci phdr.p_memsz = meta->end - meta->start; 211162306a36Sopenharmony_ci offset += phdr.p_filesz; 211262306a36Sopenharmony_ci phdr.p_flags = 0; 211362306a36Sopenharmony_ci if (meta->flags & VM_READ) 211462306a36Sopenharmony_ci phdr.p_flags |= PF_R; 211562306a36Sopenharmony_ci if (meta->flags & VM_WRITE) 211662306a36Sopenharmony_ci phdr.p_flags |= PF_W; 211762306a36Sopenharmony_ci if (meta->flags & VM_EXEC) 211862306a36Sopenharmony_ci phdr.p_flags |= PF_X; 211962306a36Sopenharmony_ci phdr.p_align = ELF_EXEC_PAGESIZE; 212062306a36Sopenharmony_ci 212162306a36Sopenharmony_ci if (!dump_emit(cprm, &phdr, sizeof(phdr))) 212262306a36Sopenharmony_ci goto end_coredump; 212362306a36Sopenharmony_ci } 212462306a36Sopenharmony_ci 212562306a36Sopenharmony_ci if (!elf_core_write_extra_phdrs(cprm, offset)) 212662306a36Sopenharmony_ci goto end_coredump; 212762306a36Sopenharmony_ci 212862306a36Sopenharmony_ci /* write out the notes section */ 212962306a36Sopenharmony_ci if (!write_note_info(&info, cprm)) 213062306a36Sopenharmony_ci goto end_coredump; 213162306a36Sopenharmony_ci 213262306a36Sopenharmony_ci /* For cell spufs */ 213362306a36Sopenharmony_ci if (elf_coredump_extra_notes_write(cprm)) 213462306a36Sopenharmony_ci goto end_coredump; 213562306a36Sopenharmony_ci 213662306a36Sopenharmony_ci /* Align to page */ 213762306a36Sopenharmony_ci dump_skip_to(cprm, dataoff); 213862306a36Sopenharmony_ci 213962306a36Sopenharmony_ci for (i = 0; i < cprm->vma_count; i++) { 214062306a36Sopenharmony_ci struct core_vma_metadata *meta = cprm->vma_meta + i; 214162306a36Sopenharmony_ci 214262306a36Sopenharmony_ci if (!dump_user_range(cprm, meta->start, meta->dump_size)) 214362306a36Sopenharmony_ci goto end_coredump; 214462306a36Sopenharmony_ci } 214562306a36Sopenharmony_ci 214662306a36Sopenharmony_ci if (!elf_core_write_extra_data(cprm)) 214762306a36Sopenharmony_ci goto end_coredump; 214862306a36Sopenharmony_ci 214962306a36Sopenharmony_ci if (e_phnum == PN_XNUM) { 215062306a36Sopenharmony_ci if (!dump_emit(cprm, shdr4extnum, sizeof(*shdr4extnum))) 215162306a36Sopenharmony_ci goto end_coredump; 215262306a36Sopenharmony_ci } 215362306a36Sopenharmony_ci 215462306a36Sopenharmony_ciend_coredump: 215562306a36Sopenharmony_ci free_note_info(&info); 215662306a36Sopenharmony_ci kfree(shdr4extnum); 215762306a36Sopenharmony_ci kfree(phdr4note); 215862306a36Sopenharmony_ci return has_dumped; 215962306a36Sopenharmony_ci} 216062306a36Sopenharmony_ci 216162306a36Sopenharmony_ci#endif /* CONFIG_ELF_CORE */ 216262306a36Sopenharmony_ci 216362306a36Sopenharmony_cistatic int __init init_elf_binfmt(void) 216462306a36Sopenharmony_ci{ 216562306a36Sopenharmony_ci register_binfmt(&elf_format); 216662306a36Sopenharmony_ci return 0; 216762306a36Sopenharmony_ci} 216862306a36Sopenharmony_ci 216962306a36Sopenharmony_cistatic void __exit exit_elf_binfmt(void) 217062306a36Sopenharmony_ci{ 217162306a36Sopenharmony_ci /* Remove the COFF and ELF loaders. */ 217262306a36Sopenharmony_ci unregister_binfmt(&elf_format); 217362306a36Sopenharmony_ci} 217462306a36Sopenharmony_ci 217562306a36Sopenharmony_cicore_initcall(init_elf_binfmt); 217662306a36Sopenharmony_cimodule_exit(exit_elf_binfmt); 217762306a36Sopenharmony_ci 217862306a36Sopenharmony_ci#ifdef CONFIG_BINFMT_ELF_KUNIT_TEST 217962306a36Sopenharmony_ci#include "binfmt_elf_test.c" 218062306a36Sopenharmony_ci#endif 2181