Received: by 2002:ac0:8c9a:0:0:0:0:0 with SMTP id r26csp909836ima; Fri, 1 Feb 2019 12:58:41 -0800 (PST) X-Google-Smtp-Source: ALg8bN5E17kqyG/o93gYGMylpszW3314/UgdbgTTacZkJjc3qPtJQ4fF5XlTgpI3b95U5c0/PS3H X-Received: by 2002:aa7:8542:: with SMTP id y2mr41499281pfn.83.1549054721529; Fri, 01 Feb 2019 12:58:41 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1549054721; cv=none; d=google.com; s=arc-20160816; b=qpHH8iDPx1X47Wpn1UuPlIL4q4LOPu6hFqTdn4YG/5JPxZObfzB57YZn6ljDmQ6OQB cuxWmSNK1R5hfc/i2oZXXdRobpFQBJQDHABhqsCzaHJl/YDBScSxFqPtcmdI1+WZZHBA 45NSXRuOCtzzKTWyVS+KZvcjtp0uFbT/ekAaxzp5CYMu5ZctgbUnqsKYQOPC7kD9eB2F Yo525bLntiI/kFWqCkLPtHzaxOLpkG9I6//P+WgSYJPEFLvgG5Owcwjx+SPjmYuDEhdH XHSxjO3K+2radvWs/i1M8o7xIhbWKergg8Xl8a6vlNKr8V2TMW95UCsiySGfr+MiiZ+p XuTQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from; bh=mFNFNS/ibwZZ1JJdQ0fK9xa6PlpbFsZqQrZnLTl3JOU=; b=O/HXi0pgTqP7XAc/g6El6k/hwlf7oZfax/eNeu0rLKPb2mYjUGrLSyVkvSapoU2l70 vi6v8yGveu3zkDm23t+FufofieJ2vxFvn7uEl1qiYKsIdLrtpfJHBDs9wrO4xr2TmnUo ftHjGHDemgs0eytOBqMYfYcQBD/b6/3ZmmOm91dP2/UqDlXxfDFtxgUADktjGUebRX/Y mc9s0SmubSVQeMnHBJQt3iVyeq8gb7p3itEG397C8yqa7BndF1L0+refjxB5NFqGPhBM xA04l/S0FM36MH9N9iDZALYmBAddlkD5EiRJggtX+2DyPJ6d+jt1gk3wQO9m1yE+NaRp cKfw== ARC-Authentication-Results: i=1; mx.google.com; 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=fail (p=NONE sp=NONE dis=NONE) header.from=intel.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id r18si8324957pls.115.2019.02.01.12.58.26; Fri, 01 Feb 2019 12:58: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; 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=fail (p=NONE sp=NONE dis=NONE) header.from=intel.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730671AbfBAUz3 (ORCPT + 99 others); Fri, 1 Feb 2019 15:55:29 -0500 Received: from mga07.intel.com ([134.134.136.100]:49748 "EHLO mga07.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730480AbfBAUzB (ORCPT ); Fri, 1 Feb 2019 15:55:01 -0500 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by orsmga105.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 01 Feb 2019 12:55:00 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.56,549,1539673200"; d="scan'208";a="140866374" Received: from chang-linux-2.sc.intel.com ([10.3.52.165]) by fmsmga004.fm.intel.com with ESMTP; 01 Feb 2019 12:55:00 -0800 From: "Chang S. Bae" To: Andy Lutomirski , Thomas Gleixner , Ingo Molnar , "H . Peter Anvin" , Andi Kleen Cc: Markus T Metzger , Ravi Shankar , "Chang S . Bae" , LKML , Dave Hansen Subject: [PATCH v5 09/13] x86/fsgsbase/64: Use the per-CPU base as GSBASE at the paranoid_entry Date: Fri, 1 Feb 2019 12:53:15 -0800 Message-Id: <20190201205319.15995-11-chang.seok.bae@intel.com> X-Mailer: git-send-email 2.19.1 In-Reply-To: <20190201205319.15995-1-chang.seok.bae@intel.com> References: <20190201205319.15995-1-chang.seok.bae@intel.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org The FSGSBASE instructions allow fast accesses on GSBASE. Now, at the paranoid_entry, the per-CPU base value can be always copied to GSBASE. And the original GSBASE value will be restored at the exit. So far, GSBASE modification has not been directly allowed from userspace. So, swapping GSBASE has been conditionally executed according to the kernel-enforced convention that a negative GSBASE indicates a kernel value. But when FSGSBASE is enabled, userspace can put an arbitrary value in GSBASE. The change will secure a correct GSBASE value with FSGSBASE. Also, factor out the RDMSR-based GSBASE read into a new macro, READ_MSR_GSBASE. Suggested-by: H. Peter Anvin Signed-off-by: Chang S. Bae Cc: Andy Lutomirski Cc: Thomas Gleixner Cc: Ingo Molnar Cc: Dave Hansen Cc: Andi Kleen --- arch/x86/entry/entry_64.S | 71 +++++++++++++++++++++++++++------ arch/x86/include/asm/fsgsbase.h | 9 +++++ 2 files changed, 67 insertions(+), 13 deletions(-) diff --git a/arch/x86/entry/entry_64.S b/arch/x86/entry/entry_64.S index 1f0efdb7b629..9df528565e40 100644 --- a/arch/x86/entry/entry_64.S +++ b/arch/x86/entry/entry_64.S @@ -38,6 +38,7 @@ #include #include #include +#include #include #include "calling.h" @@ -934,10 +935,14 @@ ENTRY(\sym) addq $EXCEPTION_STKSZ, CPU_TSS_IST(\shift_ist) .endif - /* these procedures expect "no swapgs" flag in ebx */ .if \paranoid + /* + * With FSGSBASE, original GSBASE is stored in %rbx + * Without FSGSBASE, expect "no swapgs" flag in %ebx + */ jmp paranoid_exit .else + /* Expect "no swapgs" flag in %ebx */ jmp error_exit .endif @@ -1151,22 +1156,24 @@ idtentry machine_check do_mce has_error_code=0 paranoid=1 #endif /* - * Save all registers in pt_regs, and switch gs if needed. - * Use slow, but surefire "are we in kernel?" check. - * Return: ebx=0: need swapgs on exit, ebx=1: otherwise + * Save all registers in pt_regs. + * + * When FSGSBASE enabled, current GSBASE is always copied to %rbx. + * + * Without FSGSBASE, SWAPGS is needed when entering from userspace. + * A positive GSBASE means it is a user value and a negative GSBASE + * means it is a kernel value. + * + * Return: + * With FSGSBASE, %rbx has current GSBASE. + * Without that, + * %ebx=0: need SWAPGS on exit, %ebx=1: otherwise */ ENTRY(paranoid_entry) UNWIND_HINT_FUNC cld PUSH_AND_CLEAR_REGS save_ret=1 ENCODE_FRAME_POINTER 8 - movl $1, %ebx - movl $MSR_GS_BASE, %ecx - rdmsr - testl %edx, %edx - js 1f /* negative -> in kernel */ - SWAPGS - xorl %ebx, %ebx 1: /* @@ -1178,9 +1185,38 @@ ENTRY(paranoid_entry) * This is also why CS (stashed in the "iret frame" by the * hardware at entry) can not be used: this may be a return * to kernel code, but with a user CR3 value. + * + * As long as this PTI macro doesn't depend on kernel GSBASE, + * we can do it early. This is because FIND_PERCPU_BASE + * references data in kernel space. */ SAVE_AND_SWITCH_TO_KERNEL_CR3 scratch_reg=%rax save_reg=%r14 + /* + * Read GSBASE by RDGSBASE. Kernel GSBASE is found + * from the per-CPU offset table with a CPU NR. + */ + ALTERNATIVE "jmp .Lparanoid_entry_no_fsgsbase", "",\ + X86_FEATURE_FSGSBASE + rdgsbase %rbx + FIND_PERCPU_BASE %rax + wrgsbase %rax + ret + +.Lparanoid_entry_no_fsgsbase: + movl $1, %ebx + /* + * FSGSBASE is not in use, so depend on the kernel-enforced + * convention that a negative GSBASE indicates a kernel value. + */ + READ_MSR_GSBASE save_reg=%edx + testl %edx, %edx /* Negative -> in kernel */ + jns .Lparanoid_entry_swapgs + ret + +.Lparanoid_entry_swapgs: + SWAPGS + xorl %ebx, %ebx ret END(paranoid_entry) @@ -1194,12 +1230,21 @@ END(paranoid_entry) * be complicated. Fortunately, we there's no good reason * to try to handle preemption here. * - * On entry, ebx is "no swapgs" flag (1: don't need swapgs, 0: need it) + * On entry, + * With FSGSBASE, + * %rbx is original GSBASE that needs to be restored on the exit + * Without that, + * %ebx is "no swapgs" flag (1: don't need swapgs, 0: need it) */ ENTRY(paranoid_exit) UNWIND_HINT_REGS DISABLE_INTERRUPTS(CLBR_ANY) TRACE_IRQS_OFF_DEBUG + ALTERNATIVE "jmp .Lparanoid_exit_no_fsgsbase", "nop",\ + X86_FEATURE_FSGSBASE + wrgsbase %rbx + jmp .Lparanoid_exit_no_swapgs; +.Lparanoid_exit_no_fsgsbase: testl %ebx, %ebx /* swapgs needed? */ jnz .Lparanoid_exit_no_swapgs TRACE_IRQS_IRETQ @@ -1212,7 +1257,7 @@ ENTRY(paranoid_exit) /* Always restore stashed CR3 value (see paranoid_entry) */ RESTORE_CR3 scratch_reg=%rbx save_reg=%r14 .Lparanoid_exit_restore: - jmp restore_regs_and_return_to_kernel + jmp restore_regs_and_return_to_kernel END(paranoid_exit) /* diff --git a/arch/x86/include/asm/fsgsbase.h b/arch/x86/include/asm/fsgsbase.h index eecca2250748..1cb7b03c107a 100644 --- a/arch/x86/include/asm/fsgsbase.h +++ b/arch/x86/include/asm/fsgsbase.h @@ -122,6 +122,15 @@ extern void x86_gsbase_write_cpu_inactive(unsigned long gsbase); #endif /* CONFIG_SMP */ +.macro READ_MSR_GSBASE save_reg:req + movl $MSR_GS_BASE, %ecx + /* Read MSR specified by %ecx into %edx:%eax */ + rdmsr + .ifnc \save_reg, %edx + movl %edx, \save_reg + .endif +.endm + #endif /* CONFIG_X86_64 */ #endif /* __ASSEMBLY__ */ -- 2.19.1