From patchwork Wed Oct 4 21:19:59 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thomas Garnier X-Patchwork-Id: 9985575 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 4E4A760586 for ; Wed, 4 Oct 2017 21:23:43 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 3E11528C2E for ; Wed, 4 Oct 2017 21:23:43 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 31CD028C33; Wed, 4 Oct 2017 21:23:43 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-3.6 required=2.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, RCVD_IN_DNSWL_MED, RCVD_IN_SORBS_SPAM, T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 79A9C28C2E for ; Wed, 4 Oct 2017 21:23:42 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1dzr6j-0003Vm-Vl; Wed, 04 Oct 2017 21:21:33 +0000 Received: from mail6.bemta5.messagelabs.com ([195.245.231.135]) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1dzr6i-0003SD-Jl for xen-devel@lists.xenproject.org; Wed, 04 Oct 2017 21:21:32 +0000 Received: from [85.158.139.211] by server-16.bemta-5.messagelabs.com id 90/A6-18674-BD055D95; Wed, 04 Oct 2017 21:21:31 +0000 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFtrBIsWRWlGSWpSXmKPExsVyMfTASt1bAVc jDX6+lbf4vmUykwOjx+EPV1gCGKNYM/OS8isSWDNan79jKuh1qFi84SNrA+MWky5GLg4hgRmM Ejs/f2cHcVgEXrFI7Ny4mhHEkRDoZ5V4ffspkMMJ5GRJLJrVw9zFyAFkp0ksOhEDEa6RmLR2P hOILSSgJLF1w1JmiKl/GSWmrT8DlmAT0JLY0wBSxMUhIjBLROLW6x42EIdZ4AyTxPG+k6wgU4 UFPCVeLeEAaWARUJVY9/ofM4jNK2Ap8f/JIlaIbSYSD49cA7M5geJHTrxhhthsIdF65j7TBEb BBYwMqxjVi1OLylKLdM31kooy0zNKchMzc3QNDUz1clOLixPTU3MSk4r1kvNzNzECQ44BCHYw HpvsfIhRkoNJSZR3k+/VSCG+pPyUyozE4oz4otKc1OJDjDIcHEoSvHP8gXKCRanpqRVpmTnA4 IdJS3DwKInwTgZJ8xYXJOYWZ6ZDpE4xWnJcuHPpDxPHgT23gGTHzbt/mIRY8vLzUqXEeTeDNA iANGSU5sGNg0XoJUZZKWFeRqADhXgKUotyM0tQ5V8xinMwKgnzPgCZwpOZVwK39RXQQUxAB81 pugJyUEkiQkqqgdGLKX76S79Fs5k27NxUna+dFRUjtHnHP0bFZw7nCu/I372zimeF3HXe8LVZ 9zl4/yk/fm7xrNr4VHn32pbZq54asMtlrz9778ftXW/1f66fNf9oHUu60ocbU0oz/CWMpJTET s55/l0qNaShSqEsRPxwx+VV30/PP7HQ5LbzJj5Z3cgVfZ/Sf2srsRRnJBpqMRcVJwIA0/q5Ws sCAAA= X-Env-Sender: thgarnie@google.com X-Msg-Ref: server-2.tower-206.messagelabs.com!1507152089!94009456!1 X-Originating-IP: [209.85.192.169] X-SpamReason: No, hits=0.0 required=7.0 tests= X-StarScan-Received: X-StarScan-Version: 9.4.45; banners=-,-,- X-VirusChecked: Checked Received: (qmail 61271 invoked from network); 4 Oct 2017 21:21:30 -0000 Received: from mail-pf0-f169.google.com (HELO mail-pf0-f169.google.com) (209.85.192.169) by server-2.tower-206.messagelabs.com with AES128-GCM-SHA256 encrypted SMTP; 4 Oct 2017 21:21:30 -0000 Received: by mail-pf0-f169.google.com with SMTP id u12so6900875pfl.4 for ; Wed, 04 Oct 2017 14:21:30 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=b+2UtKPVFmdgJp8w3Dga6wFhYsBezaY6O2RxiUsE13k=; b=q5StrJYMGrePJhDO9rbvClKMQ8NKSysrbhUPPXGH51Lg7Qb+i85rHgEMIh4eCLuw6K 2ztw5tcF3YAG7XKcGkTEi6EvLaRFoEToukF6W6HgZQWDCFVYHu2S/LBULrjK4RBpw6v2 VOPL9kPYkJAvR7SU/knoQoEVo55PdDhMXIaW5ltqiul49x5sa4Uf/EFvVn9PvWDh2Phe XN2YZu/71V3r8wgDVIvkWC5cSSbh+cea30AXfSuhYmHjOuYLJlM5HNwa9ygxRT3bvhLm yQEZ+4VoSwOjf9SjE+nGeZ54ZqlhSpFLWq/F9NUF/hH01jN8dM3y+jqkbMmZWLRAefyJ zq7Q== 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; bh=b+2UtKPVFmdgJp8w3Dga6wFhYsBezaY6O2RxiUsE13k=; b=SXkspVB0Xd/eQOBTwhQIzWicWAjJiGsAF8dZDWuCLQXSWhNZCzmUdu52kbtbWKWdNR inoh7qYwwiysO1JKGPW+9FxoAz68eOHHpxsXmve+c+6yFpyK/L4joseiCTm5Aml7iGBs 3EcODzv283FHnT5yZnPRLDDramSMIPv8/SutzCBAXm+zBYqrnT/pfDyARizLgrVJBAMW zDPFa8ISuz9v5UMfy8H1VJBqCn0BCbhupFaNcDnci3w+foSClI/UkHS6OAM9zSNITgzB 7u0epFCYAAO1Yr7crc0tJZZ1XRfUWUIt9HlY2rv57BoU+ijBEA2JWs/m1NdLF7Jy+TKM GX6A== X-Gm-Message-State: AMCzsaVwkq6Oh26/CvvrvcjgsarF5+mAhZ22CsVVoDxUKfV+am0FzUOU d8i7J7fY1NdKY+Q6Iu+fn0q0xA== X-Google-Smtp-Source: AOwi7QDLel0VhKMJHwDVlbvSZdpghH9epB2eZIAM/EVQKPOhQe4DHdZdXnnShtJe55QEXpRK9+YMKQ== X-Received: by 10.159.207.151 with SMTP id z23mr10019461plo.319.1507152087935; Wed, 04 Oct 2017 14:21:27 -0700 (PDT) Received: from skynet.sea.corp.google.com ([172.31.92.33]) by smtp.gmail.com with ESMTPSA id s68sm30204019pfd.72.2017.10.04.14.21.26 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 04 Oct 2017 14:21:27 -0700 (PDT) From: Thomas Garnier To: Herbert Xu , "David S . Miller" , Thomas Gleixner , Ingo Molnar , "H . Peter Anvin" , Peter Zijlstra , Josh Poimboeuf , Thomas Garnier , Arnd Bergmann , Kees Cook , Matthias Kaehlcke , Tom Lendacky , Andy Lutomirski , "Kirill A . Shutemov" , Borislav Petkov , "Rafael J . Wysocki" , Len Brown , Pavel Machek , Juergen Gross , Chris Wright , Alok Kataria , Rusty Russell , Tejun Heo , Christoph Lameter , Boris Ostrovsky , Alexey Dobriyan , Andrew Morton , Paul Gortmaker , Chris Metcalf , "Paul E . McKenney" , Nicolas Pitre , Borislav Petkov , "Luis R . Rodriguez" , Greg Kroah-Hartman , Christopher Li , Steven Rostedt , Jason Baron , Dou Liyang , "Rafael J . Wysocki" , Mika Westerberg , Lukas Wunner , Masahiro Yamada , Alexei Starovoitov , Daniel Borkmann , Markus Trippelsdorf , Paolo Bonzini , =?UTF-8?q?Radim=20Kr=C4=8Dm=C3=A1=C5=99?= , Joerg Roedel , Rik van Riel , David Howells , Ard Biesheuvel , Waiman Long , Kyle Huey , Andrey Ryabinin , Jonathan Corbet , Matthew Wilcox , Michal Hocko , Peter Foley , Paul Bolle , Jiri Kosina , Rob Landley , "H . J . Lu" , Baoquan He , =?UTF-8?q?Jan=20H=20=2E=20Sch=C3=B6nherr?= , Daniel Micay Date: Wed, 4 Oct 2017 14:19:59 -0700 Message-Id: <20171004212003.28296-24-thgarnie@google.com> X-Mailer: git-send-email 2.14.2.920.gcf0c67979c-goog In-Reply-To: <20171004212003.28296-1-thgarnie@google.com> References: <20171004212003.28296-1-thgarnie@google.com> Cc: linux-arch@vger.kernel.org, kvm@vger.kernel.org, linux-pm@vger.kernel.org, x86@kernel.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, virtualization@lists.linux-foundation.org, linux-sparse@vger.kernel.org, linux-crypto@vger.kernel.org, kernel-hardening@lists.openwall.com, xen-devel@lists.xenproject.org Subject: [Xen-devel] [RFC v3 23/27] x86/modules: Adapt module loading for PIE support X-BeenThere: xen-devel@lists.xen.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: xen-devel-bounces@lists.xen.org Sender: "Xen-devel" X-Virus-Scanned: ClamAV using ClamSMTP Adapt module loading to support PIE relocations. Generate dynamic GOT if a symbol requires it but no entry exist in the kernel GOT. Position Independent Executable (PIE) support will allow to extended the KASLR randomization range below the -2G memory limit. Signed-off-by: Thomas Garnier --- arch/x86/Makefile | 4 + arch/x86/include/asm/module.h | 14 +++ arch/x86/kernel/module.c | 204 ++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 217 insertions(+), 5 deletions(-) diff --git a/arch/x86/Makefile b/arch/x86/Makefile index 4cb4f0495ddc..42774185a58a 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile @@ -143,7 +143,11 @@ else KBUILD_CFLAGS += $(cflags-y) KBUILD_CFLAGS += -mno-red-zone +ifdef CONFIG_X86_PIE + KBUILD_LDFLAGS_MODULE += -T $(srctree)/arch/x86/kernel/module.lds +else KBUILD_CFLAGS += -mcmodel=kernel +endif # -funit-at-a-time shrinks the kernel .text considerably # unfortunately it makes reading oopses harder. diff --git a/arch/x86/include/asm/module.h b/arch/x86/include/asm/module.h index 9eb7c718aaf8..8e0bd52bbadf 100644 --- a/arch/x86/include/asm/module.h +++ b/arch/x86/include/asm/module.h @@ -4,12 +4,23 @@ #include #include +#ifdef CONFIG_X86_PIE +struct mod_got_sec { + struct elf64_shdr *got; + int got_num_entries; + int got_max_entries; +}; +#endif + struct mod_arch_specific { #ifdef CONFIG_ORC_UNWINDER unsigned int num_orcs; int *orc_unwind_ip; struct orc_entry *orc_unwind; #endif +#ifdef CONFIG_X86_PIE + struct mod_got_sec core; +#endif }; #ifdef CONFIG_X86_64 @@ -70,4 +81,7 @@ struct mod_arch_specific { # define MODULE_ARCH_VERMAGIC MODULE_PROC_FAMILY #endif + +u64 module_find_got_entry(struct module *mod, u64 addr); + #endif /* _ASM_X86_MODULE_H */ diff --git a/arch/x86/kernel/module.c b/arch/x86/kernel/module.c index 62e7d70aadd5..3b9b43a9d63b 100644 --- a/arch/x86/kernel/module.c +++ b/arch/x86/kernel/module.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -77,6 +78,195 @@ static unsigned long int get_module_load_offset(void) } #endif +#ifdef CONFIG_X86_PIE +static u64 find_got_kernel_entry(Elf64_Sym *sym, const Elf64_Rela *rela) +{ + u64 *pos; + + for (pos = (u64*)__start_got; pos < (u64*)__end_got; pos++) { + if (*pos == sym->st_value) + return (u64)pos + rela->r_addend; + } + + return 0; +} + +/* Search the GOT entry for a specific address and a module (optional) */ +u64 module_find_got_entry(struct module *mod, u64 addr) +{ + int i; + u64 *pos; + + for (pos = (u64*)__start_got; pos < (u64*)__end_got; pos++) { + if (*pos == addr) + return (u64)pos; + } + + if (!mod) + return 0; + + pos = (u64*)mod->arch.core.got->sh_addr; + for (i = 0; i < mod->arch.core.got_num_entries; i++) { + if (pos[i] == addr) + return (u64)&pos[i]; + } + return 0; +} + +static u64 module_emit_got_entry(struct module *mod, void *loc, + const Elf64_Rela *rela, Elf64_Sym *sym) +{ + struct mod_got_sec *gotsec = &mod->arch.core; + u64 *got = (u64*)gotsec->got->sh_addr; + int i = gotsec->got_num_entries; + u64 ret; + + /* Check if we can use the kernel GOT */ + ret = find_got_kernel_entry(sym, rela); + if (ret) + return ret; + + got[i] = sym->st_value; + + /* + * Check if the entry we just created is a duplicate. Given that the + * relocations are sorted, this will be the last entry we allocated. + * (if one exists). + */ + if (i > 0 && got[i] == got[i - 2]) { + ret = (u64)&got[i - 1]; + } else { + gotsec->got_num_entries++; + BUG_ON(gotsec->got_num_entries > gotsec->got_max_entries); + ret = (u64)&got[i]; + } + + return ret + rela->r_addend; +} + +#define cmp_3way(a,b) ((a) < (b) ? -1 : (a) > (b)) + +static int cmp_rela(const void *a, const void *b) +{ + const Elf64_Rela *x = a, *y = b; + int i; + + /* sort by type, symbol index and addend */ + i = cmp_3way(ELF64_R_TYPE(x->r_info), ELF64_R_TYPE(y->r_info)); + if (i == 0) + i = cmp_3way(ELF64_R_SYM(x->r_info), ELF64_R_SYM(y->r_info)); + if (i == 0) + i = cmp_3way(x->r_addend, y->r_addend); + return i; +} + +static bool duplicate_rel(const Elf64_Rela *rela, int num) +{ + /* + * Entries are sorted by type, symbol index and addend. That means + * that, if a duplicate entry exists, it must be in the preceding + * slot. + */ + return num > 0 && cmp_rela(rela + num, rela + num - 1) == 0; +} + +static unsigned int count_gots(Elf64_Sym *syms, Elf64_Rela *rela, int num) +{ + unsigned int ret = 0; + Elf64_Sym *s; + int i; + + for (i = 0; i < num; i++) { + switch (ELF64_R_TYPE(rela[i].r_info)) { + case R_X86_64_GOTPCREL: + s = syms + ELF64_R_SYM(rela[i].r_info); + + /* + * Use the kernel GOT when possible, else reserve a + * custom one for this module. + */ + if (!duplicate_rel(rela, i) && + !find_got_kernel_entry(s, rela + i)) + ret++; + break; + } + } + return ret; +} + +/* + * Generate GOT entries for GOTPCREL relocations that do not exists in the + * kernel GOT. Based on arm64 module-plts implementation. + */ +int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, + char *secstrings, struct module *mod) +{ + unsigned long gots = 0; + Elf_Shdr *symtab = NULL; + Elf64_Sym *syms = NULL; + char *strings, *name; + int i; + + /* + * Find the empty .got section so we can expand it to store the PLT + * entries. Record the symtab address as well. + */ + for (i = 0; i < ehdr->e_shnum; i++) { + if (!strcmp(secstrings + sechdrs[i].sh_name, ".got")) { + mod->arch.core.got = sechdrs + i; + } else if (sechdrs[i].sh_type == SHT_SYMTAB) { + symtab = sechdrs + i; + syms = (Elf64_Sym *)symtab->sh_addr; + } + } + + if (!mod->arch.core.got) { + pr_err("%s: module GOT section missing\n", mod->name); + return -ENOEXEC; + } + if (!syms) { + pr_err("%s: module symtab section missing\n", mod->name); + return -ENOEXEC; + } + + for (i = 0; i < ehdr->e_shnum; i++) { + Elf64_Rela *rels = (void *)ehdr + sechdrs[i].sh_offset; + int numrels = sechdrs[i].sh_size / sizeof(Elf64_Rela); + + if (sechdrs[i].sh_type != SHT_RELA) + continue; + + /* sort by type, symbol index and addend */ + sort(rels, numrels, sizeof(Elf64_Rela), cmp_rela, NULL); + + gots += count_gots(syms, rels, numrels); + } + + mod->arch.core.got->sh_type = SHT_NOBITS; + mod->arch.core.got->sh_flags = SHF_ALLOC; + mod->arch.core.got->sh_addralign = L1_CACHE_BYTES; + mod->arch.core.got->sh_size = (gots + 1) * sizeof(u64); + mod->arch.core.got_num_entries = 0; + mod->arch.core.got_max_entries = gots; + + /* + * If a _GLOBAL_OFFSET_TABLE_ symbol exists, make it absolute for + * modules to correctly reference it. Similar to s390 implementation. + */ + strings = (void *) ehdr + sechdrs[symtab->sh_link].sh_offset; + for (i = 0; i < symtab->sh_size/sizeof(Elf_Sym); i++) { + if (syms[i].st_shndx != SHN_UNDEF) + continue; + name = strings + syms[i].st_name; + if (!strcmp(name, "_GLOBAL_OFFSET_TABLE_")) { + syms[i].st_shndx = SHN_ABS; + break; + } + } + return 0; +} +#endif + void *module_alloc(unsigned long size) { void *p; @@ -184,13 +374,18 @@ int apply_relocate_add(Elf64_Shdr *sechdrs, if ((s64)val != *(s32 *)loc) goto overflow; break; +#ifdef CONFIG_X86_PIE + case R_X86_64_GOTPCREL: + val = module_emit_got_entry(me, loc, rel + i, sym); + /* fallthrough */ +#endif + case R_X86_64_PLT32: case R_X86_64_PC32: val -= (u64)loc; *(u32 *)loc = val; -#if 0 - if ((s64)val != *(s32 *)loc) + if (IS_ENABLED(CONFIG_X86_PIE) && + (s64)val != *(s32 *)loc) goto overflow; -#endif break; default: pr_err("%s: Unknown rela relocation: %llu\n", @@ -203,8 +398,7 @@ int apply_relocate_add(Elf64_Shdr *sechdrs, overflow: pr_err("overflow in relocation type %d val %Lx\n", (int)ELF64_R_TYPE(rel[i].r_info), val); - pr_err("`%s' likely not compiled with -mcmodel=kernel\n", - me->name); + pr_err("`%s' likely too far from the kernel\n", me->name); return -ENOEXEC; } #endif