From 89e6ffd9f03936d9f6f0332426e4a3cf379b90bd Mon Sep 17 00:00:00 2001 From: Greg Ungerer Date: Thu, 21 Jul 2016 16:28:48 +1000 Subject: [PATCH 01/16] m68k: fix bFLT executable running on MMU enabled systems Even after recent changes to support running flat format executables on MMU enabled systems (by nicolas.pitre@linaro.org) they still failed to run on m68k/ColdFire MMU enabled systems. On trying to run a flat format binary the application would immediately crash with a SIGSEGV. Code to setup the D5 register with the base of the application data region was only in the non-MMU code path, so it was not being set for the MMU enabled case. Flat binaries on m68k/ColdFire use this to support GOT/PIC flat built application code. Fix this so that D5 is always setup when loading/running a bFLT executable on m68k systems. Signed-off-by: Greg Ungerer --- arch/m68k/include/asm/flat.h | 6 ++++++ arch/m68k/include/asm/processor.h | 2 -- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/arch/m68k/include/asm/flat.h b/arch/m68k/include/asm/flat.h index f9454b89a51b..f46c2f044f8c 100644 --- a/arch/m68k/include/asm/flat.h +++ b/arch/m68k/include/asm/flat.h @@ -18,4 +18,10 @@ static inline int flat_set_persistent(unsigned long relval, return 0; } +#define FLAT_PLAT_INIT(regs) \ + do { \ + if (current->mm) \ + (regs)->d5 = current->mm->start_data; \ + } while (0) + #endif /* __M68KNOMMU_FLAT_H__ */ diff --git a/arch/m68k/include/asm/processor.h b/arch/m68k/include/asm/processor.h index a6ce2ec8d693..46672d1f4d62 100644 --- a/arch/m68k/include/asm/processor.h +++ b/arch/m68k/include/asm/processor.h @@ -131,8 +131,6 @@ extern int handle_kernel_fault(struct pt_regs *regs); do { \ (_regs)->pc = (_pc); \ setframeformat(_regs); \ - if (current->mm) \ - (_regs)->d5 = current->mm->start_data; \ (_regs)->sr &= ~0x2000; \ wrusp(_usp); \ } while(0) From 120c4d95b29d1c60ee8c7b72e4b96098514b2e3c Mon Sep 17 00:00:00 2001 From: Greg Ungerer Date: Thu, 21 Jul 2016 17:05:41 +1000 Subject: [PATCH 02/16] m68k: fix file path comment Remove the wrong full path name of this file. Signed-off-by: Greg Ungerer --- arch/m68k/include/asm/flat.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/m68k/include/asm/flat.h b/arch/m68k/include/asm/flat.h index f46c2f044f8c..8e58d47be90d 100644 --- a/arch/m68k/include/asm/flat.h +++ b/arch/m68k/include/asm/flat.h @@ -1,5 +1,5 @@ /* - * include/asm-m68knommu/flat.h -- uClinux flat-format executables + * flat.h -- uClinux flat-format executables */ #ifndef __M68KNOMMU_FLAT_H__ From f987e5a13c55e65df6a03677dda38c8e5fb47029 Mon Sep 17 00:00:00 2001 From: Greg Ungerer Date: Thu, 21 Jul 2016 17:29:43 +1000 Subject: [PATCH 03/16] m68k: use same start_thread() on MMU and no-MMU The MMU and no-MMU versions of start_thread() are now identical, so use the same common code for both. Signed-off-by: Greg Ungerer --- arch/m68k/include/asm/processor.h | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/arch/m68k/include/asm/processor.h b/arch/m68k/include/asm/processor.h index 46672d1f4d62..c84a2183b3f0 100644 --- a/arch/m68k/include/asm/processor.h +++ b/arch/m68k/include/asm/processor.h @@ -110,7 +110,6 @@ struct thread_struct { #define setframeformat(_regs) do { } while (0) #endif -#ifdef CONFIG_MMU /* * Do necessary setup to start up a newly executed thread. */ @@ -123,24 +122,14 @@ static inline void start_thread(struct pt_regs * regs, unsigned long pc, wrusp(usp); } +#ifdef CONFIG_MMU extern int handle_kernel_fault(struct pt_regs *regs); - #else - -#define start_thread(_regs, _pc, _usp) \ -do { \ - (_regs)->pc = (_pc); \ - setframeformat(_regs); \ - (_regs)->sr &= ~0x2000; \ - wrusp(_usp); \ -} while(0) - static inline int handle_kernel_fault(struct pt_regs *regs) { /* Any fault in kernel is fatal on non-mmu */ return 0; } - #endif /* Forward declaration, a strange C thing */ From 13c3f50c914e6a51d11e1aba4a85c2223e197e13 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Sun, 24 Jul 2016 11:30:15 -0400 Subject: [PATCH 04/16] binfmt_flat: assorted cleanups Remove excessive casts, do some code grouping, fix most important checkpatch.pl complaints, etc. No functional changes. Signed-off-by: Nicolas Pitre Reviewed-by: Greg Ungerer Signed-off-by: Greg Ungerer --- fs/binfmt_flat.c | 232 ++++++++++++++++++++++------------------------- 1 file changed, 110 insertions(+), 122 deletions(-) diff --git a/fs/binfmt_flat.c b/fs/binfmt_flat.c index caf9e39bb82b..892dba62bf2e 100644 --- a/fs/binfmt_flat.c +++ b/fs/binfmt_flat.c @@ -15,7 +15,6 @@ * JAN/99 -- coded full program relocation (gerg@snapgear.com) */ -#include #include #include #include @@ -25,8 +24,6 @@ #include #include #include -#include -#include #include #include #include @@ -34,10 +31,9 @@ #include #include #include -#include +#include #include -#include #include #include #include @@ -80,7 +76,7 @@ struct lib_info { unsigned long text_len; /* Length of text segment */ unsigned long entry; /* Start address for this module */ unsigned long build_date; /* When this one was compiled */ - short loaded; /* Has this library been loaded? */ + bool loaded; /* Has this library been loaded? */ } lib_list[MAX_SHARED_LIBS]; }; @@ -107,8 +103,8 @@ static struct linux_binfmt flat_format = { static int flat_core_dump(struct coredump_params *cprm) { printk("Process %s:%d received signr %d and should have core dumped\n", - current->comm, current->pid, (int) cprm->siginfo->si_signo); - return(1); + current->comm, current->pid, cprm->siginfo->si_signo); + return 1; } /****************************************************************************/ @@ -120,11 +116,11 @@ static int flat_core_dump(struct coredump_params *cprm) static unsigned long create_flat_tables( unsigned long pp, - struct linux_binprm * bprm) + struct linux_binprm *bprm) { - unsigned long *argv,*envp; - unsigned long * sp; - char * p = (char*)pp; + unsigned long *argv, *envp; + unsigned long *sp; + char *p = (char *)pp; int argc = bprm->argc; int envc = bprm->envc; char uninitialized_var(dummy); @@ -142,7 +138,7 @@ static unsigned long create_flat_tables( put_user(argc, sp); current->mm->arg_start = (unsigned long) p; - while (argc-->0) { + while (argc-- > 0) { put_user((unsigned long) p, argv++); do { get_user(dummy, p); p++; @@ -150,7 +146,7 @@ static unsigned long create_flat_tables( } put_user((unsigned long) NULL, argv); current->mm->arg_end = current->mm->env_start = (unsigned long) p; - while (envc-->0) { + while (envc-- > 0) { put_user((unsigned long)p, envp); envp++; do { get_user(dummy, p); p++; @@ -190,7 +186,7 @@ static int decompress_exec( loff_t fpos; int ret, retval; - DBG_FLT("decompress_exec(offset=%x,buf=%x,len=%x)\n",(int)offset, (int)dst, (int)len); + DBG_FLT("decompress_exec(offset=%lx,buf=%p,len=%lx)\n", offset, dst, len); memset(&strm, 0, sizeof(strm)); strm.workspace = kmalloc(zlib_inflate_workspacesize(), GFP_KERNEL); @@ -243,7 +239,7 @@ static int decompress_exec( ret = 10; if (buf[3] & EXTRA_FIELD) { ret += 2 + buf[10] + (buf[11] << 8); - if (unlikely(LBUFSIZE <= ret)) { + if (unlikely(ret >= LBUFSIZE)) { DBG_FLT("binfmt_flat: buffer overflow (EXTRA)?\n"); goto out_free_buf; } @@ -251,7 +247,7 @@ static int decompress_exec( if (buf[3] & ORIG_NAME) { while (ret < LBUFSIZE && buf[ret++] != 0) ; - if (unlikely(LBUFSIZE == ret)) { + if (unlikely(ret == LBUFSIZE)) { DBG_FLT("binfmt_flat: buffer overflow (ORIG_NAME)?\n"); goto out_free_buf; } @@ -259,7 +255,7 @@ static int decompress_exec( if (buf[3] & COMMENT) { while (ret < LBUFSIZE && buf[ret++] != 0) ; - if (unlikely(LBUFSIZE == ret)) { + if (unlikely(ret == LBUFSIZE)) { DBG_FLT("binfmt_flat: buffer overflow (COMMENT)?\n"); goto out_free_buf; } @@ -327,17 +323,17 @@ calc_reloc(unsigned long r, struct lib_info *p, int curid, int internalp) r &= 0x00ffffff; /* Trim ID off here */ } if (id >= MAX_SHARED_LIBS) { - printk("BINFMT_FLAT: reference 0x%x to shared library %d", - (unsigned) r, id); + printk("BINFMT_FLAT: reference 0x%lx to shared library %d", + r, id); goto failed; } if (curid != id) { if (internalp) { - printk("BINFMT_FLAT: reloc address 0x%x not in same module " - "(%d != %d)", (unsigned) r, curid, id); + printk("BINFMT_FLAT: reloc address 0x%lx not in same module " + "(%d != %d)", r, curid, id); goto failed; - } else if ( ! p->lib_list[id].loaded && - load_flat_shared_library(id, p) < 0) { + } else if (!p->lib_list[id].loaded && + load_flat_shared_library(id, p) < 0) { printk("BINFMT_FLAT: failed to load library %d", id); goto failed; } @@ -358,8 +354,8 @@ calc_reloc(unsigned long r, struct lib_info *p, int curid, int internalp) text_len = p->lib_list[id].text_len; if (!flat_reloc_valid(r, start_brk - start_data + text_len)) { - printk("BINFMT_FLAT: reloc outside program 0x%x (0 - 0x%x/0x%x)", - (int) r,(int)(start_brk-start_data+text_len),(int)text_len); + printk("BINFMT_FLAT: reloc outside program 0x%lx (0 - 0x%lx/0x%lx)", + r, start_brk-start_data+text_len, text_len); goto failed; } @@ -369,7 +365,7 @@ calc_reloc(unsigned long r, struct lib_info *p, int curid, int internalp) addr = r - text_len + start_data; /* Range checked already above so doing the range tests is redundant...*/ - return(addr); + return addr; failed: printk(", killing %s!\n", current->comm); @@ -383,11 +379,11 @@ failed: static void old_reloc(unsigned long rl) { #ifdef DEBUG - char *segment[] = { "TEXT", "DATA", "BSS", "*UNKNOWN*" }; + static const char *segment[] = { "TEXT", "DATA", "BSS", "*UNKNOWN*" }; #endif flat_v2_reloc_t r; unsigned long *ptr; - + r.value = rl; #if defined(CONFIG_COLDFIRE) ptr = (unsigned long *) (current->mm->start_code + r.reloc.offset); @@ -397,10 +393,10 @@ static void old_reloc(unsigned long rl) #ifdef DEBUG printk("Relocation of variable at DATASEG+%x " - "(address %p, currently %x) into segment %s\n", - r.reloc.offset, ptr, (int)*ptr, segment[r.reloc.type]); + "(address %p, currently %lx) into segment %s\n", + r.reloc.offset, ptr, *ptr, segment[r.reloc.type]); #endif - + switch (r.reloc.type) { case OLD_FLAT_RELOC_TYPE_TEXT: *ptr += current->mm->start_code; @@ -417,27 +413,25 @@ static void old_reloc(unsigned long rl) } #ifdef DEBUG - printk("Relocation became %x\n", (int)*ptr); + printk("Relocation became %lx\n", *ptr); #endif -} +} /****************************************************************************/ -static int load_flat_file(struct linux_binprm * bprm, +static int load_flat_file(struct linux_binprm *bprm, struct lib_info *libinfo, int id, unsigned long *extra_stack) { - struct flat_hdr * hdr; - unsigned long textpos = 0, datapos = 0, result; - unsigned long realdatastart = 0; - unsigned long text_len, data_len, bss_len, stack_len, flags; - unsigned long full_data; - unsigned long len, memp = 0; - unsigned long memp_size, extra, rlim; - unsigned long *reloc = 0, *rp; + struct flat_hdr *hdr; + unsigned long textpos, datapos, realdatastart; + unsigned long text_len, data_len, bss_len, stack_len, full_data, flags; + unsigned long len, memp, memp_size, extra, rlim; + unsigned long *reloc, *rp; struct inode *inode; - int i, rev, relocs = 0; + int i, rev, relocs; loff_t fpos; unsigned long start_code, end_code; + ssize_t result; int ret; hdr = ((struct flat_hdr *) bprm->buf); /* exec-header */ @@ -478,11 +472,11 @@ static int load_flat_file(struct linux_binprm * bprm, ret = -ENOEXEC; goto err; } - + /* Don't allow old format executables to use shared libraries */ if (rev == OLD_FLAT_VERSION && id != 0) { - printk("BINFMT_FLAT: shared libraries are not available before rev 0x%x\n", - (int) FLAT_VERSION); + printk("BINFMT_FLAT: shared libraries are not available before rev 0x%lx\n", + FLAT_VERSION); ret = -ENOEXEC; goto err; } @@ -517,11 +511,9 @@ static int load_flat_file(struct linux_binprm * bprm, /* Flush all traces of the currently running executable */ if (id == 0) { - result = flush_old_exec(bprm); - if (result) { - ret = result; + ret = flush_old_exec(bprm); + if (ret) goto err; - } /* OK, This is the point of no return */ set_personality(PER_LINUX_32BIT); @@ -549,38 +541,38 @@ static int load_flat_file(struct linux_binprm * bprm, textpos = vm_mmap(bprm->file, 0, text_len, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_EXECUTABLE, 0); if (!textpos || IS_ERR_VALUE(textpos)) { - if (!textpos) - textpos = (unsigned long) -ENOMEM; - printk("Unable to mmap process text, errno %d\n", (int)-textpos); ret = textpos; + if (!textpos) + ret = -ENOMEM; + printk("Unable to mmap process text, errno %d\n", ret); goto err; } len = data_len + extra + MAX_SHARED_LIBS * sizeof(unsigned long); len = PAGE_ALIGN(len); - realdatastart = vm_mmap(0, 0, len, + realdatastart = vm_mmap(NULL, 0, len, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE, 0); if (realdatastart == 0 || IS_ERR_VALUE(realdatastart)) { - if (!realdatastart) - realdatastart = (unsigned long) -ENOMEM; - printk("Unable to allocate RAM for process data, errno %d\n", - (int)-realdatastart); - vm_munmap(textpos, text_len); ret = realdatastart; + if (!realdatastart) + ret = -ENOMEM; + printk("Unable to allocate RAM for process data, " + "errno %d\n", ret); + vm_munmap(textpos, text_len); goto err; } datapos = ALIGN(realdatastart + MAX_SHARED_LIBS * sizeof(unsigned long), FLAT_DATA_ALIGN); - DBG_FLT("BINFMT_FLAT: Allocated data+bss+stack (%d bytes): %x\n", - (int)(data_len + bss_len + stack_len), (int)datapos); + DBG_FLT("BINFMT_FLAT: Allocated data+bss+stack (%ld bytes): %lx\n", + data_len + bss_len + stack_len, datapos); fpos = ntohl(hdr->data_start); #ifdef CONFIG_BINFMT_ZFLAT if (flags & FLAT_FLAG_GZDATA) { - result = decompress_exec(bprm, fpos, (char *) datapos, + result = decompress_exec(bprm, fpos, (char *)datapos, full_data, 0); } else #endif @@ -589,29 +581,30 @@ static int load_flat_file(struct linux_binprm * bprm, full_data); } if (IS_ERR_VALUE(result)) { - printk("Unable to read data+bss, errno %d\n", (int)-result); + ret = result; + printk("Unable to read data+bss, errno %d\n", ret); vm_munmap(textpos, text_len); vm_munmap(realdatastart, len); - ret = result; goto err; } - reloc = (unsigned long *) (datapos+(ntohl(hdr->reloc_start)-text_len)); + reloc = (unsigned long *) + (datapos + (ntohl(hdr->reloc_start) - text_len)); memp = realdatastart; memp_size = len; } else { len = text_len + data_len + extra + MAX_SHARED_LIBS * sizeof(unsigned long); len = PAGE_ALIGN(len); - textpos = vm_mmap(0, 0, len, + textpos = vm_mmap(NULL, 0, len, PROT_READ | PROT_EXEC | PROT_WRITE, MAP_PRIVATE, 0); if (!textpos || IS_ERR_VALUE(textpos)) { - if (!textpos) - textpos = (unsigned long) -ENOMEM; - printk("Unable to allocate RAM for process text/data, errno %d\n", - (int)-textpos); ret = textpos; + if (!textpos) + ret = -ENOMEM; + printk("Unable to allocate RAM for process text/data, " + "errno %d\n", ret); goto err; } @@ -629,10 +622,10 @@ static int load_flat_file(struct linux_binprm * bprm, * load it all in and treat it like a RAM load from now on */ if (flags & FLAT_FLAG_GZIP) { - result = decompress_exec(bprm, sizeof (struct flat_hdr), - (((char *) textpos) + sizeof (struct flat_hdr)), + result = decompress_exec(bprm, sizeof(struct flat_hdr), + (((char *)textpos) + sizeof(struct flat_hdr)), (text_len + full_data - - sizeof (struct flat_hdr)), + - sizeof(struct flat_hdr)), 0); memmove((void *) datapos, (void *) realdatastart, full_data); @@ -641,8 +634,7 @@ static int load_flat_file(struct linux_binprm * bprm, if (!IS_ERR_VALUE(result)) result = decompress_exec(bprm, text_len, (char *) datapos, full_data, 0); - } - else + } else #endif { result = read_code(bprm->file, textpos, 0, text_len); @@ -652,21 +644,19 @@ static int load_flat_file(struct linux_binprm * bprm, full_data); } if (IS_ERR_VALUE(result)) { - printk("Unable to read code+data+bss, errno %d\n",(int)-result); + ret = result; + printk("Unable to read code+data+bss, errno %d\n", ret); vm_munmap(textpos, text_len + data_len + extra + MAX_SHARED_LIBS * sizeof(unsigned long)); - ret = result; goto err; } } - if (flags & FLAT_FLAG_KTRACE) - printk("Mapping is %x, Entry point is %x, data_start is %x\n", - (int)textpos, 0x00ffffff&ntohl(hdr->entry), ntohl(hdr->data_start)); + start_code = textpos + sizeof(struct flat_hdr); + end_code = textpos + text_len; + text_len -= sizeof(struct flat_hdr); /* the real code len */ /* The main program needs a little extra setup in the task structure */ - start_code = textpos + sizeof (struct flat_hdr); - end_code = textpos + text_len; if (id == 0) { current->mm->start_code = start_code; current->mm->end_code = end_code; @@ -684,16 +674,14 @@ static int load_flat_file(struct linux_binprm * bprm, current->mm->context.end_brk = memp + memp_size - stack_len; } - if (flags & FLAT_FLAG_KTRACE) - printk("%s %s: TEXT=%x-%x DATA=%x-%x BSS=%x-%x\n", - id ? "Lib" : "Load", bprm->filename, - (int) start_code, (int) end_code, - (int) datapos, - (int) (datapos + data_len), - (int) (datapos + data_len), - (int) (((datapos + data_len + bss_len) + 3) & ~3)); - - text_len -= sizeof(struct flat_hdr); /* the real code len */ + if (flags & FLAT_FLAG_KTRACE) { + printk("Mapping is %lx, Entry point is %x, data_start is %x\n", + textpos, 0x00ffffff&ntohl(hdr->entry), ntohl(hdr->data_start)); + printk("%s %s: TEXT=%lx-%lx DATA=%lx-%lx BSS=%lx-%lx\n", + id ? "Lib" : "Load", bprm->filename, + start_code, end_code, datapos, datapos + data_len, + datapos + data_len, (datapos + data_len + bss_len + 3) & ~3); + } /* Store the current module values into the global library structure */ libinfo->lib_list[id].start_code = start_code; @@ -703,7 +691,7 @@ static int load_flat_file(struct linux_binprm * bprm, libinfo->lib_list[id].loaded = 1; libinfo->lib_list[id].entry = (0x00ffffff & ntohl(hdr->entry)) + textpos; libinfo->lib_list[id].build_date = ntohl(hdr->build_date); - + /* * We just load the allocations into some temporary memory to * help simplify all this mumbo jumbo @@ -743,14 +731,16 @@ static int load_flat_file(struct linux_binprm * bprm, */ if (rev > OLD_FLAT_VERSION) { unsigned long persistent = 0; - for (i=0; i < relocs; i++) { + for (i = 0; i < relocs; i++) { unsigned long addr, relval; - /* Get the address of the pointer to be - relocated (of course, the address has to be - relocated first). */ + /* + * Get the address of the pointer to be + * relocated (of course, the address has to be + * relocated first). + */ relval = ntohl(reloc[i]); - if (flat_set_persistent (relval, &persistent)) + if (flat_set_persistent(relval, &persistent)) continue; addr = flat_get_relocate_addr(relval); rp = (unsigned long *) calc_reloc(addr, libinfo, id, 1); @@ -780,14 +770,14 @@ static int load_flat_file(struct linux_binprm * bprm, } } } else { - for (i=0; i < relocs; i++) + for (i = 0; i < relocs; i++) old_reloc(ntohl(reloc[i])); } - + flush_icache_range(start_code, end_code); /* zero the BSS, BRK and stack areas */ - memset((void*)(datapos + data_len), 0, bss_len + + memset((void *)(datapos + data_len), 0, bss_len + (memp + memp_size - stack_len - /* end brk */ libinfo->lib_list[id].start_brk) + /* start brk */ stack_len); @@ -846,7 +836,7 @@ out: allow_write_access(bprm.file); fput(bprm.file); - return(res); + return res; } #endif /* CONFIG_BINFMT_SHARED_FLAT */ @@ -857,7 +847,7 @@ out: * libraries. There is no binary dependent code anywhere else. */ -static int load_flat_binary(struct linux_binprm * bprm) +static int load_flat_binary(struct linux_binprm *bprm) { struct lib_info libinfo; struct pt_regs *regs = current_pt_regs(); @@ -869,6 +859,7 @@ static int load_flat_binary(struct linux_binprm * bprm) int i, j; memset(&libinfo, 0, sizeof(libinfo)); + /* * We have to add the size of our arguments to our stack size * otherwise it's too easy for users to create stack overflows @@ -881,33 +872,33 @@ static int load_flat_binary(struct linux_binprm * bprm) stack_len += (bprm->argc + 1) * sizeof(char *); /* the argv array */ stack_len += (bprm->envc + 1) * sizeof(char *); /* the envp array */ stack_len += FLAT_STACK_ALIGN - 1; /* reserve for upcoming alignment */ - + res = load_flat_file(bprm, &libinfo, 0, &stack_len); if (res < 0) return res; - + /* Update data segment pointers for all libraries */ - for (i=0; imm->context.end_brk + stack_len + 3) & ~3) - 4; - DBG_FLT("p=%x\n", (int)p); + DBG_FLT("p=%lx\n", p); /* copy the arg pages onto the stack, this could be more efficient :-) */ for (i = TOP_OF_ARGS - 1; i >= bprm->p; i--) - * (char *) --p = + *(char *) --p = ((char *) page_address(bprm->page[i/PAGE_SIZE]))[i % PAGE_SIZE]; sp = (unsigned long *) create_flat_tables(p, bprm); - + /* Fake some return addresses to ensure the call chain will * initialise library in order for us. We are required to call * lib 1 first, then 2, ... and finally the main program (id 0). @@ -915,7 +906,7 @@ static int load_flat_binary(struct linux_binprm * bprm) start_addr = libinfo.lib_list[0].entry; #ifdef CONFIG_BINFMT_SHARED_FLAT - for (i = MAX_SHARED_LIBS-1; i>0; i--) { + for (i = MAX_SHARED_LIBS-1; i > 0; i--) { if (libinfo.lib_list[i].loaded) { /* Push previos first to call address */ --sp; put_user(start_addr, sp); @@ -923,16 +914,16 @@ static int load_flat_binary(struct linux_binprm * bprm) } } #endif - + /* Stash our initial stack pointer into the mm structure */ - current->mm->start_stack = (unsigned long )sp; + current->mm->start_stack = (unsigned long)sp; #ifdef FLAT_PLAT_INIT FLAT_PLAT_INIT(regs); #endif - DBG_FLT("start_thread(regs=0x%x, entry=0x%x, start_stack=0x%x)\n", - (int)regs, (int)start_addr, (int)current->mm->start_stack); - + + DBG_FLT("start_thread(regs=0x%p, entry=0x%lx, start_stack=0x%lx)\n", + regs, start_addr, current->mm->start_stack); start_thread(regs, start_addr, current->mm->start_stack); return 0; @@ -945,9 +936,6 @@ static int __init init_flat_binfmt(void) register_binfmt(&flat_format); return 0; } - -/****************************************************************************/ - core_initcall(init_flat_binfmt); /****************************************************************************/ From 4adbb6ac4b807e2f3f07887cf2a925fa012a7825 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Sun, 24 Jul 2016 11:30:16 -0400 Subject: [PATCH 05/16] binfmt_flat: convert printk invocations to their modern form Signed-off-by: Nicolas Pitre Signed-off-by: Greg Ungerer --- fs/binfmt_flat.c | 118 ++++++++++++++++++++--------------------------- 1 file changed, 51 insertions(+), 67 deletions(-) diff --git a/fs/binfmt_flat.c b/fs/binfmt_flat.c index 892dba62bf2e..c3ccdefdeac2 100644 --- a/fs/binfmt_flat.c +++ b/fs/binfmt_flat.c @@ -15,6 +15,8 @@ * JAN/99 -- coded full program relocation (gerg@snapgear.com) */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -40,16 +42,6 @@ /****************************************************************************/ -#if 0 -#define DEBUG 1 -#endif - -#ifdef DEBUG -#define DBG_FLT(a...) printk(a) -#else -#define DBG_FLT(a...) -#endif - /* * User data (data section and bss) needs to be aligned. * We pick 0x20 here because it is the max value elf2flt has always @@ -102,8 +94,8 @@ static struct linux_binfmt flat_format = { static int flat_core_dump(struct coredump_params *cprm) { - printk("Process %s:%d received signr %d and should have core dumped\n", - current->comm, current->pid, cprm->siginfo->si_signo); + pr_warn("Process %s:%d received signr %d and should have core dumped\n", + current->comm, current->pid, cprm->siginfo->si_signo); return 1; } @@ -186,17 +178,17 @@ static int decompress_exec( loff_t fpos; int ret, retval; - DBG_FLT("decompress_exec(offset=%lx,buf=%p,len=%lx)\n", offset, dst, len); + pr_debug("decompress_exec(offset=%lx,buf=%p,len=%lx)\n", offset, dst, len); memset(&strm, 0, sizeof(strm)); strm.workspace = kmalloc(zlib_inflate_workspacesize(), GFP_KERNEL); if (strm.workspace == NULL) { - DBG_FLT("binfmt_flat: no memory for decompress workspace\n"); + pr_debug("no memory for decompress workspace\n"); return -ENOMEM; } buf = kmalloc(LBUFSIZE, GFP_KERNEL); if (buf == NULL) { - DBG_FLT("binfmt_flat: no memory for read buffer\n"); + pr_debug("no memory for read buffer\n"); retval = -ENOMEM; goto out_free; } @@ -214,25 +206,25 @@ static int decompress_exec( /* Check minimum size -- gzip header */ if (ret < 10) { - DBG_FLT("binfmt_flat: file too small?\n"); + pr_debug("file too small?\n"); goto out_free_buf; } /* Check gzip magic number */ if ((buf[0] != 037) || ((buf[1] != 0213) && (buf[1] != 0236))) { - DBG_FLT("binfmt_flat: unknown compression magic?\n"); + pr_debug("unknown compression magic?\n"); goto out_free_buf; } /* Check gzip method */ if (buf[2] != 8) { - DBG_FLT("binfmt_flat: unknown compression method?\n"); + pr_debug("unknown compression method?\n"); goto out_free_buf; } /* Check gzip flags */ if ((buf[3] & ENCRYPTED) || (buf[3] & CONTINUATION) || (buf[3] & RESERVED)) { - DBG_FLT("binfmt_flat: unknown flags?\n"); + pr_debug("unknown flags?\n"); goto out_free_buf; } @@ -240,7 +232,7 @@ static int decompress_exec( if (buf[3] & EXTRA_FIELD) { ret += 2 + buf[10] + (buf[11] << 8); if (unlikely(ret >= LBUFSIZE)) { - DBG_FLT("binfmt_flat: buffer overflow (EXTRA)?\n"); + pr_debug("buffer overflow (EXTRA)?\n"); goto out_free_buf; } } @@ -248,7 +240,7 @@ static int decompress_exec( while (ret < LBUFSIZE && buf[ret++] != 0) ; if (unlikely(ret == LBUFSIZE)) { - DBG_FLT("binfmt_flat: buffer overflow (ORIG_NAME)?\n"); + pr_debug("buffer overflow (ORIG_NAME)?\n"); goto out_free_buf; } } @@ -256,7 +248,7 @@ static int decompress_exec( while (ret < LBUFSIZE && buf[ret++] != 0) ; if (unlikely(ret == LBUFSIZE)) { - DBG_FLT("binfmt_flat: buffer overflow (COMMENT)?\n"); + pr_debug("buffer overflow (COMMENT)?\n"); goto out_free_buf; } } @@ -269,7 +261,7 @@ static int decompress_exec( strm.total_out = 0; if (zlib_inflateInit2(&strm, -MAX_WBITS) != Z_OK) { - DBG_FLT("binfmt_flat: zlib init failed?\n"); + pr_debug("zlib init failed?\n"); goto out_free_buf; } @@ -286,7 +278,7 @@ static int decompress_exec( } if (ret < 0) { - DBG_FLT("binfmt_flat: decompression failed (%d), %s\n", + pr_debug("decompression failed (%d), %s\n", ret, strm.msg); goto out_zlib; } @@ -323,24 +315,23 @@ calc_reloc(unsigned long r, struct lib_info *p, int curid, int internalp) r &= 0x00ffffff; /* Trim ID off here */ } if (id >= MAX_SHARED_LIBS) { - printk("BINFMT_FLAT: reference 0x%lx to shared library %d", - r, id); + pr_err("reference 0x%lx to shared library %d", r, id); goto failed; } if (curid != id) { if (internalp) { - printk("BINFMT_FLAT: reloc address 0x%lx not in same module " - "(%d != %d)", r, curid, id); + pr_err("reloc address 0x%lx not in same module " + "(%d != %d)", r, curid, id); goto failed; } else if (!p->lib_list[id].loaded && load_flat_shared_library(id, p) < 0) { - printk("BINFMT_FLAT: failed to load library %d", id); + pr_err("failed to load library %d", id); goto failed; } /* Check versioning information (i.e. time stamps) */ if (p->lib_list[id].build_date && p->lib_list[curid].build_date && p->lib_list[curid].build_date < p->lib_list[id].build_date) { - printk("BINFMT_FLAT: library %d is younger than %d", id, curid); + pr_err("library %d is younger than %d", id, curid); goto failed; } } @@ -354,7 +345,7 @@ calc_reloc(unsigned long r, struct lib_info *p, int curid, int internalp) text_len = p->lib_list[id].text_len; if (!flat_reloc_valid(r, start_brk - start_data + text_len)) { - printk("BINFMT_FLAT: reloc outside program 0x%lx (0 - 0x%lx/0x%lx)", + pr_err("reloc outside program 0x%lx (0 - 0x%lx/0x%lx)", r, start_brk-start_data+text_len, text_len); goto failed; } @@ -368,7 +359,7 @@ calc_reloc(unsigned long r, struct lib_info *p, int curid, int internalp) return addr; failed: - printk(", killing %s!\n", current->comm); + pr_cont(", killing %s!\n", current->comm); send_sig(SIGSEGV, current, 0); return RELOC_FAILED; @@ -378,9 +369,7 @@ failed: static void old_reloc(unsigned long rl) { -#ifdef DEBUG static const char *segment[] = { "TEXT", "DATA", "BSS", "*UNKNOWN*" }; -#endif flat_v2_reloc_t r; unsigned long *ptr; @@ -391,11 +380,9 @@ static void old_reloc(unsigned long rl) ptr = (unsigned long *) (current->mm->start_data + r.reloc.offset); #endif -#ifdef DEBUG - printk("Relocation of variable at DATASEG+%x " - "(address %p, currently %lx) into segment %s\n", - r.reloc.offset, ptr, *ptr, segment[r.reloc.type]); -#endif + pr_debug("Relocation of variable at DATASEG+%x " + "(address %p, currently %lx) into segment %s\n", + r.reloc.offset, ptr, *ptr, segment[r.reloc.type]); switch (r.reloc.type) { case OLD_FLAT_RELOC_TYPE_TEXT: @@ -408,13 +395,11 @@ static void old_reloc(unsigned long rl) *ptr += current->mm->end_data; break; default: - printk("BINFMT_FLAT: Unknown relocation type=%x\n", r.reloc.type); + pr_err("Unknown relocation type=%x\n", r.reloc.type); break; } -#ifdef DEBUG - printk("Relocation became %lx\n", *ptr); -#endif + pr_debug("Relocation became %lx\n", *ptr); } /****************************************************************************/ @@ -463,20 +448,19 @@ static int load_flat_file(struct linux_binprm *bprm, } if (flags & FLAT_FLAG_KTRACE) - printk("BINFMT_FLAT: Loading file: %s\n", bprm->filename); + pr_info("Loading file: %s\n", bprm->filename); if (rev != FLAT_VERSION && rev != OLD_FLAT_VERSION) { - printk("BINFMT_FLAT: bad flat file version 0x%x (supported " - "0x%lx and 0x%lx)\n", - rev, FLAT_VERSION, OLD_FLAT_VERSION); + pr_err("bad flat file version 0x%x (supported 0x%lx and 0x%lx)\n", + rev, FLAT_VERSION, OLD_FLAT_VERSION); ret = -ENOEXEC; goto err; } /* Don't allow old format executables to use shared libraries */ if (rev == OLD_FLAT_VERSION && id != 0) { - printk("BINFMT_FLAT: shared libraries are not available before rev 0x%lx\n", - FLAT_VERSION); + pr_err("shared libraries are not available before rev 0x%lx\n", + FLAT_VERSION); ret = -ENOEXEC; goto err; } @@ -490,7 +474,7 @@ static int load_flat_file(struct linux_binprm *bprm, #ifndef CONFIG_BINFMT_ZFLAT if (flags & (FLAT_FLAG_GZIP|FLAT_FLAG_GZDATA)) { - printk("Support for ZFLAT executables is not enabled.\n"); + pr_err("Support for ZFLAT executables is not enabled.\n"); ret = -ENOEXEC; goto err; } @@ -536,7 +520,7 @@ static int load_flat_file(struct linux_binprm *bprm, * this should give us a ROM ptr, but if it doesn't we don't * really care */ - DBG_FLT("BINFMT_FLAT: ROM mapping of file (we hope)\n"); + pr_debug("ROM mapping of file (we hope)\n"); textpos = vm_mmap(bprm->file, 0, text_len, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_EXECUTABLE, 0); @@ -544,7 +528,7 @@ static int load_flat_file(struct linux_binprm *bprm, ret = textpos; if (!textpos) ret = -ENOMEM; - printk("Unable to mmap process text, errno %d\n", ret); + pr_err("Unable to mmap process text, errno %d\n", ret); goto err; } @@ -557,7 +541,7 @@ static int load_flat_file(struct linux_binprm *bprm, ret = realdatastart; if (!realdatastart) ret = -ENOMEM; - printk("Unable to allocate RAM for process data, " + pr_err("Unable to allocate RAM for process data, " "errno %d\n", ret); vm_munmap(textpos, text_len); goto err; @@ -566,8 +550,8 @@ static int load_flat_file(struct linux_binprm *bprm, MAX_SHARED_LIBS * sizeof(unsigned long), FLAT_DATA_ALIGN); - DBG_FLT("BINFMT_FLAT: Allocated data+bss+stack (%ld bytes): %lx\n", - data_len + bss_len + stack_len, datapos); + pr_debug("Allocated data+bss+stack (%ld bytes): %lx\n", + data_len + bss_len + stack_len, datapos); fpos = ntohl(hdr->data_start); #ifdef CONFIG_BINFMT_ZFLAT @@ -582,7 +566,7 @@ static int load_flat_file(struct linux_binprm *bprm, } if (IS_ERR_VALUE(result)) { ret = result; - printk("Unable to read data+bss, errno %d\n", ret); + pr_err("Unable to read data+bss, errno %d\n", ret); vm_munmap(textpos, text_len); vm_munmap(realdatastart, len); goto err; @@ -603,7 +587,7 @@ static int load_flat_file(struct linux_binprm *bprm, ret = textpos; if (!textpos) ret = -ENOMEM; - printk("Unable to allocate RAM for process text/data, " + pr_err("Unable to allocate RAM for process text/data, " "errno %d\n", ret); goto err; } @@ -645,7 +629,7 @@ static int load_flat_file(struct linux_binprm *bprm, } if (IS_ERR_VALUE(result)) { ret = result; - printk("Unable to read code+data+bss, errno %d\n", ret); + pr_err("Unable to read code+data+bss, errno %d\n", ret); vm_munmap(textpos, text_len + data_len + extra + MAX_SHARED_LIBS * sizeof(unsigned long)); goto err; @@ -675,12 +659,12 @@ static int load_flat_file(struct linux_binprm *bprm, } if (flags & FLAT_FLAG_KTRACE) { - printk("Mapping is %lx, Entry point is %x, data_start is %x\n", - textpos, 0x00ffffff&ntohl(hdr->entry), ntohl(hdr->data_start)); - printk("%s %s: TEXT=%lx-%lx DATA=%lx-%lx BSS=%lx-%lx\n", - id ? "Lib" : "Load", bprm->filename, - start_code, end_code, datapos, datapos + data_len, - datapos + data_len, (datapos + data_len + bss_len + 3) & ~3); + pr_info("Mapping is %lx, Entry point is %x, data_start is %x\n", + textpos, 0x00ffffff&ntohl(hdr->entry), ntohl(hdr->data_start)); + pr_info("%s %s: TEXT=%lx-%lx DATA=%lx-%lx BSS=%lx-%lx\n", + id ? "Lib" : "Load", bprm->filename, + start_code, end_code, datapos, datapos + data_len, + datapos + data_len, (datapos + data_len + bss_len + 3) & ~3); } /* Store the current module values into the global library structure */ @@ -890,7 +874,7 @@ static int load_flat_binary(struct linux_binprm *bprm) set_binfmt(&flat_format); p = ((current->mm->context.end_brk + stack_len + 3) & ~3) - 4; - DBG_FLT("p=%lx\n", p); + pr_debug("p=%lx\n", p); /* copy the arg pages onto the stack, this could be more efficient :-) */ for (i = TOP_OF_ARGS - 1; i >= bprm->p; i--) @@ -922,8 +906,8 @@ static int load_flat_binary(struct linux_binprm *bprm) FLAT_PLAT_INIT(regs); #endif - DBG_FLT("start_thread(regs=0x%p, entry=0x%lx, start_stack=0x%lx)\n", - regs, start_addr, current->mm->start_stack); + pr_debug("start_thread(regs=0x%p, entry=0x%lx, start_stack=0x%lx)\n", + regs, start_addr, current->mm->start_stack); start_thread(regs, start_addr, current->mm->start_stack); return 0; From c995ee28d29d6f256c3a8a6c4e66469554374f25 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Sun, 24 Jul 2016 11:30:17 -0400 Subject: [PATCH 06/16] binfmt_flat: prevent kernel dammage from corrupted executable headers Signed-off-by: Nicolas Pitre Signed-off-by: Greg Ungerer --- fs/binfmt_flat.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/fs/binfmt_flat.c b/fs/binfmt_flat.c index c3ccdefdeac2..03301bad1f9b 100644 --- a/fs/binfmt_flat.c +++ b/fs/binfmt_flat.c @@ -465,6 +465,17 @@ static int load_flat_file(struct linux_binprm *bprm, goto err; } + /* + * Make sure the header params are sane. + * 28 bits (256 MB) is way more than reasonable in this case. + * If some top bits are set we have probable binary corruption. + */ + if ((text_len | data_len | bss_len | stack_len | full_data) >> 28) { + pr_err("bad header\n"); + ret = -ENOEXEC; + goto err; + } + /* * fix up the flags for the older format, there were all kinds * of endian hacks, this only works for the simple cases From 7e7ec6a934349ef6983f06f7ac0da09cc8a42983 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Sun, 24 Jul 2016 11:30:18 -0400 Subject: [PATCH 07/16] elf_fdpic_transfer_args_to_stack(): make it generic This copying of arguments and environment is common to both NOMMU binary formats we support. Let's make the elf_fdpic version available to the flat format as well. While at it, improve the code a bit not to copy below the actual data area. Signed-off-by: Nicolas Pitre Reviewed-by: Greg Ungerer Signed-off-by: Greg Ungerer --- fs/binfmt_elf_fdpic.c | 38 ++------------------------------------ fs/exec.c | 33 +++++++++++++++++++++++++++++++++ include/linux/binfmts.h | 2 ++ 3 files changed, 37 insertions(+), 36 deletions(-) diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c index 203589311bf8..464a972e88c1 100644 --- a/fs/binfmt_elf_fdpic.c +++ b/fs/binfmt_elf_fdpic.c @@ -67,8 +67,6 @@ static int create_elf_fdpic_tables(struct linux_binprm *, struct mm_struct *, struct elf_fdpic_params *); #ifndef CONFIG_MMU -static int elf_fdpic_transfer_args_to_stack(struct linux_binprm *, - unsigned long *); static int elf_fdpic_map_file_constdisp_on_uclinux(struct elf_fdpic_params *, struct file *, struct mm_struct *); @@ -515,8 +513,9 @@ static int create_elf_fdpic_tables(struct linux_binprm *bprm, sp = mm->start_stack; /* stack the program arguments and environment */ - if (elf_fdpic_transfer_args_to_stack(bprm, &sp) < 0) + if (transfer_args_to_stack(bprm, &sp) < 0) return -EFAULT; + sp &= ~15; #endif /* @@ -709,39 +708,6 @@ static int create_elf_fdpic_tables(struct linux_binprm *bprm, return 0; } -/*****************************************************************************/ -/* - * transfer the program arguments and environment from the holding pages onto - * the stack - */ -#ifndef CONFIG_MMU -static int elf_fdpic_transfer_args_to_stack(struct linux_binprm *bprm, - unsigned long *_sp) -{ - unsigned long index, stop, sp; - char *src; - int ret = 0; - - stop = bprm->p >> PAGE_SHIFT; - sp = *_sp; - - for (index = MAX_ARG_PAGES - 1; index >= stop; index--) { - src = kmap(bprm->page[index]); - sp -= PAGE_SIZE; - if (copy_to_user((void *) sp, src, PAGE_SIZE) != 0) - ret = -EFAULT; - kunmap(bprm->page[index]); - if (ret < 0) - goto out; - } - - *_sp = (*_sp - (MAX_ARG_PAGES * PAGE_SIZE - bprm->p)) & ~15; - -out: - return ret; -} -#endif - /*****************************************************************************/ /* * load the appropriate binary image (executable or interpreter) into memory diff --git a/fs/exec.c b/fs/exec.c index 887c1c955df8..ef0df2f09257 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -762,6 +762,39 @@ out_unlock: } EXPORT_SYMBOL(setup_arg_pages); +#else + +/* + * Transfer the program arguments and environment from the holding pages + * onto the stack. The provided stack pointer is adjusted accordingly. + */ +int transfer_args_to_stack(struct linux_binprm *bprm, + unsigned long *sp_location) +{ + unsigned long index, stop, sp; + int ret = 0; + + stop = bprm->p >> PAGE_SHIFT; + sp = *sp_location; + + for (index = MAX_ARG_PAGES - 1; index >= stop; index--) { + unsigned int offset = index == stop ? bprm->p & ~PAGE_MASK : 0; + char *src = kmap(bprm->page[index]) + offset; + sp -= PAGE_SIZE - offset; + if (copy_to_user((void *) sp, src, PAGE_SIZE - offset) != 0) + ret = -EFAULT; + kunmap(bprm->page[index]); + if (ret) + goto out; + } + + *sp_location = sp; + +out: + return ret; +} +EXPORT_SYMBOL(transfer_args_to_stack); + #endif /* CONFIG_MMU */ static struct file *do_open_execat(int fd, struct filename *name, int flags) diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h index 314b3caa701c..1303b570b18c 100644 --- a/include/linux/binfmts.h +++ b/include/linux/binfmts.h @@ -113,6 +113,8 @@ extern int suid_dumpable; extern int setup_arg_pages(struct linux_binprm * bprm, unsigned long stack_top, int executable_stack); +extern int transfer_args_to_stack(struct linux_binprm *bprm, + unsigned long *sp_location); extern int bprm_change_interp(char *interp, struct linux_binprm *bprm); extern int copy_strings_kernel(int argc, const char *const *argv, struct linux_binprm *bprm); From 687fd7738ec322ea5994a692c20301eed315899d Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Sun, 24 Jul 2016 11:30:19 -0400 Subject: [PATCH 08/16] binfmt_flat: use generic transfer_args_to_stack() This gets rid of the rather ugly, open coded and suboptimal copy code. Signed-off-by: Nicolas Pitre Reviewed-by: Greg Ungerer Signed-off-by: Greg Ungerer --- fs/binfmt_flat.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/fs/binfmt_flat.c b/fs/binfmt_flat.c index 03301bad1f9b..a002e1a3b9e8 100644 --- a/fs/binfmt_flat.c +++ b/fs/binfmt_flat.c @@ -846,10 +846,8 @@ static int load_flat_binary(struct linux_binprm *bprm) { struct lib_info libinfo; struct pt_regs *regs = current_pt_regs(); - unsigned long p = bprm->p; - unsigned long stack_len; + unsigned long sp, stack_len; unsigned long start_addr; - unsigned long *sp; int res; int i, j; @@ -884,15 +882,15 @@ static int load_flat_binary(struct linux_binprm *bprm) set_binfmt(&flat_format); - p = ((current->mm->context.end_brk + stack_len + 3) & ~3) - 4; - pr_debug("p=%lx\n", p); + sp = ((current->mm->context.end_brk + stack_len + 3) & ~3) - 4; + pr_debug("sp=%lx\n", sp); - /* copy the arg pages onto the stack, this could be more efficient :-) */ - for (i = TOP_OF_ARGS - 1; i >= bprm->p; i--) - *(char *) --p = - ((char *) page_address(bprm->page[i/PAGE_SIZE]))[i % PAGE_SIZE]; + /* copy the arg pages onto the stack */ + res = transfer_args_to_stack(bprm, &sp); + if (res) + return res; - sp = (unsigned long *) create_flat_tables(p, bprm); + sp = create_flat_tables(sp, bprm); /* Fake some return addresses to ensure the call chain will * initialise library in order for us. We are required to call @@ -904,14 +902,14 @@ static int load_flat_binary(struct linux_binprm *bprm) for (i = MAX_SHARED_LIBS-1; i > 0; i--) { if (libinfo.lib_list[i].loaded) { /* Push previos first to call address */ - --sp; put_user(start_addr, sp); + --sp; put_user(start_addr, (unsigned long *)sp); start_addr = libinfo.lib_list[i].entry; } } #endif /* Stash our initial stack pointer into the mm structure */ - current->mm->start_stack = (unsigned long)sp; + current->mm->start_stack = sp; #ifdef FLAT_PLAT_INIT FLAT_PLAT_INIT(regs); From a97d157d00cd0ccbcfde3da7bbf34ab7c68cf4eb Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Sun, 24 Jul 2016 11:30:20 -0400 Subject: [PATCH 09/16] binfmt_flat: clean up create_flat_tables() and stack accesses In addition to better code clarity, this brings proper usage of user memory accessors everywhere the stack is touched. This is essential for making this work on MMU systems. Signed-off-by: Nicolas Pitre Reviewed-by: Greg Ungerer Signed-off-by: Greg Ungerer --- fs/binfmt_flat.c | 107 +++++++++++++++++++++++++---------------------- 1 file changed, 58 insertions(+), 49 deletions(-) diff --git a/fs/binfmt_flat.c b/fs/binfmt_flat.c index a002e1a3b9e8..5dc7968a424f 100644 --- a/fs/binfmt_flat.c +++ b/fs/binfmt_flat.c @@ -103,50 +103,58 @@ static int flat_core_dump(struct coredump_params *cprm) /* * create_flat_tables() parses the env- and arg-strings in new user * memory and creates the pointer tables from them, and puts their - * addresses on the "stack", returning the new stack pointer value. + * addresses on the "stack", recording the new stack pointer value. */ -static unsigned long create_flat_tables( - unsigned long pp, - struct linux_binprm *bprm) +static int create_flat_tables(struct linux_binprm *bprm, unsigned long arg_start) { - unsigned long *argv, *envp; - unsigned long *sp; - char *p = (char *)pp; - int argc = bprm->argc; - int envc = bprm->envc; - char uninitialized_var(dummy); + char __user *p; + unsigned long __user *sp; + long i, len; - sp = (unsigned long *)p; - sp -= (envc + argc + 2) + 1 + (flat_argvp_envp_on_stack() ? 2 : 0); - sp = (unsigned long *) ((unsigned long)sp & -FLAT_STACK_ALIGN); - argv = sp + 1 + (flat_argvp_envp_on_stack() ? 2 : 0); - envp = argv + (argc + 1); + p = (char __user *)arg_start; + sp = (unsigned long __user *)current->mm->start_stack; + sp -= bprm->envc + 1; + sp -= bprm->argc + 1; + sp -= flat_argvp_envp_on_stack() ? 2 : 0; + 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()) { - put_user((unsigned long) envp, sp + 2); - put_user((unsigned long) argv, sp + 1); + unsigned long argv, envp; + argv = (unsigned long)(sp + 2); + envp = (unsigned long)(sp + 2 + bprm->argc + 1); + __put_user(argv, sp++); + __put_user(envp, sp++); } - put_user(argc, sp); - current->mm->arg_start = (unsigned long) p; - while (argc-- > 0) { - put_user((unsigned long) p, argv++); - do { - get_user(dummy, p); p++; - } while (dummy); + current->mm->arg_start = (unsigned long)p; + for (i = bprm->argc; i > 0; i--) { + __put_user((unsigned long)p, sp++); + len = strnlen_user(p, MAX_ARG_STRLEN); + if (!len || len > MAX_ARG_STRLEN) + return -EINVAL; + p += len; } - put_user((unsigned long) NULL, argv); - current->mm->arg_end = current->mm->env_start = (unsigned long) p; - while (envc-- > 0) { - put_user((unsigned long)p, envp); envp++; - do { - get_user(dummy, p); p++; - } while (dummy); + __put_user(0, sp++); + current->mm->arg_end = (unsigned long)p; + + current->mm->env_start = (unsigned long) p; + for (i = bprm->envc; i > 0; i--) { + __put_user((unsigned long)p, sp++); + len = strnlen_user(p, MAX_ARG_STRLEN); + if (!len || len > MAX_ARG_STRLEN) + return -EINVAL; + p += len; } - put_user((unsigned long) NULL, envp); - current->mm->env_end = (unsigned long) p; - return (unsigned long)sp; + __put_user(0, sp++); + current->mm->env_end = (unsigned long)p; + + return 0; } /****************************************************************************/ @@ -846,7 +854,7 @@ static int load_flat_binary(struct linux_binprm *bprm) { struct lib_info libinfo; struct pt_regs *regs = current_pt_regs(); - unsigned long sp, stack_len; + unsigned long stack_len; unsigned long start_addr; int res; int i, j; @@ -860,11 +868,10 @@ static int load_flat_binary(struct linux_binprm *bprm) * pedantic and include space for the argv/envp array as it may have * a lot of entries. */ -#define TOP_OF_ARGS (PAGE_SIZE * MAX_ARG_PAGES - sizeof(void *)) - stack_len = TOP_OF_ARGS - bprm->p; /* the strings */ - stack_len += (bprm->argc + 1) * sizeof(char *); /* the argv array */ - stack_len += (bprm->envc + 1) * sizeof(char *); /* the envp array */ - stack_len += FLAT_STACK_ALIGN - 1; /* reserve for upcoming alignment */ + stack_len = PAGE_SIZE * MAX_ARG_PAGES - bprm->p; /* the strings */ + stack_len += (bprm->argc + 1) * sizeof(char *); /* the argv array */ + stack_len += (bprm->envc + 1) * sizeof(char *); /* the envp array */ + stack_len = ALIGN(stack_len, FLAT_STACK_ALIGN); res = load_flat_file(bprm, &libinfo, 0, &stack_len); if (res < 0) @@ -882,16 +889,18 @@ static int load_flat_binary(struct linux_binprm *bprm) set_binfmt(&flat_format); - sp = ((current->mm->context.end_brk + stack_len + 3) & ~3) - 4; - pr_debug("sp=%lx\n", sp); + /* Stash our initial stack pointer into the mm structure */ + current->mm->start_stack = + ((current->mm->context.end_brk + stack_len + 3) & ~3) - 4; + pr_debug("sp=%lx\n", current->mm->start_stack); /* copy the arg pages onto the stack */ - res = transfer_args_to_stack(bprm, &sp); + res = transfer_args_to_stack(bprm, ¤t->mm->start_stack); + if (!res) + res = create_flat_tables(bprm, current->mm->start_stack); if (res) return res; - sp = create_flat_tables(sp, bprm); - /* Fake some return addresses to ensure the call chain will * initialise library in order for us. We are required to call * lib 1 first, then 2, ... and finally the main program (id 0). @@ -902,15 +911,15 @@ static int load_flat_binary(struct linux_binprm *bprm) for (i = MAX_SHARED_LIBS-1; i > 0; i--) { if (libinfo.lib_list[i].loaded) { /* Push previos first to call address */ - --sp; put_user(start_addr, (unsigned long *)sp); + unsigned long __user *sp; + current->mm->start_stack -= sizeof(unsigned long); + sp = (unsigned long __user *)current->mm->start_stack; + __put_user(start_addr, sp); start_addr = libinfo.lib_list[i].entry; } } #endif - /* Stash our initial stack pointer into the mm structure */ - current->mm->start_stack = sp; - #ifdef FLAT_PLAT_INIT FLAT_PLAT_INIT(regs); #endif From 6e572ffe3feb8a02ed0044987654e07670aeffc2 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Sun, 24 Jul 2016 11:30:21 -0400 Subject: [PATCH 10/16] binfmt_flat: use proper user space accessors with relocs processing code Relocs are fixed up in place in user space memory. The appropriate accessors are required for this code to work with an active MMU. The architecture specific handlers flat_get_addr_from_rp() and flat_put_addr_at_rp() for ARM and M68K are adjusted with separate patches. SuperH and Xtensa are left out as they doesn't implement __get_user_unaligned() and __put_user_unaligned() yet. The other architectures that use BFLT don't have any MMU. Signed-off-by: Nicolas Pitre Reviewed-by: Greg Ungerer Signed-off-by: Greg Ungerer --- fs/binfmt_flat.c | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/fs/binfmt_flat.c b/fs/binfmt_flat.c index 5dc7968a424f..9deafb282db5 100644 --- a/fs/binfmt_flat.c +++ b/fs/binfmt_flat.c @@ -419,7 +419,7 @@ static int load_flat_file(struct linux_binprm *bprm, unsigned long textpos, datapos, realdatastart; unsigned long text_len, data_len, bss_len, stack_len, full_data, flags; unsigned long len, memp, memp_size, extra, rlim; - unsigned long *reloc, *rp; + unsigned long __user *reloc, *rp; struct inode *inode; int i, rev, relocs; loff_t fpos; @@ -591,7 +591,7 @@ static int load_flat_file(struct linux_binprm *bprm, goto err; } - reloc = (unsigned long *) + reloc = (unsigned long __user *) (datapos + (ntohl(hdr->reloc_start) - text_len)); memp = realdatastart; memp_size = len; @@ -616,7 +616,7 @@ static int load_flat_file(struct linux_binprm *bprm, MAX_SHARED_LIBS * sizeof(unsigned long), FLAT_DATA_ALIGN); - reloc = (unsigned long *) + reloc = (unsigned long __user *) (datapos + (ntohl(hdr->reloc_start) - text_len)); memp = textpos; memp_size = len; @@ -708,15 +708,20 @@ static int load_flat_file(struct linux_binprm *bprm, * image. */ if (flags & FLAT_FLAG_GOTPIC) { - for (rp = (unsigned long *)datapos; *rp != 0xffffffff; rp++) { - unsigned long addr; - if (*rp) { - addr = calc_reloc(*rp, libinfo, id, 0); + for (rp = (unsigned long __user *)datapos; ; rp++) { + unsigned long addr, rp_val; + if (get_user(rp_val, rp)) + return -EFAULT; + if (rp_val == 0xffffffff) + break; + if (rp_val) { + addr = calc_reloc(rp_val, libinfo, id, 0); if (addr == RELOC_FAILED) { ret = -ENOEXEC; goto err; } - *rp = addr; + if (put_user(addr, rp)) + return -EFAULT; } } } @@ -733,7 +738,7 @@ static int load_flat_file(struct linux_binprm *bprm, * __start to address 4 so that is okay). */ if (rev > OLD_FLAT_VERSION) { - unsigned long persistent = 0; + unsigned long __maybe_unused persistent = 0; for (i = 0; i < relocs; i++) { unsigned long addr, relval; @@ -742,12 +747,14 @@ static int load_flat_file(struct linux_binprm *bprm, * relocated (of course, the address has to be * relocated first). */ - relval = ntohl(reloc[i]); + if (get_user(relval, reloc + i)) + return -EFAULT; + relval = ntohl(relval); if (flat_set_persistent(relval, &persistent)) continue; addr = flat_get_relocate_addr(relval); - rp = (unsigned long *) calc_reloc(addr, libinfo, id, 1); - if (rp == (unsigned long *)RELOC_FAILED) { + rp = (unsigned long __user *)calc_reloc(addr, libinfo, id, 1); + if (rp == (unsigned long __user *)RELOC_FAILED) { ret = -ENOEXEC; goto err; } From 1b2ce442ea96b1e76300553963154d68cc5b4ad0 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Sun, 24 Jul 2016 11:30:22 -0400 Subject: [PATCH 11/16] binfmt_flat: use proper user space accessors with old relocs code Signed-off-by: Nicolas Pitre Reviewed-by: Greg Ungerer Signed-off-by: Greg Ungerer --- fs/binfmt_flat.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/fs/binfmt_flat.c b/fs/binfmt_flat.c index 9deafb282db5..8e812d7a62e0 100644 --- a/fs/binfmt_flat.c +++ b/fs/binfmt_flat.c @@ -379,35 +379,38 @@ static void old_reloc(unsigned long rl) { static const char *segment[] = { "TEXT", "DATA", "BSS", "*UNKNOWN*" }; flat_v2_reloc_t r; - unsigned long *ptr; + unsigned long __user *ptr; + unsigned long val; r.value = rl; #if defined(CONFIG_COLDFIRE) - ptr = (unsigned long *) (current->mm->start_code + r.reloc.offset); + ptr = (unsigned long __user *)(current->mm->start_code + r.reloc.offset); #else - ptr = (unsigned long *) (current->mm->start_data + r.reloc.offset); + ptr = (unsigned long __user *)(current->mm->start_data + r.reloc.offset); #endif + get_user(val, ptr); pr_debug("Relocation of variable at DATASEG+%x " "(address %p, currently %lx) into segment %s\n", - r.reloc.offset, ptr, *ptr, segment[r.reloc.type]); + r.reloc.offset, ptr, val, segment[r.reloc.type]); switch (r.reloc.type) { case OLD_FLAT_RELOC_TYPE_TEXT: - *ptr += current->mm->start_code; + val += current->mm->start_code; break; case OLD_FLAT_RELOC_TYPE_DATA: - *ptr += current->mm->start_data; + val += current->mm->start_data; break; case OLD_FLAT_RELOC_TYPE_BSS: - *ptr += current->mm->end_data; + val += current->mm->end_data; break; default: pr_err("Unknown relocation type=%x\n", r.reloc.type); break; } + put_user(val, ptr); - pr_debug("Relocation became %lx\n", *ptr); + pr_debug("Relocation became %lx\n", val); } /****************************************************************************/ @@ -780,8 +783,13 @@ static int load_flat_file(struct linux_binprm *bprm, } } } else { - for (i = 0; i < relocs; i++) - old_reloc(ntohl(reloc[i])); + for (i = 0; i < relocs; i++) { + unsigned long relval; + if (get_user(relval, reloc + i)) + return -EFAULT; + relval = ntohl(relval); + old_reloc(relval); + } } flush_icache_range(start_code, end_code); From 467aa1465a7b9f0bd1a23c83bff8c38e3c3e660e Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Sun, 24 Jul 2016 11:30:23 -0400 Subject: [PATCH 12/16] binfmt_flat: use clear_user() rather than memset() to clear .bss This is needed on systems with a MMU. Signed-off-by: Nicolas Pitre Reviewed-by: Greg Ungerer Signed-off-by: Greg Ungerer --- fs/binfmt_flat.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/fs/binfmt_flat.c b/fs/binfmt_flat.c index 8e812d7a62e0..eb747a266537 100644 --- a/fs/binfmt_flat.c +++ b/fs/binfmt_flat.c @@ -795,10 +795,11 @@ static int load_flat_file(struct linux_binprm *bprm, flush_icache_range(start_code, end_code); /* zero the BSS, BRK and stack areas */ - memset((void *)(datapos + data_len), 0, bss_len + - (memp + memp_size - stack_len - /* end brk */ - libinfo->lib_list[id].start_brk) + /* start brk */ - stack_len); + if (clear_user((void __user *)(datapos + data_len), bss_len + + (memp + memp_size - stack_len - /* end brk */ + libinfo->lib_list[id].start_brk) + /* start brk */ + stack_len)) + return -EFAULT; return 0; err: From af521f92dcf636c59330233a61cb689d0383c291 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Sun, 24 Jul 2016 11:30:24 -0400 Subject: [PATCH 13/16] binfmt_flat: update libraries' data segment pointer with userspace accessors This is needed on systems with a MMU. This also gets rid of the strangest C code I've seen lateli i.e. an integer indexed with a pointer value within square brackets. That really looked backwards. Signed-off-by: Nicolas Pitre Reviewed-by: Greg Ungerer Signed-off-by: Greg Ungerer --- fs/binfmt_flat.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/fs/binfmt_flat.c b/fs/binfmt_flat.c index eb747a266537..83e507137112 100644 --- a/fs/binfmt_flat.c +++ b/fs/binfmt_flat.c @@ -894,12 +894,19 @@ static int load_flat_binary(struct linux_binprm *bprm) return res; /* Update data segment pointers for all libraries */ - for (i = 0; i < MAX_SHARED_LIBS; i++) - if (libinfo.lib_list[i].loaded) - for (j = 0; j < MAX_SHARED_LIBS; j++) - (-(j+1))[(unsigned long *)(libinfo.lib_list[i].start_data)] = - (libinfo.lib_list[j].loaded) ? - libinfo.lib_list[j].start_data : UNLOADED_LIB; + for (i = 0; i < MAX_SHARED_LIBS; i++) { + if (!libinfo.lib_list[i].loaded) + continue; + for (j = 0; j < MAX_SHARED_LIBS; j++) { + unsigned long val = libinfo.lib_list[j].loaded ? + libinfo.lib_list[j].start_data : UNLOADED_LIB; + unsigned long __user *p = (unsigned long __user *) + libinfo.lib_list[i].start_data; + p -= j + 1; + if (put_user(val, p)) + return -EFAULT; + } + } install_exec_creds(bprm); From 015feacf932108429f59b511b29d7e98a629e333 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Sun, 24 Jul 2016 11:30:25 -0400 Subject: [PATCH 14/16] binfmt_flat: add MMU-specific support Not much else to do at this point except for the different stack setups. Signed-off-by: Nicolas Pitre Reviewed-by: Greg Ungerer Signed-off-by: Greg Ungerer --- fs/binfmt_flat.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/fs/binfmt_flat.c b/fs/binfmt_flat.c index 83e507137112..506139bfdc9e 100644 --- a/fs/binfmt_flat.c +++ b/fs/binfmt_flat.c @@ -537,7 +537,7 @@ static int load_flat_file(struct linux_binprm *bprm, * case, and then the fully copied to RAM case which lumps * it all together. */ - if ((flags & (FLAT_FLAG_RAM|FLAT_FLAG_GZIP)) == 0) { + if (!IS_ENABLED(CONFIG_MMU) && !(flags & (FLAT_FLAG_RAM|FLAT_FLAG_GZIP))) { /* * this should give us a ROM ptr, but if it doesn't we don't * really care @@ -677,7 +677,9 @@ static int load_flat_file(struct linux_binprm *bprm, */ current->mm->start_brk = datapos + data_len + bss_len; current->mm->brk = (current->mm->start_brk + 3) & ~3; +#ifndef CONFIG_MMU current->mm->context.end_brk = memp + memp_size - stack_len; +#endif } if (flags & FLAT_FLAG_KTRACE) { @@ -870,7 +872,7 @@ static int load_flat_binary(struct linux_binprm *bprm) { struct lib_info libinfo; struct pt_regs *regs = current_pt_regs(); - unsigned long stack_len; + unsigned long stack_len = 0; unsigned long start_addr; int res; int i, j; @@ -884,7 +886,9 @@ static int load_flat_binary(struct linux_binprm *bprm) * pedantic and include space for the argv/envp array as it may have * a lot of entries. */ - stack_len = PAGE_SIZE * MAX_ARG_PAGES - bprm->p; /* the strings */ +#ifndef CONFIG_MMU + stack_len += PAGE_SIZE * MAX_ARG_PAGES - bprm->p; /* the strings */ +#endif stack_len += (bprm->argc + 1) * sizeof(char *); /* the argv array */ stack_len += (bprm->envc + 1) * sizeof(char *); /* the envp array */ stack_len = ALIGN(stack_len, FLAT_STACK_ALIGN); @@ -912,6 +916,11 @@ static int load_flat_binary(struct linux_binprm *bprm) set_binfmt(&flat_format); +#ifdef CONFIG_MMU + res = setup_arg_pages(bprm, STACK_TOP, EXSTACK_DEFAULT); + if (!res) + res = create_flat_tables(bprm, bprm->p); +#else /* Stash our initial stack pointer into the mm structure */ current->mm->start_stack = ((current->mm->context.end_brk + stack_len + 3) & ~3) - 4; @@ -921,6 +930,7 @@ static int load_flat_binary(struct linux_binprm *bprm) res = transfer_args_to_stack(bprm, ¤t->mm->start_stack); if (!res) res = create_flat_tables(bprm, current->mm->start_stack); +#endif if (res) return res; From 472f95f32d5aa07eda96a6b2578b85d7b27c5110 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Sun, 24 Jul 2016 11:30:26 -0400 Subject: [PATCH 15/16] binfmt_flat: allow compressed flat binary format to work on MMU systems Let's take the simple and obvious approach by decompressing the binary into a kernel buffer and then copying it to user space. Those who are looking for top performance on an MMU system are unlikely to choose this executable format anyway. Signed-off-by: Nicolas Pitre Reviewed-by: Greg Ungerer Signed-off-by: Greg Ungerer --- fs/binfmt_flat.c | 44 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/fs/binfmt_flat.c b/fs/binfmt_flat.c index 506139bfdc9e..9b2917a30294 100644 --- a/fs/binfmt_flat.c +++ b/fs/binfmt_flat.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -628,6 +629,7 @@ static int load_flat_file(struct linux_binprm *bprm, * load it all in and treat it like a RAM load from now on */ if (flags & FLAT_FLAG_GZIP) { +#ifndef CONFIG_MMU result = decompress_exec(bprm, sizeof(struct flat_hdr), (((char *)textpos) + sizeof(struct flat_hdr)), (text_len + full_data @@ -635,13 +637,51 @@ static int load_flat_file(struct linux_binprm *bprm, 0); memmove((void *) datapos, (void *) realdatastart, full_data); +#else + /* + * This is used on MMU systems mainly for testing. + * Let's use a kernel buffer to simplify things. + */ + long unz_text_len = text_len - sizeof(struct flat_hdr); + long unz_len = unz_text_len + full_data; + char *unz_data = vmalloc(unz_len); + if (!unz_data) { + result = -ENOMEM; + } else { + result = decompress_exec(bprm, sizeof(struct flat_hdr), + unz_data, unz_len, 0); + if (result == 0 && + (copy_to_user((void __user *)textpos + sizeof(struct flat_hdr), + unz_data, unz_text_len) || + copy_to_user((void __user *)datapos, + unz_data + unz_text_len, full_data))) + result = -EFAULT; + vfree(unz_data); + } +#endif } else if (flags & FLAT_FLAG_GZDATA) { result = read_code(bprm->file, textpos, 0, text_len); - if (!IS_ERR_VALUE(result)) + if (!IS_ERR_VALUE(result)) { +#ifndef CONFIG_MMU result = decompress_exec(bprm, text_len, (char *) datapos, full_data, 0); - } else +#else + char *unz_data = vmalloc(full_data); + if (!unz_data) { + result = -ENOMEM; + } else { + result = decompress_exec(bprm, text_len, + unz_data, full_data, 0); + if (result == 0 && + copy_to_user((void __user *)datapos, + unz_data, full_data)) + result = -EFAULT; + vfree(unz_data); + } #endif + } + } else +#endif /* CONFIG_BINFMT_ZFLAT */ { result = read_code(bprm->file, textpos, 0, text_len); if (!IS_ERR_VALUE(result)) From 002d2f01f13f1671d771e1493a3405ed4986694d Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Sun, 24 Jul 2016 11:30:28 -0400 Subject: [PATCH 16/16] m68k: enable binfmt_flat on systems with an MMU Now that the generic changes are in place, this can be enabled on m68k with the use of proper user space accessors in the flat_get_addr_from_rp() and flat_put_addr_at_rp() handlers as rp actually holds a user space address. Signed-off-by: Nicolas Pitre Signed-off-by: Greg Ungerer --- arch/m68k/include/asm/flat.h | 5 +++-- fs/Kconfig.binfmt | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/arch/m68k/include/asm/flat.h b/arch/m68k/include/asm/flat.h index 8e58d47be90d..00c392b0cabd 100644 --- a/arch/m68k/include/asm/flat.h +++ b/arch/m68k/include/asm/flat.h @@ -8,8 +8,9 @@ #define flat_argvp_envp_on_stack() 1 #define flat_old_ram_flag(flags) (flags) #define flat_reloc_valid(reloc, size) ((reloc) <= (size)) -#define flat_get_addr_from_rp(rp, relval, flags, p) get_unaligned(rp) -#define flat_put_addr_at_rp(rp, val, relval) put_unaligned(val,rp) +#define flat_get_addr_from_rp(rp, relval, flags, p) \ + ({ unsigned long __val; __get_user_unaligned(__val, rp); __val; }) +#define flat_put_addr_at_rp(rp, val, relval) __put_user_unaligned(val, rp) #define flat_get_relocate_addr(rel) (rel) static inline int flat_set_persistent(unsigned long relval, diff --git a/fs/Kconfig.binfmt b/fs/Kconfig.binfmt index 72c03354c14b..c7efddf6e038 100644 --- a/fs/Kconfig.binfmt +++ b/fs/Kconfig.binfmt @@ -89,7 +89,8 @@ config BINFMT_SCRIPT config BINFMT_FLAT bool "Kernel support for flat binaries" - depends on !MMU && (!FRV || BROKEN) + depends on !MMU || M68K + depends on !FRV || BROKEN help Support uClinux FLAT format binaries.