https://bugs.kde.org/show_bug.cgi?id=517848

            Bug ID: 517848
           Summary: x86-64: incorrect execution of instructions with REX
                    prefixes in invalid positions
    Classification: Developer tools
           Product: valgrind
      Version First 3.27 GIT
       Reported In:
          Platform: openSUSE
                OS: Linux
            Status: REPORTED
          Severity: normal
          Priority: NOR
         Component: vex
          Assignee: [email protected]
          Reporter: [email protected]
  Target Milestone: ---

SUMMARY
I believe to have discovered a bug where libVEX is not handling ignored x86-64
REX prefixes correctly. When another prefix follows a REX prefix, the REX
prefix must be ignored. This is specified by the AMD (Volume 1, Section 3.5.2)
and Intel Manuals (Volume 2, Section 2.2.1).

Currently REX prefixes in ignored positions are not ignored by libVEX. This
means that for example 4C6601C8 (REX + DATA16 + instr) is executed as having a
REX prefix (and thus performing a 64-bit operation), instead of as having only
a DATA16 prefix (and thus performing a 16-bit operation).


STEPS TO REPRODUCE
Compile the following program and execute it in Valgrind:

#include <stdio.h>
#include <stdint.h>

int main() {
    uint64_t a = 0x11223344;
    uint64_t b = 0x55667788;
    uint64_t c = 0x99aabbcc;

    asm volatile (
        "mov %[a], %%rax\n\t"
        "mov %[b], %%rcx\n\t"
        "mov %[c], %%r9\n\t"

        ".byte 0x4C, 0x66, 0x01, 0xC8\n\t"

        "mov %%rax, %[a]\n\t"
        "mov %%rcx, %[b]\n\t"
        "mov %%r9, %[c]\n\t"
        : [a] "+r" (a), [b] "+r" (b), [c] "+r" (c)
        :
        : "rax", "rcx", "r9"
    );

    printf("a = 0x%llx\n", (unsigned long long)a);
    printf("b = 0x%llx\n", (unsigned long long)b);
    printf("c = 0x%llx\n", (unsigned long long)c);

    return 0;
}

(another fun variation is 444801C8, where valgrind takes the logical OR of both
REX prefixes instead of the last)

OBSERVED RESULT
Executing with Valgrind results in:

a = 0xaaccef10
b = 0x55667788
c = 0x99aabbcc

EXPECTED RESULT
Executing normally results in:

a = 0x1122aacc
b = 0x55667788
c = 0x99aabbcc


SOFTWARE/OS VERSIONS
Operating System: openSUSE Tumbleweed 20260307
KDE Plasma Version: 6.6.2
KDE Frameworks Version: 6.23.0
Qt Version: 6.10.2
Kernel Version: 6.19.5-2-default (64-bit)

ADDITIONAL INFORMATION
I am happy to try to fix this and provide a patch. I see two possible
approaches:

1.) Rejecting instructions with REX prefixes in ignored positions
2.) Correctly handling REX prefixes in ignored positions

Having looked at the code in VEX/priv/guest_amd64_toIR.c both approaches will
result in fairly small patches.
I would typically advocate for correctly handling every instruction, but given
that Valgrind also rejects other unexpected combinations of prefixes (like
multiple segment overrides or both F2 and F3), rejecting instructions with
ignored REX prefixes might also make sense.
I am interested in hearing your thoughts on the best approach before I start
working on a patch.

-- 
You are receiving this mail because:
You are watching all bug changes.

Reply via email to