From patchwork Thu Nov 19 19:02:34 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Chang S. Bae" X-Patchwork-Id: 41134 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 3F75239A683D; Thu, 19 Nov 2020 19:07:07 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 3F75239A683D DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1605812827; bh=mP9EBR7clV3FtgIU8vDfx22zWBVVRqWmB41OuoNIGos=; h=To:Subject:Date:In-Reply-To:References:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=PJNLkCeGc5NcbM9XryVMxolK5C7xEE/XQCMb2zrtSYA6nKisQmmP5vdFTLmzhoSwa J52v+ngZ0Y2ten04DI5wdE4saX9PG0ZAAHJ/bKa84Qq2XK6Hyx1kp7IJX+eHHtNcYh 1lAXF5HgoQl3yWoYlvRbeTawyWvUoPqZWn/FvUJE= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mga14.intel.com (mga14.intel.com [192.55.52.115]) by sourceware.org (Postfix) with ESMTPS id 535673857804 for ; Thu, 19 Nov 2020 19:07:03 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 535673857804 IronPort-SDR: 81wdrRuGWtGeqH9pvOtqD0B8NObdonasqw2M6Zd1D7HM3y+Nptb/l2wMe6tK/zSK2ZPLCZHUGO vC/a1bbdZyZg== X-IronPort-AV: E=McAfee;i="6000,8403,9810"; a="170563947" X-IronPort-AV: E=Sophos;i="5.78,354,1599548400"; d="scan'208";a="170563947" X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by fmsmga103.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 19 Nov 2020 11:06:40 -0800 IronPort-SDR: o/KL1o3LyK17PXbYYUKj/9wgCLPu8rx3BYM6J0+Yyb+Sei/0DexUT8x2AIDYhQRLCJEvqPDIXH zPBiogR0OhvA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.78,354,1599548400"; d="scan'208";a="431333990" Received: from chang-linux-3.sc.intel.com ([172.25.66.175]) by fmsmga001.fm.intel.com with ESMTP; 19 Nov 2020 11:06:39 -0800 To: tglx@linutronix.de, mingo@kernel.org, bp@suse.de, luto@kernel.org, x86@kernel.org Subject: [PATCH v2 1/4] x86/signal: Introduce helpers to get the maximum signal frame size Date: Thu, 19 Nov 2020 11:02:34 -0800 Message-Id: <20201119190237.626-2-chang.seok.bae@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20201119190237.626-1-chang.seok.bae@intel.com> References: <20201119190237.626-1-chang.seok.bae@intel.com> X-Spam-Status: No, score=-10.1 required=5.0 tests=BAYES_00, GIT_PATCH_0, KAM_ASCII_DIVIDERS, KAM_DMARC_STATUS, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: "Chang S. Bae via Libc-alpha" From: "Chang S. Bae" Reply-To: "Chang S. Bae" Cc: linux-arch@vger.kernel.org, len.brown@intel.com, tony.luck@intel.com, libc-alpha@sourceware.org, ravi.v.shankar@intel.com, chang.seok.bae@intel.com, linux-kernel@vger.kernel.org, dave.hansen@intel.com, linux-api@vger.kernel.org, Dave.Martin@arm.com Errors-To: libc-alpha-bounces@sourceware.org Sender: "Libc-alpha" Signal frames do not have a fixed format and can vary in size when a number of things change: support XSAVE features, 32 vs. 64-bit apps. Add the code to support a runtime method for userspace to dynamically discover how large a signal stack needs to be. Introduce a new variable, max_frame_size, and helper functions for the calculation to be used in a new user interface. Set max_frame_size to a system-wide worst-case value, instead of storing multiple app-specific values. Locate the body of the helper function -- fpu__get_fpstate_sigframe_size() in fpu/signal.c for its relevance. Signed-off-by: Chang S. Bae Reviewed-by: Len Brown Acked-by: H.J. Lu Cc: x86@kernel.org Cc: linux-kernel@vger.kernel.org --- Change from v1: * Took stack alignment into account for sigframe size (Dave Martin) --- arch/x86/include/asm/fpu/signal.h | 2 + arch/x86/include/asm/sigframe.h | 23 ++++++++++++ arch/x86/kernel/cpu/common.c | 3 ++ arch/x86/kernel/fpu/signal.c | 20 ++++++++++ arch/x86/kernel/signal.c | 61 ++++++++++++++++++++++++++++++- 5 files changed, 107 insertions(+), 2 deletions(-) diff --git a/arch/x86/include/asm/fpu/signal.h b/arch/x86/include/asm/fpu/signal.h index 7fb516b6893a..5bfbf8f2e5a3 100644 --- a/arch/x86/include/asm/fpu/signal.h +++ b/arch/x86/include/asm/fpu/signal.h @@ -29,6 +29,8 @@ unsigned long fpu__alloc_mathframe(unsigned long sp, int ia32_frame, unsigned long *buf_fx, unsigned long *size); +unsigned long fpu__get_fpstate_sigframe_size(void); + extern void fpu__init_prepare_fx_sw_frame(void); #endif /* _ASM_X86_FPU_SIGNAL_H */ diff --git a/arch/x86/include/asm/sigframe.h b/arch/x86/include/asm/sigframe.h index 84eab2724875..ac77f3f90bc9 100644 --- a/arch/x86/include/asm/sigframe.h +++ b/arch/x86/include/asm/sigframe.h @@ -52,6 +52,15 @@ struct rt_sigframe_ia32 { char retcode[8]; /* fp state follows here */ }; + +#define SIZEOF_sigframe_ia32 sizeof(struct sigframe_ia32) +#define SIZEOF_rt_sigframe_ia32 sizeof(struct rt_sigframe_ia32) + +#else + +#define SIZEOF_sigframe_ia32 0 +#define SIZEOF_rt_sigframe_ia32 0 + #endif /* defined(CONFIG_X86_32) || defined(CONFIG_IA32_EMULATION) */ #ifdef CONFIG_X86_64 @@ -81,8 +90,22 @@ struct rt_sigframe_x32 { /* fp state follows here */ }; +#define SIZEOF_rt_sigframe_x32 sizeof(struct rt_sigframe_x32) + #endif /* CONFIG_X86_X32_ABI */ +#define SIZEOF_rt_sigframe sizeof(struct rt_sigframe) + +#else + +#define SIZEOF_rt_sigframe 0 + #endif /* CONFIG_X86_64 */ +#ifndef SIZEOF_rt_sigframe_x32 +#define SIZEOF_rt_sigframe_x32 0 +#endif + +void __init init_sigframe_size(void); + #endif /* _ASM_X86_SIGFRAME_H */ diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index 35ad8480c464..6954932272d5 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -58,6 +58,7 @@ #include #include #include +#include #include "cpu.h" @@ -1331,6 +1332,8 @@ static void __init early_identify_cpu(struct cpuinfo_x86 *c) fpu__init_system(c); + init_sigframe_size(); + #ifdef CONFIG_X86_32 /* * Regardless of whether PCID is enumerated, the SDM says diff --git a/arch/x86/kernel/fpu/signal.c b/arch/x86/kernel/fpu/signal.c index a4ec65317a7f..9f009525f551 100644 --- a/arch/x86/kernel/fpu/signal.c +++ b/arch/x86/kernel/fpu/signal.c @@ -507,6 +507,26 @@ fpu__alloc_mathframe(unsigned long sp, int ia32_frame, return sp; } + +unsigned long fpu__get_fpstate_sigframe_size(void) +{ + unsigned long xstate_size = xstate_sigframe_size(); + unsigned long fsave_header_size = 0; + + /* + * This space is needed on (most) 32-bit kernels, or when a 32-bit + * app is running on a 64-bit kernel. To keep things simple, just + * assume the worst case and always include space for 'freg_state', + * even for 64-bit apps on 64-bit kernels. This wastes a bit of + * space, but keeps the code simple. + */ + if ((IS_ENABLED(CONFIG_IA32_EMULATION) || + IS_ENABLED(CONFIG_X86_32)) && use_fxsr()) + fsave_header_size = sizeof(struct fregs_state); + + return fsave_header_size + xstate_size; +} + /* * Prepare the SW reserved portion of the fxsave memory layout, indicating * the presence of the extended state information in the memory layout diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c index be0d7d4152ec..bae35ff6e744 100644 --- a/arch/x86/kernel/signal.c +++ b/arch/x86/kernel/signal.c @@ -212,6 +212,11 @@ do { \ * Set up a signal frame. */ +/* x86 ABI requires 16-byte alignment */ +#define FRAME_ALIGNMENT 16UL + +#define MAX_FRAME_PADDING (FRAME_ALIGNMENT - 1) + /* * Determine which stack to use.. */ @@ -222,9 +227,9 @@ static unsigned long align_sigframe(unsigned long sp) * Align the stack pointer according to the i386 ABI, * i.e. so that on function entry ((sp + 4) & 15) == 0. */ - sp = ((sp + 4) & -16ul) - 4; + sp = ((sp + 4) & -FRAME_ALIGNMENT) - 4; #else /* !CONFIG_X86_32 */ - sp = round_down(sp, 16) - 8; + sp = round_down(sp, FRAME_ALIGNMENT) - 8; #endif return sp; } @@ -663,6 +668,58 @@ SYSCALL_DEFINE0(rt_sigreturn) return 0; } +/* + * The FP state frame contains an XSAVE buffer which must be 64-byte aligned. + * If a signal frame starts at an unaligned address, extra space is required. + * This is the max alignment padding, conservatively. + */ +#define MAX_XSAVE_PADDING 63UL + +/* + * The frame data is composed of the following areas and laid out as: + * + * ------------------------- + * | alignment padding | + * ------------------------- + * | (f)xsave frame | + * ------------------------- + * | fsave header | + * ------------------------- + * | alignment padding | + * ------------------------- + * | siginfo + ucontext | + * ------------------------- + */ + +/* max_frame_size tells userspace the worst case signal stack size. */ +static unsigned long __ro_after_init max_frame_size; + +void __init init_sigframe_size(void) +{ + /* + * Use the largest of possible structure formats. This might + * slightly oversize the frame for 64-bit apps. + */ + + if (IS_ENABLED(CONFIG_X86_32) || + IS_ENABLED(CONFIG_IA32_EMULATION)) + max_frame_size = max((unsigned long)SIZEOF_sigframe_ia32, + (unsigned long)SIZEOF_rt_sigframe_ia32); + + if (IS_ENABLED(CONFIG_X86_X32_ABI)) + max_frame_size = max(max_frame_size, (unsigned long)SIZEOF_rt_sigframe_x32); + + if (IS_ENABLED(CONFIG_X86_64)) + max_frame_size = max(max_frame_size, (unsigned long)SIZEOF_rt_sigframe); + + max_frame_size += MAX_FRAME_PADDING; + + max_frame_size += fpu__get_fpstate_sigframe_size() + MAX_XSAVE_PADDING; + + /* Userspace expects an aligned size. */ + max_frame_size = round_up(max_frame_size, FRAME_ALIGNMENT); +} + static inline int is_ia32_compat_frame(struct ksignal *ksig) { return IS_ENABLED(CONFIG_IA32_EMULATION) && From patchwork Thu Nov 19 19:02:35 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Chang S. Bae" X-Patchwork-Id: 41133 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id AA01239ACC3D; Thu, 19 Nov 2020 19:07:06 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org AA01239ACC3D DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1605812826; bh=8tpi/Am7F65HoNM8UngPua6l4eBQRfbMdeNOqwHct5Y=; h=To:Subject:Date:In-Reply-To:References:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=eki68ovdmF41k+vP3gBzD16A+8G/lye6MUTG0FFfymCgYRZv0kLg0q8SWuNWOaZ8J ZAeypzPOO1+0sCPZR+RX5wqRDbH8nRpTtIQaWthVDX3y0vhVbYPLEdRFnJbVZ0JCa+ Fle8sUOeMzsxNWX05JXDNKrjnks3xgzfrpRYbGys= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mga14.intel.com (mga14.intel.com [192.55.52.115]) by sourceware.org (Postfix) with ESMTPS id E3A77398B850 for ; Thu, 19 Nov 2020 19:07:03 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org E3A77398B850 IronPort-SDR: DQIgse9iJoGWBiT4ZSV9H3J0iGvgr1XpZXoMytvyhRj1iuINVd/cL0l/4h19gVxknAW8ZjYmK5 MFQ036WP4Y8Q== X-IronPort-AV: E=McAfee;i="6000,8403,9810"; a="170563948" X-IronPort-AV: E=Sophos;i="5.78,354,1599548400"; d="scan'208";a="170563948" X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by fmsmga103.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 19 Nov 2020 11:06:40 -0800 IronPort-SDR: n8TA3IManuqrcTlk2ugPC5bmgwG8KEkOXeSI7KE5Z9OPY2kl0AH9aJt9Ksc7HD3LeJjWPShKwY isD4NikzCgOg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.78,354,1599548400"; d="scan'208";a="431333993" Received: from chang-linux-3.sc.intel.com ([172.25.66.175]) by fmsmga001.fm.intel.com with ESMTP; 19 Nov 2020 11:06:40 -0800 To: tglx@linutronix.de, mingo@kernel.org, bp@suse.de, luto@kernel.org, x86@kernel.org Subject: [PATCH v2 2/4] x86/elf: Support a new ELF aux vector AT_MINSIGSTKSZ Date: Thu, 19 Nov 2020 11:02:35 -0800 Message-Id: <20201119190237.626-3-chang.seok.bae@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20201119190237.626-1-chang.seok.bae@intel.com> References: <20201119190237.626-1-chang.seok.bae@intel.com> X-Spam-Status: No, score=-10.3 required=5.0 tests=BAYES_00, GIT_PATCH_0, KAM_DMARC_STATUS, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: "Chang S. Bae via Libc-alpha" From: "Chang S. Bae" Reply-To: "Chang S. Bae" Cc: linux-arch@vger.kernel.org, len.brown@intel.com, tony.luck@intel.com, libc-alpha@sourceware.org, ravi.v.shankar@intel.com, chang.seok.bae@intel.com, linux-kernel@vger.kernel.org, Fenghua Yu , dave.hansen@intel.com, linux-api@vger.kernel.org, Dave.Martin@arm.com Errors-To: libc-alpha-bounces@sourceware.org Sender: "Libc-alpha" Historically, signal.h defines MINSIGSTKSZ (2KB) and SIGSTKSZ (8KB), for use by all architectures with sigaltstack(2). Over time, the hardware state size grew, but these constants did not evolve. Today, literal use of these constants on several architectures may result in signal stack overflow, and thus user data corruption. A few years ago, the ARM team addressed this issue by establishing getauxval(AT_MINSIGSTKSZ), such that the kernel can supply at runtime value that is an appropriate replacement on the current and future hardware. Add getauxval(AT_MINSIGSTKSZ) support to x86, analogous to the support added for ARM in commit 94b07c1f8c39 ("arm64: signal: Report signal frame size to userspace via auxv"). Reported-by: Florian Weimer Fixes: c2bc11f10a39 ("x86, AVX-512: Enable AVX-512 States Context Switch") Signed-off-by: Chang S. Bae Reviewed-by: Len Brown Cc: H.J. Lu Cc: Fenghua Yu Cc: Dave Martin Cc: Michael Ellerman Cc: x86@kernel.org Cc: libc-alpha@sourceware.org Cc: linux-arch@vger.kernel.org Cc: linux-api@vger.kernel.org Cc: linux-kernel@vger.kernel.org Link: https://bugzilla.kernel.org/show_bug.cgi?id=153531 --- arch/x86/include/asm/elf.h | 4 ++++ arch/x86/include/uapi/asm/auxvec.h | 6 ++++-- arch/x86/kernel/signal.c | 5 +++++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/arch/x86/include/asm/elf.h b/arch/x86/include/asm/elf.h index b9a5d488f1a5..044b024abea1 100644 --- a/arch/x86/include/asm/elf.h +++ b/arch/x86/include/asm/elf.h @@ -311,6 +311,7 @@ do { \ NEW_AUX_ENT(AT_SYSINFO, VDSO_ENTRY); \ NEW_AUX_ENT(AT_SYSINFO_EHDR, VDSO_CURRENT_BASE); \ } \ + NEW_AUX_ENT(AT_MINSIGSTKSZ, get_sigframe_size()); \ } while (0) /* @@ -327,6 +328,7 @@ extern unsigned long task_size_32bit(void); extern unsigned long task_size_64bit(int full_addr_space); extern unsigned long get_mmap_base(int is_legacy); extern bool mmap_address_hint_valid(unsigned long addr, unsigned long len); +extern unsigned long get_sigframe_size(void); #ifdef CONFIG_X86_32 @@ -348,6 +350,7 @@ do { \ if (vdso64_enabled) \ NEW_AUX_ENT(AT_SYSINFO_EHDR, \ (unsigned long __force)current->mm->context.vdso); \ + NEW_AUX_ENT(AT_MINSIGSTKSZ, get_sigframe_size()); \ } while (0) /* As a historical oddity, the x32 and x86_64 vDSOs are controlled together. */ @@ -356,6 +359,7 @@ do { \ if (vdso64_enabled) \ NEW_AUX_ENT(AT_SYSINFO_EHDR, \ (unsigned long __force)current->mm->context.vdso); \ + NEW_AUX_ENT(AT_MINSIGSTKSZ, get_sigframe_size()); \ } while (0) #define AT_SYSINFO 32 diff --git a/arch/x86/include/uapi/asm/auxvec.h b/arch/x86/include/uapi/asm/auxvec.h index 580e3c567046..edd7808060e6 100644 --- a/arch/x86/include/uapi/asm/auxvec.h +++ b/arch/x86/include/uapi/asm/auxvec.h @@ -10,11 +10,13 @@ #endif #define AT_SYSINFO_EHDR 33 +#define AT_MINSIGSTKSZ 51 + /* entries in ARCH_DLINFO: */ #if defined(CONFIG_IA32_EMULATION) || !defined(CONFIG_X86_64) -# define AT_VECTOR_SIZE_ARCH 2 +# define AT_VECTOR_SIZE_ARCH 3 #else /* else it's non-compat x86-64 */ -# define AT_VECTOR_SIZE_ARCH 1 +# define AT_VECTOR_SIZE_ARCH 2 #endif #endif /* _ASM_X86_AUXVEC_H */ diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c index bae35ff6e744..ee6f1ceaa7a2 100644 --- a/arch/x86/kernel/signal.c +++ b/arch/x86/kernel/signal.c @@ -720,6 +720,11 @@ void __init init_sigframe_size(void) max_frame_size = round_up(max_frame_size, FRAME_ALIGNMENT); } +unsigned long get_sigframe_size(void) +{ + return max_frame_size; +} + static inline int is_ia32_compat_frame(struct ksignal *ksig) { return IS_ENABLED(CONFIG_IA32_EMULATION) && From patchwork Thu Nov 19 19:02:36 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Chang S. Bae" X-Patchwork-Id: 41135 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 3703139ACC47; Thu, 19 Nov 2020 19:07:09 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 3703139ACC47 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1605812829; bh=l9fMe2WYwxUuEMNrOBUHF9ClED7zmzSq383rPc8L1dg=; h=To:Subject:Date:In-Reply-To:References:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=Z/ZAoiqw0pGFWWVuwxfXzqhTR0YWKGBSHlJnt0mAshZLEez9WwpSkUJdaK7435Nsj 2CoDMVDJDqSwH5h46pRsGEZNuN5uoRjnCZyzKJMeMzOVEb1bbbhD1habJAlDpYFJMC jTl4ouHpi87qBJKpXZV9gjR7Qk7n9BdwbcMDGnXA= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mga14.intel.com (mga14.intel.com [192.55.52.115]) by sourceware.org (Postfix) with ESMTPS id BD2713857804 for ; Thu, 19 Nov 2020 19:07:05 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org BD2713857804 IronPort-SDR: FhBPTSolg6OB8Jp8Xf7lPNfNq+q6y0kCZ90B8stRCD6m4R4uMQLT3deWfCoGd8HniS5/HcBQsu IFw42TZJsO2A== X-IronPort-AV: E=McAfee;i="6000,8403,9810"; a="170563949" X-IronPort-AV: E=Sophos;i="5.78,354,1599548400"; d="scan'208";a="170563949" X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by fmsmga103.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 19 Nov 2020 11:06:40 -0800 IronPort-SDR: QvspKCblnMCzsL5wITYJlqCsyv5vaoj+VeSN8G8G3ANsVrt2oRyOfr/jIoEfE+Rm7qkyy7yfoR iAXOglYNV5mA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.78,354,1599548400"; d="scan'208";a="431333996" Received: from chang-linux-3.sc.intel.com ([172.25.66.175]) by fmsmga001.fm.intel.com with ESMTP; 19 Nov 2020 11:06:40 -0800 To: tglx@linutronix.de, mingo@kernel.org, bp@suse.de, luto@kernel.org, x86@kernel.org Subject: [PATCH v2 3/4] x86/signal: Prevent an alternate stack overflow before a signal delivery Date: Thu, 19 Nov 2020 11:02:36 -0800 Message-Id: <20201119190237.626-4-chang.seok.bae@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20201119190237.626-1-chang.seok.bae@intel.com> References: <20201119190237.626-1-chang.seok.bae@intel.com> X-Spam-Status: No, score=-10.6 required=5.0 tests=BAYES_00, GIT_PATCH_0, KAM_DMARC_STATUS, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: "Chang S. Bae via Libc-alpha" From: "Chang S. Bae" Reply-To: "Chang S. Bae" Cc: linux-arch@vger.kernel.org, len.brown@intel.com, tony.luck@intel.com, libc-alpha@sourceware.org, ravi.v.shankar@intel.com, chang.seok.bae@intel.com, linux-kernel@vger.kernel.org, dave.hansen@intel.com, linux-api@vger.kernel.org, Dave.Martin@arm.com Errors-To: libc-alpha-bounces@sourceware.org Sender: "Libc-alpha" The kernel pushes data on the userspace stack when entering a signal. If using a sigaltstack(), the kernel precisely knows the user stack size. When the kernel knows that the user stack is too small, avoid the overflow and do an immediate SIGSEGV instead. This overflow is known to occur on systems with large XSAVE state. The effort to increase the size typically used for altstacks reduces the frequency of these overflows, but this approach is still useful for legacy binaries. Here the kernel expects a bit conservative stack size (for 64-bit apps). Legacy binaries used a too-small sigaltstack would be already overflowed before this change, if they run on modern hardware. Signed-off-by: Chang S. Bae Reviewed-by: Len Brown Cc: x86@kernel.org Cc: linux-kernel@vger.kernel.org --- arch/x86/ia32/ia32_signal.c | 11 ++++++++--- arch/x86/include/asm/sigframe.h | 2 ++ arch/x86/kernel/signal.c | 16 +++++++++++++++- 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/arch/x86/ia32/ia32_signal.c b/arch/x86/ia32/ia32_signal.c index 81cf22398cd1..85abd9eb79d5 100644 --- a/arch/x86/ia32/ia32_signal.c +++ b/arch/x86/ia32/ia32_signal.c @@ -210,13 +210,18 @@ static void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs, sp = regs->sp; /* This is the X/Open sanctioned signal stack switching. */ - if (ksig->ka.sa.sa_flags & SA_ONSTACK) + if (ksig->ka.sa.sa_flags & SA_ONSTACK) { + /* If the altstack might overflow, die with SIGSEGV: */ + if (!altstack_size_ok(current)) + return (void __user *)-1L; + sp = sigsp(sp, ksig); /* This is the legacy signal stack switching. */ - else if (regs->ss != __USER32_DS && + } else if (regs->ss != __USER32_DS && !(ksig->ka.sa.sa_flags & SA_RESTORER) && - ksig->ka.sa.sa_restorer) + ksig->ka.sa.sa_restorer) { sp = (unsigned long) ksig->ka.sa.sa_restorer; + } sp = fpu__alloc_mathframe(sp, 1, &fx_aligned, &math_size); *fpstate = (struct _fpstate_32 __user *) sp; diff --git a/arch/x86/include/asm/sigframe.h b/arch/x86/include/asm/sigframe.h index ac77f3f90bc9..c9f2f9ace76f 100644 --- a/arch/x86/include/asm/sigframe.h +++ b/arch/x86/include/asm/sigframe.h @@ -106,6 +106,8 @@ struct rt_sigframe_x32 { #define SIZEOF_rt_sigframe_x32 0 #endif +bool altstack_size_ok(struct task_struct *tsk); + void __init init_sigframe_size(void); #endif /* _ASM_X86_SIGFRAME_H */ diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c index ee6f1ceaa7a2..cee41d684dc2 100644 --- a/arch/x86/kernel/signal.c +++ b/arch/x86/kernel/signal.c @@ -251,8 +251,13 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size, /* This is the X/Open sanctioned signal stack switching. */ if (ka->sa.sa_flags & SA_ONSTACK) { - if (sas_ss_flags(sp) == 0) + if (sas_ss_flags(sp) == 0) { + /* If the altstack might overflow, die with SIGSEGV: */ + if (!altstack_size_ok(current)) + return (void __user *)-1L; + sp = current->sas_ss_sp + current->sas_ss_size; + } } else if (IS_ENABLED(CONFIG_X86_32) && !onsigstack && regs->ss != __USER_DS && @@ -725,6 +730,15 @@ unsigned long get_sigframe_size(void) return max_frame_size; } +bool altstack_size_ok(struct task_struct *tsk) +{ + /* + * Can this task's sigaltstack accommodate the largest + * signal frame the kernel might need? + */ + return (tsk->sas_ss_size >= max_frame_size); +} + static inline int is_ia32_compat_frame(struct ksignal *ksig) { return IS_ENABLED(CONFIG_IA32_EMULATION) && From patchwork Thu Nov 19 19:02:37 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Chang S. Bae" X-Patchwork-Id: 41136 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id C997A39ACC4C; Thu, 19 Nov 2020 19:07:09 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org C997A39ACC4C DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1605812829; bh=926JI0zEN4O89NH8WYxgU6XY/CDI51oU4Nao6Iaoxuc=; h=To:Subject:Date:In-Reply-To:References:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=UzR0kF6hu8TSrIuFngADnU3TRJ5JCHn52rVrLdDf7zIwBTN6RgkpPtg4PXpM58ibh WuAktrsWtC2X8pY7Qch/+4hnya3kMRPD5nWOgtkhLEQ6TBa78+T39vwgfPwAOF1ol+ ivJEh2/MQdeuyQE2Z4jPwsVy8AJPQUMkFc1R+lXY= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mga14.intel.com (mga14.intel.com [192.55.52.115]) by sourceware.org (Postfix) with ESMTPS id CA718398B850 for ; Thu, 19 Nov 2020 19:07:05 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org CA718398B850 IronPort-SDR: LEo03k6MYJSCuLmPs7q56FmgP3nKkhtWG/K2KYtAwNlJiOjp2tU6AvWfBi7NVZ0fPYl7Q0tC3a m+d9kxwzp15A== X-IronPort-AV: E=McAfee;i="6000,8403,9810"; a="170563953" X-IronPort-AV: E=Sophos;i="5.78,354,1599548400"; d="scan'208";a="170563953" X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by fmsmga103.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 19 Nov 2020 11:06:40 -0800 IronPort-SDR: cRHXwcW+O3T3Lu6hmAFl89aA2EOI2uiwuiEY3qbl0hMiNN9OnNPbO6iLxi8CMh0omk72M3lJr0 9grhV6NPeSzg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.78,354,1599548400"; d="scan'208";a="431333999" Received: from chang-linux-3.sc.intel.com ([172.25.66.175]) by fmsmga001.fm.intel.com with ESMTP; 19 Nov 2020 11:06:40 -0800 To: tglx@linutronix.de, mingo@kernel.org, bp@suse.de, luto@kernel.org, x86@kernel.org Subject: [PATCH v2 4/4] selftest/x86/signal: Include test cases for validating sigaltstack Date: Thu, 19 Nov 2020 11:02:37 -0800 Message-Id: <20201119190237.626-5-chang.seok.bae@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20201119190237.626-1-chang.seok.bae@intel.com> References: <20201119190237.626-1-chang.seok.bae@intel.com> X-Spam-Status: No, score=-10.8 required=5.0 tests=BAYES_00, GIT_PATCH_0, KAM_DMARC_STATUS, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: "Chang S. Bae via Libc-alpha" From: "Chang S. Bae" Reply-To: "Chang S. Bae" Cc: linux-arch@vger.kernel.org, len.brown@intel.com, tony.luck@intel.com, libc-alpha@sourceware.org, ravi.v.shankar@intel.com, chang.seok.bae@intel.com, linux-kernel@vger.kernel.org, dave.hansen@intel.com, linux-kselftest@vger.kernel.org, linux-api@vger.kernel.org, Dave.Martin@arm.com Errors-To: libc-alpha-bounces@sourceware.org Sender: "Libc-alpha" The test measures the kernel's signal delivery with different (enough vs. insufficient) stack sizes. Signed-off-by: Chang S. Bae Reviewed-by: Len Brown Cc: x86@kernel.org Cc: linux-kselftest@vger.kernel.org Cc: linux-kernel@vger.kernel.org --- tools/testing/selftests/x86/Makefile | 2 +- tools/testing/selftests/x86/sigaltstack.c | 126 ++++++++++++++++++++++ 2 files changed, 127 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/x86/sigaltstack.c diff --git a/tools/testing/selftests/x86/Makefile b/tools/testing/selftests/x86/Makefile index 6703c7906b71..e0c52e5ab49e 100644 --- a/tools/testing/selftests/x86/Makefile +++ b/tools/testing/selftests/x86/Makefile @@ -13,7 +13,7 @@ CAN_BUILD_WITH_NOPIE := $(shell ./check_cc.sh $(CC) trivial_program.c -no-pie) TARGETS_C_BOTHBITS := single_step_syscall sysret_ss_attrs syscall_nt test_mremap_vdso \ check_initial_reg_state sigreturn iopl ioperm \ test_vdso test_vsyscall mov_ss_trap \ - syscall_arg_fault fsgsbase_restore + syscall_arg_fault fsgsbase_restore sigaltstack TARGETS_C_32BIT_ONLY := entry_from_vm86 test_syscall_vdso unwind_vdso \ test_FCMOV test_FCOMI test_FISTTP \ vdso_restorer diff --git a/tools/testing/selftests/x86/sigaltstack.c b/tools/testing/selftests/x86/sigaltstack.c new file mode 100644 index 000000000000..353679df6901 --- /dev/null +++ b/tools/testing/selftests/x86/sigaltstack.c @@ -0,0 +1,126 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* sigaltstack()-enforced minimum stack */ +#define ENFORCED_MINSIGSTKSZ 2048 + +#ifndef AT_MINSIGSTKSZ +# define AT_MINSIGSTKSZ 51 +#endif + +static int nerrs; + +static bool sigalrm_expected; + +static unsigned long at_minstack_size; + +static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *), + int flags) +{ + struct sigaction sa; + + memset(&sa, 0, sizeof(sa)); + sa.sa_sigaction = handler; + sa.sa_flags = SA_SIGINFO | flags; + sigemptyset(&sa.sa_mask); + if (sigaction(sig, &sa, 0)) + err(1, "sigaction"); +} + +static void clearhandler(int sig) +{ + struct sigaction sa; + + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = SIG_DFL; + sigemptyset(&sa.sa_mask); + if (sigaction(sig, &sa, 0)) + err(1, "sigaction"); +} + +static int setup_altstack(void *start, unsigned long size) +{ + stack_t ss; + + memset(&ss, 0, sizeof(ss)); + ss.ss_size = size; + ss.ss_sp = start; + + return sigaltstack(&ss, NULL); +} + +static jmp_buf jmpbuf; + +static void sigsegv(int sig, siginfo_t *info, void *ctx_void) +{ + if (sigalrm_expected) { + printf("[FAIL]\tSIGSEGV signal delivered.\n"); + nerrs++; + } else { + printf("[OK]\tSIGSEGV signal expectedly delivered.\n"); + } + + siglongjmp(jmpbuf, 1); +} + +static void sigalrm(int sig, siginfo_t *info, void *ctx_void) +{ + if (!sigalrm_expected) { + printf("[FAIL]\tSIGALRM sigal delivered.\n"); + nerrs++; + } else { + printf("[OK]\tSIGALRM signal expectedly delivered.\n"); + } +} + +static void test_sigaltstack(void *altstack, unsigned long size) +{ + if (setup_altstack(altstack, size)) + err(1, "sigaltstack()"); + + sigalrm_expected = (size > at_minstack_size) ? true : false; + + sethandler(SIGSEGV, sigsegv, 0); + sethandler(SIGALRM, sigalrm, SA_ONSTACK); + + if (sigsetjmp(jmpbuf, 1) == 0) { + printf("[RUN]\tTest an %s sigaltstack\n", + sigalrm_expected ? "enough" : "insufficient"); + raise(SIGALRM); + } + + clearhandler(SIGALRM); + clearhandler(SIGSEGV); +} + +int main(void) +{ + void *altstack; + + at_minstack_size = getauxval(AT_MINSIGSTKSZ); + + altstack = mmap(NULL, at_minstack_size + SIGSTKSZ, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0); + if (altstack == MAP_FAILED) + err(1, "mmap()"); + + if ((ENFORCED_MINSIGSTKSZ + 1) < at_minstack_size) + test_sigaltstack(altstack, ENFORCED_MINSIGSTKSZ + 1); + + test_sigaltstack(altstack, at_minstack_size + SIGSTKSZ); + + return nerrs == 0 ? 0 : 1; +}