copy_xstate_to_kernel(): don't leave parts of destination uninitialized

copy the corresponding pieces of init_fpstate into the gaps instead.

Cc: stable@kernel.org
Tested-by: Alexander Potapenko <glider@google.com>
Acked-by: Borislav Petkov <bp@suse.de>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>

Al Viro 9e463654 4e89b721

Changed files
+48 -38
arch
x86
kernel
fpu
+48 -38
arch/x86/kernel/fpu/xstate.c
··· 957 957 return true; 958 958 } 959 959 960 - /* 961 - * This is similar to user_regset_copyout(), but will not add offset to 962 - * the source data pointer or increment pos, count, kbuf, and ubuf. 963 - */ 964 - static inline void 965 - __copy_xstate_to_kernel(void *kbuf, const void *data, 966 - unsigned int offset, unsigned int size, unsigned int size_total) 960 + static void fill_gap(unsigned to, void **kbuf, unsigned *pos, unsigned *count) 967 961 { 968 - if (offset < size_total) { 969 - unsigned int copy = min(size, size_total - offset); 962 + if (*pos < to) { 963 + unsigned size = to - *pos; 970 964 971 - memcpy(kbuf + offset, data, copy); 965 + if (size > *count) 966 + size = *count; 967 + memcpy(*kbuf, (void *)&init_fpstate.xsave + *pos, size); 968 + *kbuf += size; 969 + *pos += size; 970 + *count -= size; 971 + } 972 + } 973 + 974 + static void copy_part(unsigned offset, unsigned size, void *from, 975 + void **kbuf, unsigned *pos, unsigned *count) 976 + { 977 + fill_gap(offset, kbuf, pos, count); 978 + if (size > *count) 979 + size = *count; 980 + if (size) { 981 + memcpy(*kbuf, from, size); 982 + *kbuf += size; 983 + *pos += size; 984 + *count -= size; 972 985 } 973 986 } 974 987 ··· 994 981 */ 995 982 int copy_xstate_to_kernel(void *kbuf, struct xregs_state *xsave, unsigned int offset_start, unsigned int size_total) 996 983 { 997 - unsigned int offset, size; 998 984 struct xstate_header header; 985 + const unsigned off_mxcsr = offsetof(struct fxregs_state, mxcsr); 986 + unsigned count = size_total; 999 987 int i; 1000 988 1001 989 /* ··· 1012 998 header.xfeatures = xsave->header.xfeatures; 1013 999 header.xfeatures &= ~XFEATURE_MASK_SUPERVISOR; 1014 1000 1001 + if (header.xfeatures & XFEATURE_MASK_FP) 1002 + copy_part(0, off_mxcsr, 1003 + &xsave->i387, &kbuf, &offset_start, &count); 1004 + if (header.xfeatures & (XFEATURE_MASK_SSE | XFEATURE_MASK_YMM)) 1005 + copy_part(off_mxcsr, MXCSR_AND_FLAGS_SIZE, 1006 + &xsave->i387.mxcsr, &kbuf, &offset_start, &count); 1007 + if (header.xfeatures & XFEATURE_MASK_FP) 1008 + copy_part(offsetof(struct fxregs_state, st_space), 128, 1009 + &xsave->i387.st_space, &kbuf, &offset_start, &count); 1010 + if (header.xfeatures & XFEATURE_MASK_SSE) 1011 + copy_part(xstate_offsets[XFEATURE_MASK_SSE], 256, 1012 + &xsave->i387.xmm_space, &kbuf, &offset_start, &count); 1013 + /* 1014 + * Fill xsave->i387.sw_reserved value for ptrace frame: 1015 + */ 1016 + copy_part(offsetof(struct fxregs_state, sw_reserved), 48, 1017 + xstate_fx_sw_bytes, &kbuf, &offset_start, &count); 1015 1018 /* 1016 1019 * Copy xregs_state->header: 1017 1020 */ 1018 - offset = offsetof(struct xregs_state, header); 1019 - size = sizeof(header); 1021 + copy_part(offsetof(struct xregs_state, header), sizeof(header), 1022 + &header, &kbuf, &offset_start, &count); 1020 1023 1021 - __copy_xstate_to_kernel(kbuf, &header, offset, size, size_total); 1022 - 1023 - for (i = 0; i < XFEATURE_MAX; i++) { 1024 + for (i = FIRST_EXTENDED_XFEATURE; i < XFEATURE_MAX; i++) { 1024 1025 /* 1025 1026 * Copy only in-use xstates: 1026 1027 */ 1027 1028 if ((header.xfeatures >> i) & 1) { 1028 1029 void *src = __raw_xsave_addr(xsave, i); 1029 1030 1030 - offset = xstate_offsets[i]; 1031 - size = xstate_sizes[i]; 1032 - 1033 - /* The next component has to fit fully into the output buffer: */ 1034 - if (offset + size > size_total) 1035 - break; 1036 - 1037 - __copy_xstate_to_kernel(kbuf, src, offset, size, size_total); 1031 + copy_part(xstate_offsets[i], xstate_sizes[i], 1032 + src, &kbuf, &offset_start, &count); 1038 1033 } 1039 1034 1040 1035 } 1041 - 1042 - if (xfeatures_mxcsr_quirk(header.xfeatures)) { 1043 - offset = offsetof(struct fxregs_state, mxcsr); 1044 - size = MXCSR_AND_FLAGS_SIZE; 1045 - __copy_xstate_to_kernel(kbuf, &xsave->i387.mxcsr, offset, size, size_total); 1046 - } 1047 - 1048 - /* 1049 - * Fill xsave->i387.sw_reserved value for ptrace frame: 1050 - */ 1051 - offset = offsetof(struct fxregs_state, sw_reserved); 1052 - size = sizeof(xstate_fx_sw_bytes); 1053 - 1054 - __copy_xstate_to_kernel(kbuf, xstate_fx_sw_bytes, offset, size, size_total); 1036 + fill_gap(size_total, &kbuf, &offset_start, &count); 1055 1037 1056 1038 return 0; 1057 1039 }