]>
Commit | Line | Data |
---|---|---|
6d825fcf TL |
1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 |
2 | From: Sean Christopherson <seanjc@google.com> | |
3 | Date: Wed, 27 Sep 2023 17:19:52 -0700 | |
4 | Subject: [PATCH] x86/fpu: Allow caller to constrain xfeatures when copying to | |
5 | uabi buffer | |
6 | ||
7 | Plumb an xfeatures mask into __copy_xstate_to_uabi_buf() so that KVM can | |
8 | constrain which xfeatures are saved into the userspace buffer without | |
9 | having to modify the user_xfeatures field in KVM's guest_fpu state. | |
10 | ||
11 | KVM's ABI for KVM_GET_XSAVE{2} is that features that are not exposed to | |
12 | guest must not show up in the effective xstate_bv field of the buffer. | |
13 | Saving only the guest-supported xfeatures allows userspace to load the | |
14 | saved state on a different host with a fewer xfeatures, so long as the | |
15 | target host supports the xfeatures that are exposed to the guest. | |
16 | ||
17 | KVM currently sets user_xfeatures directly to restrict KVM_GET_XSAVE{2} to | |
18 | the set of guest-supported xfeatures, but doing so broke KVM's historical | |
19 | ABI for KVM_SET_XSAVE, which allows userspace to load any xfeatures that | |
20 | are supported by the *host*. | |
21 | ||
22 | Cc: stable@vger.kernel.org | |
23 | Signed-off-by: Sean Christopherson <seanjc@google.com> | |
24 | Message-Id: <20230928001956.924301-2-seanjc@google.com> | |
25 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> | |
26 | (cherry picked from commit 18164f66e6c59fda15c198b371fa008431efdb22) | |
27 | Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com> | |
28 | --- | |
29 | arch/x86/include/asm/fpu/api.h | 3 ++- | |
30 | arch/x86/kernel/fpu/core.c | 5 +++-- | |
31 | arch/x86/kernel/fpu/xstate.c | 7 +++++-- | |
32 | arch/x86/kernel/fpu/xstate.h | 3 ++- | |
33 | arch/x86/kvm/x86.c | 21 +++++++++------------ | |
34 | 5 files changed, 21 insertions(+), 18 deletions(-) | |
35 | ||
36 | diff --git a/arch/x86/include/asm/fpu/api.h b/arch/x86/include/asm/fpu/api.h | |
37 | index b475d9a582b8..e829fa4c6788 100644 | |
38 | --- a/arch/x86/include/asm/fpu/api.h | |
39 | +++ b/arch/x86/include/asm/fpu/api.h | |
40 | @@ -148,7 +148,8 @@ static inline void fpu_update_guest_xfd(struct fpu_guest *guest_fpu, u64 xfd) { | |
41 | static inline void fpu_sync_guest_vmexit_xfd_state(void) { } | |
42 | #endif | |
43 | ||
44 | -extern void fpu_copy_guest_fpstate_to_uabi(struct fpu_guest *gfpu, void *buf, unsigned int size, u32 pkru); | |
45 | +extern void fpu_copy_guest_fpstate_to_uabi(struct fpu_guest *gfpu, void *buf, | |
46 | + unsigned int size, u64 xfeatures, u32 pkru); | |
47 | extern int fpu_copy_uabi_to_guest_fpstate(struct fpu_guest *gfpu, const void *buf, u64 xcr0, u32 *vpkru); | |
48 | ||
49 | static inline void fpstate_set_confidential(struct fpu_guest *gfpu) | |
50 | diff --git a/arch/x86/kernel/fpu/core.c b/arch/x86/kernel/fpu/core.c | |
ddd91a3b | 51 | index a083f9ac9e4f..1d190761d00f 100644 |
6d825fcf TL |
52 | --- a/arch/x86/kernel/fpu/core.c |
53 | +++ b/arch/x86/kernel/fpu/core.c | |
54 | @@ -369,14 +369,15 @@ int fpu_swap_kvm_fpstate(struct fpu_guest *guest_fpu, bool enter_guest) | |
55 | EXPORT_SYMBOL_GPL(fpu_swap_kvm_fpstate); | |
56 | ||
57 | void fpu_copy_guest_fpstate_to_uabi(struct fpu_guest *gfpu, void *buf, | |
58 | - unsigned int size, u32 pkru) | |
59 | + unsigned int size, u64 xfeatures, u32 pkru) | |
60 | { | |
61 | struct fpstate *kstate = gfpu->fpstate; | |
62 | union fpregs_state *ustate = buf; | |
63 | struct membuf mb = { .p = buf, .left = size }; | |
64 | ||
65 | if (cpu_feature_enabled(X86_FEATURE_XSAVE)) { | |
66 | - __copy_xstate_to_uabi_buf(mb, kstate, pkru, XSTATE_COPY_XSAVE); | |
67 | + __copy_xstate_to_uabi_buf(mb, kstate, xfeatures, pkru, | |
68 | + XSTATE_COPY_XSAVE); | |
69 | } else { | |
70 | memcpy(&ustate->fxsave, &kstate->regs.fxsave, | |
71 | sizeof(ustate->fxsave)); | |
72 | diff --git a/arch/x86/kernel/fpu/xstate.c b/arch/x86/kernel/fpu/xstate.c | |
73 | index 1afbc4866b10..463ec0cd0dab 100644 | |
74 | --- a/arch/x86/kernel/fpu/xstate.c | |
75 | +++ b/arch/x86/kernel/fpu/xstate.c | |
76 | @@ -1053,6 +1053,7 @@ static void copy_feature(bool from_xstate, struct membuf *to, void *xstate, | |
77 | * __copy_xstate_to_uabi_buf - Copy kernel saved xstate to a UABI buffer | |
78 | * @to: membuf descriptor | |
79 | * @fpstate: The fpstate buffer from which to copy | |
80 | + * @xfeatures: The mask of xfeatures to save (XSAVE mode only) | |
81 | * @pkru_val: The PKRU value to store in the PKRU component | |
82 | * @copy_mode: The requested copy mode | |
83 | * | |
84 | @@ -1063,7 +1064,8 @@ static void copy_feature(bool from_xstate, struct membuf *to, void *xstate, | |
85 | * It supports partial copy but @to.pos always starts from zero. | |
86 | */ | |
87 | void __copy_xstate_to_uabi_buf(struct membuf to, struct fpstate *fpstate, | |
88 | - u32 pkru_val, enum xstate_copy_mode copy_mode) | |
89 | + u64 xfeatures, u32 pkru_val, | |
90 | + enum xstate_copy_mode copy_mode) | |
91 | { | |
92 | const unsigned int off_mxcsr = offsetof(struct fxregs_state, mxcsr); | |
93 | struct xregs_state *xinit = &init_fpstate.regs.xsave; | |
94 | @@ -1087,7 +1089,7 @@ void __copy_xstate_to_uabi_buf(struct membuf to, struct fpstate *fpstate, | |
95 | break; | |
96 | ||
97 | case XSTATE_COPY_XSAVE: | |
98 | - header.xfeatures &= fpstate->user_xfeatures; | |
99 | + header.xfeatures &= fpstate->user_xfeatures & xfeatures; | |
100 | break; | |
101 | } | |
102 | ||
103 | @@ -1189,6 +1191,7 @@ void copy_xstate_to_uabi_buf(struct membuf to, struct task_struct *tsk, | |
104 | enum xstate_copy_mode copy_mode) | |
105 | { | |
106 | __copy_xstate_to_uabi_buf(to, tsk->thread.fpu.fpstate, | |
107 | + tsk->thread.fpu.fpstate->user_xfeatures, | |
108 | tsk->thread.pkru, copy_mode); | |
109 | } | |
110 | ||
111 | diff --git a/arch/x86/kernel/fpu/xstate.h b/arch/x86/kernel/fpu/xstate.h | |
112 | index a4ecb04d8d64..3518fb26d06b 100644 | |
113 | --- a/arch/x86/kernel/fpu/xstate.h | |
114 | +++ b/arch/x86/kernel/fpu/xstate.h | |
115 | @@ -43,7 +43,8 @@ enum xstate_copy_mode { | |
116 | ||
117 | struct membuf; | |
118 | extern void __copy_xstate_to_uabi_buf(struct membuf to, struct fpstate *fpstate, | |
119 | - u32 pkru_val, enum xstate_copy_mode copy_mode); | |
120 | + u64 xfeatures, u32 pkru_val, | |
121 | + enum xstate_copy_mode copy_mode); | |
122 | extern void copy_xstate_to_uabi_buf(struct membuf to, struct task_struct *tsk, | |
123 | enum xstate_copy_mode mode); | |
124 | extern int copy_uabi_from_kernel_to_xstate(struct fpstate *fpstate, const void *kbuf, u32 *pkru); | |
125 | diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c | |
126 | index ff92ff41d5ce..a43a950d04cb 100644 | |
127 | --- a/arch/x86/kvm/x86.c | |
128 | +++ b/arch/x86/kvm/x86.c | |
129 | @@ -5314,26 +5314,23 @@ static int kvm_vcpu_ioctl_x86_set_debugregs(struct kvm_vcpu *vcpu, | |
130 | return 0; | |
131 | } | |
132 | ||
133 | -static void kvm_vcpu_ioctl_x86_get_xsave(struct kvm_vcpu *vcpu, | |
134 | - struct kvm_xsave *guest_xsave) | |
135 | + | |
136 | +static void kvm_vcpu_ioctl_x86_get_xsave2(struct kvm_vcpu *vcpu, | |
137 | + u8 *state, unsigned int size) | |
138 | { | |
139 | if (fpstate_is_confidential(&vcpu->arch.guest_fpu)) | |
140 | return; | |
141 | ||
142 | - fpu_copy_guest_fpstate_to_uabi(&vcpu->arch.guest_fpu, | |
143 | - guest_xsave->region, | |
144 | - sizeof(guest_xsave->region), | |
145 | + fpu_copy_guest_fpstate_to_uabi(&vcpu->arch.guest_fpu, state, size, | |
146 | + vcpu->arch.guest_fpu.fpstate->user_xfeatures, | |
147 | vcpu->arch.pkru); | |
148 | } | |
149 | ||
150 | -static void kvm_vcpu_ioctl_x86_get_xsave2(struct kvm_vcpu *vcpu, | |
151 | - u8 *state, unsigned int size) | |
152 | +static void kvm_vcpu_ioctl_x86_get_xsave(struct kvm_vcpu *vcpu, | |
153 | + struct kvm_xsave *guest_xsave) | |
154 | { | |
155 | - if (fpstate_is_confidential(&vcpu->arch.guest_fpu)) | |
156 | - return; | |
157 | - | |
158 | - fpu_copy_guest_fpstate_to_uabi(&vcpu->arch.guest_fpu, | |
159 | - state, size, vcpu->arch.pkru); | |
160 | + return kvm_vcpu_ioctl_x86_get_xsave2(vcpu, (void *)guest_xsave->region, | |
161 | + sizeof(guest_xsave->region)); | |
162 | } | |
163 | ||
164 | static int kvm_vcpu_ioctl_x86_set_xsave(struct kvm_vcpu *vcpu, |