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