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)
7549df34d2SKees Cook #define MAX_SHARED_LIBS_UPDATE (0)
7604d82a6dSDamien Le Moal #else
7704d82a6dSDamien Le Moal #define DATA_START_OFFSET_WORDS (MAX_SHARED_LIBS)
7849df34d2SKees Cook #define MAX_SHARED_LIBS_UPDATE (MAX_SHARED_LIBS)
7904d82a6dSDamien Le Moal #endif
8004d82a6dSDamien Le Moal
811da177e4SLinus Torvalds struct lib_info {
821da177e4SLinus Torvalds struct {
831da177e4SLinus Torvalds unsigned long start_code; /* Start of text segment */
841da177e4SLinus Torvalds unsigned long start_data; /* Start of data segment */
851da177e4SLinus Torvalds unsigned long start_brk; /* End of data segment */
861da177e4SLinus Torvalds unsigned long text_len; /* Length of text segment */
871da177e4SLinus Torvalds unsigned long entry; /* Start address for this module */
881da177e4SLinus Torvalds unsigned long build_date; /* When this one was compiled */
8913c3f50cSNicolas Pitre bool loaded; /* Has this library been loaded? */
901da177e4SLinus Torvalds } lib_list[MAX_SHARED_LIBS];
911da177e4SLinus Torvalds };
921da177e4SLinus Torvalds
9371613c3bSAl Viro static int load_flat_binary(struct linux_binprm *);
941da177e4SLinus Torvalds
951da177e4SLinus Torvalds static struct linux_binfmt flat_format = {
961da177e4SLinus Torvalds .module = THIS_MODULE,
971da177e4SLinus Torvalds .load_binary = load_flat_binary,
981da177e4SLinus Torvalds };
991da177e4SLinus Torvalds
1001da177e4SLinus Torvalds
1011da177e4SLinus Torvalds /****************************************************************************/
1021da177e4SLinus Torvalds /*
1031da177e4SLinus Torvalds * create_flat_tables() parses the env- and arg-strings in new user
1041da177e4SLinus Torvalds * memory and creates the pointer tables from them, and puts their
105a97d157dSNicolas Pitre * addresses on the "stack", recording the new stack pointer value.
1061da177e4SLinus Torvalds */
1071da177e4SLinus Torvalds
create_flat_tables(struct linux_binprm * bprm,unsigned long arg_start)108a97d157dSNicolas Pitre static int create_flat_tables(struct linux_binprm *bprm, unsigned long arg_start)
1091da177e4SLinus Torvalds {
110a97d157dSNicolas Pitre char __user *p;
111a97d157dSNicolas Pitre unsigned long __user *sp;
112a97d157dSNicolas Pitre long i, len;
1131da177e4SLinus Torvalds
114a97d157dSNicolas Pitre p = (char __user *)arg_start;
115a97d157dSNicolas Pitre sp = (unsigned long __user *)current->mm->start_stack;
1161da177e4SLinus Torvalds
117a97d157dSNicolas Pitre sp -= bprm->envc + 1;
118a97d157dSNicolas Pitre sp -= bprm->argc + 1;
119bdd15a28SChristoph Hellwig if (IS_ENABLED(CONFIG_BINFMT_FLAT_ARGVP_ENVP_ON_STACK))
120bdd15a28SChristoph Hellwig sp -= 2; /* argvp + envp */
121a97d157dSNicolas Pitre sp -= 1; /* &argc */
122a97d157dSNicolas Pitre
123a97d157dSNicolas Pitre current->mm->start_stack = (unsigned long)sp & -FLAT_STACK_ALIGN;
124a97d157dSNicolas Pitre sp = (unsigned long __user *)current->mm->start_stack;
125a97d157dSNicolas Pitre
1268861fd57SAl Viro if (put_user(bprm->argc, sp++))
1278861fd57SAl Viro return -EFAULT;
128bdd15a28SChristoph Hellwig if (IS_ENABLED(CONFIG_BINFMT_FLAT_ARGVP_ENVP_ON_STACK)) {
129a97d157dSNicolas Pitre unsigned long argv, envp;
130a97d157dSNicolas Pitre argv = (unsigned long)(sp + 2);
131a97d157dSNicolas Pitre envp = (unsigned long)(sp + 2 + bprm->argc + 1);
1328861fd57SAl Viro if (put_user(argv, sp++) || put_user(envp, sp++))
1338861fd57SAl Viro return -EFAULT;
1341da177e4SLinus Torvalds }
1351da177e4SLinus Torvalds
1361da177e4SLinus Torvalds current->mm->arg_start = (unsigned long)p;
137a97d157dSNicolas Pitre for (i = bprm->argc; i > 0; i--) {
1388861fd57SAl Viro if (put_user((unsigned long)p, sp++))
1398861fd57SAl Viro return -EFAULT;
140a97d157dSNicolas Pitre len = strnlen_user(p, MAX_ARG_STRLEN);
141a97d157dSNicolas Pitre if (!len || len > MAX_ARG_STRLEN)
142a97d157dSNicolas Pitre return -EINVAL;
143a97d157dSNicolas Pitre p += len;
1441da177e4SLinus Torvalds }
1458861fd57SAl Viro if (put_user(0, sp++))
1468861fd57SAl Viro return -EFAULT;
147a97d157dSNicolas Pitre current->mm->arg_end = (unsigned long)p;
148a97d157dSNicolas Pitre
149a97d157dSNicolas Pitre current->mm->env_start = (unsigned long) p;
150a97d157dSNicolas Pitre for (i = bprm->envc; i > 0; i--) {
1518861fd57SAl Viro if (put_user((unsigned long)p, sp++))
1528861fd57SAl Viro return -EFAULT;
153a97d157dSNicolas Pitre len = strnlen_user(p, MAX_ARG_STRLEN);
154a97d157dSNicolas Pitre if (!len || len > MAX_ARG_STRLEN)
155a97d157dSNicolas Pitre return -EINVAL;
156a97d157dSNicolas Pitre p += len;
1571da177e4SLinus Torvalds }
1588861fd57SAl Viro if (put_user(0, sp++))
1598861fd57SAl Viro return -EFAULT;
1601da177e4SLinus Torvalds current->mm->env_end = (unsigned long)p;
161a97d157dSNicolas Pitre
162a97d157dSNicolas Pitre return 0;
1631da177e4SLinus Torvalds }
1641da177e4SLinus Torvalds
1651da177e4SLinus Torvalds /****************************************************************************/
1661da177e4SLinus Torvalds
1671da177e4SLinus Torvalds #ifdef CONFIG_BINFMT_ZFLAT
1681da177e4SLinus Torvalds
1691da177e4SLinus Torvalds #include <linux/zlib.h>
1701da177e4SLinus Torvalds
1711da177e4SLinus Torvalds #define LBUFSIZE 4000
1721da177e4SLinus Torvalds
1731da177e4SLinus Torvalds /* gzip flag byte */
1741da177e4SLinus Torvalds #define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */
1751da177e4SLinus Torvalds #define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
1761da177e4SLinus Torvalds #define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
1771da177e4SLinus Torvalds #define ORIG_NAME 0x08 /* bit 3 set: original file name present */
1781da177e4SLinus Torvalds #define COMMENT 0x10 /* bit 4 set: file comment present */
1791da177e4SLinus Torvalds #define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */
1801da177e4SLinus Torvalds #define RESERVED 0xC0 /* bit 6,7: reserved */
1811da177e4SLinus Torvalds
decompress_exec(struct linux_binprm * bprm,loff_t fpos,char * dst,long len,int fd)182bdd1d2d3SChristoph Hellwig static int decompress_exec(struct linux_binprm *bprm, loff_t fpos, char *dst,
183bdd1d2d3SChristoph Hellwig long len, int fd)
1841da177e4SLinus Torvalds {
1851da177e4SLinus Torvalds unsigned char *buf;
1861da177e4SLinus Torvalds z_stream strm;
1871da177e4SLinus Torvalds int ret, retval;
1881da177e4SLinus Torvalds
189bdd1d2d3SChristoph Hellwig pr_debug("decompress_exec(offset=%llx,buf=%p,len=%lx)\n", fpos, dst, len);
1901da177e4SLinus Torvalds
1911da177e4SLinus Torvalds memset(&strm, 0, sizeof(strm));
1921da177e4SLinus Torvalds strm.workspace = kmalloc(zlib_inflate_workspacesize(), GFP_KERNEL);
1939367bb73SMarkus Elfring if (!strm.workspace)
1941da177e4SLinus Torvalds return -ENOMEM;
1959367bb73SMarkus Elfring
1961da177e4SLinus Torvalds buf = kmalloc(LBUFSIZE, GFP_KERNEL);
1979367bb73SMarkus Elfring if (!buf) {
1981da177e4SLinus Torvalds retval = -ENOMEM;
1991da177e4SLinus Torvalds goto out_free;
2001da177e4SLinus Torvalds }
2011da177e4SLinus Torvalds
2021da177e4SLinus Torvalds /* Read in first chunk of data and parse gzip header. */
203bdd1d2d3SChristoph Hellwig ret = kernel_read(bprm->file, buf, LBUFSIZE, &fpos);
2041da177e4SLinus Torvalds
2051da177e4SLinus Torvalds strm.next_in = buf;
2061da177e4SLinus Torvalds strm.avail_in = ret;
2071da177e4SLinus Torvalds strm.total_in = 0;
2081da177e4SLinus Torvalds
2091da177e4SLinus Torvalds retval = -ENOEXEC;
2101da177e4SLinus Torvalds
2111da177e4SLinus Torvalds /* Check minimum size -- gzip header */
2121da177e4SLinus Torvalds if (ret < 10) {
2134adbb6acSNicolas Pitre pr_debug("file too small?\n");
2141da177e4SLinus Torvalds goto out_free_buf;
2151da177e4SLinus Torvalds }
2161da177e4SLinus Torvalds
2171da177e4SLinus Torvalds /* Check gzip magic number */
2181da177e4SLinus Torvalds if ((buf[0] != 037) || ((buf[1] != 0213) && (buf[1] != 0236))) {
2194adbb6acSNicolas Pitre pr_debug("unknown compression magic?\n");
2201da177e4SLinus Torvalds goto out_free_buf;
2211da177e4SLinus Torvalds }
2221da177e4SLinus Torvalds
2231da177e4SLinus Torvalds /* Check gzip method */
2241da177e4SLinus Torvalds if (buf[2] != 8) {
2254adbb6acSNicolas Pitre pr_debug("unknown compression method?\n");
2261da177e4SLinus Torvalds goto out_free_buf;
2271da177e4SLinus Torvalds }
2281da177e4SLinus Torvalds /* Check gzip flags */
2291da177e4SLinus Torvalds if ((buf[3] & ENCRYPTED) || (buf[3] & CONTINUATION) ||
2301da177e4SLinus Torvalds (buf[3] & RESERVED)) {
2314adbb6acSNicolas Pitre pr_debug("unknown flags?\n");
2321da177e4SLinus Torvalds goto out_free_buf;
2331da177e4SLinus Torvalds }
2341da177e4SLinus Torvalds
2351da177e4SLinus Torvalds ret = 10;
2361da177e4SLinus Torvalds if (buf[3] & EXTRA_FIELD) {
2371da177e4SLinus Torvalds ret += 2 + buf[10] + (buf[11] << 8);
23813c3f50cSNicolas Pitre if (unlikely(ret >= LBUFSIZE)) {
2394adbb6acSNicolas Pitre pr_debug("buffer overflow (EXTRA)?\n");
2401da177e4SLinus Torvalds goto out_free_buf;
2411da177e4SLinus Torvalds }
2421da177e4SLinus Torvalds }
2431da177e4SLinus Torvalds if (buf[3] & ORIG_NAME) {
244f4cfb18dSVolodymyr G. Lukiianyk while (ret < LBUFSIZE && buf[ret++] != 0)
2451da177e4SLinus Torvalds ;
24613c3f50cSNicolas Pitre if (unlikely(ret == LBUFSIZE)) {
2474adbb6acSNicolas Pitre pr_debug("buffer overflow (ORIG_NAME)?\n");
2481da177e4SLinus Torvalds goto out_free_buf;
2491da177e4SLinus Torvalds }
2501da177e4SLinus Torvalds }
2511da177e4SLinus Torvalds if (buf[3] & COMMENT) {
252f4cfb18dSVolodymyr G. Lukiianyk while (ret < LBUFSIZE && buf[ret++] != 0)
2531da177e4SLinus Torvalds ;
25413c3f50cSNicolas Pitre if (unlikely(ret == LBUFSIZE)) {
2554adbb6acSNicolas Pitre pr_debug("buffer overflow (COMMENT)?\n");
2561da177e4SLinus Torvalds goto out_free_buf;
2571da177e4SLinus Torvalds }
2581da177e4SLinus Torvalds }
2591da177e4SLinus Torvalds
2601da177e4SLinus Torvalds strm.next_in += ret;
2611da177e4SLinus Torvalds strm.avail_in -= ret;
2621da177e4SLinus Torvalds
2631da177e4SLinus Torvalds strm.next_out = dst;
2641da177e4SLinus Torvalds strm.avail_out = len;
2651da177e4SLinus Torvalds strm.total_out = 0;
2661da177e4SLinus Torvalds
2671da177e4SLinus Torvalds if (zlib_inflateInit2(&strm, -MAX_WBITS) != Z_OK) {
2684adbb6acSNicolas Pitre pr_debug("zlib init failed?\n");
2691da177e4SLinus Torvalds goto out_free_buf;
2701da177e4SLinus Torvalds }
2711da177e4SLinus Torvalds
2721da177e4SLinus Torvalds while ((ret = zlib_inflate(&strm, Z_NO_FLUSH)) == Z_OK) {
273bdd1d2d3SChristoph Hellwig ret = kernel_read(bprm->file, buf, LBUFSIZE, &fpos);
2741da177e4SLinus Torvalds if (ret <= 0)
2751da177e4SLinus Torvalds break;
2761da177e4SLinus Torvalds len -= ret;
2771da177e4SLinus Torvalds
2781da177e4SLinus Torvalds strm.next_in = buf;
2791da177e4SLinus Torvalds strm.avail_in = ret;
2801da177e4SLinus Torvalds strm.total_in = 0;
2811da177e4SLinus Torvalds }
2821da177e4SLinus Torvalds
2831da177e4SLinus Torvalds if (ret < 0) {
2844adbb6acSNicolas Pitre pr_debug("decompression failed (%d), %s\n",
2851da177e4SLinus Torvalds ret, strm.msg);
2861da177e4SLinus Torvalds goto out_zlib;
2871da177e4SLinus Torvalds }
2881da177e4SLinus Torvalds
2891da177e4SLinus Torvalds retval = 0;
2901da177e4SLinus Torvalds out_zlib:
2911da177e4SLinus Torvalds zlib_inflateEnd(&strm);
2921da177e4SLinus Torvalds out_free_buf:
2931da177e4SLinus Torvalds kfree(buf);
2941da177e4SLinus Torvalds out_free:
2951da177e4SLinus Torvalds kfree(strm.workspace);
2961da177e4SLinus Torvalds return retval;
2971da177e4SLinus Torvalds }
2981da177e4SLinus Torvalds
2991da177e4SLinus Torvalds #endif /* CONFIG_BINFMT_ZFLAT */
3001da177e4SLinus Torvalds
3011da177e4SLinus Torvalds /****************************************************************************/
3021da177e4SLinus Torvalds
3031da177e4SLinus Torvalds static unsigned long
calc_reloc(unsigned long r,struct lib_info * p)30470578ff3SEric W. Biederman calc_reloc(unsigned long r, struct lib_info *p)
3051da177e4SLinus Torvalds {
3061da177e4SLinus Torvalds unsigned long addr;
3071da177e4SLinus Torvalds unsigned long start_brk;
3081da177e4SLinus Torvalds unsigned long start_data;
3091da177e4SLinus Torvalds unsigned long text_len;
3101da177e4SLinus Torvalds unsigned long start_code;
3111da177e4SLinus Torvalds
31270578ff3SEric W. Biederman start_brk = p->lib_list[0].start_brk;
31370578ff3SEric W. Biederman start_data = p->lib_list[0].start_data;
31470578ff3SEric W. Biederman start_code = p->lib_list[0].start_code;
31570578ff3SEric W. Biederman text_len = p->lib_list[0].text_len;
3161da177e4SLinus Torvalds
3179ee24b2aSChristoph Hellwig if (r > start_brk - start_data + text_len) {
3184adbb6acSNicolas Pitre pr_err("reloc outside program 0x%lx (0 - 0x%lx/0x%lx)",
31913c3f50cSNicolas Pitre r, start_brk-start_data+text_len, text_len);
3201da177e4SLinus Torvalds goto failed;
3211da177e4SLinus Torvalds }
3221da177e4SLinus Torvalds
3231da177e4SLinus Torvalds if (r < text_len) /* In text segment */
3241da177e4SLinus Torvalds addr = r + start_code;
3251da177e4SLinus Torvalds else /* In data segment */
3261da177e4SLinus Torvalds addr = r - text_len + start_data;
3271da177e4SLinus Torvalds
3281da177e4SLinus Torvalds /* Range checked already above so doing the range tests is redundant...*/
32913c3f50cSNicolas Pitre return addr;
3301da177e4SLinus Torvalds
3311da177e4SLinus Torvalds failed:
3324adbb6acSNicolas Pitre pr_cont(", killing %s!\n", current->comm);
3331da177e4SLinus Torvalds send_sig(SIGSEGV, current, 0);
3341da177e4SLinus Torvalds
3351da177e4SLinus Torvalds return RELOC_FAILED;
3361da177e4SLinus Torvalds }
3371da177e4SLinus Torvalds
3381da177e4SLinus Torvalds /****************************************************************************/
3391da177e4SLinus Torvalds
340cf9a566cSChristoph Hellwig #ifdef CONFIG_BINFMT_FLAT_OLD
old_reloc(unsigned long rl)34134303435SAxel Lin static void old_reloc(unsigned long rl)
3421da177e4SLinus Torvalds {
34313c3f50cSNicolas Pitre static const char *segment[] = { "TEXT", "DATA", "BSS", "*UNKNOWN*" };
3441da177e4SLinus Torvalds flat_v2_reloc_t r;
3451b2ce442SNicolas Pitre unsigned long __user *ptr;
3461b2ce442SNicolas Pitre unsigned long val;
3471da177e4SLinus Torvalds
3481da177e4SLinus Torvalds r.value = rl;
3491da177e4SLinus Torvalds #if defined(CONFIG_COLDFIRE)
3501b2ce442SNicolas Pitre ptr = (unsigned long __user *)(current->mm->start_code + r.reloc.offset);
3511da177e4SLinus Torvalds #else
3521b2ce442SNicolas Pitre ptr = (unsigned long __user *)(current->mm->start_data + r.reloc.offset);
3531da177e4SLinus Torvalds #endif
3541b2ce442SNicolas Pitre get_user(val, ptr);
3551da177e4SLinus Torvalds
3564adbb6acSNicolas Pitre pr_debug("Relocation of variable at DATASEG+%x "
35713c3f50cSNicolas Pitre "(address %p, currently %lx) into segment %s\n",
3581b2ce442SNicolas Pitre r.reloc.offset, ptr, val, segment[r.reloc.type]);
3591da177e4SLinus Torvalds
3601da177e4SLinus Torvalds switch (r.reloc.type) {
3611da177e4SLinus Torvalds case OLD_FLAT_RELOC_TYPE_TEXT:
3621b2ce442SNicolas Pitre val += current->mm->start_code;
3631da177e4SLinus Torvalds break;
3641da177e4SLinus Torvalds case OLD_FLAT_RELOC_TYPE_DATA:
3651b2ce442SNicolas Pitre val += current->mm->start_data;
3661da177e4SLinus Torvalds break;
3671da177e4SLinus Torvalds case OLD_FLAT_RELOC_TYPE_BSS:
3681b2ce442SNicolas Pitre val += current->mm->end_data;
3691da177e4SLinus Torvalds break;
3701da177e4SLinus Torvalds default:
3714adbb6acSNicolas Pitre pr_err("Unknown relocation type=%x\n", r.reloc.type);
3721da177e4SLinus Torvalds break;
3731da177e4SLinus Torvalds }
3741b2ce442SNicolas Pitre put_user(val, ptr);
3751da177e4SLinus Torvalds
3761b2ce442SNicolas Pitre pr_debug("Relocation became %lx\n", val);
3771da177e4SLinus Torvalds }
378cf9a566cSChristoph Hellwig #endif /* CONFIG_BINFMT_FLAT_OLD */
3791da177e4SLinus Torvalds
3801da177e4SLinus Torvalds /****************************************************************************/
3811da177e4SLinus Torvalds
skip_got_header(u32 __user * rp)3826045ab5fSNiklas Cassel static inline u32 __user *skip_got_header(u32 __user *rp)
3836045ab5fSNiklas Cassel {
3846045ab5fSNiklas Cassel if (IS_ENABLED(CONFIG_RISCV)) {
3856045ab5fSNiklas Cassel /*
3866045ab5fSNiklas Cassel * RISC-V has a 16 byte GOT PLT header for elf64-riscv
3876045ab5fSNiklas Cassel * and 8 byte GOT PLT header for elf32-riscv.
3886045ab5fSNiklas Cassel * Skip the whole GOT PLT header, since it is reserved
3896045ab5fSNiklas Cassel * for the dynamic linker (ld.so).
3906045ab5fSNiklas Cassel */
3916045ab5fSNiklas Cassel u32 rp_val0, rp_val1;
3926045ab5fSNiklas Cassel
3936045ab5fSNiklas Cassel if (get_user(rp_val0, rp))
3946045ab5fSNiklas Cassel return rp;
3956045ab5fSNiklas Cassel if (get_user(rp_val1, rp + 1))
3966045ab5fSNiklas Cassel return rp;
3976045ab5fSNiklas Cassel
3986045ab5fSNiklas Cassel if (rp_val0 == 0xffffffff && rp_val1 == 0xffffffff)
3996045ab5fSNiklas Cassel rp += 4;
4006045ab5fSNiklas Cassel else if (rp_val0 == 0xffffffff)
4016045ab5fSNiklas Cassel rp += 2;
4026045ab5fSNiklas Cassel }
4036045ab5fSNiklas Cassel return rp;
4046045ab5fSNiklas Cassel }
4056045ab5fSNiklas Cassel
load_flat_file(struct linux_binprm * bprm,struct lib_info * libinfo,unsigned long * extra_stack)4061da177e4SLinus Torvalds static int load_flat_file(struct linux_binprm *bprm,
40770578ff3SEric W. Biederman struct lib_info *libinfo, unsigned long *extra_stack)
4081da177e4SLinus Torvalds {
4091da177e4SLinus Torvalds struct flat_hdr *hdr;
41013c3f50cSNicolas Pitre unsigned long textpos, datapos, realdatastart;
411468138d7SAl Viro u32 text_len, data_len, bss_len, stack_len, full_data, flags;
41213c3f50cSNicolas Pitre unsigned long len, memp, memp_size, extra, rlim;
4133b977718SChristoph Hellwig __be32 __user *reloc;
4143b977718SChristoph Hellwig u32 __user *rp;
41513c3f50cSNicolas Pitre int i, rev, relocs;
4161da177e4SLinus Torvalds loff_t fpos;
4171da177e4SLinus Torvalds unsigned long start_code, end_code;
41813c3f50cSNicolas Pitre ssize_t result;
4191ad3dcc0SLuke Yang int ret;
4201da177e4SLinus Torvalds
4211da177e4SLinus Torvalds hdr = ((struct flat_hdr *) bprm->buf); /* exec-header */
4221da177e4SLinus Torvalds
4231da177e4SLinus Torvalds text_len = ntohl(hdr->data_start);
4241da177e4SLinus Torvalds data_len = ntohl(hdr->data_end) - ntohl(hdr->data_start);
4251da177e4SLinus Torvalds bss_len = ntohl(hdr->bss_end) - ntohl(hdr->data_end);
4261da177e4SLinus Torvalds stack_len = ntohl(hdr->stack_size);
4271da177e4SLinus Torvalds if (extra_stack) {
4281da177e4SLinus Torvalds stack_len += *extra_stack;
4291da177e4SLinus Torvalds *extra_stack = stack_len;
4301da177e4SLinus Torvalds }
4311da177e4SLinus Torvalds relocs = ntohl(hdr->reloc_count);
4321da177e4SLinus Torvalds flags = ntohl(hdr->flags);
4331da177e4SLinus Torvalds rev = ntohl(hdr->rev);
4343dc20cb2SAl Viro full_data = data_len + relocs * sizeof(unsigned long);
4351da177e4SLinus Torvalds
436845884d3SGreg Ungerer if (strncmp(hdr->magic, "bFLT", 4)) {
4371da177e4SLinus Torvalds /*
438e2a366dcSMike Frysinger * Previously, here was a printk to tell people
439e2a366dcSMike Frysinger * "BINFMT_FLAT: bad header magic".
440e2a366dcSMike Frysinger * But for the kernel which also use ELF FD-PIC format, this
441e2a366dcSMike Frysinger * error message is confusing.
4421da177e4SLinus Torvalds * because a lot of people do not manage to produce good
4431da177e4SLinus Torvalds */
4441ad3dcc0SLuke Yang ret = -ENOEXEC;
4451ad3dcc0SLuke Yang goto err;
446845884d3SGreg Ungerer }
447845884d3SGreg Ungerer
448845884d3SGreg Ungerer if (flags & FLAT_FLAG_KTRACE)
4494adbb6acSNicolas Pitre pr_info("Loading file: %s\n", bprm->filename);
450845884d3SGreg Ungerer
451cf9a566cSChristoph Hellwig #ifdef CONFIG_BINFMT_FLAT_OLD
452845884d3SGreg Ungerer if (rev != FLAT_VERSION && rev != OLD_FLAT_VERSION) {
4534adbb6acSNicolas Pitre pr_err("bad flat file version 0x%x (supported 0x%lx and 0x%lx)\n",
4540e647c04SAndrew Morton rev, FLAT_VERSION, OLD_FLAT_VERSION);
4551ad3dcc0SLuke Yang ret = -ENOEXEC;
4561ad3dcc0SLuke Yang goto err;
4571da177e4SLinus Torvalds }
4581da177e4SLinus Torvalds
4591da177e4SLinus Torvalds /*
460cf9a566cSChristoph Hellwig * fix up the flags for the older format, there were all kinds
461cf9a566cSChristoph Hellwig * of endian hacks, this only works for the simple cases
462cf9a566cSChristoph Hellwig */
463cf9a566cSChristoph Hellwig if (rev == OLD_FLAT_VERSION &&
464cf9a566cSChristoph Hellwig (flags || IS_ENABLED(CONFIG_BINFMT_FLAT_OLD_ALWAYS_RAM)))
465cf9a566cSChristoph Hellwig flags = FLAT_FLAG_RAM;
466cf9a566cSChristoph Hellwig
467cf9a566cSChristoph Hellwig #else /* CONFIG_BINFMT_FLAT_OLD */
468cf9a566cSChristoph Hellwig if (rev != FLAT_VERSION) {
469cf9a566cSChristoph Hellwig pr_err("bad flat file version 0x%x (supported 0x%lx)\n",
470cf9a566cSChristoph Hellwig rev, FLAT_VERSION);
471cf9a566cSChristoph Hellwig ret = -ENOEXEC;
472cf9a566cSChristoph Hellwig goto err;
473cf9a566cSChristoph Hellwig }
474cf9a566cSChristoph Hellwig #endif /* !CONFIG_BINFMT_FLAT_OLD */
475cf9a566cSChristoph Hellwig
476cf9a566cSChristoph Hellwig /*
477c995ee28SNicolas Pitre * Make sure the header params are sane.
478c995ee28SNicolas Pitre * 28 bits (256 MB) is way more than reasonable in this case.
479c995ee28SNicolas Pitre * If some top bits are set we have probable binary corruption.
480c995ee28SNicolas Pitre */
481*d17ca8f2SDan Carpenter if ((text_len | data_len | bss_len | stack_len | relocs | full_data) >> 28) {
482c995ee28SNicolas Pitre pr_err("bad header\n");
483c995ee28SNicolas Pitre ret = -ENOEXEC;
484c995ee28SNicolas Pitre goto err;
485c995ee28SNicolas Pitre }
486c995ee28SNicolas Pitre
4871da177e4SLinus Torvalds #ifndef CONFIG_BINFMT_ZFLAT
4881da177e4SLinus Torvalds if (flags & (FLAT_FLAG_GZIP|FLAT_FLAG_GZDATA)) {
4894adbb6acSNicolas Pitre pr_err("Support for ZFLAT executables is not enabled.\n");
4901ad3dcc0SLuke Yang ret = -ENOEXEC;
4911ad3dcc0SLuke Yang goto err;
4921da177e4SLinus Torvalds }
4931da177e4SLinus Torvalds #endif
4941da177e4SLinus Torvalds
4951da177e4SLinus Torvalds /*
4961da177e4SLinus Torvalds * Check initial limits. This avoids letting people circumvent
4971da177e4SLinus Torvalds * size limits imposed on them by creating programs with large
4981da177e4SLinus Torvalds * arrays in the data or bss.
4991da177e4SLinus Torvalds */
500d554ed89SJiri Slaby rlim = rlimit(RLIMIT_DATA);
5011da177e4SLinus Torvalds if (rlim >= RLIM_INFINITY)
5021da177e4SLinus Torvalds rlim = ~0;
5031ad3dcc0SLuke Yang if (data_len + bss_len > rlim) {
5041ad3dcc0SLuke Yang ret = -ENOMEM;
5051ad3dcc0SLuke Yang goto err;
5061ad3dcc0SLuke Yang }
5071ad3dcc0SLuke Yang
5081da177e4SLinus Torvalds /* Flush all traces of the currently running executable */
5092388777aSEric W. Biederman ret = begin_new_exec(bprm);
51013c3f50cSNicolas Pitre if (ret)
511df88912aSAndrew Morton goto err;
5121da177e4SLinus Torvalds
5131da177e4SLinus Torvalds /* OK, This is the point of no return */
514fcc18e83SMalcolm Parsons set_personality(PER_LINUX_32BIT);
515221af7f8SLinus Torvalds setup_new_exec(bprm);
5161da177e4SLinus Torvalds
5171da177e4SLinus Torvalds /*
5181da177e4SLinus Torvalds * calculate the extra space we need to map in
5191da177e4SLinus Torvalds */
5200e647c04SAndrew Morton extra = max_t(unsigned long, bss_len + stack_len,
5210e647c04SAndrew Morton relocs * sizeof(unsigned long));
5221da177e4SLinus Torvalds
5231da177e4SLinus Torvalds /*
5241da177e4SLinus Torvalds * there are a couple of cases here, the separate code/data
5251da177e4SLinus Torvalds * case, and then the fully copied to RAM case which lumps
5261da177e4SLinus Torvalds * it all together.
5271da177e4SLinus Torvalds */
528015feacfSNicolas Pitre if (!IS_ENABLED(CONFIG_MMU) && !(flags & (FLAT_FLAG_RAM|FLAT_FLAG_GZIP))) {
5291da177e4SLinus Torvalds /*
5301da177e4SLinus Torvalds * this should give us a ROM ptr, but if it doesn't we don't
5311da177e4SLinus Torvalds * really care
5321da177e4SLinus Torvalds */
5334adbb6acSNicolas Pitre pr_debug("ROM mapping of file (we hope)\n");
5341da177e4SLinus Torvalds
5356be5ceb0SLinus Torvalds textpos = vm_mmap(bprm->file, 0, text_len, PROT_READ|PROT_EXEC,
536a4eec6a3SDavid Hildenbrand MAP_PRIVATE, 0);
5370b8c78f2SMike Frysinger if (!textpos || IS_ERR_VALUE(textpos)) {
5381ad3dcc0SLuke Yang ret = textpos;
53913c3f50cSNicolas Pitre if (!textpos)
54013c3f50cSNicolas Pitre ret = -ENOMEM;
5414adbb6acSNicolas Pitre pr_err("Unable to mmap process text, errno %d\n", ret);
542df88912aSAndrew Morton goto err;
5431da177e4SLinus Torvalds }
5441da177e4SLinus Torvalds
54504d82a6dSDamien Le Moal len = data_len + extra +
54604d82a6dSDamien Le Moal DATA_START_OFFSET_WORDS * sizeof(unsigned long);
5470f3e442aSDavid Howells len = PAGE_ALIGN(len);
54813c3f50cSNicolas Pitre realdatastart = vm_mmap(NULL, 0, len,
5498f5bb043SYoshinori Sato PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE, 0);
5501da177e4SLinus Torvalds
5510b8c78f2SMike Frysinger if (realdatastart == 0 || IS_ERR_VALUE(realdatastart)) {
5521ad3dcc0SLuke Yang ret = realdatastart;
55313c3f50cSNicolas Pitre if (!realdatastart)
55413c3f50cSNicolas Pitre ret = -ENOMEM;
5554adbb6acSNicolas Pitre pr_err("Unable to allocate RAM for process data, "
55613c3f50cSNicolas Pitre "errno %d\n", ret);
55713c3f50cSNicolas Pitre vm_munmap(textpos, text_len);
558df88912aSAndrew Morton goto err;
5591da177e4SLinus Torvalds }
5602217b982SMax Filippov datapos = ALIGN(realdatastart +
56104d82a6dSDamien Le Moal DATA_START_OFFSET_WORDS * sizeof(unsigned long),
5622217b982SMax Filippov FLAT_DATA_ALIGN);
5631da177e4SLinus Torvalds
564a8605423SGeert Uytterhoeven pr_debug("Allocated data+bss+stack (%u bytes): %lx\n",
56513c3f50cSNicolas Pitre data_len + bss_len + stack_len, datapos);
5661da177e4SLinus Torvalds
5671da177e4SLinus Torvalds fpos = ntohl(hdr->data_start);
5681da177e4SLinus Torvalds #ifdef CONFIG_BINFMT_ZFLAT
5691da177e4SLinus Torvalds if (flags & FLAT_FLAG_GZDATA) {
5701da177e4SLinus Torvalds result = decompress_exec(bprm, fpos, (char *)datapos,
5713dc20cb2SAl Viro full_data, 0);
5721da177e4SLinus Torvalds } else
5731da177e4SLinus Torvalds #endif
5741da177e4SLinus Torvalds {
5753dc20cb2SAl Viro result = read_code(bprm->file, datapos, fpos,
5763dc20cb2SAl Viro full_data);
5771da177e4SLinus Torvalds }
5780b8c78f2SMike Frysinger if (IS_ERR_VALUE(result)) {
57913c3f50cSNicolas Pitre ret = result;
5804adbb6acSNicolas Pitre pr_err("Unable to read data+bss, errno %d\n", ret);
5817696e0c3SAl Viro vm_munmap(textpos, text_len);
5827696e0c3SAl Viro vm_munmap(realdatastart, len);
583df88912aSAndrew Morton goto err;
5841da177e4SLinus Torvalds }
5851da177e4SLinus Torvalds
5863b977718SChristoph Hellwig reloc = (__be32 __user *)
58713c3f50cSNicolas Pitre (datapos + (ntohl(hdr->reloc_start) - text_len));
5881da177e4SLinus Torvalds memp = realdatastart;
5890f3e442aSDavid Howells memp_size = len;
5901da177e4SLinus Torvalds } else {
5911da177e4SLinus Torvalds
59204d82a6dSDamien Le Moal len = text_len + data_len + extra +
59304d82a6dSDamien Le Moal DATA_START_OFFSET_WORDS * sizeof(u32);
5940f3e442aSDavid Howells len = PAGE_ALIGN(len);
59513c3f50cSNicolas Pitre textpos = vm_mmap(NULL, 0, len,
5968f5bb043SYoshinori Sato PROT_READ | PROT_EXEC | PROT_WRITE, MAP_PRIVATE, 0);
59772613e5fSGreg Ungerer
5980b8c78f2SMike Frysinger if (!textpos || IS_ERR_VALUE(textpos)) {
5991ad3dcc0SLuke Yang ret = textpos;
60013c3f50cSNicolas Pitre if (!textpos)
60113c3f50cSNicolas Pitre ret = -ENOMEM;
6024adbb6acSNicolas Pitre pr_err("Unable to allocate RAM for process text/data, "
60313c3f50cSNicolas Pitre "errno %d\n", ret);
604df88912aSAndrew Morton goto err;
6051da177e4SLinus Torvalds }
6061da177e4SLinus Torvalds
6071da177e4SLinus Torvalds realdatastart = textpos + ntohl(hdr->data_start);
6082217b982SMax Filippov datapos = ALIGN(realdatastart +
60904d82a6dSDamien Le Moal DATA_START_OFFSET_WORDS * sizeof(u32),
6102217b982SMax Filippov FLAT_DATA_ALIGN);
611c3dc5becSOskar Schirmer
6123b977718SChristoph Hellwig reloc = (__be32 __user *)
613c3dc5becSOskar Schirmer (datapos + (ntohl(hdr->reloc_start) - text_len));
6141da177e4SLinus Torvalds memp = textpos;
6150f3e442aSDavid Howells memp_size = len;
6161da177e4SLinus Torvalds #ifdef CONFIG_BINFMT_ZFLAT
6171da177e4SLinus Torvalds /*
6181da177e4SLinus Torvalds * load it all in and treat it like a RAM load from now on
6191da177e4SLinus Torvalds */
6201da177e4SLinus Torvalds if (flags & FLAT_FLAG_GZIP) {
621472f95f3SNicolas Pitre #ifndef CONFIG_MMU
6221da177e4SLinus Torvalds result = decompress_exec(bprm, sizeof(struct flat_hdr),
6231da177e4SLinus Torvalds (((char *)textpos) + sizeof(struct flat_hdr)),
6243dc20cb2SAl Viro (text_len + full_data
6251da177e4SLinus Torvalds - sizeof(struct flat_hdr)),
6261da177e4SLinus Torvalds 0);
6271da177e4SLinus Torvalds memmove((void *) datapos, (void *) realdatastart,
6283dc20cb2SAl Viro full_data);
629472f95f3SNicolas Pitre #else
630472f95f3SNicolas Pitre /*
631472f95f3SNicolas Pitre * This is used on MMU systems mainly for testing.
632472f95f3SNicolas Pitre * Let's use a kernel buffer to simplify things.
633472f95f3SNicolas Pitre */
634472f95f3SNicolas Pitre long unz_text_len = text_len - sizeof(struct flat_hdr);
635472f95f3SNicolas Pitre long unz_len = unz_text_len + full_data;
636472f95f3SNicolas Pitre char *unz_data = vmalloc(unz_len);
637472f95f3SNicolas Pitre if (!unz_data) {
638472f95f3SNicolas Pitre result = -ENOMEM;
639472f95f3SNicolas Pitre } else {
640472f95f3SNicolas Pitre result = decompress_exec(bprm, sizeof(struct flat_hdr),
641472f95f3SNicolas Pitre unz_data, unz_len, 0);
642472f95f3SNicolas Pitre if (result == 0 &&
643472f95f3SNicolas Pitre (copy_to_user((void __user *)textpos + sizeof(struct flat_hdr),
644472f95f3SNicolas Pitre unz_data, unz_text_len) ||
645472f95f3SNicolas Pitre copy_to_user((void __user *)datapos,
646472f95f3SNicolas Pitre unz_data + unz_text_len, full_data)))
647472f95f3SNicolas Pitre result = -EFAULT;
648472f95f3SNicolas Pitre vfree(unz_data);
649472f95f3SNicolas Pitre }
650472f95f3SNicolas Pitre #endif
6511da177e4SLinus Torvalds } else if (flags & FLAT_FLAG_GZDATA) {
6523dc20cb2SAl Viro result = read_code(bprm->file, textpos, 0, text_len);
653472f95f3SNicolas Pitre if (!IS_ERR_VALUE(result)) {
654472f95f3SNicolas Pitre #ifndef CONFIG_MMU
6551da177e4SLinus Torvalds result = decompress_exec(bprm, text_len, (char *) datapos,
6563dc20cb2SAl Viro full_data, 0);
657472f95f3SNicolas Pitre #else
658472f95f3SNicolas Pitre char *unz_data = vmalloc(full_data);
659472f95f3SNicolas Pitre if (!unz_data) {
660472f95f3SNicolas Pitre result = -ENOMEM;
661472f95f3SNicolas Pitre } else {
662472f95f3SNicolas Pitre result = decompress_exec(bprm, text_len,
663472f95f3SNicolas Pitre unz_data, full_data, 0);
664472f95f3SNicolas Pitre if (result == 0 &&
665472f95f3SNicolas Pitre copy_to_user((void __user *)datapos,
666472f95f3SNicolas Pitre unz_data, full_data))
667472f95f3SNicolas Pitre result = -EFAULT;
668472f95f3SNicolas Pitre vfree(unz_data);
669472f95f3SNicolas Pitre }
6701da177e4SLinus Torvalds #endif
671472f95f3SNicolas Pitre }
672472f95f3SNicolas Pitre } else
673472f95f3SNicolas Pitre #endif /* CONFIG_BINFMT_ZFLAT */
6741da177e4SLinus Torvalds {
6753dc20cb2SAl Viro result = read_code(bprm->file, textpos, 0, text_len);
6763dc20cb2SAl Viro if (!IS_ERR_VALUE(result))
6773dc20cb2SAl Viro result = read_code(bprm->file, datapos,
6783dc20cb2SAl Viro ntohl(hdr->data_start),
6793dc20cb2SAl Viro full_data);
6801da177e4SLinus Torvalds }
6810b8c78f2SMike Frysinger if (IS_ERR_VALUE(result)) {
68213c3f50cSNicolas Pitre ret = result;
6834adbb6acSNicolas Pitre pr_err("Unable to read code+data+bss, errno %d\n", ret);
6842217b982SMax Filippov vm_munmap(textpos, text_len + data_len + extra +
68504d82a6dSDamien Le Moal DATA_START_OFFSET_WORDS * sizeof(u32));
686df88912aSAndrew Morton goto err;
6871da177e4SLinus Torvalds }
6881da177e4SLinus Torvalds }
6891da177e4SLinus Torvalds
6901da177e4SLinus Torvalds start_code = textpos + sizeof(struct flat_hdr);
6911da177e4SLinus Torvalds end_code = textpos + text_len;
69213c3f50cSNicolas Pitre text_len -= sizeof(struct flat_hdr); /* the real code len */
69313c3f50cSNicolas Pitre
69413c3f50cSNicolas Pitre /* The main program needs a little extra setup in the task structure */
6951da177e4SLinus Torvalds current->mm->start_code = start_code;
6961da177e4SLinus Torvalds current->mm->end_code = end_code;
6971da177e4SLinus Torvalds current->mm->start_data = datapos;
6981da177e4SLinus Torvalds current->mm->end_data = datapos + data_len;
6991da177e4SLinus Torvalds /*
7001da177e4SLinus Torvalds * set up the brk stuff, uses any slack left in data/bss/stack
7011da177e4SLinus Torvalds * allocation. We put the brk after the bss (between the bss
7021da177e4SLinus Torvalds * and stack) like other platforms.
7030f3e442aSDavid Howells * Userspace code relies on the stack pointer starting out at
7040f3e442aSDavid Howells * an address right at the end of a page.
7051da177e4SLinus Torvalds */
7061da177e4SLinus Torvalds current->mm->start_brk = datapos + data_len + bss_len;
7071da177e4SLinus Torvalds current->mm->brk = (current->mm->start_brk + 3) & ~3;
708015feacfSNicolas Pitre #ifndef CONFIG_MMU
7090f3e442aSDavid Howells current->mm->context.end_brk = memp + memp_size - stack_len;
710015feacfSNicolas Pitre #endif
7111da177e4SLinus Torvalds
71213c3f50cSNicolas Pitre if (flags & FLAT_FLAG_KTRACE) {
7134adbb6acSNicolas Pitre pr_info("Mapping is %lx, Entry point is %x, data_start is %x\n",
71413c3f50cSNicolas Pitre textpos, 0x00ffffff&ntohl(hdr->entry), ntohl(hdr->data_start));
7154adbb6acSNicolas Pitre pr_info("%s %s: TEXT=%lx-%lx DATA=%lx-%lx BSS=%lx-%lx\n",
71670578ff3SEric W. Biederman "Load", bprm->filename,
71713c3f50cSNicolas Pitre start_code, end_code, datapos, datapos + data_len,
71813c3f50cSNicolas Pitre datapos + data_len, (datapos + data_len + bss_len + 3) & ~3);
71913c3f50cSNicolas Pitre }
7201da177e4SLinus Torvalds
7211da177e4SLinus Torvalds /* Store the current module values into the global library structure */
72270578ff3SEric W. Biederman libinfo->lib_list[0].start_code = start_code;
72370578ff3SEric W. Biederman libinfo->lib_list[0].start_data = datapos;
72470578ff3SEric W. Biederman libinfo->lib_list[0].start_brk = datapos + data_len + bss_len;
72570578ff3SEric W. Biederman libinfo->lib_list[0].text_len = text_len;
72670578ff3SEric W. Biederman libinfo->lib_list[0].loaded = 1;
72770578ff3SEric W. Biederman libinfo->lib_list[0].entry = (0x00ffffff & ntohl(hdr->entry)) + textpos;
72870578ff3SEric W. Biederman libinfo->lib_list[0].build_date = ntohl(hdr->build_date);
7291da177e4SLinus Torvalds
7301da177e4SLinus Torvalds /*
7311da177e4SLinus Torvalds * We just load the allocations into some temporary memory to
7321da177e4SLinus Torvalds * help simplify all this mumbo jumbo
7331da177e4SLinus Torvalds *
7341da177e4SLinus Torvalds * We've got two different sections of relocation entries.
73525985edcSLucas De Marchi * The first is the GOT which resides at the beginning of the data segment
7361da177e4SLinus Torvalds * and is terminated with a -1. This one can be relocated in place.
7371da177e4SLinus Torvalds * The second is the extra relocation entries tacked after the image's
7381da177e4SLinus Torvalds * data segment. These require a little more processing as the entry is
7391da177e4SLinus Torvalds * really an offset into the image which contains an offset into the
7401da177e4SLinus Torvalds * image.
7411da177e4SLinus Torvalds */
7421da177e4SLinus Torvalds if (flags & FLAT_FLAG_GOTPIC) {
7436045ab5fSNiklas Cassel rp = skip_got_header((u32 __user *) datapos);
7446045ab5fSNiklas Cassel for (; ; rp++) {
745468138d7SAl Viro u32 addr, rp_val;
7466e572ffeSNicolas Pitre if (get_user(rp_val, rp))
7476e572ffeSNicolas Pitre return -EFAULT;
7486e572ffeSNicolas Pitre if (rp_val == 0xffffffff)
7496e572ffeSNicolas Pitre break;
7506e572ffeSNicolas Pitre if (rp_val) {
75170578ff3SEric W. Biederman addr = calc_reloc(rp_val, libinfo);
7521ad3dcc0SLuke Yang if (addr == RELOC_FAILED) {
7531ad3dcc0SLuke Yang ret = -ENOEXEC;
754df88912aSAndrew Morton goto err;
7551ad3dcc0SLuke Yang }
7566e572ffeSNicolas Pitre if (put_user(addr, rp))
7576e572ffeSNicolas Pitre return -EFAULT;
7581da177e4SLinus Torvalds }
7591da177e4SLinus Torvalds }
7601da177e4SLinus Torvalds }
7611da177e4SLinus Torvalds
7621da177e4SLinus Torvalds /*
7631da177e4SLinus Torvalds * Now run through the relocation entries.
7641da177e4SLinus Torvalds * We've got to be careful here as C++ produces relocatable zero
7651da177e4SLinus Torvalds * entries in the constructor and destructor tables which are then
7661da177e4SLinus Torvalds * tested for being not zero (which will always occur unless we're
7671da177e4SLinus Torvalds * based from address zero). This causes an endless loop as __start
7681da177e4SLinus Torvalds * is at zero. The solution used is to not relocate zero addresses.
7691da177e4SLinus Torvalds * This has the negative side effect of not allowing a global data
7701da177e4SLinus Torvalds * reference to be statically initialised to _stext (I've moved
7711da177e4SLinus Torvalds * __start to address 4 so that is okay).
7721da177e4SLinus Torvalds */
7731da177e4SLinus Torvalds if (rev > OLD_FLAT_VERSION) {
7741da177e4SLinus Torvalds for (i = 0; i < relocs; i++) {
775468138d7SAl Viro u32 addr, relval;
7763b977718SChristoph Hellwig __be32 tmp;
7771da177e4SLinus Torvalds
77813c3f50cSNicolas Pitre /*
77913c3f50cSNicolas Pitre * Get the address of the pointer to be
78013c3f50cSNicolas Pitre * relocated (of course, the address has to be
78113c3f50cSNicolas Pitre * relocated first).
78213c3f50cSNicolas Pitre */
7833b977718SChristoph Hellwig if (get_user(tmp, reloc + i))
7846e572ffeSNicolas Pitre return -EFAULT;
7853b977718SChristoph Hellwig relval = ntohl(tmp);
7861da177e4SLinus Torvalds addr = flat_get_relocate_addr(relval);
78770578ff3SEric W. Biederman rp = (u32 __user *)calc_reloc(addr, libinfo);
788468138d7SAl Viro if (rp == (u32 __user *)RELOC_FAILED) {
7891ad3dcc0SLuke Yang ret = -ENOEXEC;
790df88912aSAndrew Morton goto err;
7911ad3dcc0SLuke Yang }
7921da177e4SLinus Torvalds
7931da177e4SLinus Torvalds /* Get the pointer's value. */
7946843d8aaSChristoph Hellwig ret = flat_get_addr_from_rp(rp, relval, flags, &addr);
795468138d7SAl Viro if (unlikely(ret))
796468138d7SAl Viro goto err;
797468138d7SAl Viro
7981da177e4SLinus Torvalds if (addr != 0) {
7991da177e4SLinus Torvalds /*
8001da177e4SLinus Torvalds * Do the relocation. PIC relocs in the data section are
8011da177e4SLinus Torvalds * already in target order
8021da177e4SLinus Torvalds */
8033b977718SChristoph Hellwig if ((flags & FLAT_FLAG_GOTPIC) == 0) {
8043b977718SChristoph Hellwig /*
8053b977718SChristoph Hellwig * Meh, the same value can have a different
8063b977718SChristoph Hellwig * byte order based on a flag..
8073b977718SChristoph Hellwig */
8083b977718SChristoph Hellwig addr = ntohl((__force __be32)addr);
8093b977718SChristoph Hellwig }
81070578ff3SEric W. Biederman addr = calc_reloc(addr, libinfo);
8111ad3dcc0SLuke Yang if (addr == RELOC_FAILED) {
8121ad3dcc0SLuke Yang ret = -ENOEXEC;
813df88912aSAndrew Morton goto err;
8141ad3dcc0SLuke Yang }
8151da177e4SLinus Torvalds
8161da177e4SLinus Torvalds /* Write back the relocated pointer. */
817468138d7SAl Viro ret = flat_put_addr_at_rp(rp, addr, relval);
818468138d7SAl Viro if (unlikely(ret))
819468138d7SAl Viro goto err;
8201da177e4SLinus Torvalds }
8211da177e4SLinus Torvalds }
822cf9a566cSChristoph Hellwig #ifdef CONFIG_BINFMT_FLAT_OLD
8231da177e4SLinus Torvalds } else {
8241b2ce442SNicolas Pitre for (i = 0; i < relocs; i++) {
8253b977718SChristoph Hellwig __be32 relval;
8261b2ce442SNicolas Pitre if (get_user(relval, reloc + i))
8271b2ce442SNicolas Pitre return -EFAULT;
8283b977718SChristoph Hellwig old_reloc(ntohl(relval));
8291b2ce442SNicolas Pitre }
830cf9a566cSChristoph Hellwig #endif /* CONFIG_BINFMT_FLAT_OLD */
8311da177e4SLinus Torvalds }
8321da177e4SLinus Torvalds
83379ef1e1fSChristoph Hellwig flush_icache_user_range(start_code, end_code);
8341da177e4SLinus Torvalds
8351da177e4SLinus Torvalds /* zero the BSS, BRK and stack areas */
836467aa146SNicolas Pitre if (clear_user((void __user *)(datapos + data_len), bss_len +
8370f3e442aSDavid Howells (memp + memp_size - stack_len - /* end brk */
83870578ff3SEric W. Biederman libinfo->lib_list[0].start_brk) + /* start brk */
839467aa146SNicolas Pitre stack_len))
840467aa146SNicolas Pitre return -EFAULT;
8411da177e4SLinus Torvalds
8421da177e4SLinus Torvalds return 0;
8431ad3dcc0SLuke Yang err:
8441ad3dcc0SLuke Yang return ret;
8451da177e4SLinus Torvalds }
8461da177e4SLinus Torvalds
8471da177e4SLinus Torvalds
8481da177e4SLinus Torvalds /****************************************************************************/
8491da177e4SLinus Torvalds
8501da177e4SLinus Torvalds /*
8511da177e4SLinus Torvalds * These are the functions used to load flat style executables and shared
8521da177e4SLinus Torvalds * libraries. There is no binary dependent code anywhere else.
8531da177e4SLinus Torvalds */
8541da177e4SLinus Torvalds
load_flat_binary(struct linux_binprm * bprm)85571613c3bSAl Viro static int load_flat_binary(struct linux_binprm *bprm)
8561da177e4SLinus Torvalds {
8571da177e4SLinus Torvalds struct lib_info libinfo;
85871613c3bSAl Viro struct pt_regs *regs = current_pt_regs();
859015feacfSNicolas Pitre unsigned long stack_len = 0;
8601da177e4SLinus Torvalds unsigned long start_addr;
8611da177e4SLinus Torvalds int res;
8621da177e4SLinus Torvalds int i, j;
8631da177e4SLinus Torvalds
8641da177e4SLinus Torvalds memset(&libinfo, 0, sizeof(libinfo));
86513c3f50cSNicolas Pitre
8661da177e4SLinus Torvalds /*
8671da177e4SLinus Torvalds * We have to add the size of our arguments to our stack size
8681da177e4SLinus Torvalds * otherwise it's too easy for users to create stack overflows
8691da177e4SLinus Torvalds * by passing in a huge argument list. And yes, we have to be
8701da177e4SLinus Torvalds * pedantic and include space for the argv/envp array as it may have
8711da177e4SLinus Torvalds * a lot of entries.
8721da177e4SLinus Torvalds */
873015feacfSNicolas Pitre #ifndef CONFIG_MMU
874015feacfSNicolas Pitre stack_len += PAGE_SIZE * MAX_ARG_PAGES - bprm->p; /* the strings */
875015feacfSNicolas Pitre #endif
8761da177e4SLinus Torvalds stack_len += (bprm->argc + 1) * sizeof(char *); /* the argv array */
8771da177e4SLinus Torvalds stack_len += (bprm->envc + 1) * sizeof(char *); /* the envp array */
878a97d157dSNicolas Pitre stack_len = ALIGN(stack_len, FLAT_STACK_ALIGN);
8791da177e4SLinus Torvalds
88070578ff3SEric W. Biederman res = load_flat_file(bprm, &libinfo, &stack_len);
881287980e4SArnd Bergmann if (res < 0)
8821da177e4SLinus Torvalds return res;
8831da177e4SLinus Torvalds
8841da177e4SLinus Torvalds /* Update data segment pointers for all libraries */
88549df34d2SKees Cook for (i = 0; i < MAX_SHARED_LIBS_UPDATE; i++) {
886af521f92SNicolas Pitre if (!libinfo.lib_list[i].loaded)
887af521f92SNicolas Pitre continue;
888af521f92SNicolas Pitre for (j = 0; j < MAX_SHARED_LIBS; j++) {
889af521f92SNicolas Pitre unsigned long val = libinfo.lib_list[j].loaded ?
8901da177e4SLinus Torvalds libinfo.lib_list[j].start_data : UNLOADED_LIB;
891af521f92SNicolas Pitre unsigned long __user *p = (unsigned long __user *)
892af521f92SNicolas Pitre libinfo.lib_list[i].start_data;
893af521f92SNicolas Pitre p -= j + 1;
894af521f92SNicolas Pitre if (put_user(val, p))
895af521f92SNicolas Pitre return -EFAULT;
896af521f92SNicolas Pitre }
897af521f92SNicolas Pitre }
8981da177e4SLinus Torvalds
8991da177e4SLinus Torvalds set_binfmt(&flat_format);
9001da177e4SLinus Torvalds
901015feacfSNicolas Pitre #ifdef CONFIG_MMU
902015feacfSNicolas Pitre res = setup_arg_pages(bprm, STACK_TOP, EXSTACK_DEFAULT);
903015feacfSNicolas Pitre if (!res)
904015feacfSNicolas Pitre res = create_flat_tables(bprm, bprm->p);
905015feacfSNicolas Pitre #else
906a97d157dSNicolas Pitre /* Stash our initial stack pointer into the mm structure */
907a97d157dSNicolas Pitre current->mm->start_stack =
908a97d157dSNicolas Pitre ((current->mm->context.end_brk + stack_len + 3) & ~3) - 4;
909a97d157dSNicolas Pitre pr_debug("sp=%lx\n", current->mm->start_stack);
9101da177e4SLinus Torvalds
911687fd773SNicolas Pitre /* copy the arg pages onto the stack */
912a97d157dSNicolas Pitre res = transfer_args_to_stack(bprm, ¤t->mm->start_stack);
913a97d157dSNicolas Pitre if (!res)
914a97d157dSNicolas Pitre res = create_flat_tables(bprm, current->mm->start_stack);
915015feacfSNicolas Pitre #endif
916687fd773SNicolas Pitre if (res)
917687fd773SNicolas Pitre return res;
9181da177e4SLinus Torvalds
9191da177e4SLinus Torvalds /* Fake some return addresses to ensure the call chain will
9201da177e4SLinus Torvalds * initialise library in order for us. We are required to call
9211da177e4SLinus Torvalds * lib 1 first, then 2, ... and finally the main program (id 0).
9221da177e4SLinus Torvalds */
9231da177e4SLinus Torvalds start_addr = libinfo.lib_list[0].entry;
9241da177e4SLinus Torvalds
92574c27c43STakashi YOSHII #ifdef FLAT_PLAT_INIT
92674c27c43STakashi YOSHII FLAT_PLAT_INIT(regs);
92774c27c43STakashi YOSHII #endif
9281da177e4SLinus Torvalds
929b8383831SKees Cook finalize_exec(bprm);
9304adbb6acSNicolas Pitre pr_debug("start_thread(regs=0x%p, entry=0x%lx, start_stack=0x%lx)\n",
93113c3f50cSNicolas Pitre regs, start_addr, current->mm->start_stack);
9321da177e4SLinus Torvalds start_thread(regs, start_addr, current->mm->start_stack);
9331da177e4SLinus Torvalds
9341da177e4SLinus Torvalds return 0;
9351da177e4SLinus Torvalds }
9361da177e4SLinus Torvalds
9371da177e4SLinus Torvalds /****************************************************************************/
9381da177e4SLinus Torvalds
init_flat_binfmt(void)9391da177e4SLinus Torvalds static int __init init_flat_binfmt(void)
9401da177e4SLinus Torvalds {
9418fc3dc5aSAl Viro register_binfmt(&flat_format);
9428fc3dc5aSAl Viro return 0;
9431da177e4SLinus Torvalds }
9441da177e4SLinus Torvalds core_initcall(init_flat_binfmt);
9451da177e4SLinus Torvalds
9461da177e4SLinus Torvalds /****************************************************************************/
947