From: Thomas Garnier <thgarnie@google.com>
To: Herbert Xu <herbert@gondor.apana.org.au>,
"David S . Miller" <davem@davemloft.net>,
Thomas Gleixner <tglx@linutronix.de>,
Ingo Molnar <mingo@redhat.com>, "H . Peter Anvin" <hpa@zytor.com>,
Peter Zijlstra <peterz@infradead.org>,
Josh Poimboeuf <jpoimboe@redhat.com>,
Arnd Bergmann <arnd@arndb.de>,
Thomas Garnier <thgarnie@google.com>,
Kees Cook <keescook@chromium.org>,
Andrey Ryabinin <aryabinin@virtuozzo.com>,
Matthias Kaehlcke <mka@chromium.org>,
Tom Lendacky <thomas.lendacky@amd.com>,
Andy Lutomirski <luto@kernel.org>,
"Kirill A . Shutemov" <kirill.shutemov@linux.intel.com>,
Borislav Petkov <bp@suse.de>,
"Rafael J . Wysocki" <rjw@rjwysocki.net>,
Len Brown <len.brown@intel.com>, Pavel Machek <pavel@ucw.cz>,
Juergen Gross <jgross@suse.com>,
Chris Wright <chrisw@sous-sol.org>,
Alok Kataria <akataria@vmware.com>,
Rusty Russell <rusty@rustcorp.com.au>, Tejun Heo <tj@kernel.>
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: [PATCH v1 23/27] x86/modules: Adapt module loading for PIE support
Date: Wed, 11 Oct 2017 13:30:23 -0700 [thread overview]
Message-ID: <20171011203027.11248-24-thgarnie@google.com> (raw)
In-Reply-To: <20171011203027.11248-1-thgarnie@google.com>
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 <thgarnie@google.com>
---
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 <asm-generic/module.h>
#include <asm/orc_types.h>
+#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 <linux/gfp.h>
#include <linux/jump_label.h>
#include <linux/random.h>
+#include <linux/sort.h>
#include <asm/text-patching.h>
#include <asm/page.h>
@@ -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) }
+}
--
2.15.0.rc0.271.g36b669edcc-goog
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel
next prev parent reply other threads:[~2017-10-11 20:30 UTC|newest]
Thread overview: 44+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-10-11 20:30 [PATCH v1 00/27] x86: PIE support and option to extend KASLR randomization Thomas Garnier
2017-10-11 20:30 ` [PATCH v1 01/27] x86/crypto: Adapt assembly for PIE support Thomas Garnier
2017-10-20 8:24 ` Ingo Molnar
2017-10-20 8:28 ` Ard Biesheuvel
2017-10-20 14:48 ` Thomas Garnier
2017-10-11 20:30 ` [PATCH v1 02/27] x86: Use symbol name on bug table " Thomas Garnier
2017-10-11 20:30 ` [PATCH v1 03/27] x86: Use symbol name in jump " Thomas Garnier
2017-10-11 20:30 ` [PATCH v1 04/27] x86: Add macro to get symbol address " Thomas Garnier
2017-10-11 20:30 ` [PATCH v1 05/27] x86: relocate_kernel - Adapt assembly " Thomas Garnier
2017-10-11 20:30 ` [PATCH v1 06/27] x86/entry/64: " Thomas Garnier
2017-10-20 8:26 ` Ingo Molnar
2017-10-20 14:47 ` Thomas Garnier
2017-10-20 15:20 ` Ingo Molnar
2017-10-20 16:27 ` Andy Lutomirski
2017-10-20 17:52 ` Andy Lutomirski
2017-10-11 20:30 ` [PATCH v1 07/27] x86: pm-trace - " Thomas Garnier
2017-10-11 20:30 ` [PATCH v1 08/27] x86/CPU: " Thomas Garnier
2017-10-11 20:30 ` [PATCH v1 09/27] x86/acpi: " Thomas Garnier
2017-10-11 20:30 ` [PATCH v1 10/27] x86/boot/64: " Thomas Garnier
2017-10-11 20:30 ` [PATCH v1 11/27] x86/power/64: " Thomas Garnier
2017-10-11 20:30 ` [PATCH v1 12/27] x86/paravirt: " Thomas Garnier
2017-10-11 20:30 ` [PATCH v1 13/27] x86/boot/64: Use _text in a global " Thomas Garnier
2017-10-11 20:30 ` [PATCH v1 14/27] x86/percpu: Adapt percpu " Thomas Garnier
2017-10-11 20:30 ` [PATCH v1 15/27] compiler: Option to default to hidden symbols Thomas Garnier
2017-10-12 20:02 ` Luis R. Rodriguez
2017-10-18 23:15 ` Thomas Garnier
2017-10-19 19:38 ` Luis R. Rodriguez
2017-10-11 20:30 ` [PATCH v1 16/27] x86/relocs: Handle PIE relocations Thomas Garnier
2017-10-11 20:30 ` [PATCH v1 17/27] xen: Adapt assembly for PIE support Thomas Garnier
2017-10-11 20:30 ` [PATCH v1 18/27] kvm: " Thomas Garnier
2017-10-11 20:30 ` [PATCH v1 19/27] x86: Support global stack cookie Thomas Garnier
2017-10-11 20:30 ` [PATCH v1 20/27] x86/ftrace: Adapt function tracing for PIE support Thomas Garnier
2017-10-11 20:30 ` [PATCH v1 21/27] x86/mm/dump_pagetables: Fix address markers index on x86_64 Thomas Garnier
2017-10-11 20:30 ` [PATCH v1 22/27] x86/modules: Add option to start module section after kernel Thomas Garnier
2017-10-11 20:30 ` Thomas Garnier [this message]
2017-10-11 20:30 ` [PATCH v1 24/27] x86/mm: Make the x86 GOT read-only Thomas Garnier
2017-10-11 20:30 ` [PATCH v1 25/27] x86/pie: Add option to build the kernel as PIE Thomas Garnier
2017-10-11 20:30 ` [PATCH v1 26/27] x86/relocs: Add option to generate 64-bit relocations Thomas Garnier
2017-10-11 20:30 ` [PATCH v1 27/27] x86/kaslr: Add option to extend KASLR range from 1GB to 3GB Thomas Garnier
2017-10-11 21:34 ` [PATCH v1 00/27] x86: PIE support and option to extend KASLR randomization Tom Lendacky
2017-10-12 15:34 ` Thomas Garnier
2017-10-12 15:51 ` Markus Trippelsdorf
2017-10-12 16:28 ` Tom Lendacky
2017-10-18 23:17 ` Thomas Garnier
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20171011203027.11248-24-thgarnie@google.com \
--to=thgarnie@google.com \
--cc=akataria@vmware.com \
--cc=arnd@arndb.de \
--cc=aryabinin@virtuozzo.com \
--cc=bp@suse.de \
--cc=chrisw@sous-sol.org \
--cc=davem@davemloft.net \
--cc=herbert@gondor.apana.org.au \
--cc=hpa@zytor.com \
--cc=jgross@suse.com \
--cc=jpoimboe@redhat.com \
--cc=keescook@chromium.org \
--cc=kernel-hardening@lists.openwall.com \
--cc=kirill.shutemov@linux.intel.com \
--cc=kvm@vger.kernel.org \
--cc=len.brown@intel.com \
--cc=linux-arch@vger.kernel.org \
--cc=linux-crypto@vger.kernel.org \
--cc=linux-doc@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pm@vger.kernel.org \
--cc=linux-sparse@vger.kernel.org \
--cc=luto@kernel.org \
--cc=mingo@redhat.com \
--cc=mka@chromium.org \
--cc=pavel@ucw.cz \
--cc=peterz@infradead.org \
--cc=rjw@rjwysocki.net \
--cc=rusty@rustcorp.com.au \
--cc=tglx@linutronix.de \
--cc=thomas.lendacky@amd.com \
--cc=tj@kernel. \
--cc=virtualization@lists.linux-foundation.org \
--cc=x86@kernel.org \
--cc=xen-devel@lists.xenproject.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).