From patchwork Tue Nov 13 11:27:45 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vincent Whitchurch X-Patchwork-Id: 10680379 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id D22A613BF for ; Tue, 13 Nov 2018 11:56:53 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id BD1BD29FE8 for ; Tue, 13 Nov 2018 11:56:53 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id AC40029FE1; Tue, 13 Nov 2018 11:56:53 +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_SIGNED, DKIM_VALID,MAILING_LIST_MULTI,RCVD_IN_DNSWL_LOW autolearn=ham version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id EE10E29FE1 for ; Tue, 13 Nov 2018 11:56:51 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:Cc:List-Subscribe: List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:Message-Id:Date: Subject:To:From:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To: References:List-Owner; bh=+CgFUNoN/vjJQM6V70doZE+SsJNKS50E/EOsKTzB2C8=; b=qlP C34Ap8KADaim8J0QL3rivDejyESL+OfSJi/6VzgPOmIjhDX11D74hETx0qm+7yebqL/bbXL58nPsq 0TPaxYdpKkHUYWqVd/rScr1uZCKJAdfgpnPBIUDXs5fqksg0vid6OnF6AnIE7d/Jz5sFfFj0sTzLw 2cPp82XwAd9vsxM0qmH4mqwpeU5z8GQQetG20/0YPXq2CRrIFKjqJ9HmSiYVpLjI/98GSaU3CKQfl 51FVPaSBHos7hw0leO/z8VmM9mwD2t0pJ6ZKUmf1mE8SL6MMPq3CuALiEhdYbBq30pYEMMNIbEYD0 ATm3jEiUMwSqvmfRoV2nwL29oXf6u6Q==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1gMXJK-0002Yd-Fq; Tue, 13 Nov 2018 11:56:50 +0000 Received: from merlin.infradead.org ([2001:8b0:10b:1231::1]) by bombadil.infradead.org with esmtps (Exim 4.90_1 #2 (Red Hat Linux)) id 1gMXJ2-0002An-DO for linux-arm-kernel@bombadil.infradead.org; Tue, 13 Nov 2018 11:56:32 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=merlin.20170209; h=Message-Id:Date:Subject:Cc:To:From: Sender:Reply-To:MIME-Version:Content-Type:Content-Transfer-Encoding: Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender: Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:References:List-Id: List-Help:List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive; bh=P2KQxDVmxmH0qdypZGzlpASkuI96iPtV55jD5mncc6k=; b=QJ5ccMAL+vyqJqiYn1w6AaRt3 lWy1uf2bQHs3ud/DeJDE7CGbgcoO+EKFinfR8qyCwBpfzF6qQS2fCwYl6e8xOeLkM6GTi8AhZocd8 uDN0jLsI4FaStQi+vHgL0Z77XqPIU/PRc0gR0CgO6QGky6Z829iwf6bKQIZKhdQvU8bx7nX8YVSeD Dp1GGMbZE2MKDWdPC6ze5Og3hE82mUMafdve2l32VOpW7INDnMIO6ImnRjfW5gu82k6c5GpClTBVN Rrin6vPl3sOLyJ113gMjyeEzEe5liFmnqU/BqAFb9U2mbUTUhZgHtAEOnQSWBMl3UVKMHmAzK54Hj h8Qhx3WzQ==; Received: from bastet.se.axis.com ([195.60.68.11]) by merlin.infradead.org with esmtps (Exim 4.90_1 #2 (Red Hat Linux)) id 1gMWrw-0003vk-7g for linux-arm-kernel@lists.infradead.org; Tue, 13 Nov 2018 11:28:33 +0000 Received: from localhost (localhost [127.0.0.1]) by bastet.se.axis.com (Postfix) with ESMTP id B71ED18485; Tue, 13 Nov 2018 12:28:14 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at bastet.se.axis.com Received: from bastet.se.axis.com ([IPv6:::ffff:127.0.0.1]) by localhost (bastet.se.axis.com [::ffff:127.0.0.1]) (amavisd-new, port 10024) with LMTP id CLUekswJ9N-s; Tue, 13 Nov 2018 12:28:13 +0100 (CET) Received: from boulder02.se.axis.com (boulder02.se.axis.com [10.0.8.16]) by bastet.se.axis.com (Postfix) with ESMTPS id 8D7AB18482; Tue, 13 Nov 2018 12:28:13 +0100 (CET) Received: from boulder02.se.axis.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 791631A064; Tue, 13 Nov 2018 12:28:13 +0100 (CET) Received: from boulder02.se.axis.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 63D461A062; Tue, 13 Nov 2018 12:28:13 +0100 (CET) Received: from thoth.se.axis.com (unknown [10.0.2.173]) by boulder02.se.axis.com (Postfix) with ESMTP; Tue, 13 Nov 2018 12:28:13 +0100 (CET) Received: from lnxartpec.se.axis.com (lnxartpec.se.axis.com [10.88.4.9]) by thoth.se.axis.com (Postfix) with ESMTP id 56FCB2F48; Tue, 13 Nov 2018 12:28:13 +0100 (CET) Received: by lnxartpec.se.axis.com (Postfix, from userid 10564) id 5278180AA6; Tue, 13 Nov 2018 12:28:13 +0100 (CET) From: Vincent Whitchurch To: linux@armlinux.org.uk, jeyu@kernel.org Subject: [PATCH v3] ARM: module: Fix function kallsyms on Thumb-2 Date: Tue, 13 Nov 2018 12:27:45 +0100 Message-Id: <20181113112745.15945-1-vincent.whitchurch@axis.com> X-Mailer: git-send-email 2.11.0 X-TM-AS-GCONF: 00 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20181113_062832_538546_258057A2 X-CRM114-Status: GOOD ( 21.78 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, Vincent Whitchurch MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP Thumb-2 functions have the lowest bit set in the symbol value in the symtab. When kallsyms are generated for the vmlinux, the kallsyms are generated from the output of nm, and nm clears the lowest bit. $ arm-linux-gnueabihf-readelf -a vmlinux | grep show_interrupts 95947: 8015dc89 686 FUNC GLOBAL DEFAULT 2 show_interrupts $ arm-linux-gnueabihf-nm vmlinux | grep show_interrupts 8015dc88 T show_interrupts $ cat /proc/kallsyms | grep show_interrupts 8015dc88 T show_interrupts However, for modules, the kallsyms uses the values in the symbol table without modification, so for functions in modules, the lowest bit is set in kallsyms. $ arm-linux-gnueabihf-readelf -a drivers/net/tun.ko | grep tun_get_socket 268: 000000e1 44 FUNC GLOBAL DEFAULT 2 tun_get_socket $ arm-linux-gnueabihf-nm drivers/net/tun.ko | grep tun_get_socket 000000e0 T tun_get_socket $ cat /proc/kallsyms | grep tun_get_socket 7fcd30e1 t tun_get_socket [tun] Because of this, the offset of the crashing instruction shown in oopses is incorrect when the crash is in a module. For example, given a tun_get_socket which starts like this, 000000e0 : e0: b500 push {lr} e2: f7ff fffe bl 0 <__gnu_mcount_nc> e6: 4b08 ldr r3, [pc, #32] e8: 6942 ldr r2, [r0, #20] ea: 429a cmp r2, r3 ec: d002 beq.n f4 a crash when tun_get_socket is called with NULL results in: PC is at tun_get_socket+0x7/0x2c [tun] pc : [<7fcdb0e8>] which can result in the incorrect line being reported by gdb if this symbol+offset is used there. If the crash is on the first instruction of a function, the "PC is at" line would also report the symbol name of the preceding function. To solve this, introduce a weak module_kallsyms_symbol_value() function which arches can override to fix up these symbol values, and implement this for Thumb-2. We need to move elf_type() to st_other so that the original value of st_info is preserved. After the fix: $ cat /proc/kallsyms | grep tun_get_socket 7fcd30e0 t tun_get_socket [tun] PC is at tun_get_socket+0x8/0x2c [tun] pc : [<7fcdb0e8>] Signed-off-by: Vincent Whitchurch --- v3: Do not overwrite st_value v2: Fix build warning with !MODULES arch/arm/kernel/module.c | 10 ++++++++++ include/linux/moduleloader.h | 2 ++ kernel/module.c | 34 +++++++++++++++++++++------------- 3 files changed, 33 insertions(+), 13 deletions(-) diff --git a/arch/arm/kernel/module.c b/arch/arm/kernel/module.c index 3ff571c2c71c..89ab84a83600 100644 --- a/arch/arm/kernel/module.c +++ b/arch/arm/kernel/module.c @@ -336,6 +336,16 @@ static const Elf_Shdr *find_mod_section(const Elf32_Ehdr *hdr, extern void fixup_pv_table(const void *, unsigned long); extern void fixup_smp(const void *, unsigned long); +#ifdef CONFIG_THUMB2_KERNEL +unsigned long module_kallsyms_symbol_value(Elf_Sym *sym) +{ + if (ELF_ST_TYPE(sym->st_info) == STT_FUNC) + return sym->st_value & ~1; + + return sym->st_value; +} +#endif + int module_finalize(const Elf32_Ehdr *hdr, const Elf_Shdr *sechdrs, struct module *mod) { diff --git a/include/linux/moduleloader.h b/include/linux/moduleloader.h index 31013c2effd3..6395409b01a4 100644 --- a/include/linux/moduleloader.h +++ b/include/linux/moduleloader.h @@ -86,6 +86,8 @@ void module_arch_cleanup(struct module *mod); /* Any cleanup before freeing mod->module_init */ void module_arch_freeing_init(struct module *mod); +unsigned long module_kallsyms_symbol_value(Elf_Sym *sym); + #ifdef CONFIG_KASAN #include #define MODULE_ALIGN (PAGE_SIZE << KASAN_SHADOW_SCALE_SHIFT) diff --git a/kernel/module.c b/kernel/module.c index 49a405891587..5a588cfbb8f8 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -2682,7 +2682,7 @@ static void add_kallsyms(struct module *mod, const struct load_info *info) /* Set types up while we still have access to sections. */ for (i = 0; i < mod->kallsyms->num_symtab; i++) - mod->kallsyms->symtab[i].st_info + mod->kallsyms->symtab[i].st_other = elf_type(&mod->kallsyms->symtab[i], info); /* Now populate the cut down core kallsyms for after init. */ @@ -3916,6 +3916,11 @@ static const char *symname(struct mod_kallsyms *kallsyms, unsigned int symnum) return kallsyms->strtab + kallsyms->symtab[symnum].st_name; } +unsigned long __weak module_kallsyms_symbol_value(Elf_Sym *sym) +{ + return sym->st_value; +} + static const char *get_ksymbol(struct module *mod, unsigned long addr, unsigned long *size, @@ -3934,6 +3939,9 @@ static const char *get_ksymbol(struct module *mod, /* Scan for closest preceding symbol, and next symbol. (ELF starts real symbols at 1). */ for (i = 1; i < kallsyms->num_symtab; i++) { + unsigned long thisval = module_kallsyms_symbol_value(&kallsyms->symtab[i]); + unsigned long bestval = module_kallsyms_symbol_value(&kallsyms->symtab[best]); + if (kallsyms->symtab[i].st_shndx == SHN_UNDEF) continue; @@ -3943,21 +3951,21 @@ static const char *get_ksymbol(struct module *mod, || is_arm_mapping_symbol(symname(kallsyms, i))) continue; - if (kallsyms->symtab[i].st_value <= addr - && kallsyms->symtab[i].st_value > kallsyms->symtab[best].st_value) + if (thisval <= addr + && thisval > bestval) best = i; - if (kallsyms->symtab[i].st_value > addr - && kallsyms->symtab[i].st_value < nextval) - nextval = kallsyms->symtab[i].st_value; + if (thisval > addr + && thisval < nextval) + nextval = thisval; } if (!best) return NULL; if (size) - *size = nextval - kallsyms->symtab[best].st_value; + *size = nextval - module_kallsyms_symbol_value(&kallsyms->symtab[best]); if (offset) - *offset = addr - kallsyms->symtab[best].st_value; + *offset = addr - module_kallsyms_symbol_value(&kallsyms->symtab[best]); return symname(kallsyms, best); } @@ -4060,8 +4068,8 @@ int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type, continue; kallsyms = rcu_dereference_sched(mod->kallsyms); if (symnum < kallsyms->num_symtab) { - *value = kallsyms->symtab[symnum].st_value; - *type = kallsyms->symtab[symnum].st_info; + *value = module_kallsyms_symbol_value(&kallsyms->symtab[symnum]); + *type = kallsyms->symtab[symnum].st_other; strlcpy(name, symname(kallsyms, symnum), KSYM_NAME_LEN); strlcpy(module_name, mod->name, MODULE_NAME_LEN); *exported = is_exported(name, *value, mod); @@ -4082,7 +4090,7 @@ static unsigned long mod_find_symname(struct module *mod, const char *name) for (i = 0; i < kallsyms->num_symtab; i++) if (strcmp(name, symname(kallsyms, i)) == 0 && kallsyms->symtab[i].st_shndx != SHN_UNDEF) - return kallsyms->symtab[i].st_value; + return module_kallsyms_symbol_value(&kallsyms->symtab[i]); return 0; } @@ -4131,8 +4139,8 @@ int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *, if (kallsyms->symtab[i].st_shndx == SHN_UNDEF) continue; - ret = fn(data, symname(kallsyms, i), - mod, kallsyms->symtab[i].st_value); + ret = fn(data, symname(kallsyms, i), mod, + module_kallsyms_symbol_value(&kallsyms->symtab[i])); if (ret != 0) return ret; }