Skip to content

Commit 0cecca9

Browse files
rikvanrielsuryasaimadhu
authored andcommitted
x86/fpu: Eager switch PKRU state
While most of a task's FPU state is only needed in user space, the protection keys need to be in place immediately after a context switch. The reason is that any access to userspace memory while running in kernel mode also needs to abide by the memory permissions specified in the protection keys. The "eager switch" is a preparation for loading the FPU state on return to userland. Instead of decoupling PKRU state from xstate, update PKRU within xstate on write operations by the kernel. For user tasks the PKRU should be always read from the xsave area and it should not change anything because the PKRU value was loaded as part of FPU restore. For kernel threads the default "init_pkru_value" will be written. Before this commit, the kernel thread would end up with a random value which it inherited from the previous user task. [ bigeasy: save pkru to xstate, no cache, don't use __raw_xsave_addr() ] [ bp: update commit message, sort headers properly in asm/fpu/xstate.h ] Signed-off-by: Rik van Riel <riel@surriel.com> Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Signed-off-by: Borislav Petkov <bp@suse.de> Reviewed-by: Dave Hansen <dave.hansen@intel.com> Reviewed-by: Thomas Gleixner <tglx@linutronix.de> Cc: Andi Kleen <ak@linux.intel.com> Cc: Andy Lutomirski <luto@kernel.org> Cc: Aubrey Li <aubrey.li@intel.com> Cc: "H. Peter Anvin" <hpa@zytor.com> Cc: Ingo Molnar <mingo@redhat.com> Cc: Jann Horn <jannh@google.com> Cc: "Jason A. Donenfeld" <Jason@zx2c4.com> Cc: Joerg Roedel <jroedel@suse.de> Cc: Juergen Gross <jgross@suse.com> Cc: "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com> Cc: kvm ML <kvm@vger.kernel.org> Cc: Michal Hocko <mhocko@suse.cz> Cc: Paolo Bonzini <pbonzini@redhat.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Radim Krčmář <rkrcmar@redhat.com> Cc: x86-ml <x86@kernel.org> Link: https://lkml.kernel.org/r/20190403164156.19645-16-bigeasy@linutronix.de
1 parent 0556cbd commit 0cecca9

File tree

4 files changed

+31
-4
lines changed

4 files changed

+31
-4
lines changed

arch/x86/include/asm/fpu/internal.h

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <linux/compat.h>
1515
#include <linux/sched.h>
1616
#include <linux/slab.h>
17+
#include <linux/mm.h>
1718

1819
#include <asm/user.h>
1920
#include <asm/fpu/api.h>
@@ -534,8 +535,27 @@ switch_fpu_prepare(struct fpu *old_fpu, int cpu)
534535
*/
535536
static inline void switch_fpu_finish(struct fpu *new_fpu, int cpu)
536537
{
537-
if (static_cpu_has(X86_FEATURE_FPU))
538-
__fpregs_load_activate(new_fpu, cpu);
538+
u32 pkru_val = init_pkru_value;
539+
struct pkru_state *pk;
540+
541+
if (!static_cpu_has(X86_FEATURE_FPU))
542+
return;
543+
544+
__fpregs_load_activate(new_fpu, cpu);
545+
546+
if (!cpu_feature_enabled(X86_FEATURE_OSPKE))
547+
return;
548+
549+
/*
550+
* PKRU state is switched eagerly because it needs to be valid before we
551+
* return to userland e.g. for a copy_to_user() operation.
552+
*/
553+
if (current->mm) {
554+
pk = get_xsave_addr(&new_fpu->state.xsave, XFEATURE_PKRU);
555+
if (pk)
556+
pkru_val = pk->pkru;
557+
}
558+
__write_pkru(pkru_val);
539559
}
540560

541561
/*

arch/x86/include/asm/fpu/xstate.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@
22
#ifndef __ASM_X86_XSAVE_H
33
#define __ASM_X86_XSAVE_H
44

5+
#include <linux/uaccess.h>
56
#include <linux/types.h>
7+
68
#include <asm/processor.h>
7-
#include <linux/uaccess.h>
9+
#include <asm/user.h>
810

911
/* Bit 63 of XCR0 is reserved for future expansion */
1012
#define XFEATURE_MASK_EXTEND (~(XFEATURE_MASK_FPSSE | (1ULL << 63)))

arch/x86/include/asm/pgtable.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1355,6 +1355,12 @@ static inline pmd_t pmd_swp_clear_soft_dirty(pmd_t pmd)
13551355
#define PKRU_WD_BIT 0x2
13561356
#define PKRU_BITS_PER_PKEY 2
13571357

1358+
#ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS
1359+
extern u32 init_pkru_value;
1360+
#else
1361+
#define init_pkru_value 0
1362+
#endif
1363+
13581364
static inline bool __pkru_allows_read(u32 pkru, u16 pkey)
13591365
{
13601366
int pkru_pkey_bits = pkey * PKRU_BITS_PER_PKEY;

arch/x86/mm/pkeys.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,6 @@ int __arch_override_mprotect_pkey(struct vm_area_struct *vma, int prot, int pkey
126126
* in the process's lifetime will not accidentally get access
127127
* to data which is pkey-protected later on.
128128
*/
129-
static
130129
u32 init_pkru_value = PKRU_AD_KEY( 1) | PKRU_AD_KEY( 2) | PKRU_AD_KEY( 3) |
131130
PKRU_AD_KEY( 4) | PKRU_AD_KEY( 5) | PKRU_AD_KEY( 6) |
132131
PKRU_AD_KEY( 7) | PKRU_AD_KEY( 8) | PKRU_AD_KEY( 9) |

0 commit comments

Comments
 (0)