Re: [PATCH v2 23/28] target/i386: Honor xfeatures in xrstor_sigcontext

2024-04-09 Thread Richard Henderson

On 4/9/24 08:09, Richard Henderson wrote:

On 4/8/24 21:44, Paolo Bonzini wrote:

+    /*
+ * Restore the features indicated in the frame, masked by
+ * those currently enabled.  Re-check the frame size.
+ * ??? It is not clear where the kernel does this, but it
+ * is not in check_xstate_in_sigframe, and so (probably)
+ * does not fall back to fxrstor.
+ */


I think you're referring to this in __fpu_restore_sig?

 if (use_xsave()) {
 /*
  * Remove all UABI feature bits not set in user_xfeatures
  * from the memory xstate header which makes the full
  * restore below bring them into init state. This works for
  * fx_only mode as well because that has only FP and SSE
  * set in user_xfeatures.
  *
  * Preserve supervisor states!
  */
 u64 mask = user_xfeatures | xfeatures_mask_supervisor();

 fpregs->xsave.header.xfeatures &= mask;
 success = !os_xrstor_safe(fpu->fpstate,
   fpu_kernel_cfg.max_features);

It is not masking against the user process's xcr0, but qemu-user's xcr0
is effectively user_xfeatures (it's computed in x86_cpu_reset_hold() and
will never change afterwards since XSETBV is privileged).


No, I'm talking about verifying that the xstate_size is large enough.

In check_xstate_in_sigframe,

     if (fx_sw->magic1 != FP_XSTATE_MAGIC1 ||
     fx_sw->xstate_size < min_xstate_size ||

Check for the trivially too small case (fxregs + header).

     fx_sw->xstate_size > current->thread.fpu.fpstate->user_size ||

Check for the trivially too large case (presumably this is to catch stupidly large values, 
assuming garbage).


     fx_sw->xstate_size > fx_sw->extended_size)

Check for trivial mismatch between fields.

     goto setfx;

But there's a middle case: if xfeatures > 3, then xstate_size must be > 
min_xstate_size.

I know that the kernel will handle any #GP in xrstor_from_user_sigframe, but there doesn't 
seem to be a real check for reading garbage beyond the given size.


Oh, I meant to mention, following the

__fpu_restore_sig:
user_xfeatures = fx_sw_user.xfeatures;
...
if (!ia32_fxstate)
restore_fpregs_from_user(..., user_xfeatures, ...)

restore_fpregs_from_user(..., xrestore, ...)
xrestore &= fpu->fpstate->user_xfeatures;
__restore_fpregs_from_user(..., xrestore, ...)

path.


r~



Re: [PATCH v2 23/28] target/i386: Honor xfeatures in xrstor_sigcontext

2024-04-09 Thread Richard Henderson

On 4/8/24 21:44, Paolo Bonzini wrote:

+    /*
+ * Restore the features indicated in the frame, masked by
+ * those currently enabled.  Re-check the frame size.
+ * ??? It is not clear where the kernel does this, but it
+ * is not in check_xstate_in_sigframe, and so (probably)
+ * does not fall back to fxrstor.
+ */


I think you're referring to this in __fpu_restore_sig?

     if (use_xsave()) {
     /*
  * Remove all UABI feature bits not set in user_xfeatures
  * from the memory xstate header which makes the full
  * restore below bring them into init state. This works for
  * fx_only mode as well because that has only FP and SSE
  * set in user_xfeatures.
  *
  * Preserve supervisor states!
  */
     u64 mask = user_xfeatures | xfeatures_mask_supervisor();

     fpregs->xsave.header.xfeatures &= mask;
     success = !os_xrstor_safe(fpu->fpstate,
   fpu_kernel_cfg.max_features);

It is not masking against the user process's xcr0, but qemu-user's xcr0
is effectively user_xfeatures (it's computed in x86_cpu_reset_hold() and
will never change afterwards since XSETBV is privileged).


No, I'm talking about verifying that the xstate_size is large enough.

In check_xstate_in_sigframe,

if (fx_sw->magic1 != FP_XSTATE_MAGIC1 ||
fx_sw->xstate_size < min_xstate_size ||

Check for the trivially too small case (fxregs + header).

fx_sw->xstate_size > current->thread.fpu.fpstate->user_size ||

Check for the trivially too large case (presumably this is to catch stupidly large values, 
assuming garbage).


fx_sw->xstate_size > fx_sw->extended_size)

Check for trivial mismatch between fields.

goto setfx;

But there's a middle case: if xfeatures > 3, then xstate_size must be > 
min_xstate_size.

I know that the kernel will handle any #GP in xrstor_from_user_sigframe, but there doesn't 
seem to be a real check for reading garbage beyond the given size.



r~



Re: [PATCH v2 23/28] target/i386: Honor xfeatures in xrstor_sigcontext

2024-04-09 Thread Paolo Bonzini

On 4/9/24 07:02, Richard Henderson wrote:

Signed-off-by: Richard Henderson 
---
  linux-user/i386/signal.c | 19 ++-
  1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/linux-user/i386/signal.c b/linux-user/i386/signal.c
index d015fe520a..fd09c973d4 100644
--- a/linux-user/i386/signal.c
+++ b/linux-user/i386/signal.c
@@ -612,6 +612,7 @@ static bool xrstor_sigcontext(CPUX86State *env, FPStateKind 
fpkind,
  struct target_fpx_sw_bytes *sw = (void *)>sw_reserved;
  uint32_t magic1, magic2;
  uint32_t extended_size, xstate_size, min_size, max_size;
+uint64_t xfeatures;
  
  switch (fpkind) {

  case FPSTATE_XSAVE:
@@ -628,10 +629,25 @@ static bool xrstor_sigcontext(CPUX86State *env, 
FPStateKind fpkind,
  xstate_size > extended_size) {
  break;
  }
+
+/*
+ * Restore the features indicated in the frame, masked by
+ * those currently enabled.  Re-check the frame size.
+ * ??? It is not clear where the kernel does this, but it
+ * is not in check_xstate_in_sigframe, and so (probably)
+ * does not fall back to fxrstor.
+ */


I think you're referring to this in __fpu_restore_sig?

if (use_xsave()) {
/*
 * Remove all UABI feature bits not set in user_xfeatures
 * from the memory xstate header which makes the full
 * restore below bring them into init state. This works for
 * fx_only mode as well because that has only FP and SSE
 * set in user_xfeatures.
 *
 * Preserve supervisor states!
 */
u64 mask = user_xfeatures | xfeatures_mask_supervisor();

fpregs->xsave.header.xfeatures &= mask;
success = !os_xrstor_safe(fpu->fpstate,
  fpu_kernel_cfg.max_features);

It is not masking against the user process's xcr0, but qemu-user's xcr0
is effectively user_xfeatures (it's computed in x86_cpu_reset_hold() and
will never change afterwards since XSETBV is privileged).

Paolo


+xfeatures = tswap64(sw->xfeatures) & env->xcr0;
+min_size = xsave_area_size(xfeatures, false);
+if (xstate_size < min_size) {
+return false;
+}
+
  if (!access_ok(env_cpu(env), VERIFY_READ, fxstate_addr,
 xstate_size + TARGET_FP_XSTATE_MAGIC2_SIZE)) {
  return false;
  }
+
  /*
   * Check for the presence of second magic word at the end of memory
   * layout. This detects the case where the user just copied the legacy
@@ -644,7 +660,8 @@ static bool xrstor_sigcontext(CPUX86State *env, FPStateKind 
fpkind,
  if (magic2 != FP_XSTATE_MAGIC2) {
  break;
  }
-cpu_x86_xrstor(env, fxstate_addr, -1);
+
+cpu_x86_xrstor(env, fxstate_addr, xfeatures);
  return true;
  
  default: