xref: /kernel/linux/linux-5.10/fs/binfmt_flat.c (revision 8c2ecf20)
18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/****************************************************************************/
38c2ecf20Sopenharmony_ci/*
48c2ecf20Sopenharmony_ci *  linux/fs/binfmt_flat.c
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci *	Copyright (C) 2000-2003 David McCullough <davidm@snapgear.com>
78c2ecf20Sopenharmony_ci *	Copyright (C) 2002 Greg Ungerer <gerg@snapgear.com>
88c2ecf20Sopenharmony_ci *	Copyright (C) 2002 SnapGear, by Paul Dale <pauli@snapgear.com>
98c2ecf20Sopenharmony_ci *	Copyright (C) 2000, 2001 Lineo, by David McCullough <davidm@lineo.com>
108c2ecf20Sopenharmony_ci *  based heavily on:
118c2ecf20Sopenharmony_ci *
128c2ecf20Sopenharmony_ci *  linux/fs/binfmt_aout.c:
138c2ecf20Sopenharmony_ci *      Copyright (C) 1991, 1992, 1996  Linus Torvalds
148c2ecf20Sopenharmony_ci *  linux/fs/binfmt_flat.c for 2.0 kernel
158c2ecf20Sopenharmony_ci *	    Copyright (C) 1998  Kenneth Albanowski <kjahds@kjahds.com>
168c2ecf20Sopenharmony_ci *	JAN/99 -- coded full program relocation (gerg@snapgear.com)
178c2ecf20Sopenharmony_ci */
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#include <linux/kernel.h>
228c2ecf20Sopenharmony_ci#include <linux/sched.h>
238c2ecf20Sopenharmony_ci#include <linux/sched/task_stack.h>
248c2ecf20Sopenharmony_ci#include <linux/mm.h>
258c2ecf20Sopenharmony_ci#include <linux/mman.h>
268c2ecf20Sopenharmony_ci#include <linux/errno.h>
278c2ecf20Sopenharmony_ci#include <linux/signal.h>
288c2ecf20Sopenharmony_ci#include <linux/string.h>
298c2ecf20Sopenharmony_ci#include <linux/fs.h>
308c2ecf20Sopenharmony_ci#include <linux/file.h>
318c2ecf20Sopenharmony_ci#include <linux/ptrace.h>
328c2ecf20Sopenharmony_ci#include <linux/user.h>
338c2ecf20Sopenharmony_ci#include <linux/slab.h>
348c2ecf20Sopenharmony_ci#include <linux/binfmts.h>
358c2ecf20Sopenharmony_ci#include <linux/personality.h>
368c2ecf20Sopenharmony_ci#include <linux/init.h>
378c2ecf20Sopenharmony_ci#include <linux/flat.h>
388c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
398c2ecf20Sopenharmony_ci#include <linux/vmalloc.h>
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci#include <asm/byteorder.h>
428c2ecf20Sopenharmony_ci#include <asm/unaligned.h>
438c2ecf20Sopenharmony_ci#include <asm/cacheflush.h>
448c2ecf20Sopenharmony_ci#include <asm/page.h>
458c2ecf20Sopenharmony_ci#include <asm/flat.h>
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci#ifndef flat_get_relocate_addr
488c2ecf20Sopenharmony_ci#define flat_get_relocate_addr(rel)	(rel)
498c2ecf20Sopenharmony_ci#endif
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci/****************************************************************************/
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci/*
548c2ecf20Sopenharmony_ci * User data (data section and bss) needs to be aligned.
558c2ecf20Sopenharmony_ci * We pick 0x20 here because it is the max value elf2flt has always
568c2ecf20Sopenharmony_ci * used in producing FLAT files, and because it seems to be large
578c2ecf20Sopenharmony_ci * enough to make all the gcc alignment related tests happy.
588c2ecf20Sopenharmony_ci */
598c2ecf20Sopenharmony_ci#define FLAT_DATA_ALIGN	(0x20)
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci/*
628c2ecf20Sopenharmony_ci * User data (stack) also needs to be aligned.
638c2ecf20Sopenharmony_ci * Here we can be a bit looser than the data sections since this
648c2ecf20Sopenharmony_ci * needs to only meet arch ABI requirements.
658c2ecf20Sopenharmony_ci */
668c2ecf20Sopenharmony_ci#define FLAT_STACK_ALIGN	max_t(unsigned long, sizeof(void *), ARCH_SLAB_MINALIGN)
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci#define RELOC_FAILED 0xff00ff01		/* Relocation incorrect somewhere */
698c2ecf20Sopenharmony_ci#define UNLOADED_LIB 0x7ff000ff		/* Placeholder for unused library */
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci#ifdef CONFIG_BINFMT_SHARED_FLAT
728c2ecf20Sopenharmony_ci#define	MAX_SHARED_LIBS			(4)
738c2ecf20Sopenharmony_ci#else
748c2ecf20Sopenharmony_ci#define	MAX_SHARED_LIBS			(1)
758c2ecf20Sopenharmony_ci#endif
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_cistruct lib_info {
788c2ecf20Sopenharmony_ci	struct {
798c2ecf20Sopenharmony_ci		unsigned long start_code;		/* Start of text segment */
808c2ecf20Sopenharmony_ci		unsigned long start_data;		/* Start of data segment */
818c2ecf20Sopenharmony_ci		unsigned long start_brk;		/* End of data segment */
828c2ecf20Sopenharmony_ci		unsigned long text_len;			/* Length of text segment */
838c2ecf20Sopenharmony_ci		unsigned long entry;			/* Start address for this module */
848c2ecf20Sopenharmony_ci		unsigned long build_date;		/* When this one was compiled */
858c2ecf20Sopenharmony_ci		bool loaded;				/* Has this library been loaded? */
868c2ecf20Sopenharmony_ci	} lib_list[MAX_SHARED_LIBS];
878c2ecf20Sopenharmony_ci};
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci#ifdef CONFIG_BINFMT_SHARED_FLAT
908c2ecf20Sopenharmony_cistatic int load_flat_shared_library(int id, struct lib_info *p);
918c2ecf20Sopenharmony_ci#endif
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_cistatic int load_flat_binary(struct linux_binprm *);
948c2ecf20Sopenharmony_cistatic int flat_core_dump(struct coredump_params *cprm);
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_cistatic struct linux_binfmt flat_format = {
978c2ecf20Sopenharmony_ci	.module		= THIS_MODULE,
988c2ecf20Sopenharmony_ci	.load_binary	= load_flat_binary,
998c2ecf20Sopenharmony_ci	.core_dump	= flat_core_dump,
1008c2ecf20Sopenharmony_ci	.min_coredump	= PAGE_SIZE
1018c2ecf20Sopenharmony_ci};
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci/****************************************************************************/
1048c2ecf20Sopenharmony_ci/*
1058c2ecf20Sopenharmony_ci * Routine writes a core dump image in the current directory.
1068c2ecf20Sopenharmony_ci * Currently only a stub-function.
1078c2ecf20Sopenharmony_ci */
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_cistatic int flat_core_dump(struct coredump_params *cprm)
1108c2ecf20Sopenharmony_ci{
1118c2ecf20Sopenharmony_ci	pr_warn("Process %s:%d received signr %d and should have core dumped\n",
1128c2ecf20Sopenharmony_ci		current->comm, current->pid, cprm->siginfo->si_signo);
1138c2ecf20Sopenharmony_ci	return 1;
1148c2ecf20Sopenharmony_ci}
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci/****************************************************************************/
1178c2ecf20Sopenharmony_ci/*
1188c2ecf20Sopenharmony_ci * create_flat_tables() parses the env- and arg-strings in new user
1198c2ecf20Sopenharmony_ci * memory and creates the pointer tables from them, and puts their
1208c2ecf20Sopenharmony_ci * addresses on the "stack", recording the new stack pointer value.
1218c2ecf20Sopenharmony_ci */
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_cistatic int create_flat_tables(struct linux_binprm *bprm, unsigned long arg_start)
1248c2ecf20Sopenharmony_ci{
1258c2ecf20Sopenharmony_ci	char __user *p;
1268c2ecf20Sopenharmony_ci	unsigned long __user *sp;
1278c2ecf20Sopenharmony_ci	long i, len;
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	p = (char __user *)arg_start;
1308c2ecf20Sopenharmony_ci	sp = (unsigned long __user *)current->mm->start_stack;
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	sp -= bprm->envc + 1;
1338c2ecf20Sopenharmony_ci	sp -= bprm->argc + 1;
1348c2ecf20Sopenharmony_ci	if (IS_ENABLED(CONFIG_BINFMT_FLAT_ARGVP_ENVP_ON_STACK))
1358c2ecf20Sopenharmony_ci		sp -= 2; /* argvp + envp */
1368c2ecf20Sopenharmony_ci	sp -= 1;  /* &argc */
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	current->mm->start_stack = (unsigned long)sp & -FLAT_STACK_ALIGN;
1398c2ecf20Sopenharmony_ci	sp = (unsigned long __user *)current->mm->start_stack;
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	if (put_user(bprm->argc, sp++))
1428c2ecf20Sopenharmony_ci		return -EFAULT;
1438c2ecf20Sopenharmony_ci	if (IS_ENABLED(CONFIG_BINFMT_FLAT_ARGVP_ENVP_ON_STACK)) {
1448c2ecf20Sopenharmony_ci		unsigned long argv, envp;
1458c2ecf20Sopenharmony_ci		argv = (unsigned long)(sp + 2);
1468c2ecf20Sopenharmony_ci		envp = (unsigned long)(sp + 2 + bprm->argc + 1);
1478c2ecf20Sopenharmony_ci		if (put_user(argv, sp++) || put_user(envp, sp++))
1488c2ecf20Sopenharmony_ci			return -EFAULT;
1498c2ecf20Sopenharmony_ci	}
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	current->mm->arg_start = (unsigned long)p;
1528c2ecf20Sopenharmony_ci	for (i = bprm->argc; i > 0; i--) {
1538c2ecf20Sopenharmony_ci		if (put_user((unsigned long)p, sp++))
1548c2ecf20Sopenharmony_ci			return -EFAULT;
1558c2ecf20Sopenharmony_ci		len = strnlen_user(p, MAX_ARG_STRLEN);
1568c2ecf20Sopenharmony_ci		if (!len || len > MAX_ARG_STRLEN)
1578c2ecf20Sopenharmony_ci			return -EINVAL;
1588c2ecf20Sopenharmony_ci		p += len;
1598c2ecf20Sopenharmony_ci	}
1608c2ecf20Sopenharmony_ci	if (put_user(0, sp++))
1618c2ecf20Sopenharmony_ci		return -EFAULT;
1628c2ecf20Sopenharmony_ci	current->mm->arg_end = (unsigned long)p;
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci	current->mm->env_start = (unsigned long) p;
1658c2ecf20Sopenharmony_ci	for (i = bprm->envc; i > 0; i--) {
1668c2ecf20Sopenharmony_ci		if (put_user((unsigned long)p, sp++))
1678c2ecf20Sopenharmony_ci			return -EFAULT;
1688c2ecf20Sopenharmony_ci		len = strnlen_user(p, MAX_ARG_STRLEN);
1698c2ecf20Sopenharmony_ci		if (!len || len > MAX_ARG_STRLEN)
1708c2ecf20Sopenharmony_ci			return -EINVAL;
1718c2ecf20Sopenharmony_ci		p += len;
1728c2ecf20Sopenharmony_ci	}
1738c2ecf20Sopenharmony_ci	if (put_user(0, sp++))
1748c2ecf20Sopenharmony_ci		return -EFAULT;
1758c2ecf20Sopenharmony_ci	current->mm->env_end = (unsigned long)p;
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	return 0;
1788c2ecf20Sopenharmony_ci}
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci/****************************************************************************/
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci#ifdef CONFIG_BINFMT_ZFLAT
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci#include <linux/zlib.h>
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci#define LBUFSIZE	4000
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci/* gzip flag byte */
1898c2ecf20Sopenharmony_ci#define ASCII_FLAG   0x01 /* bit 0 set: file probably ASCII text */
1908c2ecf20Sopenharmony_ci#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
1918c2ecf20Sopenharmony_ci#define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
1928c2ecf20Sopenharmony_ci#define ORIG_NAME    0x08 /* bit 3 set: original file name present */
1938c2ecf20Sopenharmony_ci#define COMMENT      0x10 /* bit 4 set: file comment present */
1948c2ecf20Sopenharmony_ci#define ENCRYPTED    0x20 /* bit 5 set: file is encrypted */
1958c2ecf20Sopenharmony_ci#define RESERVED     0xC0 /* bit 6,7:   reserved */
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_cistatic int decompress_exec(struct linux_binprm *bprm, loff_t fpos, char *dst,
1988c2ecf20Sopenharmony_ci		long len, int fd)
1998c2ecf20Sopenharmony_ci{
2008c2ecf20Sopenharmony_ci	unsigned char *buf;
2018c2ecf20Sopenharmony_ci	z_stream strm;
2028c2ecf20Sopenharmony_ci	int ret, retval;
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	pr_debug("decompress_exec(offset=%llx,buf=%p,len=%lx)\n", fpos, dst, len);
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	memset(&strm, 0, sizeof(strm));
2078c2ecf20Sopenharmony_ci	strm.workspace = kmalloc(zlib_inflate_workspacesize(), GFP_KERNEL);
2088c2ecf20Sopenharmony_ci	if (!strm.workspace)
2098c2ecf20Sopenharmony_ci		return -ENOMEM;
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	buf = kmalloc(LBUFSIZE, GFP_KERNEL);
2128c2ecf20Sopenharmony_ci	if (!buf) {
2138c2ecf20Sopenharmony_ci		retval = -ENOMEM;
2148c2ecf20Sopenharmony_ci		goto out_free;
2158c2ecf20Sopenharmony_ci	}
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	/* Read in first chunk of data and parse gzip header. */
2188c2ecf20Sopenharmony_ci	ret = kernel_read(bprm->file, buf, LBUFSIZE, &fpos);
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	strm.next_in = buf;
2218c2ecf20Sopenharmony_ci	strm.avail_in = ret;
2228c2ecf20Sopenharmony_ci	strm.total_in = 0;
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	retval = -ENOEXEC;
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	/* Check minimum size -- gzip header */
2278c2ecf20Sopenharmony_ci	if (ret < 10) {
2288c2ecf20Sopenharmony_ci		pr_debug("file too small?\n");
2298c2ecf20Sopenharmony_ci		goto out_free_buf;
2308c2ecf20Sopenharmony_ci	}
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	/* Check gzip magic number */
2338c2ecf20Sopenharmony_ci	if ((buf[0] != 037) || ((buf[1] != 0213) && (buf[1] != 0236))) {
2348c2ecf20Sopenharmony_ci		pr_debug("unknown compression magic?\n");
2358c2ecf20Sopenharmony_ci		goto out_free_buf;
2368c2ecf20Sopenharmony_ci	}
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	/* Check gzip method */
2398c2ecf20Sopenharmony_ci	if (buf[2] != 8) {
2408c2ecf20Sopenharmony_ci		pr_debug("unknown compression method?\n");
2418c2ecf20Sopenharmony_ci		goto out_free_buf;
2428c2ecf20Sopenharmony_ci	}
2438c2ecf20Sopenharmony_ci	/* Check gzip flags */
2448c2ecf20Sopenharmony_ci	if ((buf[3] & ENCRYPTED) || (buf[3] & CONTINUATION) ||
2458c2ecf20Sopenharmony_ci	    (buf[3] & RESERVED)) {
2468c2ecf20Sopenharmony_ci		pr_debug("unknown flags?\n");
2478c2ecf20Sopenharmony_ci		goto out_free_buf;
2488c2ecf20Sopenharmony_ci	}
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	ret = 10;
2518c2ecf20Sopenharmony_ci	if (buf[3] & EXTRA_FIELD) {
2528c2ecf20Sopenharmony_ci		ret += 2 + buf[10] + (buf[11] << 8);
2538c2ecf20Sopenharmony_ci		if (unlikely(ret >= LBUFSIZE)) {
2548c2ecf20Sopenharmony_ci			pr_debug("buffer overflow (EXTRA)?\n");
2558c2ecf20Sopenharmony_ci			goto out_free_buf;
2568c2ecf20Sopenharmony_ci		}
2578c2ecf20Sopenharmony_ci	}
2588c2ecf20Sopenharmony_ci	if (buf[3] & ORIG_NAME) {
2598c2ecf20Sopenharmony_ci		while (ret < LBUFSIZE && buf[ret++] != 0)
2608c2ecf20Sopenharmony_ci			;
2618c2ecf20Sopenharmony_ci		if (unlikely(ret == LBUFSIZE)) {
2628c2ecf20Sopenharmony_ci			pr_debug("buffer overflow (ORIG_NAME)?\n");
2638c2ecf20Sopenharmony_ci			goto out_free_buf;
2648c2ecf20Sopenharmony_ci		}
2658c2ecf20Sopenharmony_ci	}
2668c2ecf20Sopenharmony_ci	if (buf[3] & COMMENT) {
2678c2ecf20Sopenharmony_ci		while (ret < LBUFSIZE && buf[ret++] != 0)
2688c2ecf20Sopenharmony_ci			;
2698c2ecf20Sopenharmony_ci		if (unlikely(ret == LBUFSIZE)) {
2708c2ecf20Sopenharmony_ci			pr_debug("buffer overflow (COMMENT)?\n");
2718c2ecf20Sopenharmony_ci			goto out_free_buf;
2728c2ecf20Sopenharmony_ci		}
2738c2ecf20Sopenharmony_ci	}
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	strm.next_in += ret;
2768c2ecf20Sopenharmony_ci	strm.avail_in -= ret;
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	strm.next_out = dst;
2798c2ecf20Sopenharmony_ci	strm.avail_out = len;
2808c2ecf20Sopenharmony_ci	strm.total_out = 0;
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	if (zlib_inflateInit2(&strm, -MAX_WBITS) != Z_OK) {
2838c2ecf20Sopenharmony_ci		pr_debug("zlib init failed?\n");
2848c2ecf20Sopenharmony_ci		goto out_free_buf;
2858c2ecf20Sopenharmony_ci	}
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci	while ((ret = zlib_inflate(&strm, Z_NO_FLUSH)) == Z_OK) {
2888c2ecf20Sopenharmony_ci		ret = kernel_read(bprm->file, buf, LBUFSIZE, &fpos);
2898c2ecf20Sopenharmony_ci		if (ret <= 0)
2908c2ecf20Sopenharmony_ci			break;
2918c2ecf20Sopenharmony_ci		len -= ret;
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci		strm.next_in = buf;
2948c2ecf20Sopenharmony_ci		strm.avail_in = ret;
2958c2ecf20Sopenharmony_ci		strm.total_in = 0;
2968c2ecf20Sopenharmony_ci	}
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	if (ret < 0) {
2998c2ecf20Sopenharmony_ci		pr_debug("decompression failed (%d), %s\n",
3008c2ecf20Sopenharmony_ci			ret, strm.msg);
3018c2ecf20Sopenharmony_ci		goto out_zlib;
3028c2ecf20Sopenharmony_ci	}
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	retval = 0;
3058c2ecf20Sopenharmony_ciout_zlib:
3068c2ecf20Sopenharmony_ci	zlib_inflateEnd(&strm);
3078c2ecf20Sopenharmony_ciout_free_buf:
3088c2ecf20Sopenharmony_ci	kfree(buf);
3098c2ecf20Sopenharmony_ciout_free:
3108c2ecf20Sopenharmony_ci	kfree(strm.workspace);
3118c2ecf20Sopenharmony_ci	return retval;
3128c2ecf20Sopenharmony_ci}
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci#endif /* CONFIG_BINFMT_ZFLAT */
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci/****************************************************************************/
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_cistatic unsigned long
3198c2ecf20Sopenharmony_cicalc_reloc(unsigned long r, struct lib_info *p, int curid, int internalp)
3208c2ecf20Sopenharmony_ci{
3218c2ecf20Sopenharmony_ci	unsigned long addr;
3228c2ecf20Sopenharmony_ci	int id;
3238c2ecf20Sopenharmony_ci	unsigned long start_brk;
3248c2ecf20Sopenharmony_ci	unsigned long start_data;
3258c2ecf20Sopenharmony_ci	unsigned long text_len;
3268c2ecf20Sopenharmony_ci	unsigned long start_code;
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci#ifdef CONFIG_BINFMT_SHARED_FLAT
3298c2ecf20Sopenharmony_ci	if (r == 0)
3308c2ecf20Sopenharmony_ci		id = curid;	/* Relocs of 0 are always self referring */
3318c2ecf20Sopenharmony_ci	else {
3328c2ecf20Sopenharmony_ci		id = (r >> 24) & 0xff;	/* Find ID for this reloc */
3338c2ecf20Sopenharmony_ci		r &= 0x00ffffff;	/* Trim ID off here */
3348c2ecf20Sopenharmony_ci	}
3358c2ecf20Sopenharmony_ci	if (id >= MAX_SHARED_LIBS) {
3368c2ecf20Sopenharmony_ci		pr_err("reference 0x%lx to shared library %d", r, id);
3378c2ecf20Sopenharmony_ci		goto failed;
3388c2ecf20Sopenharmony_ci	}
3398c2ecf20Sopenharmony_ci	if (curid != id) {
3408c2ecf20Sopenharmony_ci		if (internalp) {
3418c2ecf20Sopenharmony_ci			pr_err("reloc address 0x%lx not in same module "
3428c2ecf20Sopenharmony_ci			       "(%d != %d)", r, curid, id);
3438c2ecf20Sopenharmony_ci			goto failed;
3448c2ecf20Sopenharmony_ci		} else if (!p->lib_list[id].loaded &&
3458c2ecf20Sopenharmony_ci			   load_flat_shared_library(id, p) < 0) {
3468c2ecf20Sopenharmony_ci			pr_err("failed to load library %d", id);
3478c2ecf20Sopenharmony_ci			goto failed;
3488c2ecf20Sopenharmony_ci		}
3498c2ecf20Sopenharmony_ci		/* Check versioning information (i.e. time stamps) */
3508c2ecf20Sopenharmony_ci		if (p->lib_list[id].build_date && p->lib_list[curid].build_date &&
3518c2ecf20Sopenharmony_ci				p->lib_list[curid].build_date < p->lib_list[id].build_date) {
3528c2ecf20Sopenharmony_ci			pr_err("library %d is younger than %d", id, curid);
3538c2ecf20Sopenharmony_ci			goto failed;
3548c2ecf20Sopenharmony_ci		}
3558c2ecf20Sopenharmony_ci	}
3568c2ecf20Sopenharmony_ci#else
3578c2ecf20Sopenharmony_ci	id = 0;
3588c2ecf20Sopenharmony_ci#endif
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	start_brk = p->lib_list[id].start_brk;
3618c2ecf20Sopenharmony_ci	start_data = p->lib_list[id].start_data;
3628c2ecf20Sopenharmony_ci	start_code = p->lib_list[id].start_code;
3638c2ecf20Sopenharmony_ci	text_len = p->lib_list[id].text_len;
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	if (r > start_brk - start_data + text_len) {
3668c2ecf20Sopenharmony_ci		pr_err("reloc outside program 0x%lx (0 - 0x%lx/0x%lx)",
3678c2ecf20Sopenharmony_ci		       r, start_brk-start_data+text_len, text_len);
3688c2ecf20Sopenharmony_ci		goto failed;
3698c2ecf20Sopenharmony_ci	}
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci	if (r < text_len)			/* In text segment */
3728c2ecf20Sopenharmony_ci		addr = r + start_code;
3738c2ecf20Sopenharmony_ci	else					/* In data segment */
3748c2ecf20Sopenharmony_ci		addr = r - text_len + start_data;
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	/* Range checked already above so doing the range tests is redundant...*/
3778c2ecf20Sopenharmony_ci	return addr;
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_cifailed:
3808c2ecf20Sopenharmony_ci	pr_cont(", killing %s!\n", current->comm);
3818c2ecf20Sopenharmony_ci	send_sig(SIGSEGV, current, 0);
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci	return RELOC_FAILED;
3848c2ecf20Sopenharmony_ci}
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci/****************************************************************************/
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci#ifdef CONFIG_BINFMT_FLAT_OLD
3898c2ecf20Sopenharmony_cistatic void old_reloc(unsigned long rl)
3908c2ecf20Sopenharmony_ci{
3918c2ecf20Sopenharmony_ci	static const char *segment[] = { "TEXT", "DATA", "BSS", "*UNKNOWN*" };
3928c2ecf20Sopenharmony_ci	flat_v2_reloc_t	r;
3938c2ecf20Sopenharmony_ci	unsigned long __user *ptr;
3948c2ecf20Sopenharmony_ci	unsigned long val;
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	r.value = rl;
3978c2ecf20Sopenharmony_ci#if defined(CONFIG_COLDFIRE)
3988c2ecf20Sopenharmony_ci	ptr = (unsigned long __user *)(current->mm->start_code + r.reloc.offset);
3998c2ecf20Sopenharmony_ci#else
4008c2ecf20Sopenharmony_ci	ptr = (unsigned long __user *)(current->mm->start_data + r.reloc.offset);
4018c2ecf20Sopenharmony_ci#endif
4028c2ecf20Sopenharmony_ci	get_user(val, ptr);
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci	pr_debug("Relocation of variable at DATASEG+%x "
4058c2ecf20Sopenharmony_ci		 "(address %p, currently %lx) into segment %s\n",
4068c2ecf20Sopenharmony_ci		 r.reloc.offset, ptr, val, segment[r.reloc.type]);
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci	switch (r.reloc.type) {
4098c2ecf20Sopenharmony_ci	case OLD_FLAT_RELOC_TYPE_TEXT:
4108c2ecf20Sopenharmony_ci		val += current->mm->start_code;
4118c2ecf20Sopenharmony_ci		break;
4128c2ecf20Sopenharmony_ci	case OLD_FLAT_RELOC_TYPE_DATA:
4138c2ecf20Sopenharmony_ci		val += current->mm->start_data;
4148c2ecf20Sopenharmony_ci		break;
4158c2ecf20Sopenharmony_ci	case OLD_FLAT_RELOC_TYPE_BSS:
4168c2ecf20Sopenharmony_ci		val += current->mm->end_data;
4178c2ecf20Sopenharmony_ci		break;
4188c2ecf20Sopenharmony_ci	default:
4198c2ecf20Sopenharmony_ci		pr_err("Unknown relocation type=%x\n", r.reloc.type);
4208c2ecf20Sopenharmony_ci		break;
4218c2ecf20Sopenharmony_ci	}
4228c2ecf20Sopenharmony_ci	put_user(val, ptr);
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	pr_debug("Relocation became %lx\n", val);
4258c2ecf20Sopenharmony_ci}
4268c2ecf20Sopenharmony_ci#endif /* CONFIG_BINFMT_FLAT_OLD */
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci/****************************************************************************/
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_cistatic inline u32 __user *skip_got_header(u32 __user *rp)
4318c2ecf20Sopenharmony_ci{
4328c2ecf20Sopenharmony_ci	if (IS_ENABLED(CONFIG_RISCV)) {
4338c2ecf20Sopenharmony_ci		/*
4348c2ecf20Sopenharmony_ci		 * RISC-V has a 16 byte GOT PLT header for elf64-riscv
4358c2ecf20Sopenharmony_ci		 * and 8 byte GOT PLT header for elf32-riscv.
4368c2ecf20Sopenharmony_ci		 * Skip the whole GOT PLT header, since it is reserved
4378c2ecf20Sopenharmony_ci		 * for the dynamic linker (ld.so).
4388c2ecf20Sopenharmony_ci		 */
4398c2ecf20Sopenharmony_ci		u32 rp_val0, rp_val1;
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci		if (get_user(rp_val0, rp))
4428c2ecf20Sopenharmony_ci			return rp;
4438c2ecf20Sopenharmony_ci		if (get_user(rp_val1, rp + 1))
4448c2ecf20Sopenharmony_ci			return rp;
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci		if (rp_val0 == 0xffffffff && rp_val1 == 0xffffffff)
4478c2ecf20Sopenharmony_ci			rp += 4;
4488c2ecf20Sopenharmony_ci		else if (rp_val0 == 0xffffffff)
4498c2ecf20Sopenharmony_ci			rp += 2;
4508c2ecf20Sopenharmony_ci	}
4518c2ecf20Sopenharmony_ci	return rp;
4528c2ecf20Sopenharmony_ci}
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_cistatic int load_flat_file(struct linux_binprm *bprm,
4558c2ecf20Sopenharmony_ci		struct lib_info *libinfo, int id, unsigned long *extra_stack)
4568c2ecf20Sopenharmony_ci{
4578c2ecf20Sopenharmony_ci	struct flat_hdr *hdr;
4588c2ecf20Sopenharmony_ci	unsigned long textpos, datapos, realdatastart;
4598c2ecf20Sopenharmony_ci	u32 text_len, data_len, bss_len, stack_len, full_data, flags;
4608c2ecf20Sopenharmony_ci	unsigned long len, memp, memp_size, extra, rlim;
4618c2ecf20Sopenharmony_ci	__be32 __user *reloc;
4628c2ecf20Sopenharmony_ci	u32 __user *rp;
4638c2ecf20Sopenharmony_ci	int i, rev, relocs;
4648c2ecf20Sopenharmony_ci	loff_t fpos;
4658c2ecf20Sopenharmony_ci	unsigned long start_code, end_code;
4668c2ecf20Sopenharmony_ci	ssize_t result;
4678c2ecf20Sopenharmony_ci	int ret;
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci	hdr = ((struct flat_hdr *) bprm->buf);		/* exec-header */
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	text_len  = ntohl(hdr->data_start);
4728c2ecf20Sopenharmony_ci	data_len  = ntohl(hdr->data_end) - ntohl(hdr->data_start);
4738c2ecf20Sopenharmony_ci	bss_len   = ntohl(hdr->bss_end) - ntohl(hdr->data_end);
4748c2ecf20Sopenharmony_ci	stack_len = ntohl(hdr->stack_size);
4758c2ecf20Sopenharmony_ci	if (extra_stack) {
4768c2ecf20Sopenharmony_ci		stack_len += *extra_stack;
4778c2ecf20Sopenharmony_ci		*extra_stack = stack_len;
4788c2ecf20Sopenharmony_ci	}
4798c2ecf20Sopenharmony_ci	relocs    = ntohl(hdr->reloc_count);
4808c2ecf20Sopenharmony_ci	flags     = ntohl(hdr->flags);
4818c2ecf20Sopenharmony_ci	rev       = ntohl(hdr->rev);
4828c2ecf20Sopenharmony_ci	full_data = data_len + relocs * sizeof(unsigned long);
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci	if (strncmp(hdr->magic, "bFLT", 4)) {
4858c2ecf20Sopenharmony_ci		/*
4868c2ecf20Sopenharmony_ci		 * Previously, here was a printk to tell people
4878c2ecf20Sopenharmony_ci		 *   "BINFMT_FLAT: bad header magic".
4888c2ecf20Sopenharmony_ci		 * But for the kernel which also use ELF FD-PIC format, this
4898c2ecf20Sopenharmony_ci		 * error message is confusing.
4908c2ecf20Sopenharmony_ci		 * because a lot of people do not manage to produce good
4918c2ecf20Sopenharmony_ci		 */
4928c2ecf20Sopenharmony_ci		ret = -ENOEXEC;
4938c2ecf20Sopenharmony_ci		goto err;
4948c2ecf20Sopenharmony_ci	}
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ci	if (flags & FLAT_FLAG_KTRACE)
4978c2ecf20Sopenharmony_ci		pr_info("Loading file: %s\n", bprm->filename);
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci#ifdef CONFIG_BINFMT_FLAT_OLD
5008c2ecf20Sopenharmony_ci	if (rev != FLAT_VERSION && rev != OLD_FLAT_VERSION) {
5018c2ecf20Sopenharmony_ci		pr_err("bad flat file version 0x%x (supported 0x%lx and 0x%lx)\n",
5028c2ecf20Sopenharmony_ci		       rev, FLAT_VERSION, OLD_FLAT_VERSION);
5038c2ecf20Sopenharmony_ci		ret = -ENOEXEC;
5048c2ecf20Sopenharmony_ci		goto err;
5058c2ecf20Sopenharmony_ci	}
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci	/* Don't allow old format executables to use shared libraries */
5088c2ecf20Sopenharmony_ci	if (rev == OLD_FLAT_VERSION && id != 0) {
5098c2ecf20Sopenharmony_ci		pr_err("shared libraries are not available before rev 0x%lx\n",
5108c2ecf20Sopenharmony_ci		       FLAT_VERSION);
5118c2ecf20Sopenharmony_ci		ret = -ENOEXEC;
5128c2ecf20Sopenharmony_ci		goto err;
5138c2ecf20Sopenharmony_ci	}
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci	/*
5168c2ecf20Sopenharmony_ci	 * fix up the flags for the older format,  there were all kinds
5178c2ecf20Sopenharmony_ci	 * of endian hacks,  this only works for the simple cases
5188c2ecf20Sopenharmony_ci	 */
5198c2ecf20Sopenharmony_ci	if (rev == OLD_FLAT_VERSION &&
5208c2ecf20Sopenharmony_ci	   (flags || IS_ENABLED(CONFIG_BINFMT_FLAT_OLD_ALWAYS_RAM)))
5218c2ecf20Sopenharmony_ci		flags = FLAT_FLAG_RAM;
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci#else /* CONFIG_BINFMT_FLAT_OLD */
5248c2ecf20Sopenharmony_ci	if (rev != FLAT_VERSION) {
5258c2ecf20Sopenharmony_ci		pr_err("bad flat file version 0x%x (supported 0x%lx)\n",
5268c2ecf20Sopenharmony_ci		       rev, FLAT_VERSION);
5278c2ecf20Sopenharmony_ci		ret = -ENOEXEC;
5288c2ecf20Sopenharmony_ci		goto err;
5298c2ecf20Sopenharmony_ci	}
5308c2ecf20Sopenharmony_ci#endif /* !CONFIG_BINFMT_FLAT_OLD */
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ci	/*
5338c2ecf20Sopenharmony_ci	 * Make sure the header params are sane.
5348c2ecf20Sopenharmony_ci	 * 28 bits (256 MB) is way more than reasonable in this case.
5358c2ecf20Sopenharmony_ci	 * If some top bits are set we have probable binary corruption.
5368c2ecf20Sopenharmony_ci	*/
5378c2ecf20Sopenharmony_ci	if ((text_len | data_len | bss_len | stack_len | full_data) >> 28) {
5388c2ecf20Sopenharmony_ci		pr_err("bad header\n");
5398c2ecf20Sopenharmony_ci		ret = -ENOEXEC;
5408c2ecf20Sopenharmony_ci		goto err;
5418c2ecf20Sopenharmony_ci	}
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci#ifndef CONFIG_BINFMT_ZFLAT
5448c2ecf20Sopenharmony_ci	if (flags & (FLAT_FLAG_GZIP|FLAT_FLAG_GZDATA)) {
5458c2ecf20Sopenharmony_ci		pr_err("Support for ZFLAT executables is not enabled.\n");
5468c2ecf20Sopenharmony_ci		ret = -ENOEXEC;
5478c2ecf20Sopenharmony_ci		goto err;
5488c2ecf20Sopenharmony_ci	}
5498c2ecf20Sopenharmony_ci#endif
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_ci	/*
5528c2ecf20Sopenharmony_ci	 * Check initial limits. This avoids letting people circumvent
5538c2ecf20Sopenharmony_ci	 * size limits imposed on them by creating programs with large
5548c2ecf20Sopenharmony_ci	 * arrays in the data or bss.
5558c2ecf20Sopenharmony_ci	 */
5568c2ecf20Sopenharmony_ci	rlim = rlimit(RLIMIT_DATA);
5578c2ecf20Sopenharmony_ci	if (rlim >= RLIM_INFINITY)
5588c2ecf20Sopenharmony_ci		rlim = ~0;
5598c2ecf20Sopenharmony_ci	if (data_len + bss_len > rlim) {
5608c2ecf20Sopenharmony_ci		ret = -ENOMEM;
5618c2ecf20Sopenharmony_ci		goto err;
5628c2ecf20Sopenharmony_ci	}
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci	/* Flush all traces of the currently running executable */
5658c2ecf20Sopenharmony_ci	if (id == 0) {
5668c2ecf20Sopenharmony_ci		ret = begin_new_exec(bprm);
5678c2ecf20Sopenharmony_ci		if (ret)
5688c2ecf20Sopenharmony_ci			goto err;
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci		/* OK, This is the point of no return */
5718c2ecf20Sopenharmony_ci		set_personality(PER_LINUX_32BIT);
5728c2ecf20Sopenharmony_ci		setup_new_exec(bprm);
5738c2ecf20Sopenharmony_ci	}
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_ci	/*
5768c2ecf20Sopenharmony_ci	 * calculate the extra space we need to map in
5778c2ecf20Sopenharmony_ci	 */
5788c2ecf20Sopenharmony_ci	extra = max_t(unsigned long, bss_len + stack_len,
5798c2ecf20Sopenharmony_ci			relocs * sizeof(unsigned long));
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci	/*
5828c2ecf20Sopenharmony_ci	 * there are a couple of cases here,  the separate code/data
5838c2ecf20Sopenharmony_ci	 * case,  and then the fully copied to RAM case which lumps
5848c2ecf20Sopenharmony_ci	 * it all together.
5858c2ecf20Sopenharmony_ci	 */
5868c2ecf20Sopenharmony_ci	if (!IS_ENABLED(CONFIG_MMU) && !(flags & (FLAT_FLAG_RAM|FLAT_FLAG_GZIP))) {
5878c2ecf20Sopenharmony_ci		/*
5888c2ecf20Sopenharmony_ci		 * this should give us a ROM ptr,  but if it doesn't we don't
5898c2ecf20Sopenharmony_ci		 * really care
5908c2ecf20Sopenharmony_ci		 */
5918c2ecf20Sopenharmony_ci		pr_debug("ROM mapping of file (we hope)\n");
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_ci		textpos = vm_mmap(bprm->file, 0, text_len, PROT_READ|PROT_EXEC,
5948c2ecf20Sopenharmony_ci				  MAP_PRIVATE|MAP_EXECUTABLE, 0);
5958c2ecf20Sopenharmony_ci		if (!textpos || IS_ERR_VALUE(textpos)) {
5968c2ecf20Sopenharmony_ci			ret = textpos;
5978c2ecf20Sopenharmony_ci			if (!textpos)
5988c2ecf20Sopenharmony_ci				ret = -ENOMEM;
5998c2ecf20Sopenharmony_ci			pr_err("Unable to mmap process text, errno %d\n", ret);
6008c2ecf20Sopenharmony_ci			goto err;
6018c2ecf20Sopenharmony_ci		}
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_ci		len = data_len + extra + MAX_SHARED_LIBS * sizeof(unsigned long);
6048c2ecf20Sopenharmony_ci		len = PAGE_ALIGN(len);
6058c2ecf20Sopenharmony_ci		realdatastart = vm_mmap(NULL, 0, len,
6068c2ecf20Sopenharmony_ci			PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE, 0);
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_ci		if (realdatastart == 0 || IS_ERR_VALUE(realdatastart)) {
6098c2ecf20Sopenharmony_ci			ret = realdatastart;
6108c2ecf20Sopenharmony_ci			if (!realdatastart)
6118c2ecf20Sopenharmony_ci				ret = -ENOMEM;
6128c2ecf20Sopenharmony_ci			pr_err("Unable to allocate RAM for process data, "
6138c2ecf20Sopenharmony_ci			       "errno %d\n", ret);
6148c2ecf20Sopenharmony_ci			vm_munmap(textpos, text_len);
6158c2ecf20Sopenharmony_ci			goto err;
6168c2ecf20Sopenharmony_ci		}
6178c2ecf20Sopenharmony_ci		datapos = ALIGN(realdatastart +
6188c2ecf20Sopenharmony_ci				MAX_SHARED_LIBS * sizeof(unsigned long),
6198c2ecf20Sopenharmony_ci				FLAT_DATA_ALIGN);
6208c2ecf20Sopenharmony_ci
6218c2ecf20Sopenharmony_ci		pr_debug("Allocated data+bss+stack (%u bytes): %lx\n",
6228c2ecf20Sopenharmony_ci			 data_len + bss_len + stack_len, datapos);
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_ci		fpos = ntohl(hdr->data_start);
6258c2ecf20Sopenharmony_ci#ifdef CONFIG_BINFMT_ZFLAT
6268c2ecf20Sopenharmony_ci		if (flags & FLAT_FLAG_GZDATA) {
6278c2ecf20Sopenharmony_ci			result = decompress_exec(bprm, fpos, (char *)datapos,
6288c2ecf20Sopenharmony_ci						 full_data, 0);
6298c2ecf20Sopenharmony_ci		} else
6308c2ecf20Sopenharmony_ci#endif
6318c2ecf20Sopenharmony_ci		{
6328c2ecf20Sopenharmony_ci			result = read_code(bprm->file, datapos, fpos,
6338c2ecf20Sopenharmony_ci					full_data);
6348c2ecf20Sopenharmony_ci		}
6358c2ecf20Sopenharmony_ci		if (IS_ERR_VALUE(result)) {
6368c2ecf20Sopenharmony_ci			ret = result;
6378c2ecf20Sopenharmony_ci			pr_err("Unable to read data+bss, errno %d\n", ret);
6388c2ecf20Sopenharmony_ci			vm_munmap(textpos, text_len);
6398c2ecf20Sopenharmony_ci			vm_munmap(realdatastart, len);
6408c2ecf20Sopenharmony_ci			goto err;
6418c2ecf20Sopenharmony_ci		}
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ci		reloc = (__be32 __user *)
6448c2ecf20Sopenharmony_ci			(datapos + (ntohl(hdr->reloc_start) - text_len));
6458c2ecf20Sopenharmony_ci		memp = realdatastart;
6468c2ecf20Sopenharmony_ci		memp_size = len;
6478c2ecf20Sopenharmony_ci	} else {
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_ci		len = text_len + data_len + extra + MAX_SHARED_LIBS * sizeof(u32);
6508c2ecf20Sopenharmony_ci		len = PAGE_ALIGN(len);
6518c2ecf20Sopenharmony_ci		textpos = vm_mmap(NULL, 0, len,
6528c2ecf20Sopenharmony_ci			PROT_READ | PROT_EXEC | PROT_WRITE, MAP_PRIVATE, 0);
6538c2ecf20Sopenharmony_ci
6548c2ecf20Sopenharmony_ci		if (!textpos || IS_ERR_VALUE(textpos)) {
6558c2ecf20Sopenharmony_ci			ret = textpos;
6568c2ecf20Sopenharmony_ci			if (!textpos)
6578c2ecf20Sopenharmony_ci				ret = -ENOMEM;
6588c2ecf20Sopenharmony_ci			pr_err("Unable to allocate RAM for process text/data, "
6598c2ecf20Sopenharmony_ci			       "errno %d\n", ret);
6608c2ecf20Sopenharmony_ci			goto err;
6618c2ecf20Sopenharmony_ci		}
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci		realdatastart = textpos + ntohl(hdr->data_start);
6648c2ecf20Sopenharmony_ci		datapos = ALIGN(realdatastart +
6658c2ecf20Sopenharmony_ci				MAX_SHARED_LIBS * sizeof(u32),
6668c2ecf20Sopenharmony_ci				FLAT_DATA_ALIGN);
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_ci		reloc = (__be32 __user *)
6698c2ecf20Sopenharmony_ci			(datapos + (ntohl(hdr->reloc_start) - text_len));
6708c2ecf20Sopenharmony_ci		memp = textpos;
6718c2ecf20Sopenharmony_ci		memp_size = len;
6728c2ecf20Sopenharmony_ci#ifdef CONFIG_BINFMT_ZFLAT
6738c2ecf20Sopenharmony_ci		/*
6748c2ecf20Sopenharmony_ci		 * load it all in and treat it like a RAM load from now on
6758c2ecf20Sopenharmony_ci		 */
6768c2ecf20Sopenharmony_ci		if (flags & FLAT_FLAG_GZIP) {
6778c2ecf20Sopenharmony_ci#ifndef CONFIG_MMU
6788c2ecf20Sopenharmony_ci			result = decompress_exec(bprm, sizeof(struct flat_hdr),
6798c2ecf20Sopenharmony_ci					 (((char *)textpos) + sizeof(struct flat_hdr)),
6808c2ecf20Sopenharmony_ci					 (text_len + full_data
6818c2ecf20Sopenharmony_ci						  - sizeof(struct flat_hdr)),
6828c2ecf20Sopenharmony_ci					 0);
6838c2ecf20Sopenharmony_ci			memmove((void *) datapos, (void *) realdatastart,
6848c2ecf20Sopenharmony_ci					full_data);
6858c2ecf20Sopenharmony_ci#else
6868c2ecf20Sopenharmony_ci			/*
6878c2ecf20Sopenharmony_ci			 * This is used on MMU systems mainly for testing.
6888c2ecf20Sopenharmony_ci			 * Let's use a kernel buffer to simplify things.
6898c2ecf20Sopenharmony_ci			 */
6908c2ecf20Sopenharmony_ci			long unz_text_len = text_len - sizeof(struct flat_hdr);
6918c2ecf20Sopenharmony_ci			long unz_len = unz_text_len + full_data;
6928c2ecf20Sopenharmony_ci			char *unz_data = vmalloc(unz_len);
6938c2ecf20Sopenharmony_ci			if (!unz_data) {
6948c2ecf20Sopenharmony_ci				result = -ENOMEM;
6958c2ecf20Sopenharmony_ci			} else {
6968c2ecf20Sopenharmony_ci				result = decompress_exec(bprm, sizeof(struct flat_hdr),
6978c2ecf20Sopenharmony_ci							 unz_data, unz_len, 0);
6988c2ecf20Sopenharmony_ci				if (result == 0 &&
6998c2ecf20Sopenharmony_ci				    (copy_to_user((void __user *)textpos + sizeof(struct flat_hdr),
7008c2ecf20Sopenharmony_ci						  unz_data, unz_text_len) ||
7018c2ecf20Sopenharmony_ci				     copy_to_user((void __user *)datapos,
7028c2ecf20Sopenharmony_ci						  unz_data + unz_text_len, full_data)))
7038c2ecf20Sopenharmony_ci					result = -EFAULT;
7048c2ecf20Sopenharmony_ci				vfree(unz_data);
7058c2ecf20Sopenharmony_ci			}
7068c2ecf20Sopenharmony_ci#endif
7078c2ecf20Sopenharmony_ci		} else if (flags & FLAT_FLAG_GZDATA) {
7088c2ecf20Sopenharmony_ci			result = read_code(bprm->file, textpos, 0, text_len);
7098c2ecf20Sopenharmony_ci			if (!IS_ERR_VALUE(result)) {
7108c2ecf20Sopenharmony_ci#ifndef CONFIG_MMU
7118c2ecf20Sopenharmony_ci				result = decompress_exec(bprm, text_len, (char *) datapos,
7128c2ecf20Sopenharmony_ci						 full_data, 0);
7138c2ecf20Sopenharmony_ci#else
7148c2ecf20Sopenharmony_ci				char *unz_data = vmalloc(full_data);
7158c2ecf20Sopenharmony_ci				if (!unz_data) {
7168c2ecf20Sopenharmony_ci					result = -ENOMEM;
7178c2ecf20Sopenharmony_ci				} else {
7188c2ecf20Sopenharmony_ci					result = decompress_exec(bprm, text_len,
7198c2ecf20Sopenharmony_ci						       unz_data, full_data, 0);
7208c2ecf20Sopenharmony_ci					if (result == 0 &&
7218c2ecf20Sopenharmony_ci					    copy_to_user((void __user *)datapos,
7228c2ecf20Sopenharmony_ci							 unz_data, full_data))
7238c2ecf20Sopenharmony_ci						result = -EFAULT;
7248c2ecf20Sopenharmony_ci					vfree(unz_data);
7258c2ecf20Sopenharmony_ci				}
7268c2ecf20Sopenharmony_ci#endif
7278c2ecf20Sopenharmony_ci			}
7288c2ecf20Sopenharmony_ci		} else
7298c2ecf20Sopenharmony_ci#endif /* CONFIG_BINFMT_ZFLAT */
7308c2ecf20Sopenharmony_ci		{
7318c2ecf20Sopenharmony_ci			result = read_code(bprm->file, textpos, 0, text_len);
7328c2ecf20Sopenharmony_ci			if (!IS_ERR_VALUE(result))
7338c2ecf20Sopenharmony_ci				result = read_code(bprm->file, datapos,
7348c2ecf20Sopenharmony_ci						   ntohl(hdr->data_start),
7358c2ecf20Sopenharmony_ci						   full_data);
7368c2ecf20Sopenharmony_ci		}
7378c2ecf20Sopenharmony_ci		if (IS_ERR_VALUE(result)) {
7388c2ecf20Sopenharmony_ci			ret = result;
7398c2ecf20Sopenharmony_ci			pr_err("Unable to read code+data+bss, errno %d\n", ret);
7408c2ecf20Sopenharmony_ci			vm_munmap(textpos, text_len + data_len + extra +
7418c2ecf20Sopenharmony_ci				MAX_SHARED_LIBS * sizeof(u32));
7428c2ecf20Sopenharmony_ci			goto err;
7438c2ecf20Sopenharmony_ci		}
7448c2ecf20Sopenharmony_ci	}
7458c2ecf20Sopenharmony_ci
7468c2ecf20Sopenharmony_ci	start_code = textpos + sizeof(struct flat_hdr);
7478c2ecf20Sopenharmony_ci	end_code = textpos + text_len;
7488c2ecf20Sopenharmony_ci	text_len -= sizeof(struct flat_hdr); /* the real code len */
7498c2ecf20Sopenharmony_ci
7508c2ecf20Sopenharmony_ci	/* The main program needs a little extra setup in the task structure */
7518c2ecf20Sopenharmony_ci	if (id == 0) {
7528c2ecf20Sopenharmony_ci		current->mm->start_code = start_code;
7538c2ecf20Sopenharmony_ci		current->mm->end_code = end_code;
7548c2ecf20Sopenharmony_ci		current->mm->start_data = datapos;
7558c2ecf20Sopenharmony_ci		current->mm->end_data = datapos + data_len;
7568c2ecf20Sopenharmony_ci		/*
7578c2ecf20Sopenharmony_ci		 * set up the brk stuff, uses any slack left in data/bss/stack
7588c2ecf20Sopenharmony_ci		 * allocation.  We put the brk after the bss (between the bss
7598c2ecf20Sopenharmony_ci		 * and stack) like other platforms.
7608c2ecf20Sopenharmony_ci		 * Userspace code relies on the stack pointer starting out at
7618c2ecf20Sopenharmony_ci		 * an address right at the end of a page.
7628c2ecf20Sopenharmony_ci		 */
7638c2ecf20Sopenharmony_ci		current->mm->start_brk = datapos + data_len + bss_len;
7648c2ecf20Sopenharmony_ci		current->mm->brk = (current->mm->start_brk + 3) & ~3;
7658c2ecf20Sopenharmony_ci#ifndef CONFIG_MMU
7668c2ecf20Sopenharmony_ci		current->mm->context.end_brk = memp + memp_size - stack_len;
7678c2ecf20Sopenharmony_ci#endif
7688c2ecf20Sopenharmony_ci	}
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_ci	if (flags & FLAT_FLAG_KTRACE) {
7718c2ecf20Sopenharmony_ci		pr_info("Mapping is %lx, Entry point is %x, data_start is %x\n",
7728c2ecf20Sopenharmony_ci			textpos, 0x00ffffff&ntohl(hdr->entry), ntohl(hdr->data_start));
7738c2ecf20Sopenharmony_ci		pr_info("%s %s: TEXT=%lx-%lx DATA=%lx-%lx BSS=%lx-%lx\n",
7748c2ecf20Sopenharmony_ci			id ? "Lib" : "Load", bprm->filename,
7758c2ecf20Sopenharmony_ci			start_code, end_code, datapos, datapos + data_len,
7768c2ecf20Sopenharmony_ci			datapos + data_len, (datapos + data_len + bss_len + 3) & ~3);
7778c2ecf20Sopenharmony_ci	}
7788c2ecf20Sopenharmony_ci
7798c2ecf20Sopenharmony_ci	/* Store the current module values into the global library structure */
7808c2ecf20Sopenharmony_ci	libinfo->lib_list[id].start_code = start_code;
7818c2ecf20Sopenharmony_ci	libinfo->lib_list[id].start_data = datapos;
7828c2ecf20Sopenharmony_ci	libinfo->lib_list[id].start_brk = datapos + data_len + bss_len;
7838c2ecf20Sopenharmony_ci	libinfo->lib_list[id].text_len = text_len;
7848c2ecf20Sopenharmony_ci	libinfo->lib_list[id].loaded = 1;
7858c2ecf20Sopenharmony_ci	libinfo->lib_list[id].entry = (0x00ffffff & ntohl(hdr->entry)) + textpos;
7868c2ecf20Sopenharmony_ci	libinfo->lib_list[id].build_date = ntohl(hdr->build_date);
7878c2ecf20Sopenharmony_ci
7888c2ecf20Sopenharmony_ci	/*
7898c2ecf20Sopenharmony_ci	 * We just load the allocations into some temporary memory to
7908c2ecf20Sopenharmony_ci	 * help simplify all this mumbo jumbo
7918c2ecf20Sopenharmony_ci	 *
7928c2ecf20Sopenharmony_ci	 * We've got two different sections of relocation entries.
7938c2ecf20Sopenharmony_ci	 * The first is the GOT which resides at the beginning of the data segment
7948c2ecf20Sopenharmony_ci	 * and is terminated with a -1.  This one can be relocated in place.
7958c2ecf20Sopenharmony_ci	 * The second is the extra relocation entries tacked after the image's
7968c2ecf20Sopenharmony_ci	 * data segment. These require a little more processing as the entry is
7978c2ecf20Sopenharmony_ci	 * really an offset into the image which contains an offset into the
7988c2ecf20Sopenharmony_ci	 * image.
7998c2ecf20Sopenharmony_ci	 */
8008c2ecf20Sopenharmony_ci	if (flags & FLAT_FLAG_GOTPIC) {
8018c2ecf20Sopenharmony_ci		rp = skip_got_header((u32 __user *) datapos);
8028c2ecf20Sopenharmony_ci		for (; ; rp++) {
8038c2ecf20Sopenharmony_ci			u32 addr, rp_val;
8048c2ecf20Sopenharmony_ci			if (get_user(rp_val, rp))
8058c2ecf20Sopenharmony_ci				return -EFAULT;
8068c2ecf20Sopenharmony_ci			if (rp_val == 0xffffffff)
8078c2ecf20Sopenharmony_ci				break;
8088c2ecf20Sopenharmony_ci			if (rp_val) {
8098c2ecf20Sopenharmony_ci				addr = calc_reloc(rp_val, libinfo, id, 0);
8108c2ecf20Sopenharmony_ci				if (addr == RELOC_FAILED) {
8118c2ecf20Sopenharmony_ci					ret = -ENOEXEC;
8128c2ecf20Sopenharmony_ci					goto err;
8138c2ecf20Sopenharmony_ci				}
8148c2ecf20Sopenharmony_ci				if (put_user(addr, rp))
8158c2ecf20Sopenharmony_ci					return -EFAULT;
8168c2ecf20Sopenharmony_ci			}
8178c2ecf20Sopenharmony_ci		}
8188c2ecf20Sopenharmony_ci	}
8198c2ecf20Sopenharmony_ci
8208c2ecf20Sopenharmony_ci	/*
8218c2ecf20Sopenharmony_ci	 * Now run through the relocation entries.
8228c2ecf20Sopenharmony_ci	 * We've got to be careful here as C++ produces relocatable zero
8238c2ecf20Sopenharmony_ci	 * entries in the constructor and destructor tables which are then
8248c2ecf20Sopenharmony_ci	 * tested for being not zero (which will always occur unless we're
8258c2ecf20Sopenharmony_ci	 * based from address zero).  This causes an endless loop as __start
8268c2ecf20Sopenharmony_ci	 * is at zero.  The solution used is to not relocate zero addresses.
8278c2ecf20Sopenharmony_ci	 * This has the negative side effect of not allowing a global data
8288c2ecf20Sopenharmony_ci	 * reference to be statically initialised to _stext (I've moved
8298c2ecf20Sopenharmony_ci	 * __start to address 4 so that is okay).
8308c2ecf20Sopenharmony_ci	 */
8318c2ecf20Sopenharmony_ci	if (rev > OLD_FLAT_VERSION) {
8328c2ecf20Sopenharmony_ci		for (i = 0; i < relocs; i++) {
8338c2ecf20Sopenharmony_ci			u32 addr, relval;
8348c2ecf20Sopenharmony_ci			__be32 tmp;
8358c2ecf20Sopenharmony_ci
8368c2ecf20Sopenharmony_ci			/*
8378c2ecf20Sopenharmony_ci			 * Get the address of the pointer to be
8388c2ecf20Sopenharmony_ci			 * relocated (of course, the address has to be
8398c2ecf20Sopenharmony_ci			 * relocated first).
8408c2ecf20Sopenharmony_ci			 */
8418c2ecf20Sopenharmony_ci			if (get_user(tmp, reloc + i))
8428c2ecf20Sopenharmony_ci				return -EFAULT;
8438c2ecf20Sopenharmony_ci			relval = ntohl(tmp);
8448c2ecf20Sopenharmony_ci			addr = flat_get_relocate_addr(relval);
8458c2ecf20Sopenharmony_ci			rp = (u32 __user *)calc_reloc(addr, libinfo, id, 1);
8468c2ecf20Sopenharmony_ci			if (rp == (u32 __user *)RELOC_FAILED) {
8478c2ecf20Sopenharmony_ci				ret = -ENOEXEC;
8488c2ecf20Sopenharmony_ci				goto err;
8498c2ecf20Sopenharmony_ci			}
8508c2ecf20Sopenharmony_ci
8518c2ecf20Sopenharmony_ci			/* Get the pointer's value.  */
8528c2ecf20Sopenharmony_ci			ret = flat_get_addr_from_rp(rp, relval, flags, &addr);
8538c2ecf20Sopenharmony_ci			if (unlikely(ret))
8548c2ecf20Sopenharmony_ci				goto err;
8558c2ecf20Sopenharmony_ci
8568c2ecf20Sopenharmony_ci			if (addr != 0) {
8578c2ecf20Sopenharmony_ci				/*
8588c2ecf20Sopenharmony_ci				 * Do the relocation.  PIC relocs in the data section are
8598c2ecf20Sopenharmony_ci				 * already in target order
8608c2ecf20Sopenharmony_ci				 */
8618c2ecf20Sopenharmony_ci				if ((flags & FLAT_FLAG_GOTPIC) == 0) {
8628c2ecf20Sopenharmony_ci					/*
8638c2ecf20Sopenharmony_ci					 * Meh, the same value can have a different
8648c2ecf20Sopenharmony_ci					 * byte order based on a flag..
8658c2ecf20Sopenharmony_ci					 */
8668c2ecf20Sopenharmony_ci					addr = ntohl((__force __be32)addr);
8678c2ecf20Sopenharmony_ci				}
8688c2ecf20Sopenharmony_ci				addr = calc_reloc(addr, libinfo, id, 0);
8698c2ecf20Sopenharmony_ci				if (addr == RELOC_FAILED) {
8708c2ecf20Sopenharmony_ci					ret = -ENOEXEC;
8718c2ecf20Sopenharmony_ci					goto err;
8728c2ecf20Sopenharmony_ci				}
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_ci				/* Write back the relocated pointer.  */
8758c2ecf20Sopenharmony_ci				ret = flat_put_addr_at_rp(rp, addr, relval);
8768c2ecf20Sopenharmony_ci				if (unlikely(ret))
8778c2ecf20Sopenharmony_ci					goto err;
8788c2ecf20Sopenharmony_ci			}
8798c2ecf20Sopenharmony_ci		}
8808c2ecf20Sopenharmony_ci#ifdef CONFIG_BINFMT_FLAT_OLD
8818c2ecf20Sopenharmony_ci	} else {
8828c2ecf20Sopenharmony_ci		for (i = 0; i < relocs; i++) {
8838c2ecf20Sopenharmony_ci			__be32 relval;
8848c2ecf20Sopenharmony_ci			if (get_user(relval, reloc + i))
8858c2ecf20Sopenharmony_ci				return -EFAULT;
8868c2ecf20Sopenharmony_ci			old_reloc(ntohl(relval));
8878c2ecf20Sopenharmony_ci		}
8888c2ecf20Sopenharmony_ci#endif /* CONFIG_BINFMT_FLAT_OLD */
8898c2ecf20Sopenharmony_ci	}
8908c2ecf20Sopenharmony_ci
8918c2ecf20Sopenharmony_ci	flush_icache_user_range(start_code, end_code);
8928c2ecf20Sopenharmony_ci
8938c2ecf20Sopenharmony_ci	/* zero the BSS,  BRK and stack areas */
8948c2ecf20Sopenharmony_ci	if (clear_user((void __user *)(datapos + data_len), bss_len +
8958c2ecf20Sopenharmony_ci		       (memp + memp_size - stack_len -		/* end brk */
8968c2ecf20Sopenharmony_ci		       libinfo->lib_list[id].start_brk) +	/* start brk */
8978c2ecf20Sopenharmony_ci		       stack_len))
8988c2ecf20Sopenharmony_ci		return -EFAULT;
8998c2ecf20Sopenharmony_ci
9008c2ecf20Sopenharmony_ci	return 0;
9018c2ecf20Sopenharmony_cierr:
9028c2ecf20Sopenharmony_ci	return ret;
9038c2ecf20Sopenharmony_ci}
9048c2ecf20Sopenharmony_ci
9058c2ecf20Sopenharmony_ci
9068c2ecf20Sopenharmony_ci/****************************************************************************/
9078c2ecf20Sopenharmony_ci#ifdef CONFIG_BINFMT_SHARED_FLAT
9088c2ecf20Sopenharmony_ci
9098c2ecf20Sopenharmony_ci/*
9108c2ecf20Sopenharmony_ci * Load a shared library into memory.  The library gets its own data
9118c2ecf20Sopenharmony_ci * segment (including bss) but not argv/argc/environ.
9128c2ecf20Sopenharmony_ci */
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_cistatic int load_flat_shared_library(int id, struct lib_info *libs)
9158c2ecf20Sopenharmony_ci{
9168c2ecf20Sopenharmony_ci	/*
9178c2ecf20Sopenharmony_ci	 * This is a fake bprm struct; only the members "buf", "file" and
9188c2ecf20Sopenharmony_ci	 * "filename" are actually used.
9198c2ecf20Sopenharmony_ci	 */
9208c2ecf20Sopenharmony_ci	struct linux_binprm bprm;
9218c2ecf20Sopenharmony_ci	int res;
9228c2ecf20Sopenharmony_ci	char buf[16];
9238c2ecf20Sopenharmony_ci	loff_t pos = 0;
9248c2ecf20Sopenharmony_ci
9258c2ecf20Sopenharmony_ci	memset(&bprm, 0, sizeof(bprm));
9268c2ecf20Sopenharmony_ci
9278c2ecf20Sopenharmony_ci	/* Create the file name */
9288c2ecf20Sopenharmony_ci	sprintf(buf, "/lib/lib%d.so", id);
9298c2ecf20Sopenharmony_ci
9308c2ecf20Sopenharmony_ci	/* Open the file up */
9318c2ecf20Sopenharmony_ci	bprm.filename = buf;
9328c2ecf20Sopenharmony_ci	bprm.file = open_exec(bprm.filename);
9338c2ecf20Sopenharmony_ci	res = PTR_ERR(bprm.file);
9348c2ecf20Sopenharmony_ci	if (IS_ERR(bprm.file))
9358c2ecf20Sopenharmony_ci		return res;
9368c2ecf20Sopenharmony_ci
9378c2ecf20Sopenharmony_ci	res = kernel_read(bprm.file, bprm.buf, BINPRM_BUF_SIZE, &pos);
9388c2ecf20Sopenharmony_ci
9398c2ecf20Sopenharmony_ci	if (res >= 0)
9408c2ecf20Sopenharmony_ci		res = load_flat_file(&bprm, libs, id, NULL);
9418c2ecf20Sopenharmony_ci
9428c2ecf20Sopenharmony_ci	allow_write_access(bprm.file);
9438c2ecf20Sopenharmony_ci	fput(bprm.file);
9448c2ecf20Sopenharmony_ci
9458c2ecf20Sopenharmony_ci	return res;
9468c2ecf20Sopenharmony_ci}
9478c2ecf20Sopenharmony_ci
9488c2ecf20Sopenharmony_ci#endif /* CONFIG_BINFMT_SHARED_FLAT */
9498c2ecf20Sopenharmony_ci/****************************************************************************/
9508c2ecf20Sopenharmony_ci
9518c2ecf20Sopenharmony_ci/*
9528c2ecf20Sopenharmony_ci * These are the functions used to load flat style executables and shared
9538c2ecf20Sopenharmony_ci * libraries.  There is no binary dependent code anywhere else.
9548c2ecf20Sopenharmony_ci */
9558c2ecf20Sopenharmony_ci
9568c2ecf20Sopenharmony_cistatic int load_flat_binary(struct linux_binprm *bprm)
9578c2ecf20Sopenharmony_ci{
9588c2ecf20Sopenharmony_ci	struct lib_info libinfo;
9598c2ecf20Sopenharmony_ci	struct pt_regs *regs = current_pt_regs();
9608c2ecf20Sopenharmony_ci	unsigned long stack_len = 0;
9618c2ecf20Sopenharmony_ci	unsigned long start_addr;
9628c2ecf20Sopenharmony_ci	int res;
9638c2ecf20Sopenharmony_ci	int i, j;
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_ci	memset(&libinfo, 0, sizeof(libinfo));
9668c2ecf20Sopenharmony_ci
9678c2ecf20Sopenharmony_ci	/*
9688c2ecf20Sopenharmony_ci	 * We have to add the size of our arguments to our stack size
9698c2ecf20Sopenharmony_ci	 * otherwise it's too easy for users to create stack overflows
9708c2ecf20Sopenharmony_ci	 * by passing in a huge argument list.  And yes,  we have to be
9718c2ecf20Sopenharmony_ci	 * pedantic and include space for the argv/envp array as it may have
9728c2ecf20Sopenharmony_ci	 * a lot of entries.
9738c2ecf20Sopenharmony_ci	 */
9748c2ecf20Sopenharmony_ci#ifndef CONFIG_MMU
9758c2ecf20Sopenharmony_ci	stack_len += PAGE_SIZE * MAX_ARG_PAGES - bprm->p; /* the strings */
9768c2ecf20Sopenharmony_ci#endif
9778c2ecf20Sopenharmony_ci	stack_len += (bprm->argc + 1) * sizeof(char *);   /* the argv array */
9788c2ecf20Sopenharmony_ci	stack_len += (bprm->envc + 1) * sizeof(char *);   /* the envp array */
9798c2ecf20Sopenharmony_ci	stack_len = ALIGN(stack_len, FLAT_STACK_ALIGN);
9808c2ecf20Sopenharmony_ci
9818c2ecf20Sopenharmony_ci	res = load_flat_file(bprm, &libinfo, 0, &stack_len);
9828c2ecf20Sopenharmony_ci	if (res < 0)
9838c2ecf20Sopenharmony_ci		return res;
9848c2ecf20Sopenharmony_ci
9858c2ecf20Sopenharmony_ci	/* Update data segment pointers for all libraries */
9868c2ecf20Sopenharmony_ci	for (i = 0; i < MAX_SHARED_LIBS; i++) {
9878c2ecf20Sopenharmony_ci		if (!libinfo.lib_list[i].loaded)
9888c2ecf20Sopenharmony_ci			continue;
9898c2ecf20Sopenharmony_ci		for (j = 0; j < MAX_SHARED_LIBS; j++) {
9908c2ecf20Sopenharmony_ci			unsigned long val = libinfo.lib_list[j].loaded ?
9918c2ecf20Sopenharmony_ci				libinfo.lib_list[j].start_data : UNLOADED_LIB;
9928c2ecf20Sopenharmony_ci			unsigned long __user *p = (unsigned long __user *)
9938c2ecf20Sopenharmony_ci				libinfo.lib_list[i].start_data;
9948c2ecf20Sopenharmony_ci			p -= j + 1;
9958c2ecf20Sopenharmony_ci			if (put_user(val, p))
9968c2ecf20Sopenharmony_ci				return -EFAULT;
9978c2ecf20Sopenharmony_ci		}
9988c2ecf20Sopenharmony_ci	}
9998c2ecf20Sopenharmony_ci
10008c2ecf20Sopenharmony_ci	set_binfmt(&flat_format);
10018c2ecf20Sopenharmony_ci
10028c2ecf20Sopenharmony_ci#ifdef CONFIG_MMU
10038c2ecf20Sopenharmony_ci	res = setup_arg_pages(bprm, STACK_TOP, EXSTACK_DEFAULT);
10048c2ecf20Sopenharmony_ci	if (!res)
10058c2ecf20Sopenharmony_ci		res = create_flat_tables(bprm, bprm->p);
10068c2ecf20Sopenharmony_ci#else
10078c2ecf20Sopenharmony_ci	/* Stash our initial stack pointer into the mm structure */
10088c2ecf20Sopenharmony_ci	current->mm->start_stack =
10098c2ecf20Sopenharmony_ci		((current->mm->context.end_brk + stack_len + 3) & ~3) - 4;
10108c2ecf20Sopenharmony_ci	pr_debug("sp=%lx\n", current->mm->start_stack);
10118c2ecf20Sopenharmony_ci
10128c2ecf20Sopenharmony_ci	/* copy the arg pages onto the stack */
10138c2ecf20Sopenharmony_ci	res = transfer_args_to_stack(bprm, &current->mm->start_stack);
10148c2ecf20Sopenharmony_ci	if (!res)
10158c2ecf20Sopenharmony_ci		res = create_flat_tables(bprm, current->mm->start_stack);
10168c2ecf20Sopenharmony_ci#endif
10178c2ecf20Sopenharmony_ci	if (res)
10188c2ecf20Sopenharmony_ci		return res;
10198c2ecf20Sopenharmony_ci
10208c2ecf20Sopenharmony_ci	/* Fake some return addresses to ensure the call chain will
10218c2ecf20Sopenharmony_ci	 * initialise library in order for us.  We are required to call
10228c2ecf20Sopenharmony_ci	 * lib 1 first, then 2, ... and finally the main program (id 0).
10238c2ecf20Sopenharmony_ci	 */
10248c2ecf20Sopenharmony_ci	start_addr = libinfo.lib_list[0].entry;
10258c2ecf20Sopenharmony_ci
10268c2ecf20Sopenharmony_ci#ifdef CONFIG_BINFMT_SHARED_FLAT
10278c2ecf20Sopenharmony_ci	for (i = MAX_SHARED_LIBS-1; i > 0; i--) {
10288c2ecf20Sopenharmony_ci		if (libinfo.lib_list[i].loaded) {
10298c2ecf20Sopenharmony_ci			/* Push previos first to call address */
10308c2ecf20Sopenharmony_ci			unsigned long __user *sp;
10318c2ecf20Sopenharmony_ci			current->mm->start_stack -= sizeof(unsigned long);
10328c2ecf20Sopenharmony_ci			sp = (unsigned long __user *)current->mm->start_stack;
10338c2ecf20Sopenharmony_ci			if (put_user(start_addr, sp))
10348c2ecf20Sopenharmony_ci				return -EFAULT;
10358c2ecf20Sopenharmony_ci			start_addr = libinfo.lib_list[i].entry;
10368c2ecf20Sopenharmony_ci		}
10378c2ecf20Sopenharmony_ci	}
10388c2ecf20Sopenharmony_ci#endif
10398c2ecf20Sopenharmony_ci
10408c2ecf20Sopenharmony_ci#ifdef FLAT_PLAT_INIT
10418c2ecf20Sopenharmony_ci	FLAT_PLAT_INIT(regs);
10428c2ecf20Sopenharmony_ci#endif
10438c2ecf20Sopenharmony_ci
10448c2ecf20Sopenharmony_ci	finalize_exec(bprm);
10458c2ecf20Sopenharmony_ci	pr_debug("start_thread(regs=0x%p, entry=0x%lx, start_stack=0x%lx)\n",
10468c2ecf20Sopenharmony_ci		 regs, start_addr, current->mm->start_stack);
10478c2ecf20Sopenharmony_ci	start_thread(regs, start_addr, current->mm->start_stack);
10488c2ecf20Sopenharmony_ci
10498c2ecf20Sopenharmony_ci	return 0;
10508c2ecf20Sopenharmony_ci}
10518c2ecf20Sopenharmony_ci
10528c2ecf20Sopenharmony_ci/****************************************************************************/
10538c2ecf20Sopenharmony_ci
10548c2ecf20Sopenharmony_cistatic int __init init_flat_binfmt(void)
10558c2ecf20Sopenharmony_ci{
10568c2ecf20Sopenharmony_ci	register_binfmt(&flat_format);
10578c2ecf20Sopenharmony_ci	return 0;
10588c2ecf20Sopenharmony_ci}
10598c2ecf20Sopenharmony_cicore_initcall(init_flat_binfmt);
10608c2ecf20Sopenharmony_ci
10618c2ecf20Sopenharmony_ci/****************************************************************************/
1062