Skip to content

Commit 9e46365

Browse files
author
Al Viro
committed
copy_xstate_to_kernel(): don't leave parts of destination uninitialized
copy the corresponding pieces of init_fpstate into the gaps instead. Cc: [email protected] Tested-by: Alexander Potapenko <[email protected]> Acked-by: Borislav Petkov <[email protected]> Signed-off-by: Al Viro <[email protected]>
1 parent 4e89b72 commit 9e46365

File tree

1 file changed

+48
-38
lines changed

1 file changed

+48
-38
lines changed

arch/x86/kernel/fpu/xstate.c

Lines changed: 48 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -957,18 +957,31 @@ static inline bool xfeatures_mxcsr_quirk(u64 xfeatures)
957957
return true;
958958
}
959959

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)
967961
{
968-
if (offset < size_total) {
969-
unsigned int copy = min(size, size_total - offset);
962+
if (*pos < to) {
963+
unsigned size = to - *pos;
964+
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+
}
970973

971-
memcpy(kbuf + offset, data, copy);
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;
972985
}
973986
}
974987

@@ -981,8 +994,9 @@ __copy_xstate_to_kernel(void *kbuf, const void *data,
981994
*/
982995
int copy_xstate_to_kernel(void *kbuf, struct xregs_state *xsave, unsigned int offset_start, unsigned int size_total)
983996
{
984-
unsigned int offset, size;
985997
struct xstate_header header;
998+
const unsigned off_mxcsr = offsetof(struct fxregs_state, mxcsr);
999+
unsigned count = size_total;
9861000
int i;
9871001

9881002
/*
@@ -998,46 +1012,42 @@ int copy_xstate_to_kernel(void *kbuf, struct xregs_state *xsave, unsigned int of
9981012
header.xfeatures = xsave->header.xfeatures;
9991013
header.xfeatures &= ~XFEATURE_MASK_SUPERVISOR;
10001014

1015+
if (header.xfeatures & XFEATURE_MASK_FP)
1016+
copy_part(0, off_mxcsr,
1017+
&xsave->i387, &kbuf, &offset_start, &count);
1018+
if (header.xfeatures & (XFEATURE_MASK_SSE | XFEATURE_MASK_YMM))
1019+
copy_part(off_mxcsr, MXCSR_AND_FLAGS_SIZE,
1020+
&xsave->i387.mxcsr, &kbuf, &offset_start, &count);
1021+
if (header.xfeatures & XFEATURE_MASK_FP)
1022+
copy_part(offsetof(struct fxregs_state, st_space), 128,
1023+
&xsave->i387.st_space, &kbuf, &offset_start, &count);
1024+
if (header.xfeatures & XFEATURE_MASK_SSE)
1025+
copy_part(xstate_offsets[XFEATURE_MASK_SSE], 256,
1026+
&xsave->i387.xmm_space, &kbuf, &offset_start, &count);
1027+
/*
1028+
* Fill xsave->i387.sw_reserved value for ptrace frame:
1029+
*/
1030+
copy_part(offsetof(struct fxregs_state, sw_reserved), 48,
1031+
xstate_fx_sw_bytes, &kbuf, &offset_start, &count);
10011032
/*
10021033
* Copy xregs_state->header:
10031034
*/
1004-
offset = offsetof(struct xregs_state, header);
1005-
size = sizeof(header);
1006-
1007-
__copy_xstate_to_kernel(kbuf, &header, offset, size, size_total);
1035+
copy_part(offsetof(struct xregs_state, header), sizeof(header),
1036+
&header, &kbuf, &offset_start, &count);
10081037

1009-
for (i = 0; i < XFEATURE_MAX; i++) {
1038+
for (i = FIRST_EXTENDED_XFEATURE; i < XFEATURE_MAX; i++) {
10101039
/*
10111040
* Copy only in-use xstates:
10121041
*/
10131042
if ((header.xfeatures >> i) & 1) {
10141043
void *src = __raw_xsave_addr(xsave, i);
10151044

1016-
offset = xstate_offsets[i];
1017-
size = xstate_sizes[i];
1018-
1019-
/* The next component has to fit fully into the output buffer: */
1020-
if (offset + size > size_total)
1021-
break;
1022-
1023-
__copy_xstate_to_kernel(kbuf, src, offset, size, size_total);
1045+
copy_part(xstate_offsets[i], xstate_sizes[i],
1046+
src, &kbuf, &offset_start, &count);
10241047
}
10251048

10261049
}
1027-
1028-
if (xfeatures_mxcsr_quirk(header.xfeatures)) {
1029-
offset = offsetof(struct fxregs_state, mxcsr);
1030-
size = MXCSR_AND_FLAGS_SIZE;
1031-
__copy_xstate_to_kernel(kbuf, &xsave->i387.mxcsr, offset, size, size_total);
1032-
}
1033-
1034-
/*
1035-
* Fill xsave->i387.sw_reserved value for ptrace frame:
1036-
*/
1037-
offset = offsetof(struct fxregs_state, sw_reserved);
1038-
size = sizeof(xstate_fx_sw_bytes);
1039-
1040-
__copy_xstate_to_kernel(kbuf, xstate_fx_sw_bytes, offset, size, size_total);
1050+
fill_gap(size_total, &kbuf, &offset_start, &count);
10411051

10421052
return 0;
10431053
}

0 commit comments

Comments
 (0)