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