On 24/04/2025 2:13 pm, Fabian Specht wrote:
>>> if ( !s->rex_prefix )
>>> {
>>>     /* Convert 32-bit real/vm86 to 32-bit prot format. */
>>>     unsigned int fip = fpstate.env.mode.real.fip_lo +
>>>                                        (fpstate.env.mode.real.fip_hi << 16);
>>>     unsigned int fdp = fpstate.env.mode.real.fdp_lo +
>>>                                        (fpstate.env.mode.real.fdp_hi << 16);
>>>     unsigned int fop = fpstate.env.mode.real.fop;
>>>
>>>     fpstate.env.mode.prot.fip = fip & 0xf;
>>>     fpstate.env.mode.prot.fcs = fip >> 4;
>>>     fpstate.env.mode.prot.fop = fop;
>>>     fpstate.env.mode.prot.fdp = fdp & 0xf;
>>>     fpstate.env.mode.prot.fds = fdp >> 4;
>>> }
>> Several things.  First, please always the UBSAN analysis from the crash.
> (XEN) UBSAN: Undefined behaviour in arch/x86/x86_emulate/blk.c:87:66
> (XEN) left shift of 65535 by 16 places cannot be represented in type 'int'
> (XEN) ----[ Xen-4.20.0  x86_64  debug=y ubsan=y  Tainted:     H  ]----

Yes, it is a shift into the sign bit.

>
>> There are several different ways that shifts go wrong, and I suspect
>> this is a shift into a sign bit, which is notable given the unsigned
>> underlying type.
> Might be, but I am not entirely sure. Either way, it should be fixed
> through a simple cast to unsigned int I think.

I have a sneaking suspicion that this is sufficient:

diff --git a/xen/arch/x86/x86_emulate/private.h
b/xen/arch/x86/x86_emulate/private.h
index 30be59547032..9f3d6f0e5357 100644
--- a/xen/arch/x86/x86_emulate/private.h
+++ b/xen/arch/x86/x86_emulate/private.h
@@ -385,9 +385,9 @@ struct x87_env16 {
     union {
         struct {
             uint16_t fip_lo;
-            uint16_t fop:11, :1, fip_hi:4;
+            uint32_t fop:11, :1, fip_hi:4;
             uint16_t fdp_lo;
-            uint16_t :12, fdp_hi:4;
+            uint32_t :12, fdp_hi:4;
         } real;
         struct {
             uint16_t fip;


The problem is that a uint16_t bitfield promotes into int.  A base type
of uint32_t should cause the bitfield to promote into unsigned int directly.

>
>> Also, are you aware that the test isn't properly in Real Mode?  It's in
>> so-called unreal mode (not actually a real mode, but a consequence of
>> how the segment registers work), which is relevant to how you manage to
>> re-enter the emulator for FLDENV.
> Yes I am aware. But the bug should be triggered regardless of the
> current mode, right?

Well, that depends.  Some CPUs trucate %eip to %ip at this point.  Xen
doesn't, which is why the XTF test doesn't crash in a different way.

~Andrew

Reply via email to