From patchwork Tue Jan 17 19:26:11 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ard Biesheuvel X-Patchwork-Id: 91716 Delivered-To: patch@linaro.org Received: by 10.140.20.99 with SMTP id 90csp655150qgi; Tue, 17 Jan 2017 11:27:19 -0800 (PST) X-Received: by 10.84.224.199 with SMTP id k7mr61806746pln.25.1484681239790; Tue, 17 Jan 2017 11:27:19 -0800 (PST) Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id z43si25845773plh.111.2017.01.17.11.27.19; Tue, 17 Jan 2017 11:27:19 -0800 (PST) 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; 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 S1751159AbdAQT03 (ORCPT + 25 others); Tue, 17 Jan 2017 14:26:29 -0500 Received: from mail-wm0-f48.google.com ([74.125.82.48]:36533 "EHLO mail-wm0-f48.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751071AbdAQT00 (ORCPT ); Tue, 17 Jan 2017 14:26:26 -0500 Received: by mail-wm0-f48.google.com with SMTP id c85so214373437wmi.1 for ; Tue, 17 Jan 2017 11:26:26 -0800 (PST) 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=6BjveLswiWLNoylGErZe8kvErpMFYGm152BnKNyqIQw=; b=Ycsr7Wjf96cqRBtEa5ON/g5dInCdzpSHsY4FBoiu4IDZ2EHeAnO+Lk6TpfPcMDboOs n+6w3uoURbt2rCBLolvIu8d5TNFHcrIxcm0I8GSKTy6HHFL9X6Qatx9dSHj9KGAkZF3+ Lq5LOFmxOp3EQN0vcSqa7EIgsjRf0bpv6VGqw= 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=6BjveLswiWLNoylGErZe8kvErpMFYGm152BnKNyqIQw=; b=EDSicuYKKlAw2tHft/L2wV81v3VFM1JuYR9DdQLjFnxUUKjzSgtxd0KFA83cIMrNL0 PoOkYFgSsnCVYIn2JdvMZO0aEbllWVB+P6GG9E4Qn59vqm82gmgHA0c4W4mOml1/EWzw ZZ0BPkplJ/LLHUn8BCADMW27s4XYmdTy2Aon80JQvUqcc0GtMmFx+R/0CQut6SkqG4PR f6k/lIBTUki5qWWXPFJkHIZutwjb6587ZcOfPqEJoqZXhTy5lmzNq9sq+e0W3T1mvM/y vwSKBL5vgLQjEgdS/DlpN25ruXheGRSkVt/q49MGEzXDRK/G9iiEVT8kqjv3hlfyNLz1 MafQ== X-Gm-Message-State: AIkVDXIMhpXjqgng1Maaa7yh1G6TJGZbOs/1+ZgLK7AIbrRjCOKqG0s8bXZPbNP+YVCvlt35 X-Received: by 10.223.152.2 with SMTP id v2mr21780749wrb.109.1484681185343; Tue, 17 Jan 2017 11:26:25 -0800 (PST) Received: from localhost.localdomain ([160.167.203.25]) by smtp.gmail.com with ESMTPSA id 197sm39171953wmy.16.2017.01.17.11.26.20 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 17 Jan 2017 11:26:24 -0800 (PST) From: Ard Biesheuvel To: linux-kernel@vger.kernel.org, mpe@ellerman.id.au, jeyu@redhat.com Cc: rusty@rustcorp.com.au, suzuki.poulose@arm.com, will.deacon@arm.com, akpm@linux-foundation.org, benh@kernel.crashing.org, paulus@samba.org, arnd@arndb.de, torvalds@linux-foundation.org, viro@zeniv.linux.org.uk, linuxppc-dev@lists.ozlabs.org, Ard Biesheuvel Subject: [PATCH v4 1/3] powerpc/reloc32: fix corrupted modversion CRCs Date: Tue, 17 Jan 2017 19:26:11 +0000 Message-Id: <1484681173-11644-2-git-send-email-ard.biesheuvel@linaro.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1484681173-11644-1-git-send-email-ard.biesheuvel@linaro.org> References: <1484681173-11644-1-git-send-email-ard.biesheuvel@linaro.org> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Commit 0e0ed6406e61 ("powerpc/modules: Module CRC relocation fix causes perf issues") fixed an issue with relocatable PIE kernels in a way that essentially reintroduced the issue again for 32-bit builds. Since the chosen approach does is not applicable to 32-bit, fix the issue by updating the runtime relocation routine to ignore the load offset for the interval [__start___kcrctab, __stop___kcrctab_gpl_future), which is where the CRCs reside. This ensures that the values of the CRC pseudo-symbols are no longer made dependent on the runtime load offset. Reviewed-by: Suzuki K Poulose Signed-off-by: Ard Biesheuvel --- arch/powerpc/kernel/reloc_32.S | 36 +++++++++++++++++--- 1 file changed, 32 insertions(+), 4 deletions(-) -- 2.7.4 diff --git a/arch/powerpc/kernel/reloc_32.S b/arch/powerpc/kernel/reloc_32.S index f366fedb0872..150686b9febb 100644 --- a/arch/powerpc/kernel/reloc_32.S +++ b/arch/powerpc/kernel/reloc_32.S @@ -87,12 +87,12 @@ eodyn: /* End of Dyn Table scan */ * Work out the current offset from the link time address of .rela * section. * cur_offset[r7] = rela.run[r9] - rela.link [r7] - * _stext.link[r12] = _stext.run[r10] - cur_offset[r7] - * final_offset[r3] = _stext.final[r3] - _stext.link[r12] + * _stext.link[r11] = _stext.run[r10] - cur_offset[r7] + * final_offset[r3] = _stext.final[r3] - _stext.link[r11] */ subf r7, r7, r9 /* cur_offset */ - subf r12, r7, r10 - subf r3, r12, r3 /* final_offset */ + subf r11, r7, r10 + subf r3, r11, r3 /* final_offset */ subf r8, r6, r8 /* relaz -= relaent */ /* @@ -101,6 +101,21 @@ eodyn: /* End of Dyn Table scan */ * r13 - points to the symbol table */ +#ifdef CONFIG_MODVERSIONS + /* + * Treat R_PPC_RELATIVE relocations differently when they target the + * interval [__start___kcrctab, __stop___kcrctab_gpl_future): in this + * case, the relocated quantities are CRC pseudo-symbols, which should + * be preserved as-is, rather than be modified to take the runtime + * offset into account. + */ + lwz r10, (p_kcrc_start - 0b)(r12) + lwz r11, (p_kcrc_stop - 0b)(r12) + subf r12, r7, r12 /* link time addr of 0b */ + add r10, r10, r12 + add r11, r11, r12 +#endif + /* * Check if we have a relocation based on symbol * r5 will hold the value of the symbol. @@ -135,7 +150,15 @@ get_type: bne hi16 lwz r4, 0(r9) /* r_offset */ lwz r0, 8(r9) /* r_addend */ +#ifdef CONFIG_MODVERSIONS + cmplw r4, r10 + blt do_add + cmplw r4, r11 + blt skip_add +do_add: +#endif add r0, r0, r3 /* final addend */ +skip_add: stwx r0, r4, r7 /* memory[r4+r7]) = (u32)r0 */ b nxtrela /* continue */ @@ -207,3 +230,8 @@ p_dyn: .long __dynamic_start - 0b p_rela: .long __rela_dyn_start - 0b p_sym: .long __dynamic_symtab - 0b p_st: .long _stext - 0b + +#ifdef CONFIG_MODVERSIONS +p_kcrc_start: .long __start___kcrctab - 0b +p_kcrc_stop: .long __stop___kcrctab_gpl_future - 0b +#endif From patchwork Tue Jan 17 19:26:12 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ard Biesheuvel X-Patchwork-Id: 91714 Delivered-To: patch@linaro.org Received: by 10.140.20.99 with SMTP id 90csp654867qgi; Tue, 17 Jan 2017 11:26:41 -0800 (PST) X-Received: by 10.99.121.69 with SMTP id u66mr47072884pgc.96.1484681201113; Tue, 17 Jan 2017 11:26:41 -0800 (PST) Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id y70si25829155plh.229.2017.01.17.11.26.40; Tue, 17 Jan 2017 11:26:41 -0800 (PST) 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; 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 S1751266AbdAQT0e (ORCPT + 25 others); Tue, 17 Jan 2017 14:26:34 -0500 Received: from mail-wm0-f41.google.com ([74.125.82.41]:38588 "EHLO mail-wm0-f41.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751221AbdAQT0b (ORCPT ); Tue, 17 Jan 2017 14:26:31 -0500 Received: by mail-wm0-f41.google.com with SMTP id r144so238679185wme.1 for ; Tue, 17 Jan 2017 11:26:31 -0800 (PST) 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=50KhQCtAYNHKshLc8v9I656KZxFKwtLxgxrPl4ZMuak=; b=J01Ixbc2zrQ5XEc7vMRrrUpgRSVQ94Gam90tgHgezCtRfgtxggLkOcsulWk46u7pRw rlmXB2AR9snGB+9z1xDKnbMZ5I27BKepPQhxBgBTgtBu0the+VrjtMKGs4aqW+OkieJl pPHTYhodfdTPwZk7d8iPOcQc3HFZEJ3t07Vto= 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=50KhQCtAYNHKshLc8v9I656KZxFKwtLxgxrPl4ZMuak=; b=NsX9dKJSSAJtfs03NbZ8F/iMnXq1fY7uGq/WZj2ZbcGHDH3VOt1t473VVZtCn/SAX2 qNsfcXz7CbfWXJwYZkU0fwHNP/NzIl378PHO04ohb/9VQsfj/hmgJ9fqkMQX5VBdhxY8 p+MqJPXc8C2TQ213Qp2gM8hcmgwB4aRFH1X5veF7yAR7QmkEwVuoY5RPxr5FGn2x8aSW Iupk9GzJqZVhrWjcKIqzDwYN6TIfAvNGgO4g0yIIApzrxEwGmAyb3g2HS1PpovnUVPF8 dhF4kLZ0s3RnR7y0GP++MHyYdLkWi60TwUSg2CAeSORQHaqK6x3ooAqbAOHJP8seQLBJ b8TA== X-Gm-Message-State: AIkVDXKlImVojBEatiNeN/bYBWGR4MWaRBc/bdFAGnAtx7OwAqWNeEx4ZY3ZeYZTMxMfTeCo X-Received: by 10.28.64.132 with SMTP id n126mr19187568wma.107.1484681190111; Tue, 17 Jan 2017 11:26:30 -0800 (PST) Received: from localhost.localdomain ([160.167.203.25]) by smtp.gmail.com with ESMTPSA id 197sm39171953wmy.16.2017.01.17.11.26.25 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 17 Jan 2017 11:26:29 -0800 (PST) From: Ard Biesheuvel To: linux-kernel@vger.kernel.org, mpe@ellerman.id.au, jeyu@redhat.com Cc: rusty@rustcorp.com.au, suzuki.poulose@arm.com, will.deacon@arm.com, akpm@linux-foundation.org, benh@kernel.crashing.org, paulus@samba.org, arnd@arndb.de, torvalds@linux-foundation.org, viro@zeniv.linux.org.uk, linuxppc-dev@lists.ozlabs.org, Ard Biesheuvel Subject: [PATCH v4 2/3] powerpc/reloc64: add support for 32-bit CRC pseudo-symbols Date: Tue, 17 Jan 2017 19:26:12 +0000 Message-Id: <1484681173-11644-3-git-send-email-ard.biesheuvel@linaro.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1484681173-11644-1-git-send-email-ard.biesheuvel@linaro.org> References: <1484681173-11644-1-git-send-email-ard.biesheuvel@linaro.org> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org In preparation of modifying the core modversions code to emit the CRCs as 32-bit quantities, ensure that 64-bit PowerPC will be able to deal with this when CONFIG_RELOCATABLE=y, in which case the CRCs will be emitted into the final ELF binary as R_PPC64_ADDR32 relocations. Since 32-bit relocations cannot be used to relocate memory addresses on 64-bit architectures, and since the CRC pseudo-symbol references are emitted as anonymous relocations (i.e., against the NULL symbol in the .dynsym section) with the final value recorded in the addend (*), we can disregard any relocations where the symbol index != 0. * Note that unsatisfied CRC pseudo-symbol references are emitted as R_PPC64_ADDR32 relocations against named symbols that are typed as weak undefined in the .dynsym symbol table. These can simply be ignored (as before), considering that zero CRCs are interpreted as missing, and the module code deals with that accordingly. As it turns out, binutils for powerpc does not account for any relocations beyond R_PPC64_RELATIVE ones in the RELACOUNT field of the .dynamic section, which is unfortunate, since we need to do extra work to figure out the size of the relocation array. So with a little help from the linker scripts, grab an end pointer rather than a count, and iterate over the entire section. Signed-off-by: Ard Biesheuvel --- arch/powerpc/kernel/reloc_64.S | 60 ++++++++++++-------- arch/powerpc/kernel/vmlinux.lds.S | 1 + arch/powerpc/relocs_check.sh | 5 +- 3 files changed, 40 insertions(+), 26 deletions(-) -- 2.7.4 diff --git a/arch/powerpc/kernel/reloc_64.S b/arch/powerpc/kernel/reloc_64.S index d88736fbece6..e50f5d778ea2 100644 --- a/arch/powerpc/kernel/reloc_64.S +++ b/arch/powerpc/kernel/reloc_64.S @@ -12,8 +12,8 @@ #include RELA = 7 -RELACOUNT = 0x6ffffff9 R_PPC64_RELATIVE = 22 +R_PPC64_ADDR32 = 1 /* * r3 = desired final address of kernel @@ -29,29 +29,27 @@ _GLOBAL(relocate) add r9,r9,r12 /* r9 has runtime addr of .rela.dyn section */ ld r10,(p_st - 0b)(r12) add r10,r10,r12 /* r10 has runtime addr of _stext */ + ld r8,(p_rela_end - 0b)(r12) + add r8,r8,r12 /* r8 has addr of end of .rela.dyn section */ /* - * Scan the dynamic section for the RELA and RELACOUNT entries. + * Scan the dynamic section for the RELA entry. + * NOTE: the RELACOUNT entry only covers R_PPC64_RELATIVE relocations, + * so we cannot use it here. */ li r7,0 - li r8,0 1: ld r6,0(r11) /* get tag */ cmpdi r6,0 - beq 4f /* end of list */ + beq 3f /* end of list */ cmpdi r6,RELA - bne 2f - ld r7,8(r11) /* get RELA pointer in r7 */ - b 3f -2: addis r6,r6,(-RELACOUNT)@ha - cmpdi r6,RELACOUNT@l - bne 3f - ld r8,8(r11) /* get RELACOUNT value in r8 */ -3: addi r11,r11,16 + beq 2f + addi r11,r11,16 b 1b -4: cmpdi r7,0 /* check we have both RELA and RELACOUNT */ - cmpdi cr1,r8,0 - beq 6f - beq cr1,6f +2: ld r7,8(r11) /* get RELA pointer in r7 */ +3: cmpdi r7,0 /* check we have both RELA and a non-empty */ + cmpd cr1,r8,r9 /* .rela.dyn section */ + beq 7f + beq cr1,7f /* * Work out linktime address of _stext and hence the @@ -63,26 +61,40 @@ _GLOBAL(relocate) subf r7,r7,r9 /* cur_offset */ subf r10,r7,r10 subf r3,r10,r3 /* final_offset */ + b 4f /* * Run through the list of relocations and process the - * R_PPC64_RELATIVE ones. + * R_PPC64_RELATIVE and R_PPC64_ADDR32 ones. */ - mtctr r8 -5: ld r0,8(9) /* ELF64_R_TYPE(reloc->r_info) */ +3: addi r9,r9,24 +4: cmpd r9,r8 + beq 7f +5: ld r0,8(9) /* reloc->r_info (type *and* symbol index) */ + ld r6,0(r9) /* reloc->r_offset */ cmpdi r0,R_PPC64_RELATIVE bne 6f - ld r6,0(r9) /* reloc->r_offset */ ld r0,16(r9) /* reloc->r_addend */ add r0,r0,r3 stdx r0,r7,r6 - addi r9,r9,24 - bdnz 5b + b 3b + + /* + * CRCs of exported symbols are emitted as 32-bit relocations against + * the NULL .dynsym entry, with the CRC value recorded in the addend. + */ +6: cmpdi r0,R_PPC64_ADDR32 + bne 3b + ld r0,16(r9) /* reloc->r_addend */ + stwx r0,r7,r6 + b 3b + +7: blr -6: blr .balign 8 p_dyn: .llong __dynamic_start - 0b p_rela: .llong __rela_dyn_start - 0b +p_rela_end: + .llong __rela_dyn_end - 0b p_st: .llong _stext - 0b - diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S index 7394b770ae1f..654728fc860d 100644 --- a/arch/powerpc/kernel/vmlinux.lds.S +++ b/arch/powerpc/kernel/vmlinux.lds.S @@ -241,6 +241,7 @@ SECTIONS { __rela_dyn_start = .; *(.rela*) + __rela_dyn_end = .; } #endif /* .exit.data is discarded at runtime, not link time, diff --git a/arch/powerpc/relocs_check.sh b/arch/powerpc/relocs_check.sh index ec2d5c835170..f9636b4e4548 100755 --- a/arch/powerpc/relocs_check.sh +++ b/arch/powerpc/relocs_check.sh @@ -30,7 +30,7 @@ bad_relocs=$( # On PPC64: # R_PPC64_RELATIVE, R_PPC64_NONE # R_PPC64_ADDR64 mach_ - # R_PPC64_ADDR64 __crc_ + # R_PPC64_ADDR32 __crc_ # On PPC: # R_PPC_RELATIVE, R_PPC_ADDR16_HI, # R_PPC_ADDR16_HA,R_PPC_ADDR16_LO, @@ -43,7 +43,8 @@ R_PPC_ADDR16_HA R_PPC_RELATIVE R_PPC_NONE' | grep -E -v '\ X-Patchwork-Id: 91715 Delivered-To: patch@linaro.org Received: by 10.140.20.99 with SMTP id 90csp654873qgi; Tue, 17 Jan 2017 11:26:41 -0800 (PST) X-Received: by 10.98.29.195 with SMTP id d186mr39905985pfd.144.1484681201769; Tue, 17 Jan 2017 11:26:41 -0800 (PST) Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id y70si25829155plh.229.2017.01.17.11.26.41; Tue, 17 Jan 2017 11:26:41 -0800 (PST) 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; 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 S1751285AbdAQT0i (ORCPT + 25 others); Tue, 17 Jan 2017 14:26:38 -0500 Received: from mail-wm0-f44.google.com ([74.125.82.44]:35591 "EHLO mail-wm0-f44.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751221AbdAQT0g (ORCPT ); Tue, 17 Jan 2017 14:26:36 -0500 Received: by mail-wm0-f44.google.com with SMTP id r126so215163439wmr.0 for ; Tue, 17 Jan 2017 11:26:35 -0800 (PST) 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=JHJRPCBfrs0TZ6dR4GR3bHJFGYMhPNhdCYQPoYweNAM=; b=Q3cUCG29yRsEfeXrtUTiJVUuGJpF54Sbrbsi53j0akwvrr019iOptQQS5t+snOUcxB frN7aqMJvPbgQjZgfr/kGEPywlNwo2THRpBEzC5vENa9DnwV/L2R9bgzPdzNElOsOAf/ FY6/qAcLWVic6it/67BpHgne0LvqxGt5775es= 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=JHJRPCBfrs0TZ6dR4GR3bHJFGYMhPNhdCYQPoYweNAM=; b=nunjgVmeLs8r5u9e30VZfwZ4O7OgqjzIzjpIS3t8mixTf/2maRkWOye+2koFpIkySO EK0e4JvecFjXE6Nll0QP2f11bRp4QGRUpK2ymRIvmkhXm2d9GRPaiKH76Avv+E9S26c/ dtHKhJgHv8aI6ySXyGb6/K+ptzcHXZPSmwTAobyMKdliEvF27S3v5nq0sfExpRBxwQ3u nzu69HNTIlF6SkCRoso/Ym4O9oWG6P81OWj0X59qM5bDfPkMPn55jxoxxGWP0UOoCpFQ frW97FpJ56EYlFqftr9QlGiqG0fs/qz7HQ5A42sv8hAxyqBNcbi1rUUwENDH9wZT+Ecn zzdA== X-Gm-Message-State: AIkVDXKPciax0P79ojJCe+KGgbE+XqoXHZQYPr/oBTASTwBFe4+IWIIeU+1k6JFyGDTE8QgZ X-Received: by 10.223.136.152 with SMTP id f24mr24681275wrf.187.1484681194350; Tue, 17 Jan 2017 11:26:34 -0800 (PST) Received: from localhost.localdomain ([160.167.203.25]) by smtp.gmail.com with ESMTPSA id 197sm39171953wmy.16.2017.01.17.11.26.30 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 17 Jan 2017 11:26:33 -0800 (PST) From: Ard Biesheuvel To: linux-kernel@vger.kernel.org, mpe@ellerman.id.au, jeyu@redhat.com Cc: rusty@rustcorp.com.au, suzuki.poulose@arm.com, will.deacon@arm.com, akpm@linux-foundation.org, benh@kernel.crashing.org, paulus@samba.org, arnd@arndb.de, torvalds@linux-foundation.org, viro@zeniv.linux.org.uk, linuxppc-dev@lists.ozlabs.org, Ard Biesheuvel Subject: [PATCH v4 3/3] modversions: treat symbol CRCs as 32 bit quantities on 64 bit archs Date: Tue, 17 Jan 2017 19:26:13 +0000 Message-Id: <1484681173-11644-4-git-send-email-ard.biesheuvel@linaro.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1484681173-11644-1-git-send-email-ard.biesheuvel@linaro.org> References: <1484681173-11644-1-git-send-email-ard.biesheuvel@linaro.org> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org The modversion symbol CRCs are emitted as ELF symbols, which allows us to easily populate the kcrctab sections by relying on the linker to associate each kcrctab slot with the correct value. This has a couple of downsides: - Given that the CRCs are treated as memory addresses, we waste 4 bytes for each CRC on 64 bit architectures, - On architectures that support runtime relocation, a R__RELATIVE relocation entry is emitted for each CRC value, which identifies it as a quantity that requires fixing up based on the actual runtime load offset of the kernel. This results in corrupted CRCs unless we explicitly undo the fixup (and this is currently being handled in the core module code) - Such runtime relocation entries take up 24 bytes of __init space each, resulting in a x8 overhead in [uncompressed] kernel size for CRCs. Switching to explicit 32 bit values on 64 bit architectures fixes most of these issues, given that 32 bit values are not treated as quantities that require fixing up based on the actual runtime load offset. Note that on some ELF64 architectures [such as PPC64], these 32-bit values are still emitted as runtime relocatable quantities, even if the value resolves to a build time constant. However, these can easily be distinguished from variables that do need fixing up, and the CRCs can be emitted correctly in the arch specific runtime relocation routines right off the bat. So redefine all CRC fields and variables as u32, and redefine the __CRC_SYMBOL() macro for 64 bit builds to emit the CRC reference using inline assembler (which is necessary since 64-bit C code cannot use 32-bit types to hold memory addresses, even if they are ultimately resolved using values that do not exceed 0xffffffff. Note that this mostly reverts commit d4703aefdbc8 ("module: handle ppc64 relocating kcrctabs when CONFIG_RELOCATABLE=y") Acked-by: Rusty Russell Signed-off-by: Ard Biesheuvel --- arch/powerpc/include/asm/module.h | 4 -- arch/powerpc/kernel/module_64.c | 8 ---- include/asm-generic/export.h | 7 +-- include/linux/export.h | 8 ++++ include/linux/module.h | 14 +++--- kernel/module.c | 47 +++++++------------- 6 files changed, 33 insertions(+), 55 deletions(-) -- 2.7.4 diff --git a/arch/powerpc/include/asm/module.h b/arch/powerpc/include/asm/module.h index cc12c61ef315..53885512b8d3 100644 --- a/arch/powerpc/include/asm/module.h +++ b/arch/powerpc/include/asm/module.h @@ -90,9 +90,5 @@ static inline int module_finalize_ftrace(struct module *mod, const Elf_Shdr *sec } #endif -#if defined(CONFIG_MODVERSIONS) && defined(CONFIG_PPC64) -#define ARCH_RELOCATES_KCRCTAB -#define reloc_start PHYSICAL_START -#endif #endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_MODULE_H */ diff --git a/arch/powerpc/kernel/module_64.c b/arch/powerpc/kernel/module_64.c index bb1807184bad..0b0f89685b67 100644 --- a/arch/powerpc/kernel/module_64.c +++ b/arch/powerpc/kernel/module_64.c @@ -286,14 +286,6 @@ static void dedotify_versions(struct modversion_info *vers, for (end = (void *)vers + size; vers < end; vers++) if (vers->name[0] == '.') { memmove(vers->name, vers->name+1, strlen(vers->name)); -#ifdef ARCH_RELOCATES_KCRCTAB - /* The TOC symbol has no CRC computed. To avoid CRC - * check failing, we must force it to the expected - * value (see CRC check in module.c). - */ - if (!strcmp(vers->name, "TOC.")) - vers->crc = -(unsigned long)reloc_start; -#endif } } diff --git a/include/asm-generic/export.h b/include/asm-generic/export.h index 63554e9f6e0c..e3508a3d6e53 100644 --- a/include/asm-generic/export.h +++ b/include/asm-generic/export.h @@ -9,18 +9,15 @@ #ifndef KSYM_ALIGN #define KSYM_ALIGN 8 #endif -#ifndef KCRC_ALIGN -#define KCRC_ALIGN 8 -#endif #else #define __put .long #ifndef KSYM_ALIGN #define KSYM_ALIGN 4 #endif +#endif #ifndef KCRC_ALIGN #define KCRC_ALIGN 4 #endif -#endif #ifdef CONFIG_HAVE_UNDERSCORE_SYMBOL_PREFIX #define KSYM(name) _##name @@ -52,7 +49,7 @@ KSYM(__kstrtab_\name): .section ___kcrctab\sec+\name,"a" .balign KCRC_ALIGN KSYM(__kcrctab_\name): - __put KSYM(__crc_\name) + .long KSYM(__crc_\name) .weak KSYM(__crc_\name) .previous #endif diff --git a/include/linux/export.h b/include/linux/export.h index 2a0f61fbc731..a000d421526d 100644 --- a/include/linux/export.h +++ b/include/linux/export.h @@ -41,6 +41,7 @@ extern struct module __this_module; #if defined(__KERNEL__) && !defined(__GENKSYMS__) #ifdef CONFIG_MODVERSIONS +#ifndef CONFIG_64BIT /* Mark the CRC weak since genksyms apparently decides not to * generate a checksums for some symbols */ #define __CRC_SYMBOL(sym, sec) \ @@ -50,6 +51,13 @@ extern struct module __this_module; __attribute__((section("___kcrctab" sec "+" #sym), used)) \ = (unsigned long) &__crc_##sym; #else +#define __CRC_SYMBOL(sym, sec) \ + asm(" .section \"___kcrctab" sec "+" #sym "\", \"a\" \n" \ + " .weak " VMLINUX_SYMBOL_STR(__crc_##sym) " \n" \ + " .long " VMLINUX_SYMBOL_STR(__crc_##sym) " \n" \ + " .previous \n"); +#endif +#else #define __CRC_SYMBOL(sym, sec) #endif diff --git a/include/linux/module.h b/include/linux/module.h index 7c84273d60b9..4b65b9df3de2 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -346,7 +346,7 @@ struct module { /* Exported symbols */ const struct kernel_symbol *syms; - const unsigned long *crcs; + const u32 *crcs; unsigned int num_syms; /* Kernel parameters. */ @@ -359,18 +359,18 @@ struct module { /* GPL-only exported symbols. */ unsigned int num_gpl_syms; const struct kernel_symbol *gpl_syms; - const unsigned long *gpl_crcs; + const u32 *gpl_crcs; #ifdef CONFIG_UNUSED_SYMBOLS /* unused exported symbols. */ const struct kernel_symbol *unused_syms; - const unsigned long *unused_crcs; + const u32 *unused_crcs; unsigned int num_unused_syms; /* GPL-only, unused exported symbols. */ unsigned int num_unused_gpl_syms; const struct kernel_symbol *unused_gpl_syms; - const unsigned long *unused_gpl_crcs; + const u32 *unused_gpl_crcs; #endif #ifdef CONFIG_MODULE_SIG @@ -382,7 +382,7 @@ struct module { /* symbols that will be GPL-only in the near future. */ const struct kernel_symbol *gpl_future_syms; - const unsigned long *gpl_future_crcs; + const u32 *gpl_future_crcs; unsigned int num_gpl_future_syms; /* Exception table */ @@ -523,7 +523,7 @@ struct module *find_module(const char *name); struct symsearch { const struct kernel_symbol *start, *stop; - const unsigned long *crcs; + const u32 *crcs; enum { NOT_GPL_ONLY, GPL_ONLY, @@ -539,7 +539,7 @@ struct symsearch { */ const struct kernel_symbol *find_symbol(const char *name, struct module **owner, - const unsigned long **crc, + const u32 **crc, bool gplok, bool warn); diff --git a/kernel/module.c b/kernel/module.c index 5088784c0cf9..43d1478975a1 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -389,16 +389,16 @@ extern const struct kernel_symbol __start___ksymtab_gpl[]; extern const struct kernel_symbol __stop___ksymtab_gpl[]; extern const struct kernel_symbol __start___ksymtab_gpl_future[]; extern const struct kernel_symbol __stop___ksymtab_gpl_future[]; -extern const unsigned long __start___kcrctab[]; -extern const unsigned long __start___kcrctab_gpl[]; -extern const unsigned long __start___kcrctab_gpl_future[]; +extern const u32 __start___kcrctab[]; +extern const u32 __start___kcrctab_gpl[]; +extern const u32 __start___kcrctab_gpl_future[]; #ifdef CONFIG_UNUSED_SYMBOLS extern const struct kernel_symbol __start___ksymtab_unused[]; extern const struct kernel_symbol __stop___ksymtab_unused[]; extern const struct kernel_symbol __start___ksymtab_unused_gpl[]; extern const struct kernel_symbol __stop___ksymtab_unused_gpl[]; -extern const unsigned long __start___kcrctab_unused[]; -extern const unsigned long __start___kcrctab_unused_gpl[]; +extern const u32 __start___kcrctab_unused[]; +extern const u32 __start___kcrctab_unused_gpl[]; #endif #ifndef CONFIG_MODVERSIONS @@ -497,7 +497,7 @@ struct find_symbol_arg { /* Output */ struct module *owner; - const unsigned long *crc; + const u32 *crc; const struct kernel_symbol *sym; }; @@ -563,7 +563,7 @@ static bool find_symbol_in_section(const struct symsearch *syms, * (optional) module which owns it. Needs preempt disabled or module_mutex. */ const struct kernel_symbol *find_symbol(const char *name, struct module **owner, - const unsigned long **crc, + const u32 **crc, bool gplok, bool warn) { @@ -1249,23 +1249,11 @@ static int try_to_force_load(struct module *mod, const char *reason) } #ifdef CONFIG_MODVERSIONS -/* If the arch applies (non-zero) relocations to kernel kcrctab, unapply it. */ -static unsigned long maybe_relocated(unsigned long crc, - const struct module *crc_owner) -{ -#ifdef ARCH_RELOCATES_KCRCTAB - if (crc_owner == NULL) - return crc - (unsigned long)reloc_start; -#endif - return crc; -} - static int check_version(Elf_Shdr *sechdrs, unsigned int versindex, const char *symname, struct module *mod, - const unsigned long *crc, - const struct module *crc_owner) + const u32 *crc) { unsigned int i, num_versions; struct modversion_info *versions; @@ -1286,10 +1274,10 @@ static int check_version(Elf_Shdr *sechdrs, if (strcmp(versions[i].name, symname) != 0) continue; - if (versions[i].crc == maybe_relocated(*crc, crc_owner)) + if (versions[i].crc == *crc) return 1; - pr_debug("Found checksum %lX vs module %lX\n", - maybe_relocated(*crc, crc_owner), versions[i].crc); + pr_debug("Found checksum %X vs module %lX\n", + *crc, versions[i].crc); goto bad_version; } @@ -1307,7 +1295,7 @@ static inline int check_modstruct_version(Elf_Shdr *sechdrs, unsigned int versindex, struct module *mod) { - const unsigned long *crc; + const u32 *crc; /* * Since this should be found in kernel (which can't be removed), no @@ -1321,8 +1309,7 @@ static inline int check_modstruct_version(Elf_Shdr *sechdrs, } preempt_enable(); return check_version(sechdrs, versindex, - VMLINUX_SYMBOL_STR(module_layout), mod, crc, - NULL); + VMLINUX_SYMBOL_STR(module_layout), mod, crc); } /* First part is kernel version, which we ignore if module has crcs. */ @@ -1340,8 +1327,7 @@ static inline int check_version(Elf_Shdr *sechdrs, unsigned int versindex, const char *symname, struct module *mod, - const unsigned long *crc, - const struct module *crc_owner) + const u32 *crc) { return 1; } @@ -1368,7 +1354,7 @@ static const struct kernel_symbol *resolve_symbol(struct module *mod, { struct module *owner; const struct kernel_symbol *sym; - const unsigned long *crc; + const u32 *crc; int err; /* @@ -1383,8 +1369,7 @@ static const struct kernel_symbol *resolve_symbol(struct module *mod, if (!sym) goto unlock; - if (!check_version(info->sechdrs, info->index.vers, name, mod, crc, - owner)) { + if (!check_version(info->sechdrs, info->index.vers, name, mod, crc)) { sym = ERR_PTR(-EINVAL); goto getname; }