Merge tag 'core-rcu-2020-06-01' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-microblaze.git] / fs / binfmt_flat.c
index e4b59e7..831a2b2 100644 (file)
 #include <asm/unaligned.h>
 #include <asm/cacheflush.h>
 #include <asm/page.h>
+#include <asm/flat.h>
+
+#ifndef flat_get_relocate_addr
+#define flat_get_relocate_addr(rel)    (rel)
+#endif
 
 /****************************************************************************/
 
 #define RELOC_FAILED 0xff00ff01                /* Relocation incorrect somewhere */
 #define UNLOADED_LIB 0x7ff000ff                /* Placeholder for unused library */
 
+#ifdef CONFIG_BINFMT_SHARED_FLAT
+#define        MAX_SHARED_LIBS                 (4)
+#else
+#define        MAX_SHARED_LIBS                 (1)
+#endif
+
 struct lib_info {
        struct {
                unsigned long start_code;               /* Start of text segment */
@@ -120,14 +131,15 @@ static int create_flat_tables(struct linux_binprm *bprm, unsigned long arg_start
 
        sp -= bprm->envc + 1;
        sp -= bprm->argc + 1;
-       sp -= flat_argvp_envp_on_stack() ? 2 : 0;
+       if (IS_ENABLED(CONFIG_BINFMT_FLAT_ARGVP_ENVP_ON_STACK))
+               sp -= 2; /* argvp + envp */
        sp -= 1;  /* &argc */
 
        current->mm->start_stack = (unsigned long)sp & -FLAT_STACK_ALIGN;
        sp = (unsigned long __user *)current->mm->start_stack;
 
        __put_user(bprm->argc, sp++);
-       if (flat_argvp_envp_on_stack()) {
+       if (IS_ENABLED(CONFIG_BINFMT_FLAT_ARGVP_ENVP_ON_STACK)) {
                unsigned long argv, envp;
                argv = (unsigned long)(sp + 2);
                envp = (unsigned long)(sp + 2 + bprm->argc + 1);
@@ -345,7 +357,7 @@ calc_reloc(unsigned long r, struct lib_info *p, int curid, int internalp)
        start_code = p->lib_list[id].start_code;
        text_len = p->lib_list[id].text_len;
 
-       if (!flat_reloc_valid(r, start_brk - start_data + text_len)) {
+       if (r > start_brk - start_data + text_len) {
                pr_err("reloc outside program 0x%lx (0 - 0x%lx/0x%lx)",
                       r, start_brk-start_data+text_len, text_len);
                goto failed;
@@ -368,6 +380,7 @@ failed:
 
 /****************************************************************************/
 
+#ifdef CONFIG_BINFMT_FLAT_OLD
 static void old_reloc(unsigned long rl)
 {
        static const char *segment[] = { "TEXT", "DATA", "BSS", "*UNKNOWN*" };
@@ -405,6 +418,7 @@ static void old_reloc(unsigned long rl)
 
        pr_debug("Relocation became %lx\n", val);
 }
+#endif /* CONFIG_BINFMT_FLAT_OLD */
 
 /****************************************************************************/
 
@@ -415,8 +429,8 @@ static int load_flat_file(struct linux_binprm *bprm,
        unsigned long textpos, datapos, realdatastart;
        u32 text_len, data_len, bss_len, stack_len, full_data, flags;
        unsigned long len, memp, memp_size, extra, rlim;
-       u32 __user *reloc, *rp;
-       struct inode *inode;
+       __be32 __user *reloc;
+       u32 __user *rp;
        int i, rev, relocs;
        loff_t fpos;
        unsigned long start_code, end_code;
@@ -424,7 +438,6 @@ static int load_flat_file(struct linux_binprm *bprm,
        int ret;
 
        hdr = ((struct flat_hdr *) bprm->buf);          /* exec-header */
-       inode = file_inode(bprm->file);
 
        text_len  = ntohl(hdr->data_start);
        data_len  = ntohl(hdr->data_end) - ntohl(hdr->data_start);
@@ -454,6 +467,7 @@ static int load_flat_file(struct linux_binprm *bprm,
        if (flags & FLAT_FLAG_KTRACE)
                pr_info("Loading file: %s\n", bprm->filename);
 
+#ifdef CONFIG_BINFMT_FLAT_OLD
        if (rev != FLAT_VERSION && rev != OLD_FLAT_VERSION) {
                pr_err("bad flat file version 0x%x (supported 0x%lx and 0x%lx)\n",
                       rev, FLAT_VERSION, OLD_FLAT_VERSION);
@@ -469,6 +483,23 @@ static int load_flat_file(struct linux_binprm *bprm,
                goto err;
        }
 
+       /*
+        * fix up the flags for the older format,  there were all kinds
+        * of endian hacks,  this only works for the simple cases
+        */
+       if (rev == OLD_FLAT_VERSION &&
+          (flags || IS_ENABLED(CONFIG_BINFMT_FLAT_OLD_ALWAYS_RAM)))
+               flags = FLAT_FLAG_RAM;
+
+#else /* CONFIG_BINFMT_FLAT_OLD */
+       if (rev != FLAT_VERSION) {
+               pr_err("bad flat file version 0x%x (supported 0x%lx)\n",
+                      rev, FLAT_VERSION);
+               ret = -ENOEXEC;
+               goto err;
+       }
+#endif /* !CONFIG_BINFMT_FLAT_OLD */
+
        /*
         * Make sure the header params are sane.
         * 28 bits (256 MB) is way more than reasonable in this case.
@@ -480,13 +511,6 @@ static int load_flat_file(struct linux_binprm *bprm,
                goto err;
        }
 
-       /*
-        * fix up the flags for the older format,  there were all kinds
-        * of endian hacks,  this only works for the simple cases
-        */
-       if (rev == OLD_FLAT_VERSION && flat_old_ram_flag(flags))
-               flags = FLAT_FLAG_RAM;
-
 #ifndef CONFIG_BINFMT_ZFLAT
        if (flags & (FLAT_FLAG_GZIP|FLAT_FLAG_GZDATA)) {
                pr_err("Support for ZFLAT executables is not enabled.\n");
@@ -547,7 +571,7 @@ static int load_flat_file(struct linux_binprm *bprm,
                        goto err;
                }
 
-               len = data_len + extra + MAX_SHARED_LIBS * sizeof(unsigned long);
+               len = data_len + extra;
                len = PAGE_ALIGN(len);
                realdatastart = vm_mmap(NULL, 0, len,
                        PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE, 0);
@@ -561,9 +585,7 @@ static int load_flat_file(struct linux_binprm *bprm,
                        vm_munmap(textpos, text_len);
                        goto err;
                }
-               datapos = ALIGN(realdatastart +
-                               MAX_SHARED_LIBS * sizeof(unsigned long),
-                               FLAT_DATA_ALIGN);
+               datapos = ALIGN(realdatastart, FLAT_DATA_ALIGN);
 
                pr_debug("Allocated data+bss+stack (%u bytes): %lx\n",
                         data_len + bss_len + stack_len, datapos);
@@ -587,13 +609,13 @@ static int load_flat_file(struct linux_binprm *bprm,
                        goto err;
                }
 
-               reloc = (u32 __user *)
+               reloc = (__be32 __user *)
                        (datapos + (ntohl(hdr->reloc_start) - text_len));
                memp = realdatastart;
                memp_size = len;
        } else {
 
-               len = text_len + data_len + extra + MAX_SHARED_LIBS * sizeof(u32);
+               len = text_len + data_len + extra;
                len = PAGE_ALIGN(len);
                textpos = vm_mmap(NULL, 0, len,
                        PROT_READ | PROT_EXEC | PROT_WRITE, MAP_PRIVATE, 0);
@@ -608,11 +630,9 @@ static int load_flat_file(struct linux_binprm *bprm,
                }
 
                realdatastart = textpos + ntohl(hdr->data_start);
-               datapos = ALIGN(realdatastart +
-                               MAX_SHARED_LIBS * sizeof(u32),
-                               FLAT_DATA_ALIGN);
+               datapos = ALIGN(realdatastart, FLAT_DATA_ALIGN);
 
-               reloc = (u32 __user *)
+               reloc = (__be32 __user *)
                        (datapos + (ntohl(hdr->reloc_start) - text_len));
                memp = textpos;
                memp_size = len;
@@ -627,8 +647,9 @@ static int load_flat_file(struct linux_binprm *bprm,
                                         (text_len + full_data
                                                  - sizeof(struct flat_hdr)),
                                         0);
-                       memmove((void *) datapos, (void *) realdatastart,
-                                       full_data);
+                       if (datapos != realdatastart)
+                               memmove((void *)datapos, (void *)realdatastart,
+                                               full_data);
 #else
                        /*
                         * This is used on MMU systems mainly for testing.
@@ -684,8 +705,7 @@ static int load_flat_file(struct linux_binprm *bprm,
                if (IS_ERR_VALUE(result)) {
                        ret = result;
                        pr_err("Unable to read code+data+bss, errno %d\n", ret);
-                       vm_munmap(textpos, text_len + data_len + extra +
-                               MAX_SHARED_LIBS * sizeof(u32));
+                       vm_munmap(textpos, text_len + data_len + extra);
                        goto err;
                }
        }
@@ -775,20 +795,18 @@ static int load_flat_file(struct linux_binprm *bprm,
         * __start to address 4 so that is okay).
         */
        if (rev > OLD_FLAT_VERSION) {
-               u32 __maybe_unused persistent = 0;
                for (i = 0; i < relocs; i++) {
                        u32 addr, relval;
+                       __be32 tmp;
 
                        /*
                         * Get the address of the pointer to be
                         * relocated (of course, the address has to be
                         * relocated first).
                         */
-                       if (get_user(relval, reloc + i))
+                       if (get_user(tmp, reloc + i))
                                return -EFAULT;
-                       relval = ntohl(relval);
-                       if (flat_set_persistent(relval, &persistent))
-                               continue;
+                       relval = ntohl(tmp);
                        addr = flat_get_relocate_addr(relval);
                        rp = (u32 __user *)calc_reloc(addr, libinfo, id, 1);
                        if (rp == (u32 __user *)RELOC_FAILED) {
@@ -797,8 +815,7 @@ static int load_flat_file(struct linux_binprm *bprm,
                        }
 
                        /* Get the pointer's value.  */
-                       ret = flat_get_addr_from_rp(rp, relval, flags,
-                                                       &addr, &persistent);
+                       ret = flat_get_addr_from_rp(rp, relval, flags, &addr);
                        if (unlikely(ret))
                                goto err;
 
@@ -807,8 +824,13 @@ static int load_flat_file(struct linux_binprm *bprm,
                                 * Do the relocation.  PIC relocs in the data section are
                                 * already in target order
                                 */
-                               if ((flags & FLAT_FLAG_GOTPIC) == 0)
-                                       addr = ntohl(addr);
+                               if ((flags & FLAT_FLAG_GOTPIC) == 0) {
+                                       /*
+                                        * Meh, the same value can have a different
+                                        * byte order based on a flag..
+                                        */
+                                       addr = ntohl((__force __be32)addr);
+                               }
                                addr = calc_reloc(addr, libinfo, id, 0);
                                if (addr == RELOC_FAILED) {
                                        ret = -ENOEXEC;
@@ -821,14 +843,15 @@ static int load_flat_file(struct linux_binprm *bprm,
                                        goto err;
                        }
                }
+#ifdef CONFIG_BINFMT_FLAT_OLD
        } else {
                for (i = 0; i < relocs; i++) {
-                       u32 relval;
+                       __be32 relval;
                        if (get_user(relval, reloc + i))
                                return -EFAULT;
-                       relval = ntohl(relval);
-                       old_reloc(relval);
+                       old_reloc(ntohl(relval));
                }
+#endif /* CONFIG_BINFMT_FLAT_OLD */
        }
 
        flush_icache_range(start_code, end_code);