From patchwork Tue Jun 26 18:27:58 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ard Biesheuvel X-Patchwork-Id: 140073 Delivered-To: patch@linaro.org Received: by 2002:a2e:970d:0:0:0:0:0 with SMTP id r13-v6csp5572840lji; Tue, 26 Jun 2018 11:28:56 -0700 (PDT) X-Google-Smtp-Source: ADUXVKKQ0oIc+M46Mhl8o9fK0YHpyTwiQXPBaWsU0xpkJjUQcMOaOArnYAFVqzGUEgcj3Pn5Simy X-Received: by 2002:a17:902:b946:: with SMTP id h6-v6mr2673532pls.1.1530037736201; Tue, 26 Jun 2018 11:28:56 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1530037736; cv=none; d=google.com; s=arc-20160816; b=NQUpVIrTEtjt5A7ENJm+kj+iACBHGbUMA1BCeJ7JdkhyKxbqjEejnEZzu3oOe/wvQT gR1Sc0x2QRZDHQQ1urNO8bED5K/3ocaW+4fvB/qUx7Eeta1inLAdCA8knS3VVKJ463w5 r8rShCvGy+ep8A0XooQjuUDGlFxULpNKjsmOaxo/OUgFM3MXYhk6oxDL9bYx3bcqIXsV WoQU8/zlu+XAshcF1qZXU81GnRxAfe1Q52lOpVKFTXRcKVpGHbQ6zCHtms1NDZJ9IUpS 9Z2RQu/zLsQuV1eM67+f520P+ilkqAoxeEWj1YIq8gZxyCsLOyF5pm87bewAKUhmQnIi o41A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:arc-authentication-results; bh=o8p9Iq0iPGdylp8Oth6Hq3Y5MrX11H4f3D1X+1TovYQ=; b=SKAPGMCzcRgbZi/9ZHjqWj9X/Ve/5cIytdUjHptoSIOHnL9p5UPxhCFtcsysP/AMKO mYXEUhqn+/AzmED3JTPsUIb+hiBIit54m6r8QF/n0bMbDuum41LnbZUNUBaXwI+B8Don R6RmPKRRBjRBypBMK3SxABQ0mvvB82dOMOPFuoYjGLUjTMMK6c7m5tH8CvdgS2sTeiLJ kcFOMrVAU+OwS/AE9OIKgbu2vM9r8C0iXbsJ0FnFBgGt+CkcniDYCOL/ms5qcgLwJuz/ lHoqndftNLSL2/1WS08S/3OeKwgrJ6RvGxovZJu80pGuwdF6WeQ2H42MbSbOYisypUCP w4bw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=CmfmsAA9; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id m13-v6si1843539pgs.690.2018.06.26.11.28.55; Tue, 26 Jun 2018 11:28:56 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=CmfmsAA9; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754128AbeFZS2w (ORCPT + 31 others); Tue, 26 Jun 2018 14:28:52 -0400 Received: from mail-wr0-f195.google.com ([209.85.128.195]:33697 "EHLO mail-wr0-f195.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752886AbeFZS2r (ORCPT ); Tue, 26 Jun 2018 14:28:47 -0400 Received: by mail-wr0-f195.google.com with SMTP id k16-v6so18233904wro.0 for ; Tue, 26 Jun 2018 11:28:47 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=o8p9Iq0iPGdylp8Oth6Hq3Y5MrX11H4f3D1X+1TovYQ=; b=CmfmsAA9n5jGVS84/6q6+bWrR4dhFHwQR+xZ4QFiV0Pdh6A6snCMHLbydTlK4kaij8 ERS+hDNia2+xE0xv5ZZi1r4qFLJsBdrxfQVyL/TbjuLUv7CvaB+15uHzVYBESwYH8AXf RvdJipig0rHagy2VQx8eZskqbrkzMg5weH7eo= 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=o8p9Iq0iPGdylp8Oth6Hq3Y5MrX11H4f3D1X+1TovYQ=; b=OKgdByQE3rXT/kVEKaai7MrrxXE1utN335euJYoWsPAeFg1grx0ZBcfbxr8h7pjeRG /SMcH3MbFCxIR4LCBZE8iIWcBlYMzTv8/4hy0NSAIXxFqM8DBcplJjTY3KxsehS1Zezd 4i/LILSlXemWvzKFdWPyWT6dMVgq3F2DsMTmDMwtecKrSJNftr+RlzZD/eQ12430amSf /FIOqGEI8Z+8OrH4hoVjFvcwZkcnP8rWBDEL4WZFbGeXizHg+zsp9frBI8PXBMtFDotd 2T2VcMF4q989kEbMFNQrUNGfU6t6w07EaD9qcZnM7V4U3QVOTwqfSEyBWQJ5czEN74FU MgEA== X-Gm-Message-State: APt69E2Geoi0KGuH9MtA2K7s49sHwFXJcCMIcxFbYcIY+GPa9RPR1WWE E0fJn9ItVaDxYqJjq143Ujr+/Lf+bs8= X-Received: by 2002:adf:9063:: with SMTP id h90-v6mr2495896wrh.147.1530037726264; Tue, 26 Jun 2018 11:28:46 -0700 (PDT) Received: from rev02.home ([2a01:cb1d:112:6f00:d037:e907:f0a2:a5ea]) by smtp.gmail.com with ESMTPSA id s17-v6sm1707664wmc.34.2018.06.26.11.28.44 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 26 Jun 2018 11:28:45 -0700 (PDT) From: Ard Biesheuvel To: linux-kernel@vger.kernel.org Cc: Ard Biesheuvel , Arnd Bergmann , Kees Cook , Will Deacon , Michael Ellerman , Thomas Garnier , Thomas Gleixner , "Serge E. Hallyn" , Bjorn Helgaas , Benjamin Herrenschmidt , Russell King , Paul Mackerras , Catalin Marinas , Petr Mladek , Ingo Molnar , James Morris , Andrew Morton , Nicolas Pitre , Josh Poimboeuf , Steven Rostedt , Sergey Senozhatsky , Linus Torvalds , Jessica Yu , linux-arm-kernel@lists.infradead.org, linuxppc-dev@lists.ozlabs.org, x86@kernel.org, Ingo Molnar Subject: [PATCH v9 3/6] module: use relative references for __ksymtab entries Date: Tue, 26 Jun 2018 20:27:58 +0200 Message-Id: <20180626182802.19932-4-ard.biesheuvel@linaro.org> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20180626182802.19932-1-ard.biesheuvel@linaro.org> References: <20180626182802.19932-1-ard.biesheuvel@linaro.org> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org An ordinary arm64 defconfig build has ~64 KB worth of __ksymtab entries, each consisting of two 64-bit fields containing absolute references, to the symbol itself and to a char array containing its name, respectively. When we build the same configuration with KASLR enabled, we end up with an additional ~192 KB of relocations in the .init section, i.e., one 24 byte entry for each absolute reference, which all need to be processed at boot time. Given how the struct kernel_symbol that describes each entry is completely local to module.c (except for the references emitted by EXPORT_SYMBOL() itself), we can easily modify it to contain two 32-bit relative references instead. This reduces the size of the __ksymtab section by 50% for all 64-bit architectures, and gets rid of the runtime relocations entirely for architectures implementing KASLR, either via standard PIE linking (arm64) or using custom host tools (x86). Note that the binary search involving __ksymtab contents relies on each section being sorted by symbol name. This is implemented based on the input section names, not the names in the ksymtab entries, so this patch does not interfere with that. Given that the use of place-relative relocations requires support both in the toolchain and in the module loader, we cannot enable this feature for all architectures. So make it dependent on whether CONFIG_HAVE_ARCH_PREL32_RELOCATIONS is defined. Cc: Arnd Bergmann Cc: Andrew Morton Cc: Ingo Molnar Cc: Kees Cook Cc: Thomas Garnier Cc: Nicolas Pitre Acked-by: Jessica Yu Signed-off-by: Ard Biesheuvel --- arch/x86/include/asm/Kbuild | 1 + arch/x86/include/asm/export.h | 5 --- include/asm-generic/export.h | 12 ++++- include/linux/compiler.h | 19 ++++++++ include/linux/export.h | 46 +++++++++++++++----- kernel/module.c | 32 +++++++++++--- 6 files changed, 91 insertions(+), 24 deletions(-) -- 2.11.0 diff --git a/arch/x86/include/asm/Kbuild b/arch/x86/include/asm/Kbuild index de690c2d2e33..a0ab9ab61c75 100644 --- a/arch/x86/include/asm/Kbuild +++ b/arch/x86/include/asm/Kbuild @@ -8,5 +8,6 @@ generated-y += xen-hypercalls.h generic-y += dma-contiguous.h generic-y += early_ioremap.h +generic-y += export.h generic-y += mcs_spinlock.h generic-y += mm-arch-hooks.h diff --git a/arch/x86/include/asm/export.h b/arch/x86/include/asm/export.h deleted file mode 100644 index 2a51d66689c5..000000000000 --- a/arch/x86/include/asm/export.h +++ /dev/null @@ -1,5 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifdef CONFIG_64BIT -#define KSYM_ALIGN 16 -#endif -#include diff --git a/include/asm-generic/export.h b/include/asm-generic/export.h index 68efb950a918..4d73e6e3c66c 100644 --- a/include/asm-generic/export.h +++ b/include/asm-generic/export.h @@ -5,12 +5,10 @@ #define KSYM_FUNC(x) x #endif #ifdef CONFIG_64BIT -#define __put .quad #ifndef KSYM_ALIGN #define KSYM_ALIGN 8 #endif #else -#define __put .long #ifndef KSYM_ALIGN #define KSYM_ALIGN 4 #endif @@ -19,6 +17,16 @@ #define KCRC_ALIGN 4 #endif +.macro __put, val, name +#ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS + .long \val - ., \name - . +#elif defined(CONFIG_64BIT) + .quad \val, \name +#else + .long \val, \name +#endif +.endm + /* * note on .section use: @progbits vs %progbits nastiness doesn't matter, * since we immediately emit into those sections anyway. diff --git a/include/linux/compiler.h b/include/linux/compiler.h index 42506e4d1f53..2d9c63f41031 100644 --- a/include/linux/compiler.h +++ b/include/linux/compiler.h @@ -280,6 +280,25 @@ unsigned long read_word_at_a_time(const void *addr) #endif /* __KERNEL__ */ +/* + * Force the compiler to emit 'sym' as a symbol, so that we can reference + * it from inline assembler. Necessary in case 'sym' could be inlined + * otherwise, or eliminated entirely due to lack of references that are + * visible to the compiler. + */ +#define __ADDRESSABLE(sym) \ + static void * __attribute__((section(".discard"), used)) \ + __PASTE(__addressable_##sym, __LINE__) = (void *)&sym; + +/** + * offset_to_ptr - convert a relative memory offset to an absolute pointer + * @off: the address of the 32-bit offset value + */ +static inline void *offset_to_ptr(const int *off) +{ + return (void *)((unsigned long)off + *off); +} + #endif /* __ASSEMBLY__ */ #ifndef __optimize diff --git a/include/linux/export.h b/include/linux/export.h index ea7df303d68d..ae072bc5aacf 100644 --- a/include/linux/export.h +++ b/include/linux/export.h @@ -18,12 +18,6 @@ #define VMLINUX_SYMBOL_STR(x) __VMLINUX_SYMBOL_STR(x) #ifndef __ASSEMBLY__ -struct kernel_symbol -{ - unsigned long value; - const char *name; -}; - #ifdef MODULE extern struct module __this_module; #define THIS_MODULE (&__this_module) @@ -54,17 +48,47 @@ extern struct module __this_module; #define __CRC_SYMBOL(sym, sec) #endif +#ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS +#include +/* + * Emit the ksymtab entry as a pair of relative references: this reduces + * the size by half on 64-bit architectures, and eliminates the need for + * absolute relocations that require runtime processing on relocatable + * kernels. + */ +#define __KSYMTAB_ENTRY(sym, sec) \ + __ADDRESSABLE(sym) \ + asm(" .section \"___ksymtab" sec "+" #sym "\", \"a\" \n" \ + " .balign 8 \n" \ + "__ksymtab_" #sym ": \n" \ + " .long " #sym "- . \n" \ + " .long __kstrtab_" #sym "- . \n" \ + " .previous \n") + +struct kernel_symbol { + int value_offset; + int name_offset; +}; +#else +#define __KSYMTAB_ENTRY(sym, sec) \ + static const struct kernel_symbol __ksymtab_##sym \ + __attribute__((section("___ksymtab" sec "+" #sym), used)) \ + = { (unsigned long)&sym, __kstrtab_##sym } + +struct kernel_symbol { + unsigned long value; + const char *name; +}; +#endif + /* For every exported symbol, place a struct in the __ksymtab section */ #define ___EXPORT_SYMBOL(sym, sec) \ extern typeof(sym) sym; \ __CRC_SYMBOL(sym, sec) \ static const char __kstrtab_##sym[] \ - __attribute__((section("__ksymtab_strings"), aligned(1))) \ + __attribute__((section("__ksymtab_strings"), used, aligned(1))) \ = #sym; \ - static const struct kernel_symbol __ksymtab_##sym \ - __used \ - __attribute__((section("___ksymtab" sec "+" #sym), used)) \ - = { (unsigned long)&sym, __kstrtab_##sym } + __KSYMTAB_ENTRY(sym, sec) #if defined(__DISABLE_EXPORTS) diff --git a/kernel/module.c b/kernel/module.c index f475f30eed8c..7cb82e0fcac0 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -547,12 +547,30 @@ static bool check_symbol(const struct symsearch *syms, return true; } +static unsigned long kernel_symbol_value(const struct kernel_symbol *sym) +{ +#ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS + return (unsigned long)offset_to_ptr(&sym->value_offset); +#else + return sym->value; +#endif +} + +static const char *kernel_symbol_name(const struct kernel_symbol *sym) +{ +#ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS + return offset_to_ptr(&sym->name_offset); +#else + return sym->name; +#endif +} + static int cmp_name(const void *va, const void *vb) { const char *a; const struct kernel_symbol *b; a = va; b = vb; - return strcmp(a, b->name); + return strcmp(a, kernel_symbol_name(b)); } static bool find_symbol_in_section(const struct symsearch *syms, @@ -2192,7 +2210,7 @@ void *__symbol_get(const char *symbol) sym = NULL; preempt_enable(); - return sym ? (void *)sym->value : NULL; + return sym ? (void *)kernel_symbol_value(sym) : NULL; } EXPORT_SYMBOL_GPL(__symbol_get); @@ -2222,10 +2240,12 @@ static int verify_export_symbols(struct module *mod) for (i = 0; i < ARRAY_SIZE(arr); i++) { for (s = arr[i].sym; s < arr[i].sym + arr[i].num; s++) { - if (find_symbol(s->name, &owner, NULL, true, false)) { + if (find_symbol(kernel_symbol_name(s), &owner, NULL, + true, false)) { pr_err("%s: exports duplicate symbol %s" " (owned by %s)\n", - mod->name, s->name, module_name(owner)); + mod->name, kernel_symbol_name(s), + module_name(owner)); return -ENOEXEC; } } @@ -2274,7 +2294,7 @@ static int simplify_symbols(struct module *mod, const struct load_info *info) ksym = resolve_symbol_wait(mod, info, name); /* Ok if resolved. */ if (ksym && !IS_ERR(ksym)) { - sym[i].st_value = ksym->value; + sym[i].st_value = kernel_symbol_value(ksym); break; } @@ -2534,7 +2554,7 @@ static int is_exported(const char *name, unsigned long value, ks = lookup_symbol(name, __start___ksymtab, __stop___ksymtab); else ks = lookup_symbol(name, mod->syms, mod->syms + mod->num_syms); - return ks != NULL && ks->value == value; + return ks != NULL && kernel_symbol_value(ks) == value; } /* As per nm */