Commit 18164f66 authored by Sean Christopherson's avatar Sean Christopherson Committed by Paolo Bonzini

x86/fpu: Allow caller to constrain xfeatures when copying to uabi buffer

Plumb an xfeatures mask into __copy_xstate_to_uabi_buf() so that KVM can
constrain which xfeatures are saved into the userspace buffer without
having to modify the user_xfeatures field in KVM's guest_fpu state.

KVM's ABI for KVM_GET_XSAVE{2} is that features that are not exposed to
guest must not show up in the effective xstate_bv field of the buffer.
Saving only the guest-supported xfeatures allows userspace to load the
saved state on a different host with a fewer xfeatures, so long as the
target host supports the xfeatures that are exposed to the guest.

KVM currently sets user_xfeatures directly to restrict KVM_GET_XSAVE{2} to
the set of guest-supported xfeatures, but doing so broke KVM's historical
ABI for KVM_SET_XSAVE, which allows userspace to load any xfeatures that
are supported by the *host*.

Cc: stable@vger.kernel.org
Signed-off-by: default avatarSean Christopherson <seanjc@google.com>
Message-Id: <20230928001956.924301-2-seanjc@google.com>
Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
parent 4bcd9bc6
...@@ -157,7 +157,8 @@ static inline void fpu_update_guest_xfd(struct fpu_guest *guest_fpu, u64 xfd) { ...@@ -157,7 +157,8 @@ static inline void fpu_update_guest_xfd(struct fpu_guest *guest_fpu, u64 xfd) {
static inline void fpu_sync_guest_vmexit_xfd_state(void) { } static inline void fpu_sync_guest_vmexit_xfd_state(void) { }
#endif #endif
extern void fpu_copy_guest_fpstate_to_uabi(struct fpu_guest *gfpu, void *buf, unsigned int size, u32 pkru); extern void fpu_copy_guest_fpstate_to_uabi(struct fpu_guest *gfpu, void *buf,
unsigned int size, u64 xfeatures, u32 pkru);
extern int fpu_copy_uabi_to_guest_fpstate(struct fpu_guest *gfpu, const void *buf, u64 xcr0, u32 *vpkru); extern int fpu_copy_uabi_to_guest_fpstate(struct fpu_guest *gfpu, const void *buf, u64 xcr0, u32 *vpkru);
static inline void fpstate_set_confidential(struct fpu_guest *gfpu) static inline void fpstate_set_confidential(struct fpu_guest *gfpu)
......
...@@ -369,14 +369,15 @@ int fpu_swap_kvm_fpstate(struct fpu_guest *guest_fpu, bool enter_guest) ...@@ -369,14 +369,15 @@ int fpu_swap_kvm_fpstate(struct fpu_guest *guest_fpu, bool enter_guest)
EXPORT_SYMBOL_GPL(fpu_swap_kvm_fpstate); EXPORT_SYMBOL_GPL(fpu_swap_kvm_fpstate);
void fpu_copy_guest_fpstate_to_uabi(struct fpu_guest *gfpu, void *buf, void fpu_copy_guest_fpstate_to_uabi(struct fpu_guest *gfpu, void *buf,
unsigned int size, u32 pkru) unsigned int size, u64 xfeatures, u32 pkru)
{ {
struct fpstate *kstate = gfpu->fpstate; struct fpstate *kstate = gfpu->fpstate;
union fpregs_state *ustate = buf; union fpregs_state *ustate = buf;
struct membuf mb = { .p = buf, .left = size }; struct membuf mb = { .p = buf, .left = size };
if (cpu_feature_enabled(X86_FEATURE_XSAVE)) { if (cpu_feature_enabled(X86_FEATURE_XSAVE)) {
__copy_xstate_to_uabi_buf(mb, kstate, pkru, XSTATE_COPY_XSAVE); __copy_xstate_to_uabi_buf(mb, kstate, xfeatures, pkru,
XSTATE_COPY_XSAVE);
} else { } else {
memcpy(&ustate->fxsave, &kstate->regs.fxsave, memcpy(&ustate->fxsave, &kstate->regs.fxsave,
sizeof(ustate->fxsave)); sizeof(ustate->fxsave));
......
...@@ -1049,6 +1049,7 @@ static void copy_feature(bool from_xstate, struct membuf *to, void *xstate, ...@@ -1049,6 +1049,7 @@ static void copy_feature(bool from_xstate, struct membuf *to, void *xstate,
* __copy_xstate_to_uabi_buf - Copy kernel saved xstate to a UABI buffer * __copy_xstate_to_uabi_buf - Copy kernel saved xstate to a UABI buffer
* @to: membuf descriptor * @to: membuf descriptor
* @fpstate: The fpstate buffer from which to copy * @fpstate: The fpstate buffer from which to copy
* @xfeatures: The mask of xfeatures to save (XSAVE mode only)
* @pkru_val: The PKRU value to store in the PKRU component * @pkru_val: The PKRU value to store in the PKRU component
* @copy_mode: The requested copy mode * @copy_mode: The requested copy mode
* *
...@@ -1059,7 +1060,8 @@ static void copy_feature(bool from_xstate, struct membuf *to, void *xstate, ...@@ -1059,7 +1060,8 @@ static void copy_feature(bool from_xstate, struct membuf *to, void *xstate,
* It supports partial copy but @to.pos always starts from zero. * It supports partial copy but @to.pos always starts from zero.
*/ */
void __copy_xstate_to_uabi_buf(struct membuf to, struct fpstate *fpstate, void __copy_xstate_to_uabi_buf(struct membuf to, struct fpstate *fpstate,
u32 pkru_val, enum xstate_copy_mode copy_mode) u64 xfeatures, u32 pkru_val,
enum xstate_copy_mode copy_mode)
{ {
const unsigned int off_mxcsr = offsetof(struct fxregs_state, mxcsr); const unsigned int off_mxcsr = offsetof(struct fxregs_state, mxcsr);
struct xregs_state *xinit = &init_fpstate.regs.xsave; struct xregs_state *xinit = &init_fpstate.regs.xsave;
...@@ -1083,7 +1085,7 @@ void __copy_xstate_to_uabi_buf(struct membuf to, struct fpstate *fpstate, ...@@ -1083,7 +1085,7 @@ void __copy_xstate_to_uabi_buf(struct membuf to, struct fpstate *fpstate,
break; break;
case XSTATE_COPY_XSAVE: case XSTATE_COPY_XSAVE:
header.xfeatures &= fpstate->user_xfeatures; header.xfeatures &= fpstate->user_xfeatures & xfeatures;
break; break;
} }
...@@ -1185,6 +1187,7 @@ void copy_xstate_to_uabi_buf(struct membuf to, struct task_struct *tsk, ...@@ -1185,6 +1187,7 @@ void copy_xstate_to_uabi_buf(struct membuf to, struct task_struct *tsk,
enum xstate_copy_mode copy_mode) enum xstate_copy_mode copy_mode)
{ {
__copy_xstate_to_uabi_buf(to, tsk->thread.fpu.fpstate, __copy_xstate_to_uabi_buf(to, tsk->thread.fpu.fpstate,
tsk->thread.fpu.fpstate->user_xfeatures,
tsk->thread.pkru, copy_mode); tsk->thread.pkru, copy_mode);
} }
......
...@@ -43,7 +43,8 @@ enum xstate_copy_mode { ...@@ -43,7 +43,8 @@ enum xstate_copy_mode {
struct membuf; struct membuf;
extern void __copy_xstate_to_uabi_buf(struct membuf to, struct fpstate *fpstate, extern void __copy_xstate_to_uabi_buf(struct membuf to, struct fpstate *fpstate,
u32 pkru_val, enum xstate_copy_mode copy_mode); u64 xfeatures, u32 pkru_val,
enum xstate_copy_mode copy_mode);
extern void copy_xstate_to_uabi_buf(struct membuf to, struct task_struct *tsk, extern void copy_xstate_to_uabi_buf(struct membuf to, struct task_struct *tsk,
enum xstate_copy_mode mode); enum xstate_copy_mode mode);
extern int copy_uabi_from_kernel_to_xstate(struct fpstate *fpstate, const void *kbuf, u32 *pkru); extern int copy_uabi_from_kernel_to_xstate(struct fpstate *fpstate, const void *kbuf, u32 *pkru);
......
...@@ -5382,26 +5382,23 @@ static int kvm_vcpu_ioctl_x86_set_debugregs(struct kvm_vcpu *vcpu, ...@@ -5382,26 +5382,23 @@ static int kvm_vcpu_ioctl_x86_set_debugregs(struct kvm_vcpu *vcpu,
return 0; return 0;
} }
static void kvm_vcpu_ioctl_x86_get_xsave(struct kvm_vcpu *vcpu,
struct kvm_xsave *guest_xsave) static void kvm_vcpu_ioctl_x86_get_xsave2(struct kvm_vcpu *vcpu,
u8 *state, unsigned int size)
{ {
if (fpstate_is_confidential(&vcpu->arch.guest_fpu)) if (fpstate_is_confidential(&vcpu->arch.guest_fpu))
return; return;
fpu_copy_guest_fpstate_to_uabi(&vcpu->arch.guest_fpu, fpu_copy_guest_fpstate_to_uabi(&vcpu->arch.guest_fpu, state, size,
guest_xsave->region, vcpu->arch.guest_fpu.fpstate->user_xfeatures,
sizeof(guest_xsave->region),
vcpu->arch.pkru); vcpu->arch.pkru);
} }
static void kvm_vcpu_ioctl_x86_get_xsave2(struct kvm_vcpu *vcpu, static void kvm_vcpu_ioctl_x86_get_xsave(struct kvm_vcpu *vcpu,
u8 *state, unsigned int size) struct kvm_xsave *guest_xsave)
{ {
if (fpstate_is_confidential(&vcpu->arch.guest_fpu)) return kvm_vcpu_ioctl_x86_get_xsave2(vcpu, (void *)guest_xsave->region,
return; sizeof(guest_xsave->region));
fpu_copy_guest_fpstate_to_uabi(&vcpu->arch.guest_fpu,
state, size, vcpu->arch.pkru);
} }
static int kvm_vcpu_ioctl_x86_set_xsave(struct kvm_vcpu *vcpu, static int kvm_vcpu_ioctl_x86_set_xsave(struct kvm_vcpu *vcpu,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment