From 102a0743326a03cd1a1202ceda21e175b7d3575c Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Tue, 20 Feb 2024 01:20:52 +0000 Subject: [PATCH] add new system file --- kernel/fs/binfmt_flat.c | 136 ++++++++++++++++++++++++++++++++------------- 1 files changed, 96 insertions(+), 40 deletions(-) diff --git a/kernel/fs/binfmt_flat.c b/kernel/fs/binfmt_flat.c index e4b59e7..69f4db0 100644 --- a/kernel/fs/binfmt_flat.c +++ b/kernel/fs/binfmt_flat.c @@ -42,6 +42,11 @@ #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 /****************************************************************************/ @@ -62,6 +67,12 @@ #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 { @@ -120,41 +131,47 @@ 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 (put_user(bprm->argc, sp++)) + return -EFAULT; + 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); - __put_user(argv, sp++); - __put_user(envp, sp++); + if (put_user(argv, sp++) || put_user(envp, sp++)) + return -EFAULT; } current->mm->arg_start = (unsigned long)p; for (i = bprm->argc; i > 0; i--) { - __put_user((unsigned long)p, sp++); + if (put_user((unsigned long)p, sp++)) + return -EFAULT; len = strnlen_user(p, MAX_ARG_STRLEN); if (!len || len > MAX_ARG_STRLEN) return -EINVAL; p += len; } - __put_user(0, sp++); + if (put_user(0, sp++)) + return -EFAULT; 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++); + if (put_user((unsigned long)p, sp++)) + return -EFAULT; len = strnlen_user(p, MAX_ARG_STRLEN); if (!len || len > MAX_ARG_STRLEN) return -EINVAL; p += len; } - __put_user(0, sp++); + if (put_user(0, sp++)) + return -EFAULT; current->mm->env_end = (unsigned long)p; return 0; @@ -345,7 +362,7 @@ 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 +385,7 @@ /****************************************************************************/ +#ifdef CONFIG_BINFMT_FLAT_OLD static void old_reloc(unsigned long rl) { static const char *segment[] = { "TEXT", "DATA", "BSS", "*UNKNOWN*" }; @@ -405,8 +423,33 @@ pr_debug("Relocation became %lx\n", val); } +#endif /* CONFIG_BINFMT_FLAT_OLD */ /****************************************************************************/ + +static inline u32 __user *skip_got_header(u32 __user *rp) +{ + if (IS_ENABLED(CONFIG_RISCV)) { + /* + * RISC-V has a 16 byte GOT PLT header for elf64-riscv + * and 8 byte GOT PLT header for elf32-riscv. + * Skip the whole GOT PLT header, since it is reserved + * for the dynamic linker (ld.so). + */ + u32 rp_val0, rp_val1; + + if (get_user(rp_val0, rp)) + return rp; + if (get_user(rp_val1, rp + 1)) + return rp; + + if (rp_val0 == 0xffffffff && rp_val1 == 0xffffffff) + rp += 4; + else if (rp_val0 == 0xffffffff) + rp += 2; + } + return rp; +} static int load_flat_file(struct linux_binprm *bprm, struct lib_info *libinfo, int id, unsigned long *extra_stack) @@ -415,8 +458,8 @@ 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 +467,6 @@ 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 +496,7 @@ 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); @@ -470,6 +513,23 @@ } /* + * 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. * If some top bits are set we have probable binary corruption. @@ -479,13 +539,6 @@ 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 - */ - 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)) { @@ -510,7 +563,7 @@ /* Flush all traces of the currently running executable */ if (id == 0) { - ret = flush_old_exec(bprm); + ret = begin_new_exec(bprm); if (ret) goto err; @@ -587,7 +640,7 @@ goto err; } - reloc = (u32 __user *) + reloc = (__be32 __user *) (datapos + (ntohl(hdr->reloc_start) - text_len)); memp = realdatastart; memp_size = len; @@ -612,7 +665,7 @@ MAX_SHARED_LIBS * sizeof(u32), FLAT_DATA_ALIGN); - reloc = (u32 __user *) + reloc = (__be32 __user *) (datapos + (ntohl(hdr->reloc_start) - text_len)); memp = textpos; memp_size = len; @@ -745,7 +798,8 @@ * image. */ if (flags & FLAT_FLAG_GOTPIC) { - for (rp = (u32 __user *)datapos; ; rp++) { + rp = skip_got_header((u32 __user *) datapos); + for (; ; rp++) { u32 addr, rp_val; if (get_user(rp_val, rp)) return -EFAULT; @@ -775,20 +829,18 @@ * __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 +849,7 @@ } /* 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 +858,13 @@ * 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,17 +877,18 @@ 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); + flush_icache_user_range(start_code, end_code); /* zero the BSS, BRK and stack areas */ if (clear_user((void __user *)(datapos + data_len), bss_len + @@ -940,8 +997,6 @@ } } - install_exec_creds(bprm); - set_binfmt(&flat_format); #ifdef CONFIG_MMU @@ -975,7 +1030,8 @@ unsigned long __user *sp; current->mm->start_stack -= sizeof(unsigned long); sp = (unsigned long __user *)current->mm->start_stack; - __put_user(start_addr, sp); + if (put_user(start_addr, sp)) + return -EFAULT; start_addr = libinfo.lib_list[i].entry; } } -- Gitblit v1.6.2