From patchwork Wed Oct 11 20:30:23 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thomas Garnier X-Patchwork-Id: 10000543 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 67C12603B5 for ; Wed, 11 Oct 2017 20:33:18 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 5B69628B66 for ; Wed, 11 Oct 2017 20:33:18 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 4EE1C28B6E; Wed, 11 Oct 2017 20:33:18 +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=-4.1 required=2.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, RCVD_IN_DNSWL_MED, 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 918FC28B6A for ; Wed, 11 Oct 2017 20:33:17 +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 1e2NfP-00013e-To; Wed, 11 Oct 2017 20:31:47 +0000 Received: from mail6.bemta3.messagelabs.com ([195.245.230.39]) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1e2NfO-0000zU-8x for xen-devel@lists.xenproject.org; Wed, 11 Oct 2017 20:31:46 +0000 Received: from [85.158.137.68] by server-12.bemta-3.messagelabs.com id 67/1F-28357-1BF7ED95; Wed, 11 Oct 2017 20:31:45 +0000 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFtrFIsWRWlGSWpSXmKPExsVyMfTAVt0N9fc iDf49lrb4vmUykwOjx+EPV1gCGKNYM/OS8isSWDM275nOXtDmWHHoyFHmBsYjpl2MXBxCAjMY JU50LmcBcVgEXrFILFvcyQjiSAj0s0q0vPoIlOEEcrIkHpx6xwphp0lMn93BBGFXSjzvW8gOY gsJKEls3bCUGWLsP0aJRQfXgRWxCWhJ7GmYzwSSEBE4ISyx6cNvsBXMAmeYJI73nQQbKyzgLf H/+HcgmwPoEFWJuxOzQcK8ApYS66bOYYfYZiFx7NhhsIs4geLfNx5ihthsIbFy1nnWCYyCCxg ZVjFqFKcWlaUW6RqZ6iUVZaZnlOQmZuboGhoY6+WmFhcnpqfmJCYV6yXn525iBIZdPQMD4w7G 1hN+hxglOZiURHkfxtyLFOJLyk+pzEgszogvKs1JLT7EKMPBoSTBe7cOKCdYlJqeWpGWmQOMA Ji0BAePkghvE0iat7ggMbc4Mx0idYrRkuPCnUt/mDgO7LkFJDtu3v3DJMSSl5+XKiXO+xCkQQ CkIaM0D24cLEovMcpKCfMyMjAwCPEUpBblZpagyr9iFOdgVBLmPQwyhSczrwRu6yugg5iADhJ NuwNyUEkiQkqqgVHD8MirBx3nnePsFjxjVt05ddv+8hnqFm/aDHODNtze88RPx7fV/1WwSUjD 7bPHs14e2j/1CYtDe9yuTKm3Um2enjvXVhmYaP89cnR2ZuGkpcJ7fFsf8c9ecdCaqWjlze22P oJLnl179V5M59HWGc/rnLf6C4Ulld1QFuaOYZd+tHn2Z/5IliwlluKMREMt5qLiRACdAl89zQ IAAA== X-Env-Sender: thgarnie@google.com X-Msg-Ref: server-11.tower-31.messagelabs.com!1507753903!78986998!1 X-Originating-IP: [209.85.192.181] 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 27347 invoked from network); 11 Oct 2017 20:31:44 -0000 Received: from mail-pf0-f181.google.com (HELO mail-pf0-f181.google.com) (209.85.192.181) by server-11.tower-31.messagelabs.com with AES128-GCM-SHA256 encrypted SMTP; 11 Oct 2017 20:31:44 -0000 Received: by mail-pf0-f181.google.com with SMTP id m63so1947267pfk.7 for ; Wed, 11 Oct 2017 13:31:44 -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=nmYo1OtOwkMgCnc+wbnsHD+kNuHKTBksk4BeEw9flbs=; b=XdZo+lnTbVxMRQFicQJwFXXYEK24bGSEcOrYj7yjlbpwH9pHn2sUMXIa/JsE5c+R60 ein1DEsOAHJTkl80CVwBluU1dvJYz48rE/1Px97+RDdqS3JWXMcC1lX50k3KzeLhMAxD H1YZ8uaFAB3MP2fEFct44L68ZuGVWLJGTxz4Wgew0hMzoADoxkJCLGNJAAcxPeGILWFg wG0Bwiku4hpvNMGfCYq911GIudNyF8AmPz5YU00k8/aaQ7SFUh/dxdK1b+ddPLR4CnYl jmTAcrwdRI77h3rrSAhUNRnBKqz8j0TN1UHX0Iar+AVEHJ768eEm+cqbWHYIQN9qF0uE m4eQ== 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=nmYo1OtOwkMgCnc+wbnsHD+kNuHKTBksk4BeEw9flbs=; b=FQH8UsSWnVrfnB9JWRiP6ar5WmlqROeAKTlq9ER5l6mlyc3ooenwveh6DaMtob0zma vcbC6/2/zgExUbxvUcm987A0OobLrcbRjQ+Hb6ym0VmMg+/6EFi1vvY1NeiDMsINRPah ZwdEdjhIb0TP5qyiuqhVxLfeWBTr/a96gdzpoWAJ/wM6yoi+uO+hDDk+32j0/6ZuIoJ8 3r7aKtfDWzBwXIu/RjHpjZx73Kb4fv/DZRUimOhow/SdcNf3zToiHGbjSAbUl/l9R5m/ nq0RVSMqPG/s296VfRXtlJe7A9EGkstXGw4fV04hwjkV5G8YOYa/4q4nPQzp3tIsMTN1 dUYw== X-Gm-Message-State: AMCzsaXvraLmIknJB3C35Bh5VDpgubcVXbxYVDhoTCThQs9qysA+rW/U +GYnORE1Urwkpimjh8am/DjE8A== X-Google-Smtp-Source: AOwi7QCBRGou0vJsMUcOH5uGB9LC56+A/ZYLGtrgoEbMu1WVyvOy+AG4mLkgrOxIgF1NGUUxMZtbKg== X-Received: by 10.98.150.221 with SMTP id s90mr192707pfk.282.1507753901911; Wed, 11 Oct 2017 13:31:41 -0700 (PDT) Received: from skynet.sea.corp.google.com ([172.31.92.33]) by smtp.gmail.com with ESMTPSA id n12sm20691913pfb.149.2017.10.11.13.31.40 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 11 Oct 2017 13:31:41 -0700 (PDT) From: Thomas Garnier To: Herbert Xu , "David S . Miller" , Thomas Gleixner , Ingo Molnar , "H . Peter Anvin" , Peter Zijlstra , Josh Poimboeuf , Arnd Bergmann , Thomas Garnier , Kees Cook , Andrey Ryabinin , 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 , Paul Gortmaker , Andrew Morton , Alexey Dobriyan , "Paul E . McKenney" , Nicolas Pitre , Borislav Petkov , "Luis R . Rodriguez" , Greg Kroah-Hartman , Christopher Li , Steven Rostedt , Jason Baron , Mika Westerberg , Dou Liyang , "Rafael J . Wysocki" , 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 , Jonathan Corbet , Michal Hocko , Peter Foley , Paul Bolle , Jiri Kosina , "H . J . Lu" , Rob Landley , Baoquan He , =?UTF-8?q?Jan=20H=20=2E=20Sch=C3=B6nherr?= , Daniel Micay Date: Wed, 11 Oct 2017 13:30:23 -0700 Message-Id: <20171011203027.11248-24-thgarnie@google.com> X-Mailer: git-send-email 2.15.0.rc0.271.g36b669edcc-goog In-Reply-To: <20171011203027.11248-1-thgarnie@google.com> References: <20171011203027.11248-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] [PATCH v1 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 | 11 +++ arch/x86/include/asm/sections.h | 4 + arch/x86/kernel/module.c | 182 ++++++++++++++++++++++++++++++++++++++-- arch/x86/kernel/module.lds | 3 + 5 files changed, 199 insertions(+), 5 deletions(-) create mode 100644 arch/x86/kernel/module.lds diff --git a/arch/x86/Makefile b/arch/x86/Makefile index de228200ef2a..b592d57c531b 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile @@ -134,7 +134,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..21e0e02c0343 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 diff --git a/arch/x86/include/asm/sections.h b/arch/x86/include/asm/sections.h index 6b2d496cf1aa..92d796109da1 100644 --- a/arch/x86/include/asm/sections.h +++ b/arch/x86/include/asm/sections.h @@ -15,4 +15,8 @@ extern char __end_rodata_hpage_align[]; extern char __start_got[], __end_got[]; #endif +#if defined(CONFIG_X86_PIE) +extern char __start_got[], __end_got[]; +#endif + #endif /* _ASM_X86_SECTIONS_H */ diff --git a/arch/x86/kernel/module.c b/arch/x86/kernel/module.c index 62e7d70aadd5..aed24dfac1d3 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,173 @@ 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; +} + +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 +352,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 +376,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 diff --git a/arch/x86/kernel/module.lds b/arch/x86/kernel/module.lds new file mode 100644 index 000000000000..fd6e95a4b454 --- /dev/null +++ b/arch/x86/kernel/module.lds @@ -0,0 +1,3 @@ +SECTIONS { + .got (NOLOAD) : { BYTE(0) } +}