| .. | .. |
|---|
| 5 | 5 | |
|---|
| 6 | 6 | #include <linux/compat.h> |
|---|
| 7 | 7 | #include <linux/cpu.h> |
|---|
| 8 | +#include <linux/pagemap.h> |
|---|
| 8 | 9 | |
|---|
| 9 | 10 | #include <asm/fpu/internal.h> |
|---|
| 10 | 11 | #include <asm/fpu/signal.h> |
|---|
| .. | .. |
|---|
| 61 | 62 | struct user_i387_ia32_struct env; |
|---|
| 62 | 63 | struct _fpstate_32 __user *fp = buf; |
|---|
| 63 | 64 | |
|---|
| 65 | + fpregs_lock(); |
|---|
| 66 | + if (!test_thread_flag(TIF_NEED_FPU_LOAD)) |
|---|
| 67 | + copy_fxregs_to_kernel(&tsk->thread.fpu); |
|---|
| 68 | + fpregs_unlock(); |
|---|
| 69 | + |
|---|
| 64 | 70 | convert_from_fxsr(&env, tsk); |
|---|
| 65 | 71 | |
|---|
| 66 | 72 | if (__copy_to_user(buf, &env, sizeof(env)) || |
|---|
| .. | .. |
|---|
| 92 | 98 | return err; |
|---|
| 93 | 99 | |
|---|
| 94 | 100 | err |= __put_user(FP_XSTATE_MAGIC2, |
|---|
| 95 | | - (__u32 *)(buf + fpu_user_xstate_size)); |
|---|
| 101 | + (__u32 __user *)(buf + fpu_user_xstate_size)); |
|---|
| 96 | 102 | |
|---|
| 97 | 103 | /* |
|---|
| 98 | 104 | * Read the xfeatures which we copied (directly from the cpu or |
|---|
| 99 | 105 | * from the state in task struct) to the user buffers. |
|---|
| 100 | 106 | */ |
|---|
| 101 | | - err |= __get_user(xfeatures, (__u32 *)&x->header.xfeatures); |
|---|
| 107 | + err |= __get_user(xfeatures, (__u32 __user *)&x->header.xfeatures); |
|---|
| 102 | 108 | |
|---|
| 103 | 109 | /* |
|---|
| 104 | 110 | * For legacy compatible, we always set FP/SSE bits in the bit |
|---|
| .. | .. |
|---|
| 113 | 119 | */ |
|---|
| 114 | 120 | xfeatures |= XFEATURE_MASK_FPSSE; |
|---|
| 115 | 121 | |
|---|
| 116 | | - err |= __put_user(xfeatures, (__u32 *)&x->header.xfeatures); |
|---|
| 122 | + err |= __put_user(xfeatures, (__u32 __user *)&x->header.xfeatures); |
|---|
| 117 | 123 | |
|---|
| 118 | 124 | return err; |
|---|
| 119 | 125 | } |
|---|
| .. | .. |
|---|
| 144 | 150 | * buf == buf_fx for 64-bit frames and 32-bit fsave frame. |
|---|
| 145 | 151 | * buf != buf_fx for 32-bit frames with fxstate. |
|---|
| 146 | 152 | * |
|---|
| 147 | | - * If the fpu, extended register state is live, save the state directly |
|---|
| 148 | | - * to the user frame pointed by the aligned pointer 'buf_fx'. Otherwise, |
|---|
| 149 | | - * copy the thread's fpu state to the user frame starting at 'buf_fx'. |
|---|
| 153 | + * Try to save it directly to the user frame with disabled page fault handler. |
|---|
| 154 | + * If this fails then do the slow path where the FPU state is first saved to |
|---|
| 155 | + * task's fpu->state and then copy it to the user frame pointed to by the |
|---|
| 156 | + * aligned pointer 'buf_fx'. |
|---|
| 150 | 157 | * |
|---|
| 151 | 158 | * If this is a 32-bit frame with fxstate, put a fsave header before |
|---|
| 152 | 159 | * the aligned state at 'buf_fx'. |
|---|
| .. | .. |
|---|
| 156 | 163 | */ |
|---|
| 157 | 164 | int copy_fpstate_to_sigframe(void __user *buf, void __user *buf_fx, int size) |
|---|
| 158 | 165 | { |
|---|
| 159 | | - struct fpu *fpu = ¤t->thread.fpu; |
|---|
| 160 | | - struct xregs_state *xsave = &fpu->state.xsave; |
|---|
| 161 | 166 | struct task_struct *tsk = current; |
|---|
| 162 | 167 | int ia32_fxstate = (buf != buf_fx); |
|---|
| 168 | + int ret; |
|---|
| 163 | 169 | |
|---|
| 164 | 170 | ia32_fxstate &= (IS_ENABLED(CONFIG_X86_32) || |
|---|
| 165 | 171 | IS_ENABLED(CONFIG_IA32_EMULATION)); |
|---|
| 166 | 172 | |
|---|
| 167 | | - if (!access_ok(VERIFY_WRITE, buf, size)) |
|---|
| 173 | + if (!static_cpu_has(X86_FEATURE_FPU)) { |
|---|
| 174 | + struct user_i387_ia32_struct fp; |
|---|
| 175 | + fpregs_soft_get(current, NULL, (struct membuf){.p = &fp, |
|---|
| 176 | + .left = sizeof(fp)}); |
|---|
| 177 | + return copy_to_user(buf, &fp, sizeof(fp)) ? -EFAULT : 0; |
|---|
| 178 | + } |
|---|
| 179 | + |
|---|
| 180 | + if (!access_ok(buf, size)) |
|---|
| 168 | 181 | return -EACCES; |
|---|
| 182 | +retry: |
|---|
| 183 | + /* |
|---|
| 184 | + * Load the FPU registers if they are not valid for the current task. |
|---|
| 185 | + * With a valid FPU state we can attempt to save the state directly to |
|---|
| 186 | + * userland's stack frame which will likely succeed. If it does not, |
|---|
| 187 | + * resolve the fault in the user memory and try again. |
|---|
| 188 | + */ |
|---|
| 189 | + fpregs_lock(); |
|---|
| 190 | + if (test_thread_flag(TIF_NEED_FPU_LOAD)) |
|---|
| 191 | + __fpregs_load_activate(); |
|---|
| 169 | 192 | |
|---|
| 170 | | - if (!static_cpu_has(X86_FEATURE_FPU)) |
|---|
| 171 | | - return fpregs_soft_get(current, NULL, 0, |
|---|
| 172 | | - sizeof(struct user_i387_ia32_struct), NULL, |
|---|
| 173 | | - (struct _fpstate_32 __user *) buf) ? -1 : 1; |
|---|
| 193 | + pagefault_disable(); |
|---|
| 194 | + ret = copy_fpregs_to_sigframe(buf_fx); |
|---|
| 195 | + pagefault_enable(); |
|---|
| 196 | + fpregs_unlock(); |
|---|
| 174 | 197 | |
|---|
| 175 | | - if (fpu->initialized || using_compacted_format()) { |
|---|
| 176 | | - /* Save the live register state to the user directly. */ |
|---|
| 177 | | - if (copy_fpregs_to_sigframe(buf_fx)) |
|---|
| 178 | | - return -1; |
|---|
| 179 | | - /* Update the thread's fxstate to save the fsave header. */ |
|---|
| 180 | | - if (ia32_fxstate) |
|---|
| 181 | | - copy_fxregs_to_kernel(fpu); |
|---|
| 182 | | - } else { |
|---|
| 183 | | - /* |
|---|
| 184 | | - * It is a *bug* if kernel uses compacted-format for xsave |
|---|
| 185 | | - * area and we copy it out directly to a signal frame. It |
|---|
| 186 | | - * should have been handled above by saving the registers |
|---|
| 187 | | - * directly. |
|---|
| 188 | | - */ |
|---|
| 189 | | - if (boot_cpu_has(X86_FEATURE_XSAVES)) { |
|---|
| 190 | | - WARN_ONCE(1, "x86/fpu: saving compacted-format xsave area to a signal frame!\n"); |
|---|
| 191 | | - return -1; |
|---|
| 192 | | - } |
|---|
| 193 | | - |
|---|
| 194 | | - fpstate_sanitize_xstate(fpu); |
|---|
| 195 | | - if (__copy_to_user(buf_fx, xsave, fpu_user_xstate_size)) |
|---|
| 196 | | - return -1; |
|---|
| 198 | + if (ret) { |
|---|
| 199 | + if (!fault_in_pages_writeable(buf_fx, fpu_user_xstate_size)) |
|---|
| 200 | + goto retry; |
|---|
| 201 | + return -EFAULT; |
|---|
| 197 | 202 | } |
|---|
| 198 | 203 | |
|---|
| 199 | 204 | /* Save the fsave header for the 32-bit frames. */ |
|---|
| .. | .. |
|---|
| 207 | 212 | } |
|---|
| 208 | 213 | |
|---|
| 209 | 214 | static inline void |
|---|
| 210 | | -sanitize_restored_xstate(struct task_struct *tsk, |
|---|
| 211 | | - struct user_i387_ia32_struct *ia32_env, |
|---|
| 212 | | - u64 xfeatures, int fx_only) |
|---|
| 215 | +sanitize_restored_user_xstate(union fpregs_state *state, |
|---|
| 216 | + struct user_i387_ia32_struct *ia32_env, |
|---|
| 217 | + u64 user_xfeatures, int fx_only) |
|---|
| 213 | 218 | { |
|---|
| 214 | | - struct xregs_state *xsave = &tsk->thread.fpu.state.xsave; |
|---|
| 219 | + struct xregs_state *xsave = &state->xsave; |
|---|
| 215 | 220 | struct xstate_header *header = &xsave->header; |
|---|
| 216 | 221 | |
|---|
| 217 | 222 | if (use_xsave()) { |
|---|
| 218 | 223 | /* |
|---|
| 219 | | - * Note: we don't need to zero the reserved bits in the |
|---|
| 220 | | - * xstate_header here because we either didn't copy them at all, |
|---|
| 221 | | - * or we checked earlier that they aren't set. |
|---|
| 224 | + * Clear all feature bits which are not set in |
|---|
| 225 | + * user_xfeatures and clear all extended features |
|---|
| 226 | + * for fx_only mode. |
|---|
| 222 | 227 | */ |
|---|
| 228 | + u64 mask = fx_only ? XFEATURE_MASK_FPSSE : user_xfeatures; |
|---|
| 223 | 229 | |
|---|
| 224 | 230 | /* |
|---|
| 225 | | - * Init the state that is not present in the memory |
|---|
| 226 | | - * layout and not enabled by the OS. |
|---|
| 231 | + * Supervisor state has to be preserved. The sigframe |
|---|
| 232 | + * restore can only modify user features, i.e. @mask |
|---|
| 233 | + * cannot contain them. |
|---|
| 227 | 234 | */ |
|---|
| 228 | | - if (fx_only) |
|---|
| 229 | | - header->xfeatures = XFEATURE_MASK_FPSSE; |
|---|
| 230 | | - else |
|---|
| 231 | | - header->xfeatures &= xfeatures; |
|---|
| 235 | + header->xfeatures &= mask | xfeatures_mask_supervisor(); |
|---|
| 232 | 236 | } |
|---|
| 233 | 237 | |
|---|
| 234 | 238 | if (use_fxsr()) { |
|---|
| .. | .. |
|---|
| 238 | 242 | */ |
|---|
| 239 | 243 | xsave->i387.mxcsr &= mxcsr_feature_mask; |
|---|
| 240 | 244 | |
|---|
| 241 | | - convert_to_fxsr(tsk, ia32_env); |
|---|
| 245 | + if (ia32_env) |
|---|
| 246 | + convert_to_fxsr(&state->fxsave, ia32_env); |
|---|
| 242 | 247 | } |
|---|
| 243 | 248 | } |
|---|
| 244 | 249 | |
|---|
| 245 | 250 | /* |
|---|
| 246 | 251 | * Restore the extended state if present. Otherwise, restore the FP/SSE state. |
|---|
| 247 | 252 | */ |
|---|
| 248 | | -static inline int copy_user_to_fpregs_zeroing(void __user *buf, u64 xbv, int fx_only) |
|---|
| 253 | +static int copy_user_to_fpregs_zeroing(void __user *buf, u64 xbv, int fx_only) |
|---|
| 249 | 254 | { |
|---|
| 255 | + u64 init_bv; |
|---|
| 256 | + int r; |
|---|
| 257 | + |
|---|
| 250 | 258 | if (use_xsave()) { |
|---|
| 251 | | - if ((unsigned long)buf % 64 || fx_only) { |
|---|
| 252 | | - u64 init_bv = xfeatures_mask & ~XFEATURE_MASK_FPSSE; |
|---|
| 253 | | - copy_kernel_to_xregs(&init_fpstate.xsave, init_bv); |
|---|
| 254 | | - return copy_user_to_fxregs(buf); |
|---|
| 255 | | - } else { |
|---|
| 256 | | - u64 init_bv = xfeatures_mask & ~xbv; |
|---|
| 257 | | - if (unlikely(init_bv)) |
|---|
| 259 | + if (fx_only) { |
|---|
| 260 | + init_bv = xfeatures_mask_user() & ~XFEATURE_MASK_FPSSE; |
|---|
| 261 | + |
|---|
| 262 | + r = copy_user_to_fxregs(buf); |
|---|
| 263 | + if (!r) |
|---|
| 258 | 264 | copy_kernel_to_xregs(&init_fpstate.xsave, init_bv); |
|---|
| 259 | | - return copy_user_to_xregs(buf, xbv); |
|---|
| 265 | + return r; |
|---|
| 266 | + } else { |
|---|
| 267 | + init_bv = xfeatures_mask_user() & ~xbv; |
|---|
| 268 | + |
|---|
| 269 | + r = copy_user_to_xregs(buf, xbv); |
|---|
| 270 | + if (!r && unlikely(init_bv)) |
|---|
| 271 | + copy_kernel_to_xregs(&init_fpstate.xsave, init_bv); |
|---|
| 272 | + return r; |
|---|
| 260 | 273 | } |
|---|
| 261 | 274 | } else if (use_fxsr()) { |
|---|
| 262 | 275 | return copy_user_to_fxregs(buf); |
|---|
| .. | .. |
|---|
| 266 | 279 | |
|---|
| 267 | 280 | static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size) |
|---|
| 268 | 281 | { |
|---|
| 282 | + struct user_i387_ia32_struct *envp = NULL; |
|---|
| 283 | + int state_size = fpu_kernel_xstate_size; |
|---|
| 269 | 284 | int ia32_fxstate = (buf != buf_fx); |
|---|
| 270 | 285 | struct task_struct *tsk = current; |
|---|
| 271 | 286 | struct fpu *fpu = &tsk->thread.fpu; |
|---|
| 272 | | - int state_size = fpu_kernel_xstate_size; |
|---|
| 273 | | - u64 xfeatures = 0; |
|---|
| 287 | + struct user_i387_ia32_struct env; |
|---|
| 288 | + u64 user_xfeatures = 0; |
|---|
| 274 | 289 | int fx_only = 0; |
|---|
| 275 | 290 | int ret = 0; |
|---|
| 276 | 291 | |
|---|
| .. | .. |
|---|
| 278 | 293 | IS_ENABLED(CONFIG_IA32_EMULATION)); |
|---|
| 279 | 294 | |
|---|
| 280 | 295 | if (!buf) { |
|---|
| 281 | | - fpu__clear(fpu); |
|---|
| 296 | + fpu__clear_user_states(fpu); |
|---|
| 282 | 297 | return 0; |
|---|
| 283 | 298 | } |
|---|
| 284 | 299 | |
|---|
| 285 | | - if (!access_ok(VERIFY_READ, buf, size)) { |
|---|
| 300 | + if (!access_ok(buf, size)) { |
|---|
| 286 | 301 | ret = -EACCES; |
|---|
| 287 | | - goto out_err; |
|---|
| 302 | + goto out; |
|---|
| 288 | 303 | } |
|---|
| 289 | | - |
|---|
| 290 | | - fpu__initialize(fpu); |
|---|
| 291 | 304 | |
|---|
| 292 | 305 | if (!static_cpu_has(X86_FEATURE_FPU)) { |
|---|
| 293 | | - ret = fpregs_soft_set(current, NULL, |
|---|
| 294 | | - 0, sizeof(struct user_i387_ia32_struct), |
|---|
| 295 | | - NULL, buf) != 0; |
|---|
| 296 | | - if (ret) |
|---|
| 297 | | - goto out_err; |
|---|
| 298 | | - return 0; |
|---|
| 306 | + ret = fpregs_soft_set(current, NULL, 0, |
|---|
| 307 | + sizeof(struct user_i387_ia32_struct), |
|---|
| 308 | + NULL, buf); |
|---|
| 309 | + goto out; |
|---|
| 299 | 310 | } |
|---|
| 300 | 311 | |
|---|
| 301 | 312 | if (use_xsave()) { |
|---|
| .. | .. |
|---|
| 311 | 322 | trace_x86_fpu_xstate_check_failed(fpu); |
|---|
| 312 | 323 | } else { |
|---|
| 313 | 324 | state_size = fx_sw_user.xstate_size; |
|---|
| 314 | | - xfeatures = fx_sw_user.xfeatures; |
|---|
| 325 | + user_xfeatures = fx_sw_user.xfeatures; |
|---|
| 315 | 326 | } |
|---|
| 316 | 327 | } |
|---|
| 317 | 328 | |
|---|
| 318 | | - if (ia32_fxstate) { |
|---|
| 329 | + if ((unsigned long)buf_fx % 64) |
|---|
| 330 | + fx_only = 1; |
|---|
| 331 | + |
|---|
| 332 | + if (!ia32_fxstate) { |
|---|
| 319 | 333 | /* |
|---|
| 320 | | - * For 32-bit frames with fxstate, copy the user state to the |
|---|
| 321 | | - * thread's fpu state, reconstruct fxstate from the fsave |
|---|
| 322 | | - * header. Validate and sanitize the copied state. |
|---|
| 334 | + * Attempt to restore the FPU registers directly from user |
|---|
| 335 | + * memory. For that to succeed, the user access cannot cause |
|---|
| 336 | + * page faults. If it does, fall back to the slow path below, |
|---|
| 337 | + * going through the kernel buffer with the enabled pagefault |
|---|
| 338 | + * handler. |
|---|
| 323 | 339 | */ |
|---|
| 324 | | - struct user_i387_ia32_struct env; |
|---|
| 325 | | - int err = 0; |
|---|
| 340 | + fpregs_lock(); |
|---|
| 341 | + pagefault_disable(); |
|---|
| 342 | + ret = copy_user_to_fpregs_zeroing(buf_fx, user_xfeatures, fx_only); |
|---|
| 343 | + pagefault_enable(); |
|---|
| 344 | + if (!ret) { |
|---|
| 326 | 345 | |
|---|
| 327 | | - /* |
|---|
| 328 | | - * Drop the current fpu which clears fpu->initialized. This ensures |
|---|
| 329 | | - * that any context-switch during the copy of the new state, |
|---|
| 330 | | - * avoids the intermediate state from getting restored/saved. |
|---|
| 331 | | - * Thus avoiding the new restored state from getting corrupted. |
|---|
| 332 | | - * We will be ready to restore/save the state only after |
|---|
| 333 | | - * fpu->initialized is again set. |
|---|
| 334 | | - */ |
|---|
| 335 | | - fpu__drop(fpu); |
|---|
| 336 | | - |
|---|
| 337 | | - if (using_compacted_format()) { |
|---|
| 338 | | - err = copy_user_to_xstate(&fpu->state.xsave, buf_fx); |
|---|
| 339 | | - } else { |
|---|
| 340 | | - err = __copy_from_user(&fpu->state.xsave, buf_fx, state_size); |
|---|
| 341 | | - |
|---|
| 342 | | - if (!err && state_size > offsetof(struct xregs_state, header)) |
|---|
| 343 | | - err = validate_xstate_header(&fpu->state.xsave.header); |
|---|
| 346 | + /* |
|---|
| 347 | + * Restore supervisor states: previous context switch |
|---|
| 348 | + * etc has done XSAVES and saved the supervisor states |
|---|
| 349 | + * in the kernel buffer from which they can be restored |
|---|
| 350 | + * now. |
|---|
| 351 | + * |
|---|
| 352 | + * We cannot do a single XRSTORS here - which would |
|---|
| 353 | + * be nice - because the rest of the FPU registers are |
|---|
| 354 | + * being restored from a user buffer directly. The |
|---|
| 355 | + * single XRSTORS happens below, when the user buffer |
|---|
| 356 | + * has been copied to the kernel one. |
|---|
| 357 | + */ |
|---|
| 358 | + if (test_thread_flag(TIF_NEED_FPU_LOAD) && |
|---|
| 359 | + xfeatures_mask_supervisor()) |
|---|
| 360 | + copy_kernel_to_xregs(&fpu->state.xsave, |
|---|
| 361 | + xfeatures_mask_supervisor()); |
|---|
| 362 | + fpregs_mark_activate(); |
|---|
| 363 | + fpregs_unlock(); |
|---|
| 364 | + return 0; |
|---|
| 344 | 365 | } |
|---|
| 345 | 366 | |
|---|
| 346 | | - if (err || __copy_from_user(&env, buf, sizeof(env))) { |
|---|
| 347 | | - fpstate_init(&fpu->state); |
|---|
| 348 | | - trace_x86_fpu_init_state(fpu); |
|---|
| 349 | | - err = -1; |
|---|
| 350 | | - } else { |
|---|
| 351 | | - sanitize_restored_xstate(tsk, &env, xfeatures, fx_only); |
|---|
| 352 | | - } |
|---|
| 367 | + /* |
|---|
| 368 | + * The above did an FPU restore operation, restricted to |
|---|
| 369 | + * the user portion of the registers, and failed, but the |
|---|
| 370 | + * microcode might have modified the FPU registers |
|---|
| 371 | + * nevertheless. |
|---|
| 372 | + * |
|---|
| 373 | + * If the FPU registers do not belong to current, then |
|---|
| 374 | + * invalidate the FPU register state otherwise the task might |
|---|
| 375 | + * preempt current and return to user space with corrupted |
|---|
| 376 | + * FPU registers. |
|---|
| 377 | + * |
|---|
| 378 | + * In case current owns the FPU registers then no further |
|---|
| 379 | + * action is required. The fixup below will handle it |
|---|
| 380 | + * correctly. |
|---|
| 381 | + */ |
|---|
| 382 | + if (test_thread_flag(TIF_NEED_FPU_LOAD)) |
|---|
| 383 | + __cpu_invalidate_fpregs_state(); |
|---|
| 353 | 384 | |
|---|
| 354 | | - local_bh_disable(); |
|---|
| 355 | | - fpu->initialized = 1; |
|---|
| 356 | | - fpu__restore(fpu); |
|---|
| 357 | | - local_bh_enable(); |
|---|
| 358 | | - |
|---|
| 359 | | - /* Failure is already handled */ |
|---|
| 360 | | - return err; |
|---|
| 385 | + fpregs_unlock(); |
|---|
| 361 | 386 | } else { |
|---|
| 362 | 387 | /* |
|---|
| 363 | | - * For 64-bit frames and 32-bit fsave frames, restore the user |
|---|
| 364 | | - * state to the registers directly (with exceptions handled). |
|---|
| 388 | + * For 32-bit frames with fxstate, copy the fxstate so it can |
|---|
| 389 | + * be reconstructed later. |
|---|
| 365 | 390 | */ |
|---|
| 366 | | - user_fpu_begin(); |
|---|
| 367 | | - if (!copy_user_to_fpregs_zeroing(buf_fx, xfeatures, fx_only)) |
|---|
| 368 | | - return 0; |
|---|
| 369 | | - ret = -1; |
|---|
| 391 | + ret = __copy_from_user(&env, buf, sizeof(env)); |
|---|
| 392 | + if (ret) |
|---|
| 393 | + goto out; |
|---|
| 394 | + envp = &env; |
|---|
| 370 | 395 | } |
|---|
| 371 | 396 | |
|---|
| 372 | | -out_err: |
|---|
| 373 | | - fpu__clear(fpu); |
|---|
| 397 | + /* |
|---|
| 398 | + * By setting TIF_NEED_FPU_LOAD it is ensured that our xstate is |
|---|
| 399 | + * not modified on context switch and that the xstate is considered |
|---|
| 400 | + * to be loaded again on return to userland (overriding last_cpu avoids |
|---|
| 401 | + * the optimisation). |
|---|
| 402 | + */ |
|---|
| 403 | + fpregs_lock(); |
|---|
| 404 | + |
|---|
| 405 | + if (!test_thread_flag(TIF_NEED_FPU_LOAD)) { |
|---|
| 406 | + |
|---|
| 407 | + /* |
|---|
| 408 | + * Supervisor states are not modified by user space input. Save |
|---|
| 409 | + * current supervisor states first and invalidate the FPU regs. |
|---|
| 410 | + */ |
|---|
| 411 | + if (xfeatures_mask_supervisor()) |
|---|
| 412 | + copy_supervisor_to_kernel(&fpu->state.xsave); |
|---|
| 413 | + set_thread_flag(TIF_NEED_FPU_LOAD); |
|---|
| 414 | + } |
|---|
| 415 | + __fpu_invalidate_fpregs_state(fpu); |
|---|
| 416 | + fpregs_unlock(); |
|---|
| 417 | + |
|---|
| 418 | + if (use_xsave() && !fx_only) { |
|---|
| 419 | + u64 init_bv = xfeatures_mask_user() & ~user_xfeatures; |
|---|
| 420 | + |
|---|
| 421 | + ret = copy_user_to_xstate(&fpu->state.xsave, buf_fx); |
|---|
| 422 | + if (ret) |
|---|
| 423 | + goto out; |
|---|
| 424 | + |
|---|
| 425 | + sanitize_restored_user_xstate(&fpu->state, envp, user_xfeatures, |
|---|
| 426 | + fx_only); |
|---|
| 427 | + |
|---|
| 428 | + fpregs_lock(); |
|---|
| 429 | + if (unlikely(init_bv)) |
|---|
| 430 | + copy_kernel_to_xregs(&init_fpstate.xsave, init_bv); |
|---|
| 431 | + |
|---|
| 432 | + /* |
|---|
| 433 | + * Restore previously saved supervisor xstates along with |
|---|
| 434 | + * copied-in user xstates. |
|---|
| 435 | + */ |
|---|
| 436 | + ret = copy_kernel_to_xregs_err(&fpu->state.xsave, |
|---|
| 437 | + user_xfeatures | xfeatures_mask_supervisor()); |
|---|
| 438 | + |
|---|
| 439 | + } else if (use_fxsr()) { |
|---|
| 440 | + ret = __copy_from_user(&fpu->state.fxsave, buf_fx, state_size); |
|---|
| 441 | + if (ret) { |
|---|
| 442 | + ret = -EFAULT; |
|---|
| 443 | + goto out; |
|---|
| 444 | + } |
|---|
| 445 | + |
|---|
| 446 | + sanitize_restored_user_xstate(&fpu->state, envp, user_xfeatures, |
|---|
| 447 | + fx_only); |
|---|
| 448 | + |
|---|
| 449 | + fpregs_lock(); |
|---|
| 450 | + if (use_xsave()) { |
|---|
| 451 | + u64 init_bv; |
|---|
| 452 | + |
|---|
| 453 | + init_bv = xfeatures_mask_user() & ~XFEATURE_MASK_FPSSE; |
|---|
| 454 | + copy_kernel_to_xregs(&init_fpstate.xsave, init_bv); |
|---|
| 455 | + } |
|---|
| 456 | + |
|---|
| 457 | + ret = copy_kernel_to_fxregs_err(&fpu->state.fxsave); |
|---|
| 458 | + } else { |
|---|
| 459 | + ret = __copy_from_user(&fpu->state.fsave, buf_fx, state_size); |
|---|
| 460 | + if (ret) |
|---|
| 461 | + goto out; |
|---|
| 462 | + |
|---|
| 463 | + fpregs_lock(); |
|---|
| 464 | + ret = copy_kernel_to_fregs_err(&fpu->state.fsave); |
|---|
| 465 | + } |
|---|
| 466 | + if (!ret) |
|---|
| 467 | + fpregs_mark_activate(); |
|---|
| 468 | + else |
|---|
| 469 | + fpregs_deactivate(fpu); |
|---|
| 470 | + fpregs_unlock(); |
|---|
| 471 | + |
|---|
| 472 | +out: |
|---|
| 473 | + if (ret) |
|---|
| 474 | + fpu__clear_user_states(fpu); |
|---|
| 374 | 475 | return ret; |
|---|
| 375 | 476 | } |
|---|
| 376 | 477 | |
|---|
| .. | .. |
|---|
| 425 | 526 | |
|---|
| 426 | 527 | fx_sw_reserved.magic1 = FP_XSTATE_MAGIC1; |
|---|
| 427 | 528 | fx_sw_reserved.extended_size = size; |
|---|
| 428 | | - fx_sw_reserved.xfeatures = xfeatures_mask; |
|---|
| 529 | + fx_sw_reserved.xfeatures = xfeatures_mask_user(); |
|---|
| 429 | 530 | fx_sw_reserved.xstate_size = fpu_user_xstate_size; |
|---|
| 430 | 531 | |
|---|
| 431 | 532 | if (IS_ENABLED(CONFIG_IA32_EMULATION) || |
|---|