From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2D3EAC433E0 for ; Sat, 27 Feb 2021 17:26:22 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id DC0D264E4D for ; Sat, 27 Feb 2021 17:26:21 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230282AbhB0RZF (ORCPT ); Sat, 27 Feb 2021 12:25:05 -0500 Received: from mga01.intel.com ([192.55.52.88]:56739 "EHLO mga01.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230370AbhB0RMK (ORCPT ); Sat, 27 Feb 2021 12:12:10 -0500 IronPort-SDR: tQ3nt26qHzn60S6tgma9wTD5mb55+x7RHFbbQu8sBUncjtUjKNmZL7dj8CvYmhx+usp+thN1ds jFRwG0Swqflw== X-IronPort-AV: E=McAfee;i="6000,8403,9908"; a="205700336" X-IronPort-AV: E=Sophos;i="5.81,211,1610438400"; d="scan'208";a="205700336" Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by fmsmga101.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 27 Feb 2021 09:03:59 -0800 IronPort-SDR: qDBf28JvrWl4kJOegFm5AnoReBa7dcgejc0weSFNCzsG3g9f5PVOp9XdK57fuq1YLVaYXqDhn2 v+SheuDRzpGw== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.81,211,1610438400"; d="scan'208";a="503906854" Received: from chang-linux-3.sc.intel.com ([172.25.66.175]) by fmsmga001.fm.intel.com with ESMTP; 27 Feb 2021 09:03:58 -0800 From: "Chang S. Bae" To: bp@suse.de, tglx@linutronix.de, mingo@kernel.org, luto@kernel.org, x86@kernel.org Cc: len.brown@intel.com, dave.hansen@intel.com, hjl.tools@gmail.com, Dave.Martin@arm.com, jannh@google.com, mpe@ellerman.id.au, carlos@redhat.com, tony.luck@intel.com, ravi.v.shankar@intel.com, libc-alpha@sourceware.org, linux-arch@vger.kernel.org, linux-api@vger.kernel.org, linux-kernel@vger.kernel.org, chang.seok.bae@intel.com Subject: [PATCH v6 5/6] x86/signal: Detect and prevent an alternate signal stack overflow Date: Sat, 27 Feb 2021 08:59:10 -0800 Message-Id: <20210227165911.32757-6-chang.seok.bae@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210227165911.32757-1-chang.seok.bae@intel.com> References: <20210227165911.32757-1-chang.seok.bae@intel.com> Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org The kernel pushes context on to the userspace stack to prepare for the user's signal handler. When the user has supplied an alternate signal stack, via sigaltstack(2), it is easy for the kernel to verify that the stack size is sufficient for the current hardware context. Check if writing the hardware context to the alternate stack will exceed it's size. If yes, then instead of corrupting user-data and proceeding with the original signal handler, an immediate SIGSEGV signal is delivered. Instead of calling on_sig_stack(), directly check the new stack pointer whether in the bounds. While the kernel allows new source code to discover and use a sufficient alternate signal stack size, this check is still necessary to protect binaries with insufficient alternate signal stack size from data corruption. Suggested-by: Jann Horn Signed-off-by: Chang S. Bae Reviewed-by: Len Brown Reviewed-by: Jann Horn Cc: Andy Lutomirski Cc: Jann Horn Cc: x86@kernel.org Cc: linux-kernel@vger.kernel.org --- Changes from v5: * Fixed the overflow check. (Andy Lutomirski) * Updated the changelog. Changes from v3: * Updated the changelog (Borislav Petkov) Changes from v2: * Simplified the implementation (Jann Horn) --- arch/x86/kernel/signal.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c index 0d24f64d0145..9a62604fbf63 100644 --- a/arch/x86/kernel/signal.c +++ b/arch/x86/kernel/signal.c @@ -242,7 +242,7 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size, unsigned long math_size = 0; unsigned long sp = regs->sp; unsigned long buf_fx = 0; - int onsigstack = on_sig_stack(sp); + bool onsigstack = on_sig_stack(sp); int ret; /* redzone */ @@ -251,8 +251,11 @@ 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) { sp = current->sas_ss_sp + current->sas_ss_size; + /* On the alternate signal stack */ + onsigstack = true; + } } else if (IS_ENABLED(CONFIG_X86_32) && !onsigstack && regs->ss != __USER_DS && @@ -272,7 +275,8 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size, * If we are on the alternate signal stack and would overflow it, don't. * Return an always-bogus address instead so we will die with SIGSEGV. */ - if (onsigstack && !likely(on_sig_stack(sp))) + if (onsigstack && unlikely(sp <= current->sas_ss_sp || + sp - current->sas_ss_sp > current->sas_ss_size)) return (void __user *)-1L; /* save i387 and extended state */ -- 2.17.1