Skip to content

Commit 980fe2f

Browse files
KAGA-KOKObonzini
authored andcommitted
x86/fpu: Extend fpu_xstate_prctl() with guest permissions
KVM requires a clear separation of host user space and guest permissions for dynamic XSTATE components. Add a guest permissions member to struct fpu and a separate set of prctl() arguments: ARCH_GET_XCOMP_GUEST_PERM and ARCH_REQ_XCOMP_GUEST_PERM. The semantics are equivalent to the host user space permission control except for the following constraints: 1) Permissions have to be requested before the first vCPU is created 2) Permissions are frozen when the first vCPU is created to ensure consistency. Any attempt to expand permissions via the prctl() after that point is rejected. Signed-off-by: Thomas Gleixner <[email protected]> Signed-off-by: Jing Liu <[email protected]> Signed-off-by: Yang Zhong <[email protected]> Message-Id: <[email protected]> Signed-off-by: Paolo Bonzini <[email protected]>
1 parent 96c1a62 commit 980fe2f

File tree

7 files changed

+80
-28
lines changed

7 files changed

+80
-28
lines changed

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,8 @@ static inline void fpstate_free(struct fpu *fpu) { }
132132
/* fpstate-related functions which are exported to KVM */
133133
extern void fpstate_clear_xstate_component(struct fpstate *fps, unsigned int xfeature);
134134

135+
extern inline u64 xstate_get_guest_group_perm(void);
136+
135137
/* KVM specific functions */
136138
extern bool fpu_alloc_guest_fpstate(struct fpu_guest *gfpu);
137139
extern void fpu_free_guest_fpstate(struct fpu_guest *gfpu);

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,8 @@ struct fpstate {
387387
/* @regs is dynamically sized! Don't add anything after @regs! */
388388
} __aligned(64);
389389

390+
#define FPU_GUEST_PERM_LOCKED BIT_ULL(63)
391+
390392
struct fpu_state_perm {
391393
/*
392394
* @__state_perm:
@@ -476,6 +478,13 @@ struct fpu {
476478
*/
477479
struct fpu_state_perm perm;
478480

481+
/*
482+
* @guest_perm:
483+
*
484+
* Permission related information for guest pseudo FPUs
485+
*/
486+
struct fpu_state_perm guest_perm;
487+
479488
/*
480489
* @__fpstate:
481490
*

arch/x86/include/uapi/asm/prctl.h

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,22 @@
22
#ifndef _ASM_X86_PRCTL_H
33
#define _ASM_X86_PRCTL_H
44

5-
#define ARCH_SET_GS 0x1001
6-
#define ARCH_SET_FS 0x1002
7-
#define ARCH_GET_FS 0x1003
8-
#define ARCH_GET_GS 0x1004
5+
#define ARCH_SET_GS 0x1001
6+
#define ARCH_SET_FS 0x1002
7+
#define ARCH_GET_FS 0x1003
8+
#define ARCH_GET_GS 0x1004
99

10-
#define ARCH_GET_CPUID 0x1011
11-
#define ARCH_SET_CPUID 0x1012
10+
#define ARCH_GET_CPUID 0x1011
11+
#define ARCH_SET_CPUID 0x1012
1212

13-
#define ARCH_GET_XCOMP_SUPP 0x1021
14-
#define ARCH_GET_XCOMP_PERM 0x1022
15-
#define ARCH_REQ_XCOMP_PERM 0x1023
13+
#define ARCH_GET_XCOMP_SUPP 0x1021
14+
#define ARCH_GET_XCOMP_PERM 0x1022
15+
#define ARCH_REQ_XCOMP_PERM 0x1023
16+
#define ARCH_GET_XCOMP_GUEST_PERM 0x1024
17+
#define ARCH_REQ_XCOMP_GUEST_PERM 0x1025
1618

17-
#define ARCH_MAP_VDSO_X32 0x2001
18-
#define ARCH_MAP_VDSO_32 0x2002
19-
#define ARCH_MAP_VDSO_64 0x2003
19+
#define ARCH_MAP_VDSO_X32 0x2001
20+
#define ARCH_MAP_VDSO_32 0x2002
21+
#define ARCH_MAP_VDSO_64 0x2003
2022

2123
#endif /* _ASM_X86_PRCTL_H */

arch/x86/kernel/fpu/core.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,8 @@ void fpstate_reset(struct fpu *fpu)
450450
fpu->perm.__state_perm = fpu_kernel_cfg.default_features;
451451
fpu->perm.__state_size = fpu_kernel_cfg.default_size;
452452
fpu->perm.__user_state_size = fpu_user_cfg.default_size;
453+
/* Same defaults for guests */
454+
fpu->guest_perm = fpu->perm;
453455
}
454456

455457
static inline void fpu_inherit_perms(struct fpu *dst_fpu)
@@ -460,6 +462,7 @@ static inline void fpu_inherit_perms(struct fpu *dst_fpu)
460462
spin_lock_irq(&current->sighand->siglock);
461463
/* Fork also inherits the permissions of the parent */
462464
dst_fpu->perm = src_fpu->perm;
465+
dst_fpu->guest_perm = src_fpu->guest_perm;
463466
spin_unlock_irq(&current->sighand->siglock);
464467
}
465468
}

arch/x86/kernel/fpu/xstate.c

Lines changed: 39 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1595,7 +1595,7 @@ static int validate_sigaltstack(unsigned int usize)
15951595
return 0;
15961596
}
15971597

1598-
static int __xstate_request_perm(u64 permitted, u64 requested)
1598+
static int __xstate_request_perm(u64 permitted, u64 requested, bool guest)
15991599
{
16001600
/*
16011601
* This deliberately does not exclude !XSAVES as we still might
@@ -1605,9 +1605,10 @@ static int __xstate_request_perm(u64 permitted, u64 requested)
16051605
*/
16061606
bool compacted = cpu_feature_enabled(X86_FEATURE_XSAVES);
16071607
struct fpu *fpu = &current->group_leader->thread.fpu;
1608+
struct fpu_state_perm *perm;
16081609
unsigned int ksize, usize;
16091610
u64 mask;
1610-
int ret;
1611+
int ret = 0;
16111612

16121613
/* Check whether fully enabled */
16131614
if ((permitted & requested) == requested)
@@ -1621,15 +1622,18 @@ static int __xstate_request_perm(u64 permitted, u64 requested)
16211622
mask &= XFEATURE_MASK_USER_SUPPORTED;
16221623
usize = xstate_calculate_size(mask, false);
16231624

1624-
ret = validate_sigaltstack(usize);
1625-
if (ret)
1626-
return ret;
1625+
if (!guest) {
1626+
ret = validate_sigaltstack(usize);
1627+
if (ret)
1628+
return ret;
1629+
}
16271630

1631+
perm = guest ? &fpu->guest_perm : &fpu->perm;
16281632
/* Pairs with the READ_ONCE() in xstate_get_group_perm() */
1629-
WRITE_ONCE(fpu->perm.__state_perm, requested);
1633+
WRITE_ONCE(perm->__state_perm, requested);
16301634
/* Protected by sighand lock */
1631-
fpu->perm.__state_size = ksize;
1632-
fpu->perm.__user_state_size = usize;
1635+
perm->__state_size = ksize;
1636+
perm->__user_state_size = usize;
16331637
return ret;
16341638
}
16351639

@@ -1640,7 +1644,7 @@ static const u64 xstate_prctl_req[XFEATURE_MAX] = {
16401644
[XFEATURE_XTILE_DATA] = XFEATURE_MASK_XTILE_DATA,
16411645
};
16421646

1643-
static int xstate_request_perm(unsigned long idx)
1647+
static int xstate_request_perm(unsigned long idx, bool guest)
16441648
{
16451649
u64 permitted, requested;
16461650
int ret;
@@ -1661,14 +1665,19 @@ static int xstate_request_perm(unsigned long idx)
16611665
return -EOPNOTSUPP;
16621666

16631667
/* Lockless quick check */
1664-
permitted = xstate_get_host_group_perm();
1668+
permitted = xstate_get_group_perm(guest);
16651669
if ((permitted & requested) == requested)
16661670
return 0;
16671671

16681672
/* Protect against concurrent modifications */
16691673
spin_lock_irq(&current->sighand->siglock);
1670-
permitted = xstate_get_host_group_perm();
1671-
ret = __xstate_request_perm(permitted, requested);
1674+
permitted = xstate_get_group_perm(guest);
1675+
1676+
/* First vCPU allocation locks the permissions. */
1677+
if (guest && (permitted & FPU_GUEST_PERM_LOCKED))
1678+
ret = -EBUSY;
1679+
else
1680+
ret = __xstate_request_perm(permitted, requested, guest);
16721681
spin_unlock_irq(&current->sighand->siglock);
16731682
return ret;
16741683
}
@@ -1713,12 +1722,18 @@ int xfd_enable_feature(u64 xfd_err)
17131722
return 0;
17141723
}
17151724
#else /* CONFIG_X86_64 */
1716-
static inline int xstate_request_perm(unsigned long idx)
1725+
static inline int xstate_request_perm(unsigned long idx, bool guest)
17171726
{
17181727
return -EPERM;
17191728
}
17201729
#endif /* !CONFIG_X86_64 */
17211730

1731+
inline u64 xstate_get_guest_group_perm(void)
1732+
{
1733+
return xstate_get_group_perm(true);
1734+
}
1735+
EXPORT_SYMBOL_GPL(xstate_get_guest_group_perm);
1736+
17221737
/**
17231738
* fpu_xstate_prctl - xstate permission operations
17241739
* @tsk: Redundant pointer to current
@@ -1742,6 +1757,7 @@ long fpu_xstate_prctl(struct task_struct *tsk, int option, unsigned long arg2)
17421757
u64 __user *uptr = (u64 __user *)arg2;
17431758
u64 permitted, supported;
17441759
unsigned long idx = arg2;
1760+
bool guest = false;
17451761

17461762
if (tsk != current)
17471763
return -EPERM;
@@ -1760,11 +1776,20 @@ long fpu_xstate_prctl(struct task_struct *tsk, int option, unsigned long arg2)
17601776
permitted &= XFEATURE_MASK_USER_SUPPORTED;
17611777
return put_user(permitted, uptr);
17621778

1779+
case ARCH_GET_XCOMP_GUEST_PERM:
1780+
permitted = xstate_get_guest_group_perm();
1781+
permitted &= XFEATURE_MASK_USER_SUPPORTED;
1782+
return put_user(permitted, uptr);
1783+
1784+
case ARCH_REQ_XCOMP_GUEST_PERM:
1785+
guest = true;
1786+
fallthrough;
1787+
17631788
case ARCH_REQ_XCOMP_PERM:
17641789
if (!IS_ENABLED(CONFIG_X86_64))
17651790
return -EOPNOTSUPP;
17661791

1767-
return xstate_request_perm(idx);
1792+
return xstate_request_perm(idx, guest);
17681793

17691794
default:
17701795
return -EINVAL;

arch/x86/kernel/fpu/xstate.h

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,19 @@ static inline void xstate_init_xcomp_bv(struct xregs_state *xsave, u64 mask)
2020
xsave->header.xcomp_bv = mask | XCOMP_BV_COMPACTED_FORMAT;
2121
}
2222

23-
static inline u64 xstate_get_host_group_perm(void)
23+
static inline u64 xstate_get_group_perm(bool guest)
2424
{
25+
struct fpu *fpu = &current->group_leader->thread.fpu;
26+
struct fpu_state_perm *perm;
27+
2528
/* Pairs with WRITE_ONCE() in xstate_request_perm() */
26-
return READ_ONCE(current->group_leader->thread.fpu.perm.__state_perm);
29+
perm = guest ? &fpu->guest_perm : &fpu->perm;
30+
return READ_ONCE(perm->__state_perm);
31+
}
32+
33+
static inline u64 xstate_get_host_group_perm(void)
34+
{
35+
return xstate_get_group_perm(false);
2736
}
2837

2938
enum xstate_copy_mode {

arch/x86/kernel/process.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -993,6 +993,8 @@ long do_arch_prctl_common(struct task_struct *task, int option,
993993
case ARCH_GET_XCOMP_SUPP:
994994
case ARCH_GET_XCOMP_PERM:
995995
case ARCH_REQ_XCOMP_PERM:
996+
case ARCH_GET_XCOMP_GUEST_PERM:
997+
case ARCH_REQ_XCOMP_GUEST_PERM:
996998
return fpu_xstate_prctl(task, option, arg2);
997999
}
9981000

0 commit comments

Comments
 (0)