Received: by 2002:a05:6a10:1287:0:0:0:0 with SMTP id d7csp3839380pxv; Mon, 19 Jul 2021 09:59:28 -0700 (PDT) X-Google-Smtp-Source: ABdhPJxegFwMo4xWwfAgEEtRtGDSy4N4qGX9rj9O8icmqNOg3KH6GgdZihh25hicQmkThmeWo5pU X-Received: by 2002:a05:6602:1203:: with SMTP id y3mr12408319iot.192.1626713968024; Mon, 19 Jul 2021 09:59:28 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1626713968; cv=none; d=google.com; s=arc-20160816; b=Y3iqa8fvLWxct3JLYOiYWwvH2hsX6QrjltzxUlWLdcOblWGS7z4x6UZMnFFdIB4ZGs 4tw4DzxKyTBURMUqGq2iMz5oeJ22NtEOtlkG0VAaCuXGSCEThFt5d0r40aetCf4c6tXY DFLZ3uo92qpq3/GvrZs07fMZGGMO8exym9itP50ul5p4yp2wJTBh5O3ZPDr6Mkgn2Xpb 7iaw8xi/vRLkyJeDMfJEwAtq+W7+OYjiJPyA5eJuSjUWXhpsbmqHmVKqDklAuZwNXbqa uYFQMfzhLVtsBXNSvMXK8Bde0aR2HBXaOFxX+P2O7PzrqZtBpqBqOnFH3tifao9gSMFn zSpw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=a46EYh/FIKA8yRje54RZ4c7VIEViYm2C0XKsQMvKW14=; b=NAx2fiI19+Wn1blo1i/JhgRO9d5RjjbqaN12hUQwITu5Qn8gqwM8ZQX3RH2s9SwXoE B66KDF8S6vMsHgDYLWySUz24Or72Oxq7ZSt33Urj2QrNMmPa8Nxz8vmRS9abbNLS46+l 3nGyNBnu7U/UDm9hMETNlmXYfSeNdRR7Ts9447vFX9sH0MLN/bCE+h79Npb07TdnqtLq 7soGh3/GgbO+KdiHgWihKS+5Q+Gi7uoPTejDOiwb+1H5GlZcuxxgDvLf5eYkRc31jvW9 +A8gE3okunwijcvCXg5aaNDZkE2k10FM9e9n7umrZ2wIbroefdXO8HuMIvuwIXdghiAE ZlzQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=Gcw7ZPb4; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linuxfoundation.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id g2si13566948ioo.75.2021.07.19.09.59.15; Mon, 19 Jul 2021 09:59:28 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=Gcw7ZPb4; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linuxfoundation.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1353514AbhGSQQz (ORCPT + 99 others); Mon, 19 Jul 2021 12:16:55 -0400 Received: from mail.kernel.org ([198.145.29.99]:46912 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1345217AbhGSPK1 (ORCPT ); Mon, 19 Jul 2021 11:10:27 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id 0A3E16113B; Mon, 19 Jul 2021 15:51:05 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1626709866; bh=avXpt2IE8evYRyq1qslB7oJTaE/69xXYFne8L/SFsqc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Gcw7ZPb4NNhwwNQfjVXhzDFdP6yflkJaIqIwVqmbEjHkdc3DFaJTACdGupq+n/Ree DAJLHj1XKs/fW7XtUm9qpB8ZfaYU92/mL5o55nfCWG+c2OlW/ajSfpW7mDU16MsQPG NgNMW4w2DRTfHng8ZxMCiUPVU523760EmselOrbM= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Florian Weimer , Jann Horn , Andy Lutomirski , "Chang S. Bae" , Borislav Petkov , Len Brown , Thomas Gleixner , Sasha Levin Subject: [PATCH 5.4 096/149] x86/signal: Detect and prevent an alternate signal stack overflow Date: Mon, 19 Jul 2021 16:53:24 +0200 Message-Id: <20210719144924.106579372@linuxfoundation.org> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210719144901.370365147@linuxfoundation.org> References: <20210719144901.370365147@linuxfoundation.org> User-Agent: quilt/0.66 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Chang S. Bae [ Upstream commit 2beb4a53fc3f1081cedc1c1a198c7f56cc4fc60c ] 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. Refactor the stack pointer check code from on_sig_stack() and use the new helper. 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. Fixes: c2bc11f10a39 ("x86, AVX-512: Enable AVX-512 States Context Switch") Reported-by: Florian Weimer Suggested-by: Jann Horn Suggested-by: Andy Lutomirski Signed-off-by: Chang S. Bae Signed-off-by: Borislav Petkov Reviewed-by: Len Brown Acked-by: Thomas Gleixner Link: https://lkml.kernel.org/r/20210518200320.17239-6-chang.seok.bae@intel.com Link: https://bugzilla.kernel.org/show_bug.cgi?id=153531 Signed-off-by: Sasha Levin --- arch/x86/kernel/signal.c | 24 ++++++++++++++++++++---- include/linux/sched/signal.h | 19 ++++++++++++------- 2 files changed, 32 insertions(+), 11 deletions(-) diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c index 2fdbf5ef8c39..026ce06a24c0 100644 --- a/arch/x86/kernel/signal.c +++ b/arch/x86/kernel/signal.c @@ -241,10 +241,11 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size, void __user **fpstate) { /* Default to using normal stack */ + bool nested_altstack = on_sig_stack(regs->sp); + bool entering_altstack = false; unsigned long math_size = 0; unsigned long sp = regs->sp; unsigned long buf_fx = 0; - int onsigstack = on_sig_stack(sp); int ret; /* redzone */ @@ -253,15 +254,23 @@ 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) + /* + * This checks nested_altstack via sas_ss_flags(). Sensible + * programs use SS_AUTODISARM, which disables that check, and + * programs that don't use SS_AUTODISARM get compatible. + */ + if (sas_ss_flags(sp) == 0) { sp = current->sas_ss_sp + current->sas_ss_size; + entering_altstack = true; + } } else if (IS_ENABLED(CONFIG_X86_32) && - !onsigstack && + !nested_altstack && regs->ss != __USER_DS && !(ka->sa.sa_flags & SA_RESTORER) && ka->sa.sa_restorer) { /* This is the legacy signal stack switching. */ sp = (unsigned long) ka->sa.sa_restorer; + entering_altstack = true; } sp = fpu__alloc_mathframe(sp, IS_ENABLED(CONFIG_X86_32), @@ -274,8 +283,15 @@ 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 (unlikely((nested_altstack || entering_altstack) && + !__on_sig_stack(sp))) { + + if (show_unhandled_signals && printk_ratelimit()) + pr_info("%s[%d] overflowed sigaltstack\n", + current->comm, task_pid_nr(current)); + return (void __user *)-1L; + } /* save i387 and extended state */ ret = copy_fpstate_to_sigframe(*fpstate, (void __user *)buf_fx, math_size); diff --git a/include/linux/sched/signal.h b/include/linux/sched/signal.h index baf58f4cb057..b3f88470cbb5 100644 --- a/include/linux/sched/signal.h +++ b/include/linux/sched/signal.h @@ -509,6 +509,17 @@ static inline int kill_cad_pid(int sig, int priv) #define SEND_SIG_NOINFO ((struct kernel_siginfo *) 0) #define SEND_SIG_PRIV ((struct kernel_siginfo *) 1) +static inline int __on_sig_stack(unsigned long sp) +{ +#ifdef CONFIG_STACK_GROWSUP + return sp >= current->sas_ss_sp && + sp - current->sas_ss_sp < current->sas_ss_size; +#else + return sp > current->sas_ss_sp && + sp - current->sas_ss_sp <= current->sas_ss_size; +#endif +} + /* * True if we are on the alternate signal stack. */ @@ -526,13 +537,7 @@ static inline int on_sig_stack(unsigned long sp) if (current->sas_ss_flags & SS_AUTODISARM) return 0; -#ifdef CONFIG_STACK_GROWSUP - return sp >= current->sas_ss_sp && - sp - current->sas_ss_sp < current->sas_ss_size; -#else - return sp > current->sas_ss_sp && - sp - current->sas_ss_sp <= current->sas_ss_size; -#endif + return __on_sig_stack(sp); } static inline int sas_ss_flags(unsigned long sp) -- 2.30.2