xref: /openbmc/linux/fs/binfmt_flat.c (revision 70578ff3)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /****************************************************************************/
31da177e4SLinus Torvalds /*
41da177e4SLinus Torvalds  *  linux/fs/binfmt_flat.c
51da177e4SLinus Torvalds  *
61da177e4SLinus Torvalds  *	Copyright (C) 2000-2003 David McCullough <davidm@snapgear.com>
71da177e4SLinus Torvalds  *	Copyright (C) 2002 Greg Ungerer <gerg@snapgear.com>
81da177e4SLinus Torvalds  *	Copyright (C) 2002 SnapGear, by Paul Dale <pauli@snapgear.com>
91da177e4SLinus Torvalds  *	Copyright (C) 2000, 2001 Lineo, by David McCullough <davidm@lineo.com>
101da177e4SLinus Torvalds  *  based heavily on:
111da177e4SLinus Torvalds  *
121da177e4SLinus Torvalds  *  linux/fs/binfmt_aout.c:
131da177e4SLinus Torvalds  *      Copyright (C) 1991, 1992, 1996  Linus Torvalds
141da177e4SLinus Torvalds  *  linux/fs/binfmt_flat.c for 2.0 kernel
151da177e4SLinus Torvalds  *	    Copyright (C) 1998  Kenneth Albanowski <kjahds@kjahds.com>
161da177e4SLinus Torvalds  *	JAN/99 -- coded full program relocation (gerg@snapgear.com)
171da177e4SLinus Torvalds  */
181da177e4SLinus Torvalds 
194adbb6acSNicolas Pitre #define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
204adbb6acSNicolas Pitre 
211da177e4SLinus Torvalds #include <linux/kernel.h>
221da177e4SLinus Torvalds #include <linux/sched.h>
2368db0cf1SIngo Molnar #include <linux/sched/task_stack.h>
241da177e4SLinus Torvalds #include <linux/mm.h>
251da177e4SLinus Torvalds #include <linux/mman.h>
261da177e4SLinus Torvalds #include <linux/errno.h>
271da177e4SLinus Torvalds #include <linux/signal.h>
281da177e4SLinus Torvalds #include <linux/string.h>
291da177e4SLinus Torvalds #include <linux/fs.h>
301da177e4SLinus Torvalds #include <linux/file.h>
311da177e4SLinus Torvalds #include <linux/ptrace.h>
321da177e4SLinus Torvalds #include <linux/user.h>
331da177e4SLinus Torvalds #include <linux/slab.h>
341da177e4SLinus Torvalds #include <linux/binfmts.h>
351da177e4SLinus Torvalds #include <linux/personality.h>
361da177e4SLinus Torvalds #include <linux/init.h>
371da177e4SLinus Torvalds #include <linux/flat.h>
3813c3f50cSNicolas Pitre #include <linux/uaccess.h>
39472f95f3SNicolas Pitre #include <linux/vmalloc.h>
401da177e4SLinus Torvalds 
411da177e4SLinus Torvalds #include <asm/byteorder.h>
421da177e4SLinus Torvalds #include <asm/unaligned.h>
431da177e4SLinus Torvalds #include <asm/cacheflush.h>
44c3dc5becSOskar Schirmer #include <asm/page.h>
4506d2bfedSChristoph Hellwig #include <asm/flat.h>
461da177e4SLinus Torvalds 
4702da2833SChristoph Hellwig #ifndef flat_get_relocate_addr
4802da2833SChristoph Hellwig #define flat_get_relocate_addr(rel)	(rel)
4902da2833SChristoph Hellwig #endif
501da177e4SLinus Torvalds 
511da177e4SLinus Torvalds /****************************************************************************/
521da177e4SLinus Torvalds 
53c3dc5becSOskar Schirmer /*
542e94de8aSMike Frysinger  * User data (data section and bss) needs to be aligned.
552e94de8aSMike Frysinger  * We pick 0x20 here because it is the max value elf2flt has always
562e94de8aSMike Frysinger  * used in producing FLAT files, and because it seems to be large
572e94de8aSMike Frysinger  * enough to make all the gcc alignment related tests happy.
582e94de8aSMike Frysinger  */
592e94de8aSMike Frysinger #define FLAT_DATA_ALIGN	(0x20)
602e94de8aSMike Frysinger 
612e94de8aSMike Frysinger /*
622e94de8aSMike Frysinger  * User data (stack) also needs to be aligned.
632e94de8aSMike Frysinger  * Here we can be a bit looser than the data sections since this
642e94de8aSMike Frysinger  * needs to only meet arch ABI requirements.
65c3dc5becSOskar Schirmer  */
662952095cSMike Frysinger #define FLAT_STACK_ALIGN	max_t(unsigned long, sizeof(void *), ARCH_SLAB_MINALIGN)
67c3dc5becSOskar Schirmer 
681da177e4SLinus Torvalds #define RELOC_FAILED 0xff00ff01		/* Relocation incorrect somewhere */
691da177e4SLinus Torvalds #define UNLOADED_LIB 0x7ff000ff		/* Placeholder for unused library */
701da177e4SLinus Torvalds 
71a445d988SChristoph Hellwig #define MAX_SHARED_LIBS			(1)
72a445d988SChristoph Hellwig 
7304d82a6dSDamien Le Moal #ifdef CONFIG_BINFMT_FLAT_NO_DATA_START_OFFSET
7404d82a6dSDamien Le Moal #define DATA_START_OFFSET_WORDS		(0)
7504d82a6dSDamien Le Moal #else
7604d82a6dSDamien Le Moal #define DATA_START_OFFSET_WORDS		(MAX_SHARED_LIBS)
7704d82a6dSDamien Le Moal #endif
7804d82a6dSDamien Le Moal 
791da177e4SLinus Torvalds struct lib_info {
801da177e4SLinus Torvalds 	struct {
811da177e4SLinus Torvalds 		unsigned long start_code;		/* Start of text segment */
821da177e4SLinus Torvalds 		unsigned long start_data;		/* Start of data segment */
831da177e4SLinus Torvalds 		unsigned long start_brk;		/* End of data segment */
841da177e4SLinus Torvalds 		unsigned long text_len;			/* Length of text segment */
851da177e4SLinus Torvalds 		unsigned long entry;			/* Start address for this module */
861da177e4SLinus Torvalds 		unsigned long build_date;		/* When this one was compiled */
8713c3f50cSNicolas Pitre 		bool loaded;				/* Has this library been loaded? */
881da177e4SLinus Torvalds 	} lib_list[MAX_SHARED_LIBS];
891da177e4SLinus Torvalds };
901da177e4SLinus Torvalds 
9171613c3bSAl Viro static int load_flat_binary(struct linux_binprm *);
921da177e4SLinus Torvalds 
931da177e4SLinus Torvalds static struct linux_binfmt flat_format = {
941da177e4SLinus Torvalds 	.module		= THIS_MODULE,
951da177e4SLinus Torvalds 	.load_binary	= load_flat_binary,
961da177e4SLinus Torvalds };
971da177e4SLinus Torvalds 
981da177e4SLinus Torvalds 
991da177e4SLinus Torvalds /****************************************************************************/
1001da177e4SLinus Torvalds /*
1011da177e4SLinus Torvalds  * create_flat_tables() parses the env- and arg-strings in new user
1021da177e4SLinus Torvalds  * memory and creates the pointer tables from them, and puts their
103a97d157dSNicolas Pitre  * addresses on the "stack", recording the new stack pointer value.
1041da177e4SLinus Torvalds  */
1051da177e4SLinus Torvalds 
create_flat_tables(struct linux_binprm * bprm,unsigned long arg_start)106a97d157dSNicolas Pitre static int create_flat_tables(struct linux_binprm *bprm, unsigned long arg_start)
1071da177e4SLinus Torvalds {
108a97d157dSNicolas Pitre 	char __user *p;
109a97d157dSNicolas Pitre 	unsigned long __user *sp;
110a97d157dSNicolas Pitre 	long i, len;
1111da177e4SLinus Torvalds 
112a97d157dSNicolas Pitre 	p = (char __user *)arg_start;
113a97d157dSNicolas Pitre 	sp = (unsigned long __user *)current->mm->start_stack;
1141da177e4SLinus Torvalds 
115a97d157dSNicolas Pitre 	sp -= bprm->envc + 1;
116a97d157dSNicolas Pitre 	sp -= bprm->argc + 1;
117bdd15a28SChristoph Hellwig 	if (IS_ENABLED(CONFIG_BINFMT_FLAT_ARGVP_ENVP_ON_STACK))
118bdd15a28SChristoph Hellwig 		sp -= 2; /* argvp + envp */
119a97d157dSNicolas Pitre 	sp -= 1;  /* &argc */
120a97d157dSNicolas Pitre 
121a97d157dSNicolas Pitre 	current->mm->start_stack = (unsigned long)sp & -FLAT_STACK_ALIGN;
122a97d157dSNicolas Pitre 	sp = (unsigned long __user *)current->mm->start_stack;
123a97d157dSNicolas Pitre 
1248861fd57SAl Viro 	if (put_user(bprm->argc, sp++))
1258861fd57SAl Viro 		return -EFAULT;
126bdd15a28SChristoph Hellwig 	if (IS_ENABLED(CONFIG_BINFMT_FLAT_ARGVP_ENVP_ON_STACK)) {
127a97d157dSNicolas Pitre 		unsigned long argv, envp;
128a97d157dSNicolas Pitre 		argv = (unsigned long)(sp + 2);
129a97d157dSNicolas Pitre 		envp = (unsigned long)(sp + 2 + bprm->argc + 1);
1308861fd57SAl Viro 		if (put_user(argv, sp++) || put_user(envp, sp++))
1318861fd57SAl Viro 			return -EFAULT;
1321da177e4SLinus Torvalds 	}
1331da177e4SLinus Torvalds 
1341da177e4SLinus Torvalds 	current->mm->arg_start = (unsigned long)p;
135a97d157dSNicolas Pitre 	for (i = bprm->argc; i > 0; i--) {
1368861fd57SAl Viro 		if (put_user((unsigned long)p, sp++))
1378861fd57SAl Viro 			return -EFAULT;
138a97d157dSNicolas Pitre 		len = strnlen_user(p, MAX_ARG_STRLEN);
139a97d157dSNicolas Pitre 		if (!len || len > MAX_ARG_STRLEN)
140a97d157dSNicolas Pitre 			return -EINVAL;
141a97d157dSNicolas Pitre 		p += len;
1421da177e4SLinus Torvalds 	}
1438861fd57SAl Viro 	if (put_user(0, sp++))
1448861fd57SAl Viro 		return -EFAULT;
145a97d157dSNicolas Pitre 	current->mm->arg_end = (unsigned long)p;
146a97d157dSNicolas Pitre 
147a97d157dSNicolas Pitre 	current->mm->env_start = (unsigned long) p;
148a97d157dSNicolas Pitre 	for (i = bprm->envc; i > 0; i--) {
1498861fd57SAl Viro 		if (put_user((unsigned long)p, sp++))
1508861fd57SAl Viro 			return -EFAULT;
151a97d157dSNicolas Pitre 		len = strnlen_user(p, MAX_ARG_STRLEN);
152a97d157dSNicolas Pitre 		if (!len || len > MAX_ARG_STRLEN)
153a97d157dSNicolas Pitre 			return -EINVAL;
154a97d157dSNicolas Pitre 		p += len;
1551da177e4SLinus Torvalds 	}
1568861fd57SAl Viro 	if (put_user(0, sp++))
1578861fd57SAl Viro 		return -EFAULT;
1581da177e4SLinus Torvalds 	current->mm->env_end = (unsigned long)p;
159a97d157dSNicolas Pitre 
160a97d157dSNicolas Pitre 	return 0;
1611da177e4SLinus Torvalds }
1621da177e4SLinus Torvalds 
1631da177e4SLinus Torvalds /****************************************************************************/
1641da177e4SLinus Torvalds 
1651da177e4SLinus Torvalds #ifdef CONFIG_BINFMT_ZFLAT
1661da177e4SLinus Torvalds 
1671da177e4SLinus Torvalds #include <linux/zlib.h>
1681da177e4SLinus Torvalds 
1691da177e4SLinus Torvalds #define LBUFSIZE	4000
1701da177e4SLinus Torvalds 
1711da177e4SLinus Torvalds /* gzip flag byte */
1721da177e4SLinus Torvalds #define ASCII_FLAG   0x01 /* bit 0 set: file probably ASCII text */
1731da177e4SLinus Torvalds #define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
1741da177e4SLinus Torvalds #define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
1751da177e4SLinus Torvalds #define ORIG_NAME    0x08 /* bit 3 set: original file name present */
1761da177e4SLinus Torvalds #define COMMENT      0x10 /* bit 4 set: file comment present */
1771da177e4SLinus Torvalds #define ENCRYPTED    0x20 /* bit 5 set: file is encrypted */
1781da177e4SLinus Torvalds #define RESERVED     0xC0 /* bit 6,7:   reserved */
1791da177e4SLinus Torvalds 
decompress_exec(struct linux_binprm * bprm,loff_t fpos,char * dst,long len,int fd)180bdd1d2d3SChristoph Hellwig static int decompress_exec(struct linux_binprm *bprm, loff_t fpos, char *dst,
181bdd1d2d3SChristoph Hellwig 		long len, int fd)
1821da177e4SLinus Torvalds {
1831da177e4SLinus Torvalds 	unsigned char *buf;
1841da177e4SLinus Torvalds 	z_stream strm;
1851da177e4SLinus Torvalds 	int ret, retval;
1861da177e4SLinus Torvalds 
187bdd1d2d3SChristoph Hellwig 	pr_debug("decompress_exec(offset=%llx,buf=%p,len=%lx)\n", fpos, dst, len);
1881da177e4SLinus Torvalds 
1891da177e4SLinus Torvalds 	memset(&strm, 0, sizeof(strm));
1901da177e4SLinus Torvalds 	strm.workspace = kmalloc(zlib_inflate_workspacesize(), GFP_KERNEL);
1919367bb73SMarkus Elfring 	if (!strm.workspace)
1921da177e4SLinus Torvalds 		return -ENOMEM;
1939367bb73SMarkus Elfring 
1941da177e4SLinus Torvalds 	buf = kmalloc(LBUFSIZE, GFP_KERNEL);
1959367bb73SMarkus Elfring 	if (!buf) {
1961da177e4SLinus Torvalds 		retval = -ENOMEM;
1971da177e4SLinus Torvalds 		goto out_free;
1981da177e4SLinus Torvalds 	}
1991da177e4SLinus Torvalds 
2001da177e4SLinus Torvalds 	/* Read in first chunk of data and parse gzip header. */
201bdd1d2d3SChristoph Hellwig 	ret = kernel_read(bprm->file, buf, LBUFSIZE, &fpos);
2021da177e4SLinus Torvalds 
2031da177e4SLinus Torvalds 	strm.next_in = buf;
2041da177e4SLinus Torvalds 	strm.avail_in = ret;
2051da177e4SLinus Torvalds 	strm.total_in = 0;
2061da177e4SLinus Torvalds 
2071da177e4SLinus Torvalds 	retval = -ENOEXEC;
2081da177e4SLinus Torvalds 
2091da177e4SLinus Torvalds 	/* Check minimum size -- gzip header */
2101da177e4SLinus Torvalds 	if (ret < 10) {
2114adbb6acSNicolas Pitre 		pr_debug("file too small?\n");
2121da177e4SLinus Torvalds 		goto out_free_buf;
2131da177e4SLinus Torvalds 	}
2141da177e4SLinus Torvalds 
2151da177e4SLinus Torvalds 	/* Check gzip magic number */
2161da177e4SLinus Torvalds 	if ((buf[0] != 037) || ((buf[1] != 0213) && (buf[1] != 0236))) {
2174adbb6acSNicolas Pitre 		pr_debug("unknown compression magic?\n");
2181da177e4SLinus Torvalds 		goto out_free_buf;
2191da177e4SLinus Torvalds 	}
2201da177e4SLinus Torvalds 
2211da177e4SLinus Torvalds 	/* Check gzip method */
2221da177e4SLinus Torvalds 	if (buf[2] != 8) {
2234adbb6acSNicolas Pitre 		pr_debug("unknown compression method?\n");
2241da177e4SLinus Torvalds 		goto out_free_buf;
2251da177e4SLinus Torvalds 	}
2261da177e4SLinus Torvalds 	/* Check gzip flags */
2271da177e4SLinus Torvalds 	if ((buf[3] & ENCRYPTED) || (buf[3] & CONTINUATION) ||
2281da177e4SLinus Torvalds 	    (buf[3] & RESERVED)) {
2294adbb6acSNicolas Pitre 		pr_debug("unknown flags?\n");
2301da177e4SLinus Torvalds 		goto out_free_buf;
2311da177e4SLinus Torvalds 	}
2321da177e4SLinus Torvalds 
2331da177e4SLinus Torvalds 	ret = 10;
2341da177e4SLinus Torvalds 	if (buf[3] & EXTRA_FIELD) {
2351da177e4SLinus Torvalds 		ret += 2 + buf[10] + (buf[11] << 8);
23613c3f50cSNicolas Pitre 		if (unlikely(ret >= LBUFSIZE)) {
2374adbb6acSNicolas Pitre 			pr_debug("buffer overflow (EXTRA)?\n");
2381da177e4SLinus Torvalds 			goto out_free_buf;
2391da177e4SLinus Torvalds 		}
2401da177e4SLinus Torvalds 	}
2411da177e4SLinus Torvalds 	if (buf[3] & ORIG_NAME) {
242f4cfb18dSVolodymyr G. Lukiianyk 		while (ret < LBUFSIZE && buf[ret++] != 0)
2431da177e4SLinus Torvalds 			;
24413c3f50cSNicolas Pitre 		if (unlikely(ret == LBUFSIZE)) {
2454adbb6acSNicolas Pitre 			pr_debug("buffer overflow (ORIG_NAME)?\n");
2461da177e4SLinus Torvalds 			goto out_free_buf;
2471da177e4SLinus Torvalds 		}
2481da177e4SLinus Torvalds 	}
2491da177e4SLinus Torvalds 	if (buf[3] & COMMENT) {
250f4cfb18dSVolodymyr G. Lukiianyk 		while (ret < LBUFSIZE && buf[ret++] != 0)
2511da177e4SLinus Torvalds 			;
25213c3f50cSNicolas Pitre 		if (unlikely(ret == LBUFSIZE)) {
2534adbb6acSNicolas Pitre 			pr_debug("buffer overflow (COMMENT)?\n");
2541da177e4SLinus Torvalds 			goto out_free_buf;
2551da177e4SLinus Torvalds 		}
2561da177e4SLinus Torvalds 	}
2571da177e4SLinus Torvalds 
2581da177e4SLinus Torvalds 	strm.next_in += ret;
2591da177e4SLinus Torvalds 	strm.avail_in -= ret;
2601da177e4SLinus Torvalds 
2611da177e4SLinus Torvalds 	strm.next_out = dst;
2621da177e4SLinus Torvalds 	strm.avail_out = len;
2631da177e4SLinus Torvalds 	strm.total_out = 0;
2641da177e4SLinus Torvalds 
2651da177e4SLinus Torvalds 	if (zlib_inflateInit2(&strm, -MAX_WBITS) != Z_OK) {
2664adbb6acSNicolas Pitre 		pr_debug("zlib init failed?\n");
2671da177e4SLinus Torvalds 		goto out_free_buf;
2681da177e4SLinus Torvalds 	}
2691da177e4SLinus Torvalds 
2701da177e4SLinus Torvalds 	while ((ret = zlib_inflate(&strm, Z_NO_FLUSH)) == Z_OK) {
271bdd1d2d3SChristoph Hellwig 		ret = kernel_read(bprm->file, buf, LBUFSIZE, &fpos);
2721da177e4SLinus Torvalds 		if (ret <= 0)
2731da177e4SLinus Torvalds 			break;
2741da177e4SLinus Torvalds 		len -= ret;
2751da177e4SLinus Torvalds 
2761da177e4SLinus Torvalds 		strm.next_in = buf;
2771da177e4SLinus Torvalds 		strm.avail_in = ret;
2781da177e4SLinus Torvalds 		strm.total_in = 0;
2791da177e4SLinus Torvalds 	}
2801da177e4SLinus Torvalds 
2811da177e4SLinus Torvalds 	if (ret < 0) {
2824adbb6acSNicolas Pitre 		pr_debug("decompression failed (%d), %s\n",
2831da177e4SLinus Torvalds 			ret, strm.msg);
2841da177e4SLinus Torvalds 		goto out_zlib;
2851da177e4SLinus Torvalds 	}
2861da177e4SLinus Torvalds 
2871da177e4SLinus Torvalds 	retval = 0;
2881da177e4SLinus Torvalds out_zlib:
2891da177e4SLinus Torvalds 	zlib_inflateEnd(&strm);
2901da177e4SLinus Torvalds out_free_buf:
2911da177e4SLinus Torvalds 	kfree(buf);
2921da177e4SLinus Torvalds out_free:
2931da177e4SLinus Torvalds 	kfree(strm.workspace);
2941da177e4SLinus Torvalds 	return retval;
2951da177e4SLinus Torvalds }
2961da177e4SLinus Torvalds 
2971da177e4SLinus Torvalds #endif /* CONFIG_BINFMT_ZFLAT */
2981da177e4SLinus Torvalds 
2991da177e4SLinus Torvalds /****************************************************************************/
3001da177e4SLinus Torvalds 
3011da177e4SLinus Torvalds static unsigned long
calc_reloc(unsigned long r,struct lib_info * p)302*70578ff3SEric W. Biederman calc_reloc(unsigned long r, struct lib_info *p)
3031da177e4SLinus Torvalds {
3041da177e4SLinus Torvalds 	unsigned long addr;
3051da177e4SLinus Torvalds 	unsigned long start_brk;
3061da177e4SLinus Torvalds 	unsigned long start_data;
3071da177e4SLinus Torvalds 	unsigned long text_len;
3081da177e4SLinus Torvalds 	unsigned long start_code;
3091da177e4SLinus Torvalds 
310*70578ff3SEric W. Biederman 	start_brk = p->lib_list[0].start_brk;
311*70578ff3SEric W. Biederman 	start_data = p->lib_list[0].start_data;
312*70578ff3SEric W. Biederman 	start_code = p->lib_list[0].start_code;
313*70578ff3SEric W. Biederman 	text_len = p->lib_list[0].text_len;
3141da177e4SLinus Torvalds 
3159ee24b2aSChristoph Hellwig 	if (r > start_brk - start_data + text_len) {
3164adbb6acSNicolas Pitre 		pr_err("reloc outside program 0x%lx (0 - 0x%lx/0x%lx)",
31713c3f50cSNicolas Pitre 		       r, start_brk-start_data+text_len, text_len);
3181da177e4SLinus Torvalds 		goto failed;
3191da177e4SLinus Torvalds 	}
3201da177e4SLinus Torvalds 
3211da177e4SLinus Torvalds 	if (r < text_len)			/* In text segment */
3221da177e4SLinus Torvalds 		addr = r + start_code;
3231da177e4SLinus Torvalds 	else					/* In data segment */
3241da177e4SLinus Torvalds 		addr = r - text_len + start_data;
3251da177e4SLinus Torvalds 
3261da177e4SLinus Torvalds 	/* Range checked already above so doing the range tests is redundant...*/
32713c3f50cSNicolas Pitre 	return addr;
3281da177e4SLinus Torvalds 
3291da177e4SLinus Torvalds failed:
3304adbb6acSNicolas Pitre 	pr_cont(", killing %s!\n", current->comm);
3311da177e4SLinus Torvalds 	send_sig(SIGSEGV, current, 0);
3321da177e4SLinus Torvalds 
3331da177e4SLinus Torvalds 	return RELOC_FAILED;
3341da177e4SLinus Torvalds }
3351da177e4SLinus Torvalds 
3361da177e4SLinus Torvalds /****************************************************************************/
3371da177e4SLinus Torvalds 
338cf9a566cSChristoph Hellwig #ifdef CONFIG_BINFMT_FLAT_OLD
old_reloc(unsigned long rl)33934303435SAxel Lin static void old_reloc(unsigned long rl)
3401da177e4SLinus Torvalds {
34113c3f50cSNicolas Pitre 	static const char *segment[] = { "TEXT", "DATA", "BSS", "*UNKNOWN*" };
3421da177e4SLinus Torvalds 	flat_v2_reloc_t	r;
3431b2ce442SNicolas Pitre 	unsigned long __user *ptr;
3441b2ce442SNicolas Pitre 	unsigned long val;
3451da177e4SLinus Torvalds 
3461da177e4SLinus Torvalds 	r.value = rl;
3471da177e4SLinus Torvalds #if defined(CONFIG_COLDFIRE)
3481b2ce442SNicolas Pitre 	ptr = (unsigned long __user *)(current->mm->start_code + r.reloc.offset);
3491da177e4SLinus Torvalds #else
3501b2ce442SNicolas Pitre 	ptr = (unsigned long __user *)(current->mm->start_data + r.reloc.offset);
3511da177e4SLinus Torvalds #endif
3521b2ce442SNicolas Pitre 	get_user(val, ptr);
3531da177e4SLinus Torvalds 
3544adbb6acSNicolas Pitre 	pr_debug("Relocation of variable at DATASEG+%x "
35513c3f50cSNicolas Pitre 		 "(address %p, currently %lx) into segment %s\n",
3561b2ce442SNicolas Pitre 		 r.reloc.offset, ptr, val, segment[r.reloc.type]);
3571da177e4SLinus Torvalds 
3581da177e4SLinus Torvalds 	switch (r.reloc.type) {
3591da177e4SLinus Torvalds 	case OLD_FLAT_RELOC_TYPE_TEXT:
3601b2ce442SNicolas Pitre 		val += current->mm->start_code;
3611da177e4SLinus Torvalds 		break;
3621da177e4SLinus Torvalds 	case OLD_FLAT_RELOC_TYPE_DATA:
3631b2ce442SNicolas Pitre 		val += current->mm->start_data;
3641da177e4SLinus Torvalds 		break;
3651da177e4SLinus Torvalds 	case OLD_FLAT_RELOC_TYPE_BSS:
3661b2ce442SNicolas Pitre 		val += current->mm->end_data;
3671da177e4SLinus Torvalds 		break;
3681da177e4SLinus Torvalds 	default:
3694adbb6acSNicolas Pitre 		pr_err("Unknown relocation type=%x\n", r.reloc.type);
3701da177e4SLinus Torvalds 		break;
3711da177e4SLinus Torvalds 	}
3721b2ce442SNicolas Pitre 	put_user(val, ptr);
3731da177e4SLinus Torvalds 
3741b2ce442SNicolas Pitre 	pr_debug("Relocation became %lx\n", val);
3751da177e4SLinus Torvalds }
376cf9a566cSChristoph Hellwig #endif /* CONFIG_BINFMT_FLAT_OLD */
3771da177e4SLinus Torvalds 
3781da177e4SLinus Torvalds /****************************************************************************/
3791da177e4SLinus Torvalds 
skip_got_header(u32 __user * rp)3806045ab5fSNiklas Cassel static inline u32 __user *skip_got_header(u32 __user *rp)
3816045ab5fSNiklas Cassel {
3826045ab5fSNiklas Cassel 	if (IS_ENABLED(CONFIG_RISCV)) {
3836045ab5fSNiklas Cassel 		/*
3846045ab5fSNiklas Cassel 		 * RISC-V has a 16 byte GOT PLT header for elf64-riscv
3856045ab5fSNiklas Cassel 		 * and 8 byte GOT PLT header for elf32-riscv.
3866045ab5fSNiklas Cassel 		 * Skip the whole GOT PLT header, since it is reserved
3876045ab5fSNiklas Cassel 		 * for the dynamic linker (ld.so).
3886045ab5fSNiklas Cassel 		 */
3896045ab5fSNiklas Cassel 		u32 rp_val0, rp_val1;
3906045ab5fSNiklas Cassel 
3916045ab5fSNiklas Cassel 		if (get_user(rp_val0, rp))
3926045ab5fSNiklas Cassel 			return rp;
3936045ab5fSNiklas Cassel 		if (get_user(rp_val1, rp + 1))
3946045ab5fSNiklas Cassel 			return rp;
3956045ab5fSNiklas Cassel 
3966045ab5fSNiklas Cassel 		if (rp_val0 == 0xffffffff && rp_val1 == 0xffffffff)
3976045ab5fSNiklas Cassel 			rp += 4;
3986045ab5fSNiklas Cassel 		else if (rp_val0 == 0xffffffff)
3996045ab5fSNiklas Cassel 			rp += 2;
4006045ab5fSNiklas Cassel 	}
4016045ab5fSNiklas Cassel 	return rp;
4026045ab5fSNiklas Cassel }
4036045ab5fSNiklas Cassel 
load_flat_file(struct linux_binprm * bprm,struct lib_info * libinfo,unsigned long * extra_stack)4041da177e4SLinus Torvalds static int load_flat_file(struct linux_binprm *bprm,
405*70578ff3SEric W. Biederman 		struct lib_info *libinfo, unsigned long *extra_stack)
4061da177e4SLinus Torvalds {
4071da177e4SLinus Torvalds 	struct flat_hdr *hdr;
40813c3f50cSNicolas Pitre 	unsigned long textpos, datapos, realdatastart;
409468138d7SAl Viro 	u32 text_len, data_len, bss_len, stack_len, full_data, flags;
41013c3f50cSNicolas Pitre 	unsigned long len, memp, memp_size, extra, rlim;
4113b977718SChristoph Hellwig 	__be32 __user *reloc;
4123b977718SChristoph Hellwig 	u32 __user *rp;
41313c3f50cSNicolas Pitre 	int i, rev, relocs;
4141da177e4SLinus Torvalds 	loff_t fpos;
4151da177e4SLinus Torvalds 	unsigned long start_code, end_code;
41613c3f50cSNicolas Pitre 	ssize_t result;
4171ad3dcc0SLuke Yang 	int ret;
4181da177e4SLinus Torvalds 
4191da177e4SLinus Torvalds 	hdr = ((struct flat_hdr *) bprm->buf);		/* exec-header */
4201da177e4SLinus Torvalds 
4211da177e4SLinus Torvalds 	text_len  = ntohl(hdr->data_start);
4221da177e4SLinus Torvalds 	data_len  = ntohl(hdr->data_end) - ntohl(hdr->data_start);
4231da177e4SLinus Torvalds 	bss_len   = ntohl(hdr->bss_end) - ntohl(hdr->data_end);
4241da177e4SLinus Torvalds 	stack_len = ntohl(hdr->stack_size);
4251da177e4SLinus Torvalds 	if (extra_stack) {
4261da177e4SLinus Torvalds 		stack_len += *extra_stack;
4271da177e4SLinus Torvalds 		*extra_stack = stack_len;
4281da177e4SLinus Torvalds 	}
4291da177e4SLinus Torvalds 	relocs    = ntohl(hdr->reloc_count);
4301da177e4SLinus Torvalds 	flags     = ntohl(hdr->flags);
4311da177e4SLinus Torvalds 	rev       = ntohl(hdr->rev);
4323dc20cb2SAl Viro 	full_data = data_len + relocs * sizeof(unsigned long);
4331da177e4SLinus Torvalds 
434845884d3SGreg Ungerer 	if (strncmp(hdr->magic, "bFLT", 4)) {
4351da177e4SLinus Torvalds 		/*
436e2a366dcSMike Frysinger 		 * Previously, here was a printk to tell people
437e2a366dcSMike Frysinger 		 *   "BINFMT_FLAT: bad header magic".
438e2a366dcSMike Frysinger 		 * But for the kernel which also use ELF FD-PIC format, this
439e2a366dcSMike Frysinger 		 * error message is confusing.
4401da177e4SLinus Torvalds 		 * because a lot of people do not manage to produce good
4411da177e4SLinus Torvalds 		 */
4421ad3dcc0SLuke Yang 		ret = -ENOEXEC;
4431ad3dcc0SLuke Yang 		goto err;
444845884d3SGreg Ungerer 	}
445845884d3SGreg Ungerer 
446845884d3SGreg Ungerer 	if (flags & FLAT_FLAG_KTRACE)
4474adbb6acSNicolas Pitre 		pr_info("Loading file: %s\n", bprm->filename);
448845884d3SGreg Ungerer 
449cf9a566cSChristoph Hellwig #ifdef CONFIG_BINFMT_FLAT_OLD
450845884d3SGreg Ungerer 	if (rev != FLAT_VERSION && rev != OLD_FLAT_VERSION) {
4514adbb6acSNicolas Pitre 		pr_err("bad flat file version 0x%x (supported 0x%lx and 0x%lx)\n",
4520e647c04SAndrew Morton 		       rev, FLAT_VERSION, OLD_FLAT_VERSION);
4531ad3dcc0SLuke Yang 		ret = -ENOEXEC;
4541ad3dcc0SLuke Yang 		goto err;
4551da177e4SLinus Torvalds 	}
4561da177e4SLinus Torvalds 
4571da177e4SLinus Torvalds 	/*
458cf9a566cSChristoph Hellwig 	 * fix up the flags for the older format,  there were all kinds
459cf9a566cSChristoph Hellwig 	 * of endian hacks,  this only works for the simple cases
460cf9a566cSChristoph Hellwig 	 */
461cf9a566cSChristoph Hellwig 	if (rev == OLD_FLAT_VERSION &&
462cf9a566cSChristoph Hellwig 	   (flags || IS_ENABLED(CONFIG_BINFMT_FLAT_OLD_ALWAYS_RAM)))
463cf9a566cSChristoph Hellwig 		flags = FLAT_FLAG_RAM;
464cf9a566cSChristoph Hellwig 
465cf9a566cSChristoph Hellwig #else /* CONFIG_BINFMT_FLAT_OLD */
466cf9a566cSChristoph Hellwig 	if (rev != FLAT_VERSION) {
467cf9a566cSChristoph Hellwig 		pr_err("bad flat file version 0x%x (supported 0x%lx)\n",
468cf9a566cSChristoph Hellwig 		       rev, FLAT_VERSION);
469cf9a566cSChristoph Hellwig 		ret = -ENOEXEC;
470cf9a566cSChristoph Hellwig 		goto err;
471cf9a566cSChristoph Hellwig 	}
472cf9a566cSChristoph Hellwig #endif /* !CONFIG_BINFMT_FLAT_OLD */
473cf9a566cSChristoph Hellwig 
474cf9a566cSChristoph Hellwig 	/*
475c995ee28SNicolas Pitre 	 * Make sure the header params are sane.
476c995ee28SNicolas Pitre 	 * 28 bits (256 MB) is way more than reasonable in this case.
477c995ee28SNicolas Pitre 	 * If some top bits are set we have probable binary corruption.
478c995ee28SNicolas Pitre 	*/
479c995ee28SNicolas Pitre 	if ((text_len | data_len | bss_len | stack_len | full_data) >> 28) {
480c995ee28SNicolas Pitre 		pr_err("bad header\n");
481c995ee28SNicolas Pitre 		ret = -ENOEXEC;
482c995ee28SNicolas Pitre 		goto err;
483c995ee28SNicolas Pitre 	}
484c995ee28SNicolas Pitre 
4851da177e4SLinus Torvalds #ifndef CONFIG_BINFMT_ZFLAT
4861da177e4SLinus Torvalds 	if (flags & (FLAT_FLAG_GZIP|FLAT_FLAG_GZDATA)) {
4874adbb6acSNicolas Pitre 		pr_err("Support for ZFLAT executables is not enabled.\n");
4881ad3dcc0SLuke Yang 		ret = -ENOEXEC;
4891ad3dcc0SLuke Yang 		goto err;
4901da177e4SLinus Torvalds 	}
4911da177e4SLinus Torvalds #endif
4921da177e4SLinus Torvalds 
4931da177e4SLinus Torvalds 	/*
4941da177e4SLinus Torvalds 	 * Check initial limits. This avoids letting people circumvent
4951da177e4SLinus Torvalds 	 * size limits imposed on them by creating programs with large
4961da177e4SLinus Torvalds 	 * arrays in the data or bss.
4971da177e4SLinus Torvalds 	 */
498d554ed89SJiri Slaby 	rlim = rlimit(RLIMIT_DATA);
4991da177e4SLinus Torvalds 	if (rlim >= RLIM_INFINITY)
5001da177e4SLinus Torvalds 		rlim = ~0;
5011ad3dcc0SLuke Yang 	if (data_len + bss_len > rlim) {
5021ad3dcc0SLuke Yang 		ret = -ENOMEM;
5031ad3dcc0SLuke Yang 		goto err;
5041ad3dcc0SLuke Yang 	}
5051ad3dcc0SLuke Yang 
5061da177e4SLinus Torvalds 	/* Flush all traces of the currently running executable */
5072388777aSEric W. Biederman 	ret = begin_new_exec(bprm);
50813c3f50cSNicolas Pitre 	if (ret)
509df88912aSAndrew Morton 		goto err;
5101da177e4SLinus Torvalds 
5111da177e4SLinus Torvalds 	/* OK, This is the point of no return */
512fcc18e83SMalcolm Parsons 	set_personality(PER_LINUX_32BIT);
513221af7f8SLinus Torvalds 	setup_new_exec(bprm);
5141da177e4SLinus Torvalds 
5151da177e4SLinus Torvalds 	/*
5161da177e4SLinus Torvalds 	 * calculate the extra space we need to map in
5171da177e4SLinus Torvalds 	 */
5180e647c04SAndrew Morton 	extra = max_t(unsigned long, bss_len + stack_len,
5190e647c04SAndrew Morton 			relocs * sizeof(unsigned long));
5201da177e4SLinus Torvalds 
5211da177e4SLinus Torvalds 	/*
5221da177e4SLinus Torvalds 	 * there are a couple of cases here,  the separate code/data
5231da177e4SLinus Torvalds 	 * case,  and then the fully copied to RAM case which lumps
5241da177e4SLinus Torvalds 	 * it all together.
5251da177e4SLinus Torvalds 	 */
526015feacfSNicolas Pitre 	if (!IS_ENABLED(CONFIG_MMU) && !(flags & (FLAT_FLAG_RAM|FLAT_FLAG_GZIP))) {
5271da177e4SLinus Torvalds 		/*
5281da177e4SLinus Torvalds 		 * this should give us a ROM ptr,  but if it doesn't we don't
5291da177e4SLinus Torvalds 		 * really care
5301da177e4SLinus Torvalds 		 */
5314adbb6acSNicolas Pitre 		pr_debug("ROM mapping of file (we hope)\n");
5321da177e4SLinus Torvalds 
5336be5ceb0SLinus Torvalds 		textpos = vm_mmap(bprm->file, 0, text_len, PROT_READ|PROT_EXEC,
534a4eec6a3SDavid Hildenbrand 				  MAP_PRIVATE, 0);
5350b8c78f2SMike Frysinger 		if (!textpos || IS_ERR_VALUE(textpos)) {
5361ad3dcc0SLuke Yang 			ret = textpos;
53713c3f50cSNicolas Pitre 			if (!textpos)
53813c3f50cSNicolas Pitre 				ret = -ENOMEM;
5394adbb6acSNicolas Pitre 			pr_err("Unable to mmap process text, errno %d\n", ret);
540df88912aSAndrew Morton 			goto err;
5411da177e4SLinus Torvalds 		}
5421da177e4SLinus Torvalds 
54304d82a6dSDamien Le Moal 		len = data_len + extra +
54404d82a6dSDamien Le Moal 			DATA_START_OFFSET_WORDS * sizeof(unsigned long);
5450f3e442aSDavid Howells 		len = PAGE_ALIGN(len);
54613c3f50cSNicolas Pitre 		realdatastart = vm_mmap(NULL, 0, len,
5478f5bb043SYoshinori Sato 			PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE, 0);
5481da177e4SLinus Torvalds 
5490b8c78f2SMike Frysinger 		if (realdatastart == 0 || IS_ERR_VALUE(realdatastart)) {
5501ad3dcc0SLuke Yang 			ret = realdatastart;
55113c3f50cSNicolas Pitre 			if (!realdatastart)
55213c3f50cSNicolas Pitre 				ret = -ENOMEM;
5534adbb6acSNicolas Pitre 			pr_err("Unable to allocate RAM for process data, "
55413c3f50cSNicolas Pitre 			       "errno %d\n", ret);
55513c3f50cSNicolas Pitre 			vm_munmap(textpos, text_len);
556df88912aSAndrew Morton 			goto err;
5571da177e4SLinus Torvalds 		}
5582217b982SMax Filippov 		datapos = ALIGN(realdatastart +
55904d82a6dSDamien Le Moal 				DATA_START_OFFSET_WORDS * sizeof(unsigned long),
5602217b982SMax Filippov 				FLAT_DATA_ALIGN);
5611da177e4SLinus Torvalds 
562a8605423SGeert Uytterhoeven 		pr_debug("Allocated data+bss+stack (%u bytes): %lx\n",
56313c3f50cSNicolas Pitre 			 data_len + bss_len + stack_len, datapos);
5641da177e4SLinus Torvalds 
5651da177e4SLinus Torvalds 		fpos = ntohl(hdr->data_start);
5661da177e4SLinus Torvalds #ifdef CONFIG_BINFMT_ZFLAT
5671da177e4SLinus Torvalds 		if (flags & FLAT_FLAG_GZDATA) {
5681da177e4SLinus Torvalds 			result = decompress_exec(bprm, fpos, (char *)datapos,
5693dc20cb2SAl Viro 						 full_data, 0);
5701da177e4SLinus Torvalds 		} else
5711da177e4SLinus Torvalds #endif
5721da177e4SLinus Torvalds 		{
5733dc20cb2SAl Viro 			result = read_code(bprm->file, datapos, fpos,
5743dc20cb2SAl Viro 					full_data);
5751da177e4SLinus Torvalds 		}
5760b8c78f2SMike Frysinger 		if (IS_ERR_VALUE(result)) {
57713c3f50cSNicolas Pitre 			ret = result;
5784adbb6acSNicolas Pitre 			pr_err("Unable to read data+bss, errno %d\n", ret);
5797696e0c3SAl Viro 			vm_munmap(textpos, text_len);
5807696e0c3SAl Viro 			vm_munmap(realdatastart, len);
581df88912aSAndrew Morton 			goto err;
5821da177e4SLinus Torvalds 		}
5831da177e4SLinus Torvalds 
5843b977718SChristoph Hellwig 		reloc = (__be32 __user *)
58513c3f50cSNicolas Pitre 			(datapos + (ntohl(hdr->reloc_start) - text_len));
5861da177e4SLinus Torvalds 		memp = realdatastart;
5870f3e442aSDavid Howells 		memp_size = len;
5881da177e4SLinus Torvalds 	} else {
5891da177e4SLinus Torvalds 
59004d82a6dSDamien Le Moal 		len = text_len + data_len + extra +
59104d82a6dSDamien Le Moal 			DATA_START_OFFSET_WORDS * sizeof(u32);
5920f3e442aSDavid Howells 		len = PAGE_ALIGN(len);
59313c3f50cSNicolas Pitre 		textpos = vm_mmap(NULL, 0, len,
5948f5bb043SYoshinori Sato 			PROT_READ | PROT_EXEC | PROT_WRITE, MAP_PRIVATE, 0);
59572613e5fSGreg Ungerer 
5960b8c78f2SMike Frysinger 		if (!textpos || IS_ERR_VALUE(textpos)) {
5971ad3dcc0SLuke Yang 			ret = textpos;
59813c3f50cSNicolas Pitre 			if (!textpos)
59913c3f50cSNicolas Pitre 				ret = -ENOMEM;
6004adbb6acSNicolas Pitre 			pr_err("Unable to allocate RAM for process text/data, "
60113c3f50cSNicolas Pitre 			       "errno %d\n", ret);
602df88912aSAndrew Morton 			goto err;
6031da177e4SLinus Torvalds 		}
6041da177e4SLinus Torvalds 
6051da177e4SLinus Torvalds 		realdatastart = textpos + ntohl(hdr->data_start);
6062217b982SMax Filippov 		datapos = ALIGN(realdatastart +
60704d82a6dSDamien Le Moal 				DATA_START_OFFSET_WORDS * sizeof(u32),
6082217b982SMax Filippov 				FLAT_DATA_ALIGN);
609c3dc5becSOskar Schirmer 
6103b977718SChristoph Hellwig 		reloc = (__be32 __user *)
611c3dc5becSOskar Schirmer 			(datapos + (ntohl(hdr->reloc_start) - text_len));
6121da177e4SLinus Torvalds 		memp = textpos;
6130f3e442aSDavid Howells 		memp_size = len;
6141da177e4SLinus Torvalds #ifdef CONFIG_BINFMT_ZFLAT
6151da177e4SLinus Torvalds 		/*
6161da177e4SLinus Torvalds 		 * load it all in and treat it like a RAM load from now on
6171da177e4SLinus Torvalds 		 */
6181da177e4SLinus Torvalds 		if (flags & FLAT_FLAG_GZIP) {
619472f95f3SNicolas Pitre #ifndef CONFIG_MMU
6201da177e4SLinus Torvalds 			result = decompress_exec(bprm, sizeof(struct flat_hdr),
6211da177e4SLinus Torvalds 					 (((char *)textpos) + sizeof(struct flat_hdr)),
6223dc20cb2SAl Viro 					 (text_len + full_data
6231da177e4SLinus Torvalds 						  - sizeof(struct flat_hdr)),
6241da177e4SLinus Torvalds 					 0);
6251da177e4SLinus Torvalds 			memmove((void *) datapos, (void *) realdatastart,
6263dc20cb2SAl Viro 					full_data);
627472f95f3SNicolas Pitre #else
628472f95f3SNicolas Pitre 			/*
629472f95f3SNicolas Pitre 			 * This is used on MMU systems mainly for testing.
630472f95f3SNicolas Pitre 			 * Let's use a kernel buffer to simplify things.
631472f95f3SNicolas Pitre 			 */
632472f95f3SNicolas Pitre 			long unz_text_len = text_len - sizeof(struct flat_hdr);
633472f95f3SNicolas Pitre 			long unz_len = unz_text_len + full_data;
634472f95f3SNicolas Pitre 			char *unz_data = vmalloc(unz_len);
635472f95f3SNicolas Pitre 			if (!unz_data) {
636472f95f3SNicolas Pitre 				result = -ENOMEM;
637472f95f3SNicolas Pitre 			} else {
638472f95f3SNicolas Pitre 				result = decompress_exec(bprm, sizeof(struct flat_hdr),
639472f95f3SNicolas Pitre 							 unz_data, unz_len, 0);
640472f95f3SNicolas Pitre 				if (result == 0 &&
641472f95f3SNicolas Pitre 				    (copy_to_user((void __user *)textpos + sizeof(struct flat_hdr),
642472f95f3SNicolas Pitre 						  unz_data, unz_text_len) ||
643472f95f3SNicolas Pitre 				     copy_to_user((void __user *)datapos,
644472f95f3SNicolas Pitre 						  unz_data + unz_text_len, full_data)))
645472f95f3SNicolas Pitre 					result = -EFAULT;
646472f95f3SNicolas Pitre 				vfree(unz_data);
647472f95f3SNicolas Pitre 			}
648472f95f3SNicolas Pitre #endif
6491da177e4SLinus Torvalds 		} else if (flags & FLAT_FLAG_GZDATA) {
6503dc20cb2SAl Viro 			result = read_code(bprm->file, textpos, 0, text_len);
651472f95f3SNicolas Pitre 			if (!IS_ERR_VALUE(result)) {
652472f95f3SNicolas Pitre #ifndef CONFIG_MMU
6531da177e4SLinus Torvalds 				result = decompress_exec(bprm, text_len, (char *) datapos,
6543dc20cb2SAl Viro 						 full_data, 0);
655472f95f3SNicolas Pitre #else
656472f95f3SNicolas Pitre 				char *unz_data = vmalloc(full_data);
657472f95f3SNicolas Pitre 				if (!unz_data) {
658472f95f3SNicolas Pitre 					result = -ENOMEM;
659472f95f3SNicolas Pitre 				} else {
660472f95f3SNicolas Pitre 					result = decompress_exec(bprm, text_len,
661472f95f3SNicolas Pitre 						       unz_data, full_data, 0);
662472f95f3SNicolas Pitre 					if (result == 0 &&
663472f95f3SNicolas Pitre 					    copy_to_user((void __user *)datapos,
664472f95f3SNicolas Pitre 							 unz_data, full_data))
665472f95f3SNicolas Pitre 						result = -EFAULT;
666472f95f3SNicolas Pitre 					vfree(unz_data);
667472f95f3SNicolas Pitre 				}
6681da177e4SLinus Torvalds #endif
669472f95f3SNicolas Pitre 			}
670472f95f3SNicolas Pitre 		} else
671472f95f3SNicolas Pitre #endif /* CONFIG_BINFMT_ZFLAT */
6721da177e4SLinus Torvalds 		{
6733dc20cb2SAl Viro 			result = read_code(bprm->file, textpos, 0, text_len);
6743dc20cb2SAl Viro 			if (!IS_ERR_VALUE(result))
6753dc20cb2SAl Viro 				result = read_code(bprm->file, datapos,
6763dc20cb2SAl Viro 						   ntohl(hdr->data_start),
6773dc20cb2SAl Viro 						   full_data);
6781da177e4SLinus Torvalds 		}
6790b8c78f2SMike Frysinger 		if (IS_ERR_VALUE(result)) {
68013c3f50cSNicolas Pitre 			ret = result;
6814adbb6acSNicolas Pitre 			pr_err("Unable to read code+data+bss, errno %d\n", ret);
6822217b982SMax Filippov 			vm_munmap(textpos, text_len + data_len + extra +
68304d82a6dSDamien Le Moal 				  DATA_START_OFFSET_WORDS * sizeof(u32));
684df88912aSAndrew Morton 			goto err;
6851da177e4SLinus Torvalds 		}
6861da177e4SLinus Torvalds 	}
6871da177e4SLinus Torvalds 
6881da177e4SLinus Torvalds 	start_code = textpos + sizeof(struct flat_hdr);
6891da177e4SLinus Torvalds 	end_code = textpos + text_len;
69013c3f50cSNicolas Pitre 	text_len -= sizeof(struct flat_hdr); /* the real code len */
69113c3f50cSNicolas Pitre 
69213c3f50cSNicolas Pitre 	/* The main program needs a little extra setup in the task structure */
6931da177e4SLinus Torvalds 	current->mm->start_code = start_code;
6941da177e4SLinus Torvalds 	current->mm->end_code = end_code;
6951da177e4SLinus Torvalds 	current->mm->start_data = datapos;
6961da177e4SLinus Torvalds 	current->mm->end_data = datapos + data_len;
6971da177e4SLinus Torvalds 	/*
6981da177e4SLinus Torvalds 	 * set up the brk stuff, uses any slack left in data/bss/stack
6991da177e4SLinus Torvalds 	 * allocation.  We put the brk after the bss (between the bss
7001da177e4SLinus Torvalds 	 * and stack) like other platforms.
7010f3e442aSDavid Howells 	 * Userspace code relies on the stack pointer starting out at
7020f3e442aSDavid Howells 	 * an address right at the end of a page.
7031da177e4SLinus Torvalds 	 */
7041da177e4SLinus Torvalds 	current->mm->start_brk = datapos + data_len + bss_len;
7051da177e4SLinus Torvalds 	current->mm->brk = (current->mm->start_brk + 3) & ~3;
706015feacfSNicolas Pitre #ifndef CONFIG_MMU
7070f3e442aSDavid Howells 	current->mm->context.end_brk = memp + memp_size - stack_len;
708015feacfSNicolas Pitre #endif
7091da177e4SLinus Torvalds 
71013c3f50cSNicolas Pitre 	if (flags & FLAT_FLAG_KTRACE) {
7114adbb6acSNicolas Pitre 		pr_info("Mapping is %lx, Entry point is %x, data_start is %x\n",
71213c3f50cSNicolas Pitre 			textpos, 0x00ffffff&ntohl(hdr->entry), ntohl(hdr->data_start));
7134adbb6acSNicolas Pitre 		pr_info("%s %s: TEXT=%lx-%lx DATA=%lx-%lx BSS=%lx-%lx\n",
714*70578ff3SEric W. Biederman 			"Load", bprm->filename,
71513c3f50cSNicolas Pitre 			start_code, end_code, datapos, datapos + data_len,
71613c3f50cSNicolas Pitre 			datapos + data_len, (datapos + data_len + bss_len + 3) & ~3);
71713c3f50cSNicolas Pitre 	}
7181da177e4SLinus Torvalds 
7191da177e4SLinus Torvalds 	/* Store the current module values into the global library structure */
720*70578ff3SEric W. Biederman 	libinfo->lib_list[0].start_code = start_code;
721*70578ff3SEric W. Biederman 	libinfo->lib_list[0].start_data = datapos;
722*70578ff3SEric W. Biederman 	libinfo->lib_list[0].start_brk = datapos + data_len + bss_len;
723*70578ff3SEric W. Biederman 	libinfo->lib_list[0].text_len = text_len;
724*70578ff3SEric W. Biederman 	libinfo->lib_list[0].loaded = 1;
725*70578ff3SEric W. Biederman 	libinfo->lib_list[0].entry = (0x00ffffff & ntohl(hdr->entry)) + textpos;
726*70578ff3SEric W. Biederman 	libinfo->lib_list[0].build_date = ntohl(hdr->build_date);
7271da177e4SLinus Torvalds 
7281da177e4SLinus Torvalds 	/*
7291da177e4SLinus Torvalds 	 * We just load the allocations into some temporary memory to
7301da177e4SLinus Torvalds 	 * help simplify all this mumbo jumbo
7311da177e4SLinus Torvalds 	 *
7321da177e4SLinus Torvalds 	 * We've got two different sections of relocation entries.
73325985edcSLucas De Marchi 	 * The first is the GOT which resides at the beginning of the data segment
7341da177e4SLinus Torvalds 	 * and is terminated with a -1.  This one can be relocated in place.
7351da177e4SLinus Torvalds 	 * The second is the extra relocation entries tacked after the image's
7361da177e4SLinus Torvalds 	 * data segment. These require a little more processing as the entry is
7371da177e4SLinus Torvalds 	 * really an offset into the image which contains an offset into the
7381da177e4SLinus Torvalds 	 * image.
7391da177e4SLinus Torvalds 	 */
7401da177e4SLinus Torvalds 	if (flags & FLAT_FLAG_GOTPIC) {
7416045ab5fSNiklas Cassel 		rp = skip_got_header((u32 __user *) datapos);
7426045ab5fSNiklas Cassel 		for (; ; rp++) {
743468138d7SAl Viro 			u32 addr, rp_val;
7446e572ffeSNicolas Pitre 			if (get_user(rp_val, rp))
7456e572ffeSNicolas Pitre 				return -EFAULT;
7466e572ffeSNicolas Pitre 			if (rp_val == 0xffffffff)
7476e572ffeSNicolas Pitre 				break;
7486e572ffeSNicolas Pitre 			if (rp_val) {
749*70578ff3SEric W. Biederman 				addr = calc_reloc(rp_val, libinfo);
7501ad3dcc0SLuke Yang 				if (addr == RELOC_FAILED) {
7511ad3dcc0SLuke Yang 					ret = -ENOEXEC;
752df88912aSAndrew Morton 					goto err;
7531ad3dcc0SLuke Yang 				}
7546e572ffeSNicolas Pitre 				if (put_user(addr, rp))
7556e572ffeSNicolas Pitre 					return -EFAULT;
7561da177e4SLinus Torvalds 			}
7571da177e4SLinus Torvalds 		}
7581da177e4SLinus Torvalds 	}
7591da177e4SLinus Torvalds 
7601da177e4SLinus Torvalds 	/*
7611da177e4SLinus Torvalds 	 * Now run through the relocation entries.
7621da177e4SLinus Torvalds 	 * We've got to be careful here as C++ produces relocatable zero
7631da177e4SLinus Torvalds 	 * entries in the constructor and destructor tables which are then
7641da177e4SLinus Torvalds 	 * tested for being not zero (which will always occur unless we're
7651da177e4SLinus Torvalds 	 * based from address zero).  This causes an endless loop as __start
7661da177e4SLinus Torvalds 	 * is at zero.  The solution used is to not relocate zero addresses.
7671da177e4SLinus Torvalds 	 * This has the negative side effect of not allowing a global data
7681da177e4SLinus Torvalds 	 * reference to be statically initialised to _stext (I've moved
7691da177e4SLinus Torvalds 	 * __start to address 4 so that is okay).
7701da177e4SLinus Torvalds 	 */
7711da177e4SLinus Torvalds 	if (rev > OLD_FLAT_VERSION) {
7721da177e4SLinus Torvalds 		for (i = 0; i < relocs; i++) {
773468138d7SAl Viro 			u32 addr, relval;
7743b977718SChristoph Hellwig 			__be32 tmp;
7751da177e4SLinus Torvalds 
77613c3f50cSNicolas Pitre 			/*
77713c3f50cSNicolas Pitre 			 * Get the address of the pointer to be
77813c3f50cSNicolas Pitre 			 * relocated (of course, the address has to be
77913c3f50cSNicolas Pitre 			 * relocated first).
78013c3f50cSNicolas Pitre 			 */
7813b977718SChristoph Hellwig 			if (get_user(tmp, reloc + i))
7826e572ffeSNicolas Pitre 				return -EFAULT;
7833b977718SChristoph Hellwig 			relval = ntohl(tmp);
7841da177e4SLinus Torvalds 			addr = flat_get_relocate_addr(relval);
785*70578ff3SEric W. Biederman 			rp = (u32 __user *)calc_reloc(addr, libinfo);
786468138d7SAl Viro 			if (rp == (u32 __user *)RELOC_FAILED) {
7871ad3dcc0SLuke Yang 				ret = -ENOEXEC;
788df88912aSAndrew Morton 				goto err;
7891ad3dcc0SLuke Yang 			}
7901da177e4SLinus Torvalds 
7911da177e4SLinus Torvalds 			/* Get the pointer's value.  */
7926843d8aaSChristoph Hellwig 			ret = flat_get_addr_from_rp(rp, relval, flags, &addr);
793468138d7SAl Viro 			if (unlikely(ret))
794468138d7SAl Viro 				goto err;
795468138d7SAl Viro 
7961da177e4SLinus Torvalds 			if (addr != 0) {
7971da177e4SLinus Torvalds 				/*
7981da177e4SLinus Torvalds 				 * Do the relocation.  PIC relocs in the data section are
7991da177e4SLinus Torvalds 				 * already in target order
8001da177e4SLinus Torvalds 				 */
8013b977718SChristoph Hellwig 				if ((flags & FLAT_FLAG_GOTPIC) == 0) {
8023b977718SChristoph Hellwig 					/*
8033b977718SChristoph Hellwig 					 * Meh, the same value can have a different
8043b977718SChristoph Hellwig 					 * byte order based on a flag..
8053b977718SChristoph Hellwig 					 */
8063b977718SChristoph Hellwig 					addr = ntohl((__force __be32)addr);
8073b977718SChristoph Hellwig 				}
808*70578ff3SEric W. Biederman 				addr = calc_reloc(addr, libinfo);
8091ad3dcc0SLuke Yang 				if (addr == RELOC_FAILED) {
8101ad3dcc0SLuke Yang 					ret = -ENOEXEC;
811df88912aSAndrew Morton 					goto err;
8121ad3dcc0SLuke Yang 				}
8131da177e4SLinus Torvalds 
8141da177e4SLinus Torvalds 				/* Write back the relocated pointer.  */
815468138d7SAl Viro 				ret = flat_put_addr_at_rp(rp, addr, relval);
816468138d7SAl Viro 				if (unlikely(ret))
817468138d7SAl Viro 					goto err;
8181da177e4SLinus Torvalds 			}
8191da177e4SLinus Torvalds 		}
820cf9a566cSChristoph Hellwig #ifdef CONFIG_BINFMT_FLAT_OLD
8211da177e4SLinus Torvalds 	} else {
8221b2ce442SNicolas Pitre 		for (i = 0; i < relocs; i++) {
8233b977718SChristoph Hellwig 			__be32 relval;
8241b2ce442SNicolas Pitre 			if (get_user(relval, reloc + i))
8251b2ce442SNicolas Pitre 				return -EFAULT;
8263b977718SChristoph Hellwig 			old_reloc(ntohl(relval));
8271b2ce442SNicolas Pitre 		}
828cf9a566cSChristoph Hellwig #endif /* CONFIG_BINFMT_FLAT_OLD */
8291da177e4SLinus Torvalds 	}
8301da177e4SLinus Torvalds 
83179ef1e1fSChristoph Hellwig 	flush_icache_user_range(start_code, end_code);
8321da177e4SLinus Torvalds 
8331da177e4SLinus Torvalds 	/* zero the BSS,  BRK and stack areas */
834467aa146SNicolas Pitre 	if (clear_user((void __user *)(datapos + data_len), bss_len +
8350f3e442aSDavid Howells 		       (memp + memp_size - stack_len -		/* end brk */
836*70578ff3SEric W. Biederman 		       libinfo->lib_list[0].start_brk) +	/* start brk */
837467aa146SNicolas Pitre 		       stack_len))
838467aa146SNicolas Pitre 		return -EFAULT;
8391da177e4SLinus Torvalds 
8401da177e4SLinus Torvalds 	return 0;
8411ad3dcc0SLuke Yang err:
8421ad3dcc0SLuke Yang 	return ret;
8431da177e4SLinus Torvalds }
8441da177e4SLinus Torvalds 
8451da177e4SLinus Torvalds 
8461da177e4SLinus Torvalds /****************************************************************************/
8471da177e4SLinus Torvalds 
8481da177e4SLinus Torvalds /*
8491da177e4SLinus Torvalds  * These are the functions used to load flat style executables and shared
8501da177e4SLinus Torvalds  * libraries.  There is no binary dependent code anywhere else.
8511da177e4SLinus Torvalds  */
8521da177e4SLinus Torvalds 
load_flat_binary(struct linux_binprm * bprm)85371613c3bSAl Viro static int load_flat_binary(struct linux_binprm *bprm)
8541da177e4SLinus Torvalds {
8551da177e4SLinus Torvalds 	struct lib_info libinfo;
85671613c3bSAl Viro 	struct pt_regs *regs = current_pt_regs();
857015feacfSNicolas Pitre 	unsigned long stack_len = 0;
8581da177e4SLinus Torvalds 	unsigned long start_addr;
8591da177e4SLinus Torvalds 	int res;
8601da177e4SLinus Torvalds 	int i, j;
8611da177e4SLinus Torvalds 
8621da177e4SLinus Torvalds 	memset(&libinfo, 0, sizeof(libinfo));
86313c3f50cSNicolas Pitre 
8641da177e4SLinus Torvalds 	/*
8651da177e4SLinus Torvalds 	 * We have to add the size of our arguments to our stack size
8661da177e4SLinus Torvalds 	 * otherwise it's too easy for users to create stack overflows
8671da177e4SLinus Torvalds 	 * by passing in a huge argument list.  And yes,  we have to be
8681da177e4SLinus Torvalds 	 * pedantic and include space for the argv/envp array as it may have
8691da177e4SLinus Torvalds 	 * a lot of entries.
8701da177e4SLinus Torvalds 	 */
871015feacfSNicolas Pitre #ifndef CONFIG_MMU
872015feacfSNicolas Pitre 	stack_len += PAGE_SIZE * MAX_ARG_PAGES - bprm->p; /* the strings */
873015feacfSNicolas Pitre #endif
8741da177e4SLinus Torvalds 	stack_len += (bprm->argc + 1) * sizeof(char *);   /* the argv array */
8751da177e4SLinus Torvalds 	stack_len += (bprm->envc + 1) * sizeof(char *);   /* the envp array */
876a97d157dSNicolas Pitre 	stack_len = ALIGN(stack_len, FLAT_STACK_ALIGN);
8771da177e4SLinus Torvalds 
878*70578ff3SEric W. Biederman 	res = load_flat_file(bprm, &libinfo, &stack_len);
879287980e4SArnd Bergmann 	if (res < 0)
8801da177e4SLinus Torvalds 		return res;
8811da177e4SLinus Torvalds 
8821da177e4SLinus Torvalds 	/* Update data segment pointers for all libraries */
883af521f92SNicolas Pitre 	for (i = 0; i < MAX_SHARED_LIBS; i++) {
884af521f92SNicolas Pitre 		if (!libinfo.lib_list[i].loaded)
885af521f92SNicolas Pitre 			continue;
886af521f92SNicolas Pitre 		for (j = 0; j < MAX_SHARED_LIBS; j++) {
887af521f92SNicolas Pitre 			unsigned long val = libinfo.lib_list[j].loaded ?
8881da177e4SLinus Torvalds 				libinfo.lib_list[j].start_data : UNLOADED_LIB;
889af521f92SNicolas Pitre 			unsigned long __user *p = (unsigned long __user *)
890af521f92SNicolas Pitre 				libinfo.lib_list[i].start_data;
891af521f92SNicolas Pitre 			p -= j + 1;
892af521f92SNicolas Pitre 			if (put_user(val, p))
893af521f92SNicolas Pitre 				return -EFAULT;
894af521f92SNicolas Pitre 		}
895af521f92SNicolas Pitre 	}
8961da177e4SLinus Torvalds 
8971da177e4SLinus Torvalds 	set_binfmt(&flat_format);
8981da177e4SLinus Torvalds 
899015feacfSNicolas Pitre #ifdef CONFIG_MMU
900015feacfSNicolas Pitre 	res = setup_arg_pages(bprm, STACK_TOP, EXSTACK_DEFAULT);
901015feacfSNicolas Pitre 	if (!res)
902015feacfSNicolas Pitre 		res = create_flat_tables(bprm, bprm->p);
903015feacfSNicolas Pitre #else
904a97d157dSNicolas Pitre 	/* Stash our initial stack pointer into the mm structure */
905a97d157dSNicolas Pitre 	current->mm->start_stack =
906a97d157dSNicolas Pitre 		((current->mm->context.end_brk + stack_len + 3) & ~3) - 4;
907a97d157dSNicolas Pitre 	pr_debug("sp=%lx\n", current->mm->start_stack);
9081da177e4SLinus Torvalds 
909687fd773SNicolas Pitre 	/* copy the arg pages onto the stack */
910a97d157dSNicolas Pitre 	res = transfer_args_to_stack(bprm, &current->mm->start_stack);
911a97d157dSNicolas Pitre 	if (!res)
912a97d157dSNicolas Pitre 		res = create_flat_tables(bprm, current->mm->start_stack);
913015feacfSNicolas Pitre #endif
914687fd773SNicolas Pitre 	if (res)
915687fd773SNicolas Pitre 		return res;
9161da177e4SLinus Torvalds 
9171da177e4SLinus Torvalds 	/* Fake some return addresses to ensure the call chain will
9181da177e4SLinus Torvalds 	 * initialise library in order for us.  We are required to call
9191da177e4SLinus Torvalds 	 * lib 1 first, then 2, ... and finally the main program (id 0).
9201da177e4SLinus Torvalds 	 */
9211da177e4SLinus Torvalds 	start_addr = libinfo.lib_list[0].entry;
9221da177e4SLinus Torvalds 
92374c27c43STakashi YOSHII #ifdef FLAT_PLAT_INIT
92474c27c43STakashi YOSHII 	FLAT_PLAT_INIT(regs);
92574c27c43STakashi YOSHII #endif
9261da177e4SLinus Torvalds 
927b8383831SKees Cook 	finalize_exec(bprm);
9284adbb6acSNicolas Pitre 	pr_debug("start_thread(regs=0x%p, entry=0x%lx, start_stack=0x%lx)\n",
92913c3f50cSNicolas Pitre 		 regs, start_addr, current->mm->start_stack);
9301da177e4SLinus Torvalds 	start_thread(regs, start_addr, current->mm->start_stack);
9311da177e4SLinus Torvalds 
9321da177e4SLinus Torvalds 	return 0;
9331da177e4SLinus Torvalds }
9341da177e4SLinus Torvalds 
9351da177e4SLinus Torvalds /****************************************************************************/
9361da177e4SLinus Torvalds 
init_flat_binfmt(void)9371da177e4SLinus Torvalds static int __init init_flat_binfmt(void)
9381da177e4SLinus Torvalds {
9398fc3dc5aSAl Viro 	register_binfmt(&flat_format);
9408fc3dc5aSAl Viro 	return 0;
9411da177e4SLinus Torvalds }
9421da177e4SLinus Torvalds core_initcall(init_flat_binfmt);
9431da177e4SLinus Torvalds 
9441da177e4SLinus Torvalds /****************************************************************************/
945