Skip to content

Commit 783e87b

Browse files
ChangSeokBaesuryasaimadhu
authored andcommitted
x86/fpu/xstate: Add XFD #NM handler
If the XFD MSR has feature bits set then #NM will be raised when user space attempts to use an instruction related to one of these features. When the task has no permissions to use that feature, raise SIGILL, which is the same behavior as #UD. If the task has permissions, calculate the new buffer size for the extended feature set and allocate a larger fpstate. In the unlikely case that vzalloc() fails, SIGSEGV is raised. The allocation function will be added in the next step. Provide a stub which fails for now. [ tglx: Updated serialization ] Signed-off-by: Chang S. Bae <[email protected]> Signed-off-by: Thomas Gleixner <[email protected]> Signed-off-by: Borislav Petkov <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 6723654 commit 783e87b

File tree

3 files changed

+87
-0
lines changed

3 files changed

+87
-0
lines changed

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,8 @@ int xfeature_size(int xfeature_nr);
9999
void xsaves(struct xregs_state *xsave, u64 mask);
100100
void xrstors(struct xregs_state *xsave, u64 mask);
101101

102+
int xfd_enable_feature(u64 xfd_err);
103+
102104
#ifdef CONFIG_X86_64
103105
DECLARE_STATIC_KEY_FALSE(__fpu_state_size_dynamic);
104106
#endif

arch/x86/kernel/fpu/xstate.c

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1464,6 +1464,53 @@ static int xstate_request_perm(unsigned long idx)
14641464
spin_unlock_irq(&current->sighand->siglock);
14651465
return ret;
14661466
}
1467+
1468+
/* Place holder for now */
1469+
static int fpstate_realloc(u64 xfeatures, unsigned int ksize,
1470+
unsigned int usize)
1471+
{
1472+
return -ENOMEM;
1473+
}
1474+
1475+
int xfd_enable_feature(u64 xfd_err)
1476+
{
1477+
u64 xfd_event = xfd_err & XFEATURE_MASK_USER_DYNAMIC;
1478+
unsigned int ksize, usize;
1479+
struct fpu *fpu;
1480+
1481+
if (!xfd_event) {
1482+
pr_err_once("XFD: Invalid xfd error: %016llx\n", xfd_err);
1483+
return 0;
1484+
}
1485+
1486+
/* Protect against concurrent modifications */
1487+
spin_lock_irq(&current->sighand->siglock);
1488+
1489+
/* If not permitted let it die */
1490+
if ((xstate_get_host_group_perm() & xfd_event) != xfd_event) {
1491+
spin_unlock_irq(&current->sighand->siglock);
1492+
return -EPERM;
1493+
}
1494+
1495+
fpu = &current->group_leader->thread.fpu;
1496+
ksize = fpu->perm.__state_size;
1497+
usize = fpu->perm.__user_state_size;
1498+
/*
1499+
* The feature is permitted. State size is sufficient. Dropping
1500+
* the lock is safe here even if more features are added from
1501+
* another task, the retrieved buffer sizes are valid for the
1502+
* currently requested feature(s).
1503+
*/
1504+
spin_unlock_irq(&current->sighand->siglock);
1505+
1506+
/*
1507+
* Try to allocate a new fpstate. If that fails there is no way
1508+
* out.
1509+
*/
1510+
if (fpstate_realloc(xfd_event, ksize, usize))
1511+
return -EFAULT;
1512+
return 0;
1513+
}
14671514
#else /* CONFIG_X86_64 */
14681515
static inline int xstate_request_perm(unsigned long idx)
14691516
{

arch/x86/kernel/traps.c

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1108,10 +1108,48 @@ DEFINE_IDTENTRY(exc_spurious_interrupt_bug)
11081108
*/
11091109
}
11101110

1111+
static bool handle_xfd_event(struct pt_regs *regs)
1112+
{
1113+
u64 xfd_err;
1114+
int err;
1115+
1116+
if (!IS_ENABLED(CONFIG_X86_64) || !cpu_feature_enabled(X86_FEATURE_XFD))
1117+
return false;
1118+
1119+
rdmsrl(MSR_IA32_XFD_ERR, xfd_err);
1120+
if (!xfd_err)
1121+
return false;
1122+
1123+
wrmsrl(MSR_IA32_XFD_ERR, 0);
1124+
1125+
/* Die if that happens in kernel space */
1126+
if (WARN_ON(!user_mode(regs)))
1127+
return false;
1128+
1129+
local_irq_enable();
1130+
1131+
err = xfd_enable_feature(xfd_err);
1132+
1133+
switch (err) {
1134+
case -EPERM:
1135+
force_sig_fault(SIGILL, ILL_ILLOPC, error_get_trap_addr(regs));
1136+
break;
1137+
case -EFAULT:
1138+
force_sig(SIGSEGV);
1139+
break;
1140+
}
1141+
1142+
local_irq_disable();
1143+
return true;
1144+
}
1145+
11111146
DEFINE_IDTENTRY(exc_device_not_available)
11121147
{
11131148
unsigned long cr0 = read_cr0();
11141149

1150+
if (handle_xfd_event(regs))
1151+
return;
1152+
11151153
#ifdef CONFIG_MATH_EMULATION
11161154
if (!boot_cpu_has(X86_FEATURE_FPU) && (cr0 & X86_CR0_EM)) {
11171155
struct math_emu_info info = { };

0 commit comments

Comments
 (0)