From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from smtp.codeaurora.org by pdx-caf-mail.web.codeaurora.org (Dovecot) with LMTP id owdMBuNRGVuwEwAAmS7hNA ; Thu, 07 Jun 2018 15:43:06 +0000 Received: by smtp.codeaurora.org (Postfix, from userid 1000) id 1810E608B8; Thu, 7 Jun 2018 15:43:06 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on pdx-caf-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-2.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI autolearn=unavailable autolearn_force=no version=3.4.0 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by smtp.codeaurora.org (Postfix) with ESMTP id 65C6760590; Thu, 7 Jun 2018 15:43:05 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 smtp.codeaurora.org 65C6760590 Authentication-Results: pdx-caf-mail.web.codeaurora.org; dmarc=fail (p=none dis=none) header.from=intel.com Authentication-Results: pdx-caf-mail.web.codeaurora.org; spf=none smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S935215AbeFGPmt (ORCPT + 25 others); Thu, 7 Jun 2018 11:42:49 -0400 Received: from mga09.intel.com ([134.134.136.24]:36348 "EHLO mga09.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S934592AbeFGOlb (ORCPT ); Thu, 7 Jun 2018 10:41:31 -0400 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga001.jf.intel.com ([10.7.209.18]) by orsmga102.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 07 Jun 2018 07:41:30 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.49,486,1520924400"; d="scan'208";a="62632625" Received: from 2b52.sc.intel.com ([143.183.136.51]) by orsmga001.jf.intel.com with ESMTP; 07 Jun 2018 07:41:30 -0700 From: Yu-cheng Yu To: linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, linux-mm@kvack.org, linux-arch@vger.kernel.org, x86@kernel.org, "H. Peter Anvin" , Thomas Gleixner , Ingo Molnar , "H.J. Lu" , Vedvyas Shanbhogue , "Ravi V. Shankar" , Dave Hansen , Andy Lutomirski , Jonathan Corbet , Oleg Nesterov , Arnd Bergmann , Mike Kravetz Cc: Yu-cheng Yu Subject: [PATCH 03/10] x86/cet: Signal handling for shadow stack Date: Thu, 7 Jun 2018 07:38:00 -0700 Message-Id: <20180607143807.3611-4-yu-cheng.yu@intel.com> X-Mailer: git-send-email 2.15.1 In-Reply-To: <20180607143807.3611-1-yu-cheng.yu@intel.com> References: <20180607143807.3611-1-yu-cheng.yu@intel.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Set and restore shadow stack pointer for signals. Signed-off-by: Yu-cheng Yu --- arch/x86/ia32/ia32_signal.c | 5 ++++ arch/x86/include/asm/cet.h | 7 +++++ arch/x86/include/uapi/asm/sigcontext.h | 4 +++ arch/x86/kernel/cet.c | 51 ++++++++++++++++++++++++++++++++++ arch/x86/kernel/signal.c | 11 ++++++++ 5 files changed, 78 insertions(+) diff --git a/arch/x86/ia32/ia32_signal.c b/arch/x86/ia32/ia32_signal.c index 86b1341cba9a..26a776baff7c 100644 --- a/arch/x86/ia32/ia32_signal.c +++ b/arch/x86/ia32/ia32_signal.c @@ -34,6 +34,7 @@ #include #include #include +#include /* * Do a signal return; undo the signal stack. @@ -74,6 +75,7 @@ static int ia32_restore_sigcontext(struct pt_regs *regs, unsigned int tmpflags, err = 0; void __user *buf; u32 tmp; + u32 ssp; /* Always make any pending restarted system calls return -EINTR */ current->restart_block.fn = do_no_restart_syscall; @@ -104,9 +106,11 @@ static int ia32_restore_sigcontext(struct pt_regs *regs, get_user_ex(tmp, &sc->fpstate); buf = compat_ptr(tmp); + get_user_ex(ssp, &sc->ssp); } get_user_catch(err); err |= fpu__restore_sig(buf, 1); + err |= cet_restore_signal((unsigned long)ssp); force_iret(); @@ -194,6 +198,7 @@ static int ia32_setup_sigcontext(struct sigcontext_32 __user *sc, put_user_ex(current->thread.trap_nr, &sc->trapno); put_user_ex(current->thread.error_code, &sc->err); put_user_ex(regs->ip, &sc->ip); + put_user_ex((u32)cet_get_shstk_ptr(), &sc->ssp); put_user_ex(regs->cs, (unsigned int __user *)&sc->cs); put_user_ex(regs->flags, &sc->flags); put_user_ex(regs->sp, &sc->sp_at_signal); diff --git a/arch/x86/include/asm/cet.h b/arch/x86/include/asm/cet.h index 9d5bc1efc9b7..5507469cb803 100644 --- a/arch/x86/include/asm/cet.h +++ b/arch/x86/include/asm/cet.h @@ -17,14 +17,21 @@ struct cet_stat { #ifdef CONFIG_X86_INTEL_CET unsigned long cet_get_shstk_ptr(void); +int cet_push_shstk(int ia32, unsigned long ssp, unsigned long val); int cet_setup_shstk(void); void cet_disable_shstk(void); void cet_disable_free_shstk(struct task_struct *p); +int cet_restore_signal(unsigned long ssp); +int cet_setup_signal(int ia32, unsigned long addr); #else static inline unsigned long cet_get_shstk_ptr(void) { return 0; } +static inline int cet_push_shstk(int ia32, unsigned long ssp, + unsigned long val) { return 0; } static inline int cet_setup_shstk(void) { return 0; } static inline void cet_disable_shstk(void) {} static inline void cet_disable_free_shstk(struct task_struct *p) {} +static inline int cet_restore_signal(unsigned long ssp) { return 0; } +static inline int cet_setup_signal(int ia32, unsigned long addr) { return 0; } #endif #endif /* __ASSEMBLY__ */ diff --git a/arch/x86/include/uapi/asm/sigcontext.h b/arch/x86/include/uapi/asm/sigcontext.h index 844d60eb1882..6c8997a0156a 100644 --- a/arch/x86/include/uapi/asm/sigcontext.h +++ b/arch/x86/include/uapi/asm/sigcontext.h @@ -230,6 +230,7 @@ struct sigcontext_32 { __u32 fpstate; /* Zero when no FPU/extended context */ __u32 oldmask; __u32 cr2; + __u32 ssp; }; /* @@ -262,6 +263,7 @@ struct sigcontext_64 { __u64 trapno; __u64 oldmask; __u64 cr2; + __u64 ssp; /* * fpstate is really (struct _fpstate *) or (struct _xstate *) @@ -320,6 +322,7 @@ struct sigcontext { struct _fpstate __user *fpstate; __u32 oldmask; __u32 cr2; + __u32 ssp; }; # else /* __x86_64__: */ struct sigcontext { @@ -377,6 +380,7 @@ struct sigcontext { __u64 trapno; __u64 oldmask; __u64 cr2; + __u64 ssp; struct _fpstate __user *fpstate; /* Zero when no FPU context */ # ifdef __ILP32__ __u32 __fpstate_pad; diff --git a/arch/x86/kernel/cet.c b/arch/x86/kernel/cet.c index 8abbfd44322a..6f445ce94c83 100644 --- a/arch/x86/kernel/cet.c +++ b/arch/x86/kernel/cet.c @@ -17,6 +17,7 @@ #include #include #include +#include #define SHSTK_SIZE (0x8000 * (test_thread_flag(TIF_IA32) ? 4 : 8)) @@ -47,6 +48,24 @@ unsigned long cet_get_shstk_ptr(void) return ptr; } +int cet_push_shstk(int ia32, unsigned long ssp, unsigned long val) +{ + if (val >= TASK_SIZE) + return -EINVAL; + + if (IS_ENABLED(CONFIG_IA32_EMULATION) && ia32) { + if (!IS_ALIGNED(ssp, 4)) + return -EINVAL; + cet_set_shstk_ptr(ssp); + return write_user_shstk_32(ssp, (unsigned int)val); + } else { + if (!IS_ALIGNED(ssp, 8)) + return -EINVAL; + cet_set_shstk_ptr(ssp); + return write_user_shstk_64(ssp, val); + } +} + static unsigned long shstk_mmap(unsigned long addr, unsigned long len) { struct mm_struct *mm = current->mm; @@ -121,3 +140,35 @@ void cet_disable_free_shstk(struct task_struct *tsk) tsk->thread.cet.shstk_enabled = 0; } + +int cet_restore_signal(unsigned long ssp) +{ + if (!current->thread.cet.shstk_enabled) + return 0; + return cet_set_shstk_ptr(ssp); +} + +int cet_setup_signal(int ia32, unsigned long rstor_addr) +{ + unsigned long ssp; + struct cet_stat *cet = ¤t->thread.cet; + + if (!current->thread.cet.shstk_enabled) + return 0; + + ssp = cet_get_shstk_ptr(); + + /* + * Put the restorer address on the shstk + */ + if (ia32) + ssp -= sizeof(u32); + else + ssp -= sizeof(rstor_addr); + + if (ssp >= (cet->shstk_base + cet->shstk_size) || + ssp < cet->shstk_base) + return -EINVAL; + + return cet_push_shstk(ia32, ssp, rstor_addr); +} diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c index da270b95fe4d..86fb897cae19 100644 --- a/arch/x86/kernel/signal.c +++ b/arch/x86/kernel/signal.c @@ -46,6 +46,7 @@ #include #include +#include #define COPY(x) do { \ get_user_ex(regs->x, &sc->x); \ @@ -102,6 +103,7 @@ static int restore_sigcontext(struct pt_regs *regs, void __user *buf; unsigned int tmpflags; unsigned int err = 0; + unsigned long ssp = 0; /* Always make any pending restarted system calls return -EINTR */ current->restart_block.fn = do_no_restart_syscall; @@ -148,9 +150,11 @@ static int restore_sigcontext(struct pt_regs *regs, get_user_ex(buf_val, &sc->fpstate); buf = (void __user *)buf_val; + get_user_ex(ssp, &sc->ssp); } get_user_catch(err); err |= fpu__restore_sig(buf, IS_ENABLED(CONFIG_X86_32)); + err |= cet_restore_signal(ssp); force_iret(); @@ -193,6 +197,7 @@ int setup_sigcontext(struct sigcontext __user *sc, void __user *fpstate, put_user_ex(current->thread.trap_nr, &sc->trapno); put_user_ex(current->thread.error_code, &sc->err); put_user_ex(regs->ip, &sc->ip); + put_user_ex(cet_get_shstk_ptr(), &sc->ssp); #ifdef CONFIG_X86_32 put_user_ex(regs->cs, (unsigned int __user *)&sc->cs); put_user_ex(regs->flags, &sc->flags); @@ -742,6 +747,12 @@ handle_signal(struct ksignal *ksig, struct pt_regs *regs) user_disable_single_step(current); failed = (setup_rt_frame(ksig, regs) < 0); + if (!failed) { + unsigned long rstor = (unsigned long)ksig->ka.sa.sa_restorer; + int ia32 = is_ia32_frame(ksig); + + failed = cet_setup_signal(ia32, rstor); + } if (!failed) { /* * Clear the direction flag as per the ABI for function entry. -- 2.15.1