Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

x86/fpu: Add address range checks to copy_user_to_xstate()

copy_user_to_xstate() uses __copy_from_user(), which provides a negligible
speedup. Fortunately, both call sites are at least almost correct.

__fpu__restore_sig() checks access_ok() with xstate_sigframe_size()
length and ptrace regset access uses fpu_user_xstate_size. These should
be valid upper bounds on the length, so, at worst, this would cause
spurious failures and not accesses to kernel memory.

Nonetheless, this is far more fragile than necessary and none of these
callers are in a hotpath.

Use copy_from_user() instead.

Signed-off-by: Andy Lutomirski <luto@kernel.org>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Borislav Petkov <bp@suse.de>
Acked-by: Dave Hansen <dave.hansen@linux.intel.com>
Acked-by: Rik van Riel <riel@surriel.com>
Link: https://lkml.kernel.org/r/20210608144346.140254130@linutronix.de

authored by

Andy Lutomirski and committed by
Borislav Petkov
f72a249b 8919f072

+3 -3
+3 -3
arch/x86/kernel/fpu/xstate.c
··· 1190 1190 offset = offsetof(struct xregs_state, header); 1191 1191 size = sizeof(hdr); 1192 1192 1193 - if (__copy_from_user(&hdr, ubuf + offset, size)) 1193 + if (copy_from_user(&hdr, ubuf + offset, size)) 1194 1194 return -EFAULT; 1195 1195 1196 1196 if (validate_user_xstate_header(&hdr)) ··· 1205 1205 offset = xstate_offsets[i]; 1206 1206 size = xstate_sizes[i]; 1207 1207 1208 - if (__copy_from_user(dst, ubuf + offset, size)) 1208 + if (copy_from_user(dst, ubuf + offset, size)) 1209 1209 return -EFAULT; 1210 1210 } 1211 1211 } ··· 1213 1213 if (xfeatures_mxcsr_quirk(hdr.xfeatures)) { 1214 1214 offset = offsetof(struct fxregs_state, mxcsr); 1215 1215 size = MXCSR_AND_FLAGS_SIZE; 1216 - if (__copy_from_user(&xsave->i387.mxcsr, ubuf + offset, size)) 1216 + if (copy_from_user(&xsave->i387.mxcsr, ubuf + offset, size)) 1217 1217 return -EFAULT; 1218 1218 } 1219 1219