From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.6 required=3.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2DB60C432BE for ; Thu, 26 Aug 2021 21:41:54 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 73E9460F39 for ; Thu, 26 Aug 2021 21:41:53 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.1 mail.kernel.org 73E9460F39 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=bsdimp.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=nongnu.org Received: from localhost ([::1]:42774 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1mJN8C-0000Mr-En for qemu-devel@archiver.kernel.org; Thu, 26 Aug 2021 17:41:52 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:39316) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1mJMgJ-0006kq-7u for qemu-devel@nongnu.org; Thu, 26 Aug 2021 17:13:03 -0400 Received: from mail-il1-x133.google.com ([2607:f8b0:4864:20::133]:34464) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1mJMgF-00073V-58 for qemu-devel@nongnu.org; Thu, 26 Aug 2021 17:13:02 -0400 Received: by mail-il1-x133.google.com with SMTP id j15so4767245ila.1 for ; Thu, 26 Aug 2021 14:12:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bsdimp-com.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=uV3DXKMiMilvUYIlhME781+iz+qiR6o//M5DU+AgnMw=; b=KV9EiQs80I4ykiZk0E83WNgfYZkGeNdsm547DPUwvyNlw+FnV77d5K/YGxD5jJCaCl 0YRmFp6f5zSz3n9k1QxduSUe1qHNOysJfy0oqeQuOa40d3N4yBhi4Xo92YzGrlk/giSZ Nh6gQG/uhbW261NwrBz53PACuIRf/ISqpI3SP25YpLmyiwWH1PU9SFvZ0IaW8mExmWkb EWVhAgUOo9C80QaXjx73hIOLfi4e6sWOz/6z4If+2p1DfLac4SuMkx+EQImuM4PaOrfJ Tzr3JexJguD++bB9PQUq83Ru4OtZ6cTPygy6QJKH9uOAEveMuhFGZOu80pgB51hz9SJG YjLw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=uV3DXKMiMilvUYIlhME781+iz+qiR6o//M5DU+AgnMw=; b=YJNDnHcIJqgDrK/W0XZtA4E+0sBlQH4DnJ89gK6Ou9useHe18NqGv3Ah5a12IEqL2b m4Hz8l9BHyHjuYdgRmJRNFuubePacE1oSnRuMjtn5hLPWghf/pqmjO9xTF9OsDtgjwzZ mM/D8yULJvcc14SGcrYXIht1ZAgslbC7Hed/pcO1YmIdu69xk0DRSjtkrS4xuLX1pHKj 82J/lEkn/1deHhBUhMezHaB9wJv1WGP1Pp0nIkxda52f3MqyxtuxSRJJeXSN20YU4wBn UTTogPC8icq1VZOs29yGTDN8ZyZG5SpRRYYL+VAkEGjynwdb4DdVgK3T/60dit0VLIEm utPg== X-Gm-Message-State: AOAM532aRizHbH2rPNFJ7eTIZB1+aqc8JwrVY4xe1pkXk/nb7ae2ywfO +gB+Z4rfIKrfn3huaADH8pG7wdOCmwisAUvP X-Google-Smtp-Source: ABdhPJyIWptCroI9EyI3k444HaDvYAe/Q7DRxolbFycfuBJ56yoTAaBlVNtO9rEvC2x2blmAH1RL2w== X-Received: by 2002:a92:4a10:: with SMTP id m16mr4033874ilf.233.1630012376302; Thu, 26 Aug 2021 14:12:56 -0700 (PDT) Received: from dune.bsdimp.com (50-253-99-174-static.hfc.comcastbusiness.net. [50.253.99.174]) by smtp.gmail.com with ESMTPSA id a17sm2348633ilp.75.2021.08.26.14.12.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 26 Aug 2021 14:12:55 -0700 (PDT) From: imp@bsdimp.com To: qemu-devel@nongnu.org Subject: [PATCH v2 38/43] bsd-user: Refactor load_elf_sections and is_target_elf_binary Date: Thu, 26 Aug 2021 15:11:56 -0600 Message-Id: <20210826211201.98877-39-imp@bsdimp.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210826211201.98877-1-imp@bsdimp.com> References: <20210826211201.98877-1-imp@bsdimp.com> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Received-SPF: none client-ip=2607:f8b0:4864:20::133; envelope-from=imp@bsdimp.com; helo=mail-il1-x133.google.com X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_NONE=0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Stacey Son , Warner Losh , Warner Losh , =?UTF-8?q?Mika=C3=ABl=20Urankar?= Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" From: Warner Losh Factor out load_elf_sections and is_target_elf_binary out of load_elf_interp. Signed-off-by: Mikaƫl Urankar Signed-off-by: Stacey Son Signed-off-by: Warner Losh --- bsd-user/elfload.c | 350 +++++++++++++++++++++------------------------ 1 file changed, 164 insertions(+), 186 deletions(-) diff --git a/bsd-user/elfload.c b/bsd-user/elfload.c index bdf18f3dce..aed28f2f73 100644 --- a/bsd-user/elfload.c +++ b/bsd-user/elfload.c @@ -36,6 +36,8 @@ abi_ulong target_stksiz; abi_ulong target_stkbas; static int elf_core_dump(int signr, CPUArchState *env); +static int load_elf_sections(const struct elfhdr *hdr, struct elf_phdr *phdr, + int fd, abi_ulong rbase, abi_ulong *baddrp); static inline void memcpy_fromfs(void *to, const void *from, unsigned long n) { @@ -271,16 +273,10 @@ static abi_ulong load_elf_interp(struct elfhdr *interp_elf_ex, abi_ulong *interp_load_addr) { struct elf_phdr *elf_phdata = NULL; - struct elf_phdr *eppnt; - abi_ulong load_addr = 0; - int load_addr_set = 0; + abi_ulong rbase; int retval; - abi_ulong last_bss, elf_bss; - abi_ulong error; - int i; + abi_ulong baddr, error; - elf_bss = 0; - last_bss = 0; error = 0; bswap_ehdr(interp_elf_ex); @@ -325,6 +321,7 @@ static abi_ulong load_elf_interp(struct elfhdr *interp_elf_ex, } bswap_phdr(elf_phdata, interp_elf_ex->e_phnum); + rbase = 0; if (interp_elf_ex->e_type == ET_DYN) { /* * In order to avoid hardcoding the interpreter load @@ -332,86 +329,25 @@ static abi_ulong load_elf_interp(struct elfhdr *interp_elf_ex, */ error = target_mmap(0, INTERP_MAP_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANON, -1, 0); - if (error == -1) { + if (rbase == -1) { perror("mmap"); exit(-1); } - load_addr = error; - load_addr_set = 1; - } - - eppnt = elf_phdata; - for (i = 0; i < interp_elf_ex->e_phnum; i++, eppnt++) - if (eppnt->p_type == PT_LOAD) { - int elf_type = MAP_PRIVATE | MAP_DENYWRITE; - int elf_prot = 0; - abi_ulong vaddr = 0; - abi_ulong k; - - if (eppnt->p_flags & PF_R) elf_prot = PROT_READ; - if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE; - if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC; - if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) { - elf_type |= MAP_FIXED; - vaddr = eppnt->p_vaddr; - } - error = target_mmap(load_addr + TARGET_ELF_PAGESTART(vaddr), - eppnt->p_filesz + TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr), - elf_prot, - elf_type, - interpreter_fd, - eppnt->p_offset - TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr)); - - if (error == -1) { - /* Real error */ - close(interpreter_fd); - free(elf_phdata); - return ~((abi_ulong)0UL); - } - - if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) { - load_addr = error; - load_addr_set = 1; - } - - /* - * Find the end of the file mapping for this phdr, and keep - * track of the largest address we see for this. - */ - k = load_addr + eppnt->p_vaddr + eppnt->p_filesz; - if (k > elf_bss) elf_bss = k; + } - /* - * Do the same thing for the memory mapping - between - * elf_bss and last_bss is the bss section. - */ - k = load_addr + eppnt->p_memsz + eppnt->p_vaddr; - if (k > last_bss) last_bss = k; - } + error = load_elf_sections(interp_elf_ex, elf_phdata, interpreter_fd, rbase, + &baddr); + if (error != 0) { + perror("load_elf_sections"); + exit(-1); + } /* Now use mmap to map the library into memory. */ - close(interpreter_fd); - - /* - * Now fill out the bss section. First pad the last page up - * to the page boundary, and then perform a mmap to make sure - * that there are zeromapped pages up to and including the last - * bss page. - */ - padzero(elf_bss, last_bss); - elf_bss = TARGET_ELF_PAGESTART(elf_bss + qemu_host_page_size - 1); /* What we have mapped so far */ - - /* Map the last of the bss segment */ - if (last_bss > elf_bss) { - target_mmap(elf_bss, last_bss - elf_bss, - PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_FIXED | MAP_PRIVATE | MAP_ANON, -1, 0); - } free(elf_phdata); - *interp_load_addr = load_addr; - return ((abi_ulong) interp_elf_ex->e_entry) + load_addr; + *interp_load_addr = baddr; + return ((abi_ulong) interp_elf_ex->e_entry) + rbase; } static int symfind(const void *s0, const void *s1) @@ -521,6 +457,10 @@ found: } continue; } +#if defined(TARGET_ARM) || defined(TARGET_MIPS) + /* The bottom address bit marks a Thumb or MIPS16 symbol. */ + syms[i].st_value &= ~(target_ulong)1; +#endif i++; } @@ -560,26 +500,119 @@ found: syminfos = s; } +/* Check the elf header and see if this a target elf binary. */ +int is_target_elf_binary(int fd) +{ + uint8_t buf[128]; + struct elfhdr elf_ex; + + if (lseek(fd, 0L, SEEK_SET) < 0) { + return 0; + } + if (read(fd, buf, sizeof(buf)) < 0) { + return 0; + } + + elf_ex = *((struct elfhdr *)buf); + bswap_ehdr(&elf_ex); + + if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) || + (!elf_check_arch(elf_ex.e_machine))) { + return 0; + } else { + return 1; + } +} + +static int +load_elf_sections(const struct elfhdr *hdr, struct elf_phdr *phdr, int fd, + abi_ulong rbase, abi_ulong *baddrp) +{ + struct elf_phdr *elf_ppnt; + abi_ulong baddr; + int i; + bool first; + + /* + * Now we do a little grungy work by mmaping the ELF image into + * the correct location in memory. At this point, we assume that + * the image should be loaded at fixed address, not at a variable + * address. + */ + first = true; + for (i = 0, elf_ppnt = phdr; i < hdr->e_phnum; i++, elf_ppnt++) { + int elf_prot = 0; + abi_ulong error; + + /* XXX Skip memsz == 0. */ + if (elf_ppnt->p_type != PT_LOAD) { + continue; + } + + if (elf_ppnt->p_flags & PF_R) { + elf_prot |= PROT_READ; + } + if (elf_ppnt->p_flags & PF_W) { + elf_prot |= PROT_WRITE; + } + if (elf_ppnt->p_flags & PF_X) { + elf_prot |= PROT_EXEC; + } + + error = target_mmap(TARGET_ELF_PAGESTART(rbase + elf_ppnt->p_vaddr), + (elf_ppnt->p_filesz + + TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)), + elf_prot, + (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE), + fd, + (elf_ppnt->p_offset - + TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr))); + if (error == -1) { + perror("mmap"); + exit(-1); + } else if (elf_ppnt->p_memsz != elf_ppnt->p_filesz) { + abi_ulong start_bss, end_bss; + + start_bss = rbase + elf_ppnt->p_vaddr + elf_ppnt->p_filesz; + end_bss = rbase + elf_ppnt->p_vaddr + elf_ppnt->p_memsz; + + /* + * Calling set_brk effectively mmaps the pages that we need for the + * bss and break sections. + */ + set_brk(start_bss, end_bss); + padzero(start_bss, end_bss); + } + + if (first) { + baddr = TARGET_ELF_PAGESTART(rbase + elf_ppnt->p_vaddr); + first = false; + } + } + + if (baddrp != NULL) { + *baddrp = baddr; + } + return 0; +} + int load_elf_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs, struct image_info *info) { struct elfhdr elf_ex; struct elfhdr interp_elf_ex; int interpreter_fd = -1; /* avoid warning */ - abi_ulong load_addr, load_bias; - int load_addr_set = 0; + abi_ulong load_addr; int i; - struct elf_phdr * elf_ppnt; + struct elf_phdr *elf_ppnt; struct elf_phdr *elf_phdata; - abi_ulong elf_bss, k, elf_brk; - int retval; - char * elf_interpreter; - abi_ulong elf_entry, interp_load_addr = 0; - abi_ulong start_code, end_code, start_data, end_data; + abi_ulong elf_brk; + int error, retval; + char *elf_interpreter; + abi_ulong baddr, elf_entry, et_dyn_addr, interp_load_addr = 0; abi_ulong reloc_func_desc = 0; load_addr = 0; - load_bias = 0; elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */ bswap_ehdr(&elf_ex); @@ -618,16 +651,10 @@ int load_elf_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs, bswap_phdr(elf_phdata, elf_ex.e_phnum); elf_ppnt = elf_phdata; - elf_bss = 0; elf_brk = 0; elf_interpreter = NULL; - start_code = ~((abi_ulong)0UL); - end_code = 0; - start_data = 0; - end_data = 0; - for (i = 0; i < elf_ex.e_phnum; i++) { if (elf_ppnt->p_type == PT_INTERP) { if (elf_interpreter != NULL) { @@ -714,94 +741,45 @@ int load_elf_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs, info->mmap = 0; elf_entry = (abi_ulong) elf_ex.e_entry; - /* Do this so that we can load the interpreter, if need be. We will - change some of these later */ + /* XXX Join this with PT_INTERP search? */ + baddr = 0; + for (i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) { + if (elf_ppnt->p_type != PT_LOAD) { + continue; + } + baddr = elf_ppnt->p_vaddr; + break; + } + + et_dyn_addr = 0; + if (elf_ex.e_type == ET_DYN && baddr == 0) { + et_dyn_addr = ELF_ET_DYN_LOAD_ADDR; + } + + /* + * Do this so that we can load the interpreter, if need be. We will + * change some of these later + */ info->rss = 0; setup_arg_pages(bprm, info, &bprm->p, &bprm->stringp); info->start_stack = bprm->p; - /* Now we do a little grungy work by mmaping the ELF image into - * the correct location in memory. At this point, we assume that - * the image should be loaded at fixed address, not at a variable - * address. - */ + info->elf_flags = elf_ex.e_flags; + error = load_elf_sections(&elf_ex, elf_phdata, bprm->fd, et_dyn_addr, + &load_addr); for (i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) { - int elf_prot = 0; - int elf_flags = 0; - abi_ulong error; - - if (elf_ppnt->p_type != PT_LOAD) + if (elf_ppnt->p_type != PT_LOAD) { continue; - - if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ; - if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE; - if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC; - elf_flags = MAP_PRIVATE | MAP_DENYWRITE; - if (elf_ex.e_type == ET_EXEC || load_addr_set) { - elf_flags |= MAP_FIXED; - } else if (elf_ex.e_type == ET_DYN) { - /* Try and get dynamic programs out of the way of the default mmap - base, as well as whatever program they might try to exec. This - is because the brk will follow the loader, and is not movable. */ - /* NOTE: for qemu, we do a big mmap to get enough space - without hardcoding any address */ - error = target_mmap(0, ET_DYN_MAP_SIZE, - PROT_NONE, MAP_PRIVATE | MAP_ANON, - -1, 0); - if (error == -1) { - perror("mmap"); - exit(-1); - } - load_bias = TARGET_ELF_PAGESTART(error - elf_ppnt->p_vaddr); } - - error = target_mmap(TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr), - (elf_ppnt->p_filesz + - TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)), - elf_prot, - (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE), - bprm->fd, - (elf_ppnt->p_offset - - TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr))); - if (error == -1) { - perror("mmap"); - exit(-1); - } - - if (!load_addr_set) { - load_addr_set = 1; - load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset; - if (elf_ex.e_type == ET_DYN) { - load_bias += error - - TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr); - load_addr += load_bias; - reloc_func_desc = load_bias; - } - } - k = elf_ppnt->p_vaddr; - if (k < start_code) - start_code = k; - if (start_data < k) - start_data = k; - k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz; - if (k > elf_bss) - elf_bss = k; - if ((elf_ppnt->p_flags & PF_X) && end_code < k) - end_code = k; - if (end_data < k) - end_data = k; - k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz; - if (k > elf_brk) elf_brk = k; - } - - elf_entry += load_bias; - elf_bss += load_bias; - elf_brk += load_bias; - start_code += load_bias; - end_code += load_bias; - start_data += load_bias; - end_data += load_bias; + if (elf_ppnt->p_memsz > elf_ppnt->p_filesz) + elf_brk = MAX(elf_brk, et_dyn_addr + elf_ppnt->p_vaddr + + elf_ppnt->p_memsz); + } + if (error != 0) { + perror("load_elf_sections"); + exit(-1); + } if (elf_interpreter) { elf_entry = load_elf_interp(&interp_elf_ex, interpreter_fd, @@ -817,6 +795,9 @@ int load_elf_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs, exit(-1); return 0; } + } else { + interp_load_addr = et_dyn_addr; + elf_entry += interp_load_addr; } free(elf_phdata); @@ -827,21 +808,18 @@ int load_elf_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs, close(bprm->fd); - bprm->p = target_create_elf_tables(bprm->p, bprm->argc, bprm->envc, bprm->stringp, - &elf_ex, load_addr, load_bias, interp_load_addr, info); + bprm->p = target_create_elf_tables(bprm->p, + bprm->argc, + bprm->envc, + bprm->stringp, + &elf_ex, + load_addr, et_dyn_addr, + interp_load_addr, + info); info->load_addr = reloc_func_desc; info->start_brk = info->brk = elf_brk; - info->end_code = end_code; - info->start_code = start_code; - info->start_data = start_data; - info->end_data = end_data; info->start_stack = bprm->p; - - /* Calling set_brk effectively mmaps the pages that we need for the bss and break - sections */ - set_brk(elf_bss, elf_brk); - - padzero(elf_bss, elf_brk); + info->load_bias = 0; info->entry = elf_entry; -- 2.32.0