162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/****************************************************************************/ 362306a36Sopenharmony_ci/* 462306a36Sopenharmony_ci * linux/fs/binfmt_flat.c 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (C) 2000-2003 David McCullough <davidm@snapgear.com> 762306a36Sopenharmony_ci * Copyright (C) 2002 Greg Ungerer <gerg@snapgear.com> 862306a36Sopenharmony_ci * Copyright (C) 2002 SnapGear, by Paul Dale <pauli@snapgear.com> 962306a36Sopenharmony_ci * Copyright (C) 2000, 2001 Lineo, by David McCullough <davidm@lineo.com> 1062306a36Sopenharmony_ci * based heavily on: 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * linux/fs/binfmt_aout.c: 1362306a36Sopenharmony_ci * Copyright (C) 1991, 1992, 1996 Linus Torvalds 1462306a36Sopenharmony_ci * linux/fs/binfmt_flat.c for 2.0 kernel 1562306a36Sopenharmony_ci * Copyright (C) 1998 Kenneth Albanowski <kjahds@kjahds.com> 1662306a36Sopenharmony_ci * JAN/99 -- coded full program relocation (gerg@snapgear.com) 1762306a36Sopenharmony_ci */ 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#include <linux/kernel.h> 2262306a36Sopenharmony_ci#include <linux/sched.h> 2362306a36Sopenharmony_ci#include <linux/sched/task_stack.h> 2462306a36Sopenharmony_ci#include <linux/mm.h> 2562306a36Sopenharmony_ci#include <linux/mman.h> 2662306a36Sopenharmony_ci#include <linux/errno.h> 2762306a36Sopenharmony_ci#include <linux/signal.h> 2862306a36Sopenharmony_ci#include <linux/string.h> 2962306a36Sopenharmony_ci#include <linux/fs.h> 3062306a36Sopenharmony_ci#include <linux/file.h> 3162306a36Sopenharmony_ci#include <linux/ptrace.h> 3262306a36Sopenharmony_ci#include <linux/user.h> 3362306a36Sopenharmony_ci#include <linux/slab.h> 3462306a36Sopenharmony_ci#include <linux/binfmts.h> 3562306a36Sopenharmony_ci#include <linux/personality.h> 3662306a36Sopenharmony_ci#include <linux/init.h> 3762306a36Sopenharmony_ci#include <linux/flat.h> 3862306a36Sopenharmony_ci#include <linux/uaccess.h> 3962306a36Sopenharmony_ci#include <linux/vmalloc.h> 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci#include <asm/byteorder.h> 4262306a36Sopenharmony_ci#include <asm/unaligned.h> 4362306a36Sopenharmony_ci#include <asm/cacheflush.h> 4462306a36Sopenharmony_ci#include <asm/page.h> 4562306a36Sopenharmony_ci#include <asm/flat.h> 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci#ifndef flat_get_relocate_addr 4862306a36Sopenharmony_ci#define flat_get_relocate_addr(rel) (rel) 4962306a36Sopenharmony_ci#endif 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci/****************************************************************************/ 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci/* 5462306a36Sopenharmony_ci * User data (data section and bss) needs to be aligned. 5562306a36Sopenharmony_ci * We pick 0x20 here because it is the max value elf2flt has always 5662306a36Sopenharmony_ci * used in producing FLAT files, and because it seems to be large 5762306a36Sopenharmony_ci * enough to make all the gcc alignment related tests happy. 5862306a36Sopenharmony_ci */ 5962306a36Sopenharmony_ci#define FLAT_DATA_ALIGN (0x20) 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci/* 6262306a36Sopenharmony_ci * User data (stack) also needs to be aligned. 6362306a36Sopenharmony_ci * Here we can be a bit looser than the data sections since this 6462306a36Sopenharmony_ci * needs to only meet arch ABI requirements. 6562306a36Sopenharmony_ci */ 6662306a36Sopenharmony_ci#define FLAT_STACK_ALIGN max_t(unsigned long, sizeof(void *), ARCH_SLAB_MINALIGN) 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci#define RELOC_FAILED 0xff00ff01 /* Relocation incorrect somewhere */ 6962306a36Sopenharmony_ci#define UNLOADED_LIB 0x7ff000ff /* Placeholder for unused library */ 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci#define MAX_SHARED_LIBS (1) 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci#ifdef CONFIG_BINFMT_FLAT_NO_DATA_START_OFFSET 7462306a36Sopenharmony_ci#define DATA_START_OFFSET_WORDS (0) 7562306a36Sopenharmony_ci#else 7662306a36Sopenharmony_ci#define DATA_START_OFFSET_WORDS (MAX_SHARED_LIBS) 7762306a36Sopenharmony_ci#endif 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_cistruct lib_info { 8062306a36Sopenharmony_ci struct { 8162306a36Sopenharmony_ci unsigned long start_code; /* Start of text segment */ 8262306a36Sopenharmony_ci unsigned long start_data; /* Start of data segment */ 8362306a36Sopenharmony_ci unsigned long start_brk; /* End of data segment */ 8462306a36Sopenharmony_ci unsigned long text_len; /* Length of text segment */ 8562306a36Sopenharmony_ci unsigned long entry; /* Start address for this module */ 8662306a36Sopenharmony_ci unsigned long build_date; /* When this one was compiled */ 8762306a36Sopenharmony_ci bool loaded; /* Has this library been loaded? */ 8862306a36Sopenharmony_ci } lib_list[MAX_SHARED_LIBS]; 8962306a36Sopenharmony_ci}; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_cistatic int load_flat_binary(struct linux_binprm *); 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_cistatic struct linux_binfmt flat_format = { 9462306a36Sopenharmony_ci .module = THIS_MODULE, 9562306a36Sopenharmony_ci .load_binary = load_flat_binary, 9662306a36Sopenharmony_ci}; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci/****************************************************************************/ 10062306a36Sopenharmony_ci/* 10162306a36Sopenharmony_ci * create_flat_tables() parses the env- and arg-strings in new user 10262306a36Sopenharmony_ci * memory and creates the pointer tables from them, and puts their 10362306a36Sopenharmony_ci * addresses on the "stack", recording the new stack pointer value. 10462306a36Sopenharmony_ci */ 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cistatic int create_flat_tables(struct linux_binprm *bprm, unsigned long arg_start) 10762306a36Sopenharmony_ci{ 10862306a36Sopenharmony_ci char __user *p; 10962306a36Sopenharmony_ci unsigned long __user *sp; 11062306a36Sopenharmony_ci long i, len; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci p = (char __user *)arg_start; 11362306a36Sopenharmony_ci sp = (unsigned long __user *)current->mm->start_stack; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci sp -= bprm->envc + 1; 11662306a36Sopenharmony_ci sp -= bprm->argc + 1; 11762306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_BINFMT_FLAT_ARGVP_ENVP_ON_STACK)) 11862306a36Sopenharmony_ci sp -= 2; /* argvp + envp */ 11962306a36Sopenharmony_ci sp -= 1; /* &argc */ 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci current->mm->start_stack = (unsigned long)sp & -FLAT_STACK_ALIGN; 12262306a36Sopenharmony_ci sp = (unsigned long __user *)current->mm->start_stack; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci if (put_user(bprm->argc, sp++)) 12562306a36Sopenharmony_ci return -EFAULT; 12662306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_BINFMT_FLAT_ARGVP_ENVP_ON_STACK)) { 12762306a36Sopenharmony_ci unsigned long argv, envp; 12862306a36Sopenharmony_ci argv = (unsigned long)(sp + 2); 12962306a36Sopenharmony_ci envp = (unsigned long)(sp + 2 + bprm->argc + 1); 13062306a36Sopenharmony_ci if (put_user(argv, sp++) || put_user(envp, sp++)) 13162306a36Sopenharmony_ci return -EFAULT; 13262306a36Sopenharmony_ci } 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci current->mm->arg_start = (unsigned long)p; 13562306a36Sopenharmony_ci for (i = bprm->argc; i > 0; i--) { 13662306a36Sopenharmony_ci if (put_user((unsigned long)p, sp++)) 13762306a36Sopenharmony_ci return -EFAULT; 13862306a36Sopenharmony_ci len = strnlen_user(p, MAX_ARG_STRLEN); 13962306a36Sopenharmony_ci if (!len || len > MAX_ARG_STRLEN) 14062306a36Sopenharmony_ci return -EINVAL; 14162306a36Sopenharmony_ci p += len; 14262306a36Sopenharmony_ci } 14362306a36Sopenharmony_ci if (put_user(0, sp++)) 14462306a36Sopenharmony_ci return -EFAULT; 14562306a36Sopenharmony_ci current->mm->arg_end = (unsigned long)p; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci current->mm->env_start = (unsigned long) p; 14862306a36Sopenharmony_ci for (i = bprm->envc; i > 0; i--) { 14962306a36Sopenharmony_ci if (put_user((unsigned long)p, sp++)) 15062306a36Sopenharmony_ci return -EFAULT; 15162306a36Sopenharmony_ci len = strnlen_user(p, MAX_ARG_STRLEN); 15262306a36Sopenharmony_ci if (!len || len > MAX_ARG_STRLEN) 15362306a36Sopenharmony_ci return -EINVAL; 15462306a36Sopenharmony_ci p += len; 15562306a36Sopenharmony_ci } 15662306a36Sopenharmony_ci if (put_user(0, sp++)) 15762306a36Sopenharmony_ci return -EFAULT; 15862306a36Sopenharmony_ci current->mm->env_end = (unsigned long)p; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci return 0; 16162306a36Sopenharmony_ci} 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci/****************************************************************************/ 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci#ifdef CONFIG_BINFMT_ZFLAT 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci#include <linux/zlib.h> 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci#define LBUFSIZE 4000 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci/* gzip flag byte */ 17262306a36Sopenharmony_ci#define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */ 17362306a36Sopenharmony_ci#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */ 17462306a36Sopenharmony_ci#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ 17562306a36Sopenharmony_ci#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ 17662306a36Sopenharmony_ci#define COMMENT 0x10 /* bit 4 set: file comment present */ 17762306a36Sopenharmony_ci#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */ 17862306a36Sopenharmony_ci#define RESERVED 0xC0 /* bit 6,7: reserved */ 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_cistatic int decompress_exec(struct linux_binprm *bprm, loff_t fpos, char *dst, 18162306a36Sopenharmony_ci long len, int fd) 18262306a36Sopenharmony_ci{ 18362306a36Sopenharmony_ci unsigned char *buf; 18462306a36Sopenharmony_ci z_stream strm; 18562306a36Sopenharmony_ci int ret, retval; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci pr_debug("decompress_exec(offset=%llx,buf=%p,len=%lx)\n", fpos, dst, len); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci memset(&strm, 0, sizeof(strm)); 19062306a36Sopenharmony_ci strm.workspace = kmalloc(zlib_inflate_workspacesize(), GFP_KERNEL); 19162306a36Sopenharmony_ci if (!strm.workspace) 19262306a36Sopenharmony_ci return -ENOMEM; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci buf = kmalloc(LBUFSIZE, GFP_KERNEL); 19562306a36Sopenharmony_ci if (!buf) { 19662306a36Sopenharmony_ci retval = -ENOMEM; 19762306a36Sopenharmony_ci goto out_free; 19862306a36Sopenharmony_ci } 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci /* Read in first chunk of data and parse gzip header. */ 20162306a36Sopenharmony_ci ret = kernel_read(bprm->file, buf, LBUFSIZE, &fpos); 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci strm.next_in = buf; 20462306a36Sopenharmony_ci strm.avail_in = ret; 20562306a36Sopenharmony_ci strm.total_in = 0; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci retval = -ENOEXEC; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci /* Check minimum size -- gzip header */ 21062306a36Sopenharmony_ci if (ret < 10) { 21162306a36Sopenharmony_ci pr_debug("file too small?\n"); 21262306a36Sopenharmony_ci goto out_free_buf; 21362306a36Sopenharmony_ci } 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci /* Check gzip magic number */ 21662306a36Sopenharmony_ci if ((buf[0] != 037) || ((buf[1] != 0213) && (buf[1] != 0236))) { 21762306a36Sopenharmony_ci pr_debug("unknown compression magic?\n"); 21862306a36Sopenharmony_ci goto out_free_buf; 21962306a36Sopenharmony_ci } 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci /* Check gzip method */ 22262306a36Sopenharmony_ci if (buf[2] != 8) { 22362306a36Sopenharmony_ci pr_debug("unknown compression method?\n"); 22462306a36Sopenharmony_ci goto out_free_buf; 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci /* Check gzip flags */ 22762306a36Sopenharmony_ci if ((buf[3] & ENCRYPTED) || (buf[3] & CONTINUATION) || 22862306a36Sopenharmony_ci (buf[3] & RESERVED)) { 22962306a36Sopenharmony_ci pr_debug("unknown flags?\n"); 23062306a36Sopenharmony_ci goto out_free_buf; 23162306a36Sopenharmony_ci } 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci ret = 10; 23462306a36Sopenharmony_ci if (buf[3] & EXTRA_FIELD) { 23562306a36Sopenharmony_ci ret += 2 + buf[10] + (buf[11] << 8); 23662306a36Sopenharmony_ci if (unlikely(ret >= LBUFSIZE)) { 23762306a36Sopenharmony_ci pr_debug("buffer overflow (EXTRA)?\n"); 23862306a36Sopenharmony_ci goto out_free_buf; 23962306a36Sopenharmony_ci } 24062306a36Sopenharmony_ci } 24162306a36Sopenharmony_ci if (buf[3] & ORIG_NAME) { 24262306a36Sopenharmony_ci while (ret < LBUFSIZE && buf[ret++] != 0) 24362306a36Sopenharmony_ci ; 24462306a36Sopenharmony_ci if (unlikely(ret == LBUFSIZE)) { 24562306a36Sopenharmony_ci pr_debug("buffer overflow (ORIG_NAME)?\n"); 24662306a36Sopenharmony_ci goto out_free_buf; 24762306a36Sopenharmony_ci } 24862306a36Sopenharmony_ci } 24962306a36Sopenharmony_ci if (buf[3] & COMMENT) { 25062306a36Sopenharmony_ci while (ret < LBUFSIZE && buf[ret++] != 0) 25162306a36Sopenharmony_ci ; 25262306a36Sopenharmony_ci if (unlikely(ret == LBUFSIZE)) { 25362306a36Sopenharmony_ci pr_debug("buffer overflow (COMMENT)?\n"); 25462306a36Sopenharmony_ci goto out_free_buf; 25562306a36Sopenharmony_ci } 25662306a36Sopenharmony_ci } 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci strm.next_in += ret; 25962306a36Sopenharmony_ci strm.avail_in -= ret; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci strm.next_out = dst; 26262306a36Sopenharmony_ci strm.avail_out = len; 26362306a36Sopenharmony_ci strm.total_out = 0; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci if (zlib_inflateInit2(&strm, -MAX_WBITS) != Z_OK) { 26662306a36Sopenharmony_ci pr_debug("zlib init failed?\n"); 26762306a36Sopenharmony_ci goto out_free_buf; 26862306a36Sopenharmony_ci } 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci while ((ret = zlib_inflate(&strm, Z_NO_FLUSH)) == Z_OK) { 27162306a36Sopenharmony_ci ret = kernel_read(bprm->file, buf, LBUFSIZE, &fpos); 27262306a36Sopenharmony_ci if (ret <= 0) 27362306a36Sopenharmony_ci break; 27462306a36Sopenharmony_ci len -= ret; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci strm.next_in = buf; 27762306a36Sopenharmony_ci strm.avail_in = ret; 27862306a36Sopenharmony_ci strm.total_in = 0; 27962306a36Sopenharmony_ci } 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci if (ret < 0) { 28262306a36Sopenharmony_ci pr_debug("decompression failed (%d), %s\n", 28362306a36Sopenharmony_ci ret, strm.msg); 28462306a36Sopenharmony_ci goto out_zlib; 28562306a36Sopenharmony_ci } 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci retval = 0; 28862306a36Sopenharmony_ciout_zlib: 28962306a36Sopenharmony_ci zlib_inflateEnd(&strm); 29062306a36Sopenharmony_ciout_free_buf: 29162306a36Sopenharmony_ci kfree(buf); 29262306a36Sopenharmony_ciout_free: 29362306a36Sopenharmony_ci kfree(strm.workspace); 29462306a36Sopenharmony_ci return retval; 29562306a36Sopenharmony_ci} 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci#endif /* CONFIG_BINFMT_ZFLAT */ 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci/****************************************************************************/ 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_cistatic unsigned long 30262306a36Sopenharmony_cicalc_reloc(unsigned long r, struct lib_info *p) 30362306a36Sopenharmony_ci{ 30462306a36Sopenharmony_ci unsigned long addr; 30562306a36Sopenharmony_ci unsigned long start_brk; 30662306a36Sopenharmony_ci unsigned long start_data; 30762306a36Sopenharmony_ci unsigned long text_len; 30862306a36Sopenharmony_ci unsigned long start_code; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci start_brk = p->lib_list[0].start_brk; 31162306a36Sopenharmony_ci start_data = p->lib_list[0].start_data; 31262306a36Sopenharmony_ci start_code = p->lib_list[0].start_code; 31362306a36Sopenharmony_ci text_len = p->lib_list[0].text_len; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci if (r > start_brk - start_data + text_len) { 31662306a36Sopenharmony_ci pr_err("reloc outside program 0x%lx (0 - 0x%lx/0x%lx)", 31762306a36Sopenharmony_ci r, start_brk-start_data+text_len, text_len); 31862306a36Sopenharmony_ci goto failed; 31962306a36Sopenharmony_ci } 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci if (r < text_len) /* In text segment */ 32262306a36Sopenharmony_ci addr = r + start_code; 32362306a36Sopenharmony_ci else /* In data segment */ 32462306a36Sopenharmony_ci addr = r - text_len + start_data; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci /* Range checked already above so doing the range tests is redundant...*/ 32762306a36Sopenharmony_ci return addr; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_cifailed: 33062306a36Sopenharmony_ci pr_cont(", killing %s!\n", current->comm); 33162306a36Sopenharmony_ci send_sig(SIGSEGV, current, 0); 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci return RELOC_FAILED; 33462306a36Sopenharmony_ci} 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci/****************************************************************************/ 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci#ifdef CONFIG_BINFMT_FLAT_OLD 33962306a36Sopenharmony_cistatic void old_reloc(unsigned long rl) 34062306a36Sopenharmony_ci{ 34162306a36Sopenharmony_ci static const char *segment[] = { "TEXT", "DATA", "BSS", "*UNKNOWN*" }; 34262306a36Sopenharmony_ci flat_v2_reloc_t r; 34362306a36Sopenharmony_ci unsigned long __user *ptr; 34462306a36Sopenharmony_ci unsigned long val; 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci r.value = rl; 34762306a36Sopenharmony_ci#if defined(CONFIG_COLDFIRE) 34862306a36Sopenharmony_ci ptr = (unsigned long __user *)(current->mm->start_code + r.reloc.offset); 34962306a36Sopenharmony_ci#else 35062306a36Sopenharmony_ci ptr = (unsigned long __user *)(current->mm->start_data + r.reloc.offset); 35162306a36Sopenharmony_ci#endif 35262306a36Sopenharmony_ci get_user(val, ptr); 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci pr_debug("Relocation of variable at DATASEG+%x " 35562306a36Sopenharmony_ci "(address %p, currently %lx) into segment %s\n", 35662306a36Sopenharmony_ci r.reloc.offset, ptr, val, segment[r.reloc.type]); 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci switch (r.reloc.type) { 35962306a36Sopenharmony_ci case OLD_FLAT_RELOC_TYPE_TEXT: 36062306a36Sopenharmony_ci val += current->mm->start_code; 36162306a36Sopenharmony_ci break; 36262306a36Sopenharmony_ci case OLD_FLAT_RELOC_TYPE_DATA: 36362306a36Sopenharmony_ci val += current->mm->start_data; 36462306a36Sopenharmony_ci break; 36562306a36Sopenharmony_ci case OLD_FLAT_RELOC_TYPE_BSS: 36662306a36Sopenharmony_ci val += current->mm->end_data; 36762306a36Sopenharmony_ci break; 36862306a36Sopenharmony_ci default: 36962306a36Sopenharmony_ci pr_err("Unknown relocation type=%x\n", r.reloc.type); 37062306a36Sopenharmony_ci break; 37162306a36Sopenharmony_ci } 37262306a36Sopenharmony_ci put_user(val, ptr); 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci pr_debug("Relocation became %lx\n", val); 37562306a36Sopenharmony_ci} 37662306a36Sopenharmony_ci#endif /* CONFIG_BINFMT_FLAT_OLD */ 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci/****************************************************************************/ 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_cistatic inline u32 __user *skip_got_header(u32 __user *rp) 38162306a36Sopenharmony_ci{ 38262306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_RISCV)) { 38362306a36Sopenharmony_ci /* 38462306a36Sopenharmony_ci * RISC-V has a 16 byte GOT PLT header for elf64-riscv 38562306a36Sopenharmony_ci * and 8 byte GOT PLT header for elf32-riscv. 38662306a36Sopenharmony_ci * Skip the whole GOT PLT header, since it is reserved 38762306a36Sopenharmony_ci * for the dynamic linker (ld.so). 38862306a36Sopenharmony_ci */ 38962306a36Sopenharmony_ci u32 rp_val0, rp_val1; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci if (get_user(rp_val0, rp)) 39262306a36Sopenharmony_ci return rp; 39362306a36Sopenharmony_ci if (get_user(rp_val1, rp + 1)) 39462306a36Sopenharmony_ci return rp; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci if (rp_val0 == 0xffffffff && rp_val1 == 0xffffffff) 39762306a36Sopenharmony_ci rp += 4; 39862306a36Sopenharmony_ci else if (rp_val0 == 0xffffffff) 39962306a36Sopenharmony_ci rp += 2; 40062306a36Sopenharmony_ci } 40162306a36Sopenharmony_ci return rp; 40262306a36Sopenharmony_ci} 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_cistatic int load_flat_file(struct linux_binprm *bprm, 40562306a36Sopenharmony_ci struct lib_info *libinfo, unsigned long *extra_stack) 40662306a36Sopenharmony_ci{ 40762306a36Sopenharmony_ci struct flat_hdr *hdr; 40862306a36Sopenharmony_ci unsigned long textpos, datapos, realdatastart; 40962306a36Sopenharmony_ci u32 text_len, data_len, bss_len, stack_len, full_data, flags; 41062306a36Sopenharmony_ci unsigned long len, memp, memp_size, extra, rlim; 41162306a36Sopenharmony_ci __be32 __user *reloc; 41262306a36Sopenharmony_ci u32 __user *rp; 41362306a36Sopenharmony_ci int i, rev, relocs; 41462306a36Sopenharmony_ci loff_t fpos; 41562306a36Sopenharmony_ci unsigned long start_code, end_code; 41662306a36Sopenharmony_ci ssize_t result; 41762306a36Sopenharmony_ci int ret; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci hdr = ((struct flat_hdr *) bprm->buf); /* exec-header */ 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci text_len = ntohl(hdr->data_start); 42262306a36Sopenharmony_ci data_len = ntohl(hdr->data_end) - ntohl(hdr->data_start); 42362306a36Sopenharmony_ci bss_len = ntohl(hdr->bss_end) - ntohl(hdr->data_end); 42462306a36Sopenharmony_ci stack_len = ntohl(hdr->stack_size); 42562306a36Sopenharmony_ci if (extra_stack) { 42662306a36Sopenharmony_ci stack_len += *extra_stack; 42762306a36Sopenharmony_ci *extra_stack = stack_len; 42862306a36Sopenharmony_ci } 42962306a36Sopenharmony_ci relocs = ntohl(hdr->reloc_count); 43062306a36Sopenharmony_ci flags = ntohl(hdr->flags); 43162306a36Sopenharmony_ci rev = ntohl(hdr->rev); 43262306a36Sopenharmony_ci full_data = data_len + relocs * sizeof(unsigned long); 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci if (strncmp(hdr->magic, "bFLT", 4)) { 43562306a36Sopenharmony_ci /* 43662306a36Sopenharmony_ci * Previously, here was a printk to tell people 43762306a36Sopenharmony_ci * "BINFMT_FLAT: bad header magic". 43862306a36Sopenharmony_ci * But for the kernel which also use ELF FD-PIC format, this 43962306a36Sopenharmony_ci * error message is confusing. 44062306a36Sopenharmony_ci * because a lot of people do not manage to produce good 44162306a36Sopenharmony_ci */ 44262306a36Sopenharmony_ci ret = -ENOEXEC; 44362306a36Sopenharmony_ci goto err; 44462306a36Sopenharmony_ci } 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci if (flags & FLAT_FLAG_KTRACE) 44762306a36Sopenharmony_ci pr_info("Loading file: %s\n", bprm->filename); 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci#ifdef CONFIG_BINFMT_FLAT_OLD 45062306a36Sopenharmony_ci if (rev != FLAT_VERSION && rev != OLD_FLAT_VERSION) { 45162306a36Sopenharmony_ci pr_err("bad flat file version 0x%x (supported 0x%lx and 0x%lx)\n", 45262306a36Sopenharmony_ci rev, FLAT_VERSION, OLD_FLAT_VERSION); 45362306a36Sopenharmony_ci ret = -ENOEXEC; 45462306a36Sopenharmony_ci goto err; 45562306a36Sopenharmony_ci } 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci /* 45862306a36Sopenharmony_ci * fix up the flags for the older format, there were all kinds 45962306a36Sopenharmony_ci * of endian hacks, this only works for the simple cases 46062306a36Sopenharmony_ci */ 46162306a36Sopenharmony_ci if (rev == OLD_FLAT_VERSION && 46262306a36Sopenharmony_ci (flags || IS_ENABLED(CONFIG_BINFMT_FLAT_OLD_ALWAYS_RAM))) 46362306a36Sopenharmony_ci flags = FLAT_FLAG_RAM; 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci#else /* CONFIG_BINFMT_FLAT_OLD */ 46662306a36Sopenharmony_ci if (rev != FLAT_VERSION) { 46762306a36Sopenharmony_ci pr_err("bad flat file version 0x%x (supported 0x%lx)\n", 46862306a36Sopenharmony_ci rev, FLAT_VERSION); 46962306a36Sopenharmony_ci ret = -ENOEXEC; 47062306a36Sopenharmony_ci goto err; 47162306a36Sopenharmony_ci } 47262306a36Sopenharmony_ci#endif /* !CONFIG_BINFMT_FLAT_OLD */ 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci /* 47562306a36Sopenharmony_ci * Make sure the header params are sane. 47662306a36Sopenharmony_ci * 28 bits (256 MB) is way more than reasonable in this case. 47762306a36Sopenharmony_ci * If some top bits are set we have probable binary corruption. 47862306a36Sopenharmony_ci */ 47962306a36Sopenharmony_ci if ((text_len | data_len | bss_len | stack_len | full_data) >> 28) { 48062306a36Sopenharmony_ci pr_err("bad header\n"); 48162306a36Sopenharmony_ci ret = -ENOEXEC; 48262306a36Sopenharmony_ci goto err; 48362306a36Sopenharmony_ci } 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci#ifndef CONFIG_BINFMT_ZFLAT 48662306a36Sopenharmony_ci if (flags & (FLAT_FLAG_GZIP|FLAT_FLAG_GZDATA)) { 48762306a36Sopenharmony_ci pr_err("Support for ZFLAT executables is not enabled.\n"); 48862306a36Sopenharmony_ci ret = -ENOEXEC; 48962306a36Sopenharmony_ci goto err; 49062306a36Sopenharmony_ci } 49162306a36Sopenharmony_ci#endif 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci /* 49462306a36Sopenharmony_ci * Check initial limits. This avoids letting people circumvent 49562306a36Sopenharmony_ci * size limits imposed on them by creating programs with large 49662306a36Sopenharmony_ci * arrays in the data or bss. 49762306a36Sopenharmony_ci */ 49862306a36Sopenharmony_ci rlim = rlimit(RLIMIT_DATA); 49962306a36Sopenharmony_ci if (rlim >= RLIM_INFINITY) 50062306a36Sopenharmony_ci rlim = ~0; 50162306a36Sopenharmony_ci if (data_len + bss_len > rlim) { 50262306a36Sopenharmony_ci ret = -ENOMEM; 50362306a36Sopenharmony_ci goto err; 50462306a36Sopenharmony_ci } 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci /* Flush all traces of the currently running executable */ 50762306a36Sopenharmony_ci ret = begin_new_exec(bprm); 50862306a36Sopenharmony_ci if (ret) 50962306a36Sopenharmony_ci goto err; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci /* OK, This is the point of no return */ 51262306a36Sopenharmony_ci set_personality(PER_LINUX_32BIT); 51362306a36Sopenharmony_ci setup_new_exec(bprm); 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci /* 51662306a36Sopenharmony_ci * calculate the extra space we need to map in 51762306a36Sopenharmony_ci */ 51862306a36Sopenharmony_ci extra = max_t(unsigned long, bss_len + stack_len, 51962306a36Sopenharmony_ci relocs * sizeof(unsigned long)); 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci /* 52262306a36Sopenharmony_ci * there are a couple of cases here, the separate code/data 52362306a36Sopenharmony_ci * case, and then the fully copied to RAM case which lumps 52462306a36Sopenharmony_ci * it all together. 52562306a36Sopenharmony_ci */ 52662306a36Sopenharmony_ci if (!IS_ENABLED(CONFIG_MMU) && !(flags & (FLAT_FLAG_RAM|FLAT_FLAG_GZIP))) { 52762306a36Sopenharmony_ci /* 52862306a36Sopenharmony_ci * this should give us a ROM ptr, but if it doesn't we don't 52962306a36Sopenharmony_ci * really care 53062306a36Sopenharmony_ci */ 53162306a36Sopenharmony_ci pr_debug("ROM mapping of file (we hope)\n"); 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci textpos = vm_mmap(bprm->file, 0, text_len, PROT_READ|PROT_EXEC, 53462306a36Sopenharmony_ci MAP_PRIVATE, 0); 53562306a36Sopenharmony_ci if (!textpos || IS_ERR_VALUE(textpos)) { 53662306a36Sopenharmony_ci ret = textpos; 53762306a36Sopenharmony_ci if (!textpos) 53862306a36Sopenharmony_ci ret = -ENOMEM; 53962306a36Sopenharmony_ci pr_err("Unable to mmap process text, errno %d\n", ret); 54062306a36Sopenharmony_ci goto err; 54162306a36Sopenharmony_ci } 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci len = data_len + extra + 54462306a36Sopenharmony_ci DATA_START_OFFSET_WORDS * sizeof(unsigned long); 54562306a36Sopenharmony_ci len = PAGE_ALIGN(len); 54662306a36Sopenharmony_ci realdatastart = vm_mmap(NULL, 0, len, 54762306a36Sopenharmony_ci PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE, 0); 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci if (realdatastart == 0 || IS_ERR_VALUE(realdatastart)) { 55062306a36Sopenharmony_ci ret = realdatastart; 55162306a36Sopenharmony_ci if (!realdatastart) 55262306a36Sopenharmony_ci ret = -ENOMEM; 55362306a36Sopenharmony_ci pr_err("Unable to allocate RAM for process data, " 55462306a36Sopenharmony_ci "errno %d\n", ret); 55562306a36Sopenharmony_ci vm_munmap(textpos, text_len); 55662306a36Sopenharmony_ci goto err; 55762306a36Sopenharmony_ci } 55862306a36Sopenharmony_ci datapos = ALIGN(realdatastart + 55962306a36Sopenharmony_ci DATA_START_OFFSET_WORDS * sizeof(unsigned long), 56062306a36Sopenharmony_ci FLAT_DATA_ALIGN); 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci pr_debug("Allocated data+bss+stack (%u bytes): %lx\n", 56362306a36Sopenharmony_ci data_len + bss_len + stack_len, datapos); 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci fpos = ntohl(hdr->data_start); 56662306a36Sopenharmony_ci#ifdef CONFIG_BINFMT_ZFLAT 56762306a36Sopenharmony_ci if (flags & FLAT_FLAG_GZDATA) { 56862306a36Sopenharmony_ci result = decompress_exec(bprm, fpos, (char *)datapos, 56962306a36Sopenharmony_ci full_data, 0); 57062306a36Sopenharmony_ci } else 57162306a36Sopenharmony_ci#endif 57262306a36Sopenharmony_ci { 57362306a36Sopenharmony_ci result = read_code(bprm->file, datapos, fpos, 57462306a36Sopenharmony_ci full_data); 57562306a36Sopenharmony_ci } 57662306a36Sopenharmony_ci if (IS_ERR_VALUE(result)) { 57762306a36Sopenharmony_ci ret = result; 57862306a36Sopenharmony_ci pr_err("Unable to read data+bss, errno %d\n", ret); 57962306a36Sopenharmony_ci vm_munmap(textpos, text_len); 58062306a36Sopenharmony_ci vm_munmap(realdatastart, len); 58162306a36Sopenharmony_ci goto err; 58262306a36Sopenharmony_ci } 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci reloc = (__be32 __user *) 58562306a36Sopenharmony_ci (datapos + (ntohl(hdr->reloc_start) - text_len)); 58662306a36Sopenharmony_ci memp = realdatastart; 58762306a36Sopenharmony_ci memp_size = len; 58862306a36Sopenharmony_ci } else { 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci len = text_len + data_len + extra + 59162306a36Sopenharmony_ci DATA_START_OFFSET_WORDS * sizeof(u32); 59262306a36Sopenharmony_ci len = PAGE_ALIGN(len); 59362306a36Sopenharmony_ci textpos = vm_mmap(NULL, 0, len, 59462306a36Sopenharmony_ci PROT_READ | PROT_EXEC | PROT_WRITE, MAP_PRIVATE, 0); 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci if (!textpos || IS_ERR_VALUE(textpos)) { 59762306a36Sopenharmony_ci ret = textpos; 59862306a36Sopenharmony_ci if (!textpos) 59962306a36Sopenharmony_ci ret = -ENOMEM; 60062306a36Sopenharmony_ci pr_err("Unable to allocate RAM for process text/data, " 60162306a36Sopenharmony_ci "errno %d\n", ret); 60262306a36Sopenharmony_ci goto err; 60362306a36Sopenharmony_ci } 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci realdatastart = textpos + ntohl(hdr->data_start); 60662306a36Sopenharmony_ci datapos = ALIGN(realdatastart + 60762306a36Sopenharmony_ci DATA_START_OFFSET_WORDS * sizeof(u32), 60862306a36Sopenharmony_ci FLAT_DATA_ALIGN); 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci reloc = (__be32 __user *) 61162306a36Sopenharmony_ci (datapos + (ntohl(hdr->reloc_start) - text_len)); 61262306a36Sopenharmony_ci memp = textpos; 61362306a36Sopenharmony_ci memp_size = len; 61462306a36Sopenharmony_ci#ifdef CONFIG_BINFMT_ZFLAT 61562306a36Sopenharmony_ci /* 61662306a36Sopenharmony_ci * load it all in and treat it like a RAM load from now on 61762306a36Sopenharmony_ci */ 61862306a36Sopenharmony_ci if (flags & FLAT_FLAG_GZIP) { 61962306a36Sopenharmony_ci#ifndef CONFIG_MMU 62062306a36Sopenharmony_ci result = decompress_exec(bprm, sizeof(struct flat_hdr), 62162306a36Sopenharmony_ci (((char *)textpos) + sizeof(struct flat_hdr)), 62262306a36Sopenharmony_ci (text_len + full_data 62362306a36Sopenharmony_ci - sizeof(struct flat_hdr)), 62462306a36Sopenharmony_ci 0); 62562306a36Sopenharmony_ci memmove((void *) datapos, (void *) realdatastart, 62662306a36Sopenharmony_ci full_data); 62762306a36Sopenharmony_ci#else 62862306a36Sopenharmony_ci /* 62962306a36Sopenharmony_ci * This is used on MMU systems mainly for testing. 63062306a36Sopenharmony_ci * Let's use a kernel buffer to simplify things. 63162306a36Sopenharmony_ci */ 63262306a36Sopenharmony_ci long unz_text_len = text_len - sizeof(struct flat_hdr); 63362306a36Sopenharmony_ci long unz_len = unz_text_len + full_data; 63462306a36Sopenharmony_ci char *unz_data = vmalloc(unz_len); 63562306a36Sopenharmony_ci if (!unz_data) { 63662306a36Sopenharmony_ci result = -ENOMEM; 63762306a36Sopenharmony_ci } else { 63862306a36Sopenharmony_ci result = decompress_exec(bprm, sizeof(struct flat_hdr), 63962306a36Sopenharmony_ci unz_data, unz_len, 0); 64062306a36Sopenharmony_ci if (result == 0 && 64162306a36Sopenharmony_ci (copy_to_user((void __user *)textpos + sizeof(struct flat_hdr), 64262306a36Sopenharmony_ci unz_data, unz_text_len) || 64362306a36Sopenharmony_ci copy_to_user((void __user *)datapos, 64462306a36Sopenharmony_ci unz_data + unz_text_len, full_data))) 64562306a36Sopenharmony_ci result = -EFAULT; 64662306a36Sopenharmony_ci vfree(unz_data); 64762306a36Sopenharmony_ci } 64862306a36Sopenharmony_ci#endif 64962306a36Sopenharmony_ci } else if (flags & FLAT_FLAG_GZDATA) { 65062306a36Sopenharmony_ci result = read_code(bprm->file, textpos, 0, text_len); 65162306a36Sopenharmony_ci if (!IS_ERR_VALUE(result)) { 65262306a36Sopenharmony_ci#ifndef CONFIG_MMU 65362306a36Sopenharmony_ci result = decompress_exec(bprm, text_len, (char *) datapos, 65462306a36Sopenharmony_ci full_data, 0); 65562306a36Sopenharmony_ci#else 65662306a36Sopenharmony_ci char *unz_data = vmalloc(full_data); 65762306a36Sopenharmony_ci if (!unz_data) { 65862306a36Sopenharmony_ci result = -ENOMEM; 65962306a36Sopenharmony_ci } else { 66062306a36Sopenharmony_ci result = decompress_exec(bprm, text_len, 66162306a36Sopenharmony_ci unz_data, full_data, 0); 66262306a36Sopenharmony_ci if (result == 0 && 66362306a36Sopenharmony_ci copy_to_user((void __user *)datapos, 66462306a36Sopenharmony_ci unz_data, full_data)) 66562306a36Sopenharmony_ci result = -EFAULT; 66662306a36Sopenharmony_ci vfree(unz_data); 66762306a36Sopenharmony_ci } 66862306a36Sopenharmony_ci#endif 66962306a36Sopenharmony_ci } 67062306a36Sopenharmony_ci } else 67162306a36Sopenharmony_ci#endif /* CONFIG_BINFMT_ZFLAT */ 67262306a36Sopenharmony_ci { 67362306a36Sopenharmony_ci result = read_code(bprm->file, textpos, 0, text_len); 67462306a36Sopenharmony_ci if (!IS_ERR_VALUE(result)) 67562306a36Sopenharmony_ci result = read_code(bprm->file, datapos, 67662306a36Sopenharmony_ci ntohl(hdr->data_start), 67762306a36Sopenharmony_ci full_data); 67862306a36Sopenharmony_ci } 67962306a36Sopenharmony_ci if (IS_ERR_VALUE(result)) { 68062306a36Sopenharmony_ci ret = result; 68162306a36Sopenharmony_ci pr_err("Unable to read code+data+bss, errno %d\n", ret); 68262306a36Sopenharmony_ci vm_munmap(textpos, text_len + data_len + extra + 68362306a36Sopenharmony_ci DATA_START_OFFSET_WORDS * sizeof(u32)); 68462306a36Sopenharmony_ci goto err; 68562306a36Sopenharmony_ci } 68662306a36Sopenharmony_ci } 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci start_code = textpos + sizeof(struct flat_hdr); 68962306a36Sopenharmony_ci end_code = textpos + text_len; 69062306a36Sopenharmony_ci text_len -= sizeof(struct flat_hdr); /* the real code len */ 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci /* The main program needs a little extra setup in the task structure */ 69362306a36Sopenharmony_ci current->mm->start_code = start_code; 69462306a36Sopenharmony_ci current->mm->end_code = end_code; 69562306a36Sopenharmony_ci current->mm->start_data = datapos; 69662306a36Sopenharmony_ci current->mm->end_data = datapos + data_len; 69762306a36Sopenharmony_ci /* 69862306a36Sopenharmony_ci * set up the brk stuff, uses any slack left in data/bss/stack 69962306a36Sopenharmony_ci * allocation. We put the brk after the bss (between the bss 70062306a36Sopenharmony_ci * and stack) like other platforms. 70162306a36Sopenharmony_ci * Userspace code relies on the stack pointer starting out at 70262306a36Sopenharmony_ci * an address right at the end of a page. 70362306a36Sopenharmony_ci */ 70462306a36Sopenharmony_ci current->mm->start_brk = datapos + data_len + bss_len; 70562306a36Sopenharmony_ci current->mm->brk = (current->mm->start_brk + 3) & ~3; 70662306a36Sopenharmony_ci#ifndef CONFIG_MMU 70762306a36Sopenharmony_ci current->mm->context.end_brk = memp + memp_size - stack_len; 70862306a36Sopenharmony_ci#endif 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci if (flags & FLAT_FLAG_KTRACE) { 71162306a36Sopenharmony_ci pr_info("Mapping is %lx, Entry point is %x, data_start is %x\n", 71262306a36Sopenharmony_ci textpos, 0x00ffffff&ntohl(hdr->entry), ntohl(hdr->data_start)); 71362306a36Sopenharmony_ci pr_info("%s %s: TEXT=%lx-%lx DATA=%lx-%lx BSS=%lx-%lx\n", 71462306a36Sopenharmony_ci "Load", bprm->filename, 71562306a36Sopenharmony_ci start_code, end_code, datapos, datapos + data_len, 71662306a36Sopenharmony_ci datapos + data_len, (datapos + data_len + bss_len + 3) & ~3); 71762306a36Sopenharmony_ci } 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci /* Store the current module values into the global library structure */ 72062306a36Sopenharmony_ci libinfo->lib_list[0].start_code = start_code; 72162306a36Sopenharmony_ci libinfo->lib_list[0].start_data = datapos; 72262306a36Sopenharmony_ci libinfo->lib_list[0].start_brk = datapos + data_len + bss_len; 72362306a36Sopenharmony_ci libinfo->lib_list[0].text_len = text_len; 72462306a36Sopenharmony_ci libinfo->lib_list[0].loaded = 1; 72562306a36Sopenharmony_ci libinfo->lib_list[0].entry = (0x00ffffff & ntohl(hdr->entry)) + textpos; 72662306a36Sopenharmony_ci libinfo->lib_list[0].build_date = ntohl(hdr->build_date); 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci /* 72962306a36Sopenharmony_ci * We just load the allocations into some temporary memory to 73062306a36Sopenharmony_ci * help simplify all this mumbo jumbo 73162306a36Sopenharmony_ci * 73262306a36Sopenharmony_ci * We've got two different sections of relocation entries. 73362306a36Sopenharmony_ci * The first is the GOT which resides at the beginning of the data segment 73462306a36Sopenharmony_ci * and is terminated with a -1. This one can be relocated in place. 73562306a36Sopenharmony_ci * The second is the extra relocation entries tacked after the image's 73662306a36Sopenharmony_ci * data segment. These require a little more processing as the entry is 73762306a36Sopenharmony_ci * really an offset into the image which contains an offset into the 73862306a36Sopenharmony_ci * image. 73962306a36Sopenharmony_ci */ 74062306a36Sopenharmony_ci if (flags & FLAT_FLAG_GOTPIC) { 74162306a36Sopenharmony_ci rp = skip_got_header((u32 __user *) datapos); 74262306a36Sopenharmony_ci for (; ; rp++) { 74362306a36Sopenharmony_ci u32 addr, rp_val; 74462306a36Sopenharmony_ci if (get_user(rp_val, rp)) 74562306a36Sopenharmony_ci return -EFAULT; 74662306a36Sopenharmony_ci if (rp_val == 0xffffffff) 74762306a36Sopenharmony_ci break; 74862306a36Sopenharmony_ci if (rp_val) { 74962306a36Sopenharmony_ci addr = calc_reloc(rp_val, libinfo); 75062306a36Sopenharmony_ci if (addr == RELOC_FAILED) { 75162306a36Sopenharmony_ci ret = -ENOEXEC; 75262306a36Sopenharmony_ci goto err; 75362306a36Sopenharmony_ci } 75462306a36Sopenharmony_ci if (put_user(addr, rp)) 75562306a36Sopenharmony_ci return -EFAULT; 75662306a36Sopenharmony_ci } 75762306a36Sopenharmony_ci } 75862306a36Sopenharmony_ci } 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci /* 76162306a36Sopenharmony_ci * Now run through the relocation entries. 76262306a36Sopenharmony_ci * We've got to be careful here as C++ produces relocatable zero 76362306a36Sopenharmony_ci * entries in the constructor and destructor tables which are then 76462306a36Sopenharmony_ci * tested for being not zero (which will always occur unless we're 76562306a36Sopenharmony_ci * based from address zero). This causes an endless loop as __start 76662306a36Sopenharmony_ci * is at zero. The solution used is to not relocate zero addresses. 76762306a36Sopenharmony_ci * This has the negative side effect of not allowing a global data 76862306a36Sopenharmony_ci * reference to be statically initialised to _stext (I've moved 76962306a36Sopenharmony_ci * __start to address 4 so that is okay). 77062306a36Sopenharmony_ci */ 77162306a36Sopenharmony_ci if (rev > OLD_FLAT_VERSION) { 77262306a36Sopenharmony_ci for (i = 0; i < relocs; i++) { 77362306a36Sopenharmony_ci u32 addr, relval; 77462306a36Sopenharmony_ci __be32 tmp; 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci /* 77762306a36Sopenharmony_ci * Get the address of the pointer to be 77862306a36Sopenharmony_ci * relocated (of course, the address has to be 77962306a36Sopenharmony_ci * relocated first). 78062306a36Sopenharmony_ci */ 78162306a36Sopenharmony_ci if (get_user(tmp, reloc + i)) 78262306a36Sopenharmony_ci return -EFAULT; 78362306a36Sopenharmony_ci relval = ntohl(tmp); 78462306a36Sopenharmony_ci addr = flat_get_relocate_addr(relval); 78562306a36Sopenharmony_ci rp = (u32 __user *)calc_reloc(addr, libinfo); 78662306a36Sopenharmony_ci if (rp == (u32 __user *)RELOC_FAILED) { 78762306a36Sopenharmony_ci ret = -ENOEXEC; 78862306a36Sopenharmony_ci goto err; 78962306a36Sopenharmony_ci } 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci /* Get the pointer's value. */ 79262306a36Sopenharmony_ci ret = flat_get_addr_from_rp(rp, relval, flags, &addr); 79362306a36Sopenharmony_ci if (unlikely(ret)) 79462306a36Sopenharmony_ci goto err; 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci if (addr != 0) { 79762306a36Sopenharmony_ci /* 79862306a36Sopenharmony_ci * Do the relocation. PIC relocs in the data section are 79962306a36Sopenharmony_ci * already in target order 80062306a36Sopenharmony_ci */ 80162306a36Sopenharmony_ci if ((flags & FLAT_FLAG_GOTPIC) == 0) { 80262306a36Sopenharmony_ci /* 80362306a36Sopenharmony_ci * Meh, the same value can have a different 80462306a36Sopenharmony_ci * byte order based on a flag.. 80562306a36Sopenharmony_ci */ 80662306a36Sopenharmony_ci addr = ntohl((__force __be32)addr); 80762306a36Sopenharmony_ci } 80862306a36Sopenharmony_ci addr = calc_reloc(addr, libinfo); 80962306a36Sopenharmony_ci if (addr == RELOC_FAILED) { 81062306a36Sopenharmony_ci ret = -ENOEXEC; 81162306a36Sopenharmony_ci goto err; 81262306a36Sopenharmony_ci } 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci /* Write back the relocated pointer. */ 81562306a36Sopenharmony_ci ret = flat_put_addr_at_rp(rp, addr, relval); 81662306a36Sopenharmony_ci if (unlikely(ret)) 81762306a36Sopenharmony_ci goto err; 81862306a36Sopenharmony_ci } 81962306a36Sopenharmony_ci } 82062306a36Sopenharmony_ci#ifdef CONFIG_BINFMT_FLAT_OLD 82162306a36Sopenharmony_ci } else { 82262306a36Sopenharmony_ci for (i = 0; i < relocs; i++) { 82362306a36Sopenharmony_ci __be32 relval; 82462306a36Sopenharmony_ci if (get_user(relval, reloc + i)) 82562306a36Sopenharmony_ci return -EFAULT; 82662306a36Sopenharmony_ci old_reloc(ntohl(relval)); 82762306a36Sopenharmony_ci } 82862306a36Sopenharmony_ci#endif /* CONFIG_BINFMT_FLAT_OLD */ 82962306a36Sopenharmony_ci } 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci flush_icache_user_range(start_code, end_code); 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci /* zero the BSS, BRK and stack areas */ 83462306a36Sopenharmony_ci if (clear_user((void __user *)(datapos + data_len), bss_len + 83562306a36Sopenharmony_ci (memp + memp_size - stack_len - /* end brk */ 83662306a36Sopenharmony_ci libinfo->lib_list[0].start_brk) + /* start brk */ 83762306a36Sopenharmony_ci stack_len)) 83862306a36Sopenharmony_ci return -EFAULT; 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci return 0; 84162306a36Sopenharmony_cierr: 84262306a36Sopenharmony_ci return ret; 84362306a36Sopenharmony_ci} 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci/****************************************************************************/ 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci/* 84962306a36Sopenharmony_ci * These are the functions used to load flat style executables and shared 85062306a36Sopenharmony_ci * libraries. There is no binary dependent code anywhere else. 85162306a36Sopenharmony_ci */ 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_cistatic int load_flat_binary(struct linux_binprm *bprm) 85462306a36Sopenharmony_ci{ 85562306a36Sopenharmony_ci struct lib_info libinfo; 85662306a36Sopenharmony_ci struct pt_regs *regs = current_pt_regs(); 85762306a36Sopenharmony_ci unsigned long stack_len = 0; 85862306a36Sopenharmony_ci unsigned long start_addr; 85962306a36Sopenharmony_ci int res; 86062306a36Sopenharmony_ci int i, j; 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci memset(&libinfo, 0, sizeof(libinfo)); 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci /* 86562306a36Sopenharmony_ci * We have to add the size of our arguments to our stack size 86662306a36Sopenharmony_ci * otherwise it's too easy for users to create stack overflows 86762306a36Sopenharmony_ci * by passing in a huge argument list. And yes, we have to be 86862306a36Sopenharmony_ci * pedantic and include space for the argv/envp array as it may have 86962306a36Sopenharmony_ci * a lot of entries. 87062306a36Sopenharmony_ci */ 87162306a36Sopenharmony_ci#ifndef CONFIG_MMU 87262306a36Sopenharmony_ci stack_len += PAGE_SIZE * MAX_ARG_PAGES - bprm->p; /* the strings */ 87362306a36Sopenharmony_ci#endif 87462306a36Sopenharmony_ci stack_len += (bprm->argc + 1) * sizeof(char *); /* the argv array */ 87562306a36Sopenharmony_ci stack_len += (bprm->envc + 1) * sizeof(char *); /* the envp array */ 87662306a36Sopenharmony_ci stack_len = ALIGN(stack_len, FLAT_STACK_ALIGN); 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci res = load_flat_file(bprm, &libinfo, &stack_len); 87962306a36Sopenharmony_ci if (res < 0) 88062306a36Sopenharmony_ci return res; 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci /* Update data segment pointers for all libraries */ 88362306a36Sopenharmony_ci for (i = 0; i < MAX_SHARED_LIBS; i++) { 88462306a36Sopenharmony_ci if (!libinfo.lib_list[i].loaded) 88562306a36Sopenharmony_ci continue; 88662306a36Sopenharmony_ci for (j = 0; j < MAX_SHARED_LIBS; j++) { 88762306a36Sopenharmony_ci unsigned long val = libinfo.lib_list[j].loaded ? 88862306a36Sopenharmony_ci libinfo.lib_list[j].start_data : UNLOADED_LIB; 88962306a36Sopenharmony_ci unsigned long __user *p = (unsigned long __user *) 89062306a36Sopenharmony_ci libinfo.lib_list[i].start_data; 89162306a36Sopenharmony_ci p -= j + 1; 89262306a36Sopenharmony_ci if (put_user(val, p)) 89362306a36Sopenharmony_ci return -EFAULT; 89462306a36Sopenharmony_ci } 89562306a36Sopenharmony_ci } 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci set_binfmt(&flat_format); 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci#ifdef CONFIG_MMU 90062306a36Sopenharmony_ci res = setup_arg_pages(bprm, STACK_TOP, EXSTACK_DEFAULT); 90162306a36Sopenharmony_ci if (!res) 90262306a36Sopenharmony_ci res = create_flat_tables(bprm, bprm->p); 90362306a36Sopenharmony_ci#else 90462306a36Sopenharmony_ci /* Stash our initial stack pointer into the mm structure */ 90562306a36Sopenharmony_ci current->mm->start_stack = 90662306a36Sopenharmony_ci ((current->mm->context.end_brk + stack_len + 3) & ~3) - 4; 90762306a36Sopenharmony_ci pr_debug("sp=%lx\n", current->mm->start_stack); 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci /* copy the arg pages onto the stack */ 91062306a36Sopenharmony_ci res = transfer_args_to_stack(bprm, ¤t->mm->start_stack); 91162306a36Sopenharmony_ci if (!res) 91262306a36Sopenharmony_ci res = create_flat_tables(bprm, current->mm->start_stack); 91362306a36Sopenharmony_ci#endif 91462306a36Sopenharmony_ci if (res) 91562306a36Sopenharmony_ci return res; 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci /* Fake some return addresses to ensure the call chain will 91862306a36Sopenharmony_ci * initialise library in order for us. We are required to call 91962306a36Sopenharmony_ci * lib 1 first, then 2, ... and finally the main program (id 0). 92062306a36Sopenharmony_ci */ 92162306a36Sopenharmony_ci start_addr = libinfo.lib_list[0].entry; 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci#ifdef FLAT_PLAT_INIT 92462306a36Sopenharmony_ci FLAT_PLAT_INIT(regs); 92562306a36Sopenharmony_ci#endif 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci finalize_exec(bprm); 92862306a36Sopenharmony_ci pr_debug("start_thread(regs=0x%p, entry=0x%lx, start_stack=0x%lx)\n", 92962306a36Sopenharmony_ci regs, start_addr, current->mm->start_stack); 93062306a36Sopenharmony_ci start_thread(regs, start_addr, current->mm->start_stack); 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci return 0; 93362306a36Sopenharmony_ci} 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci/****************************************************************************/ 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_cistatic int __init init_flat_binfmt(void) 93862306a36Sopenharmony_ci{ 93962306a36Sopenharmony_ci register_binfmt(&flat_format); 94062306a36Sopenharmony_ci return 0; 94162306a36Sopenharmony_ci} 94262306a36Sopenharmony_cicore_initcall(init_flat_binfmt); 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci/****************************************************************************/ 945