Summary: | vex amd64->IR: unhandled instruction bytes: 0x48 0xCF 0xF 0x1F 0x0 0xFF 0xD2 0xCC 0x90 0x55 | ||
---|---|---|---|
Product: | [Developer tools] valgrind | Reporter: | Alex Henrie <alexhenrie24> |
Component: | vex | Assignee: | Julian Seward <jseward> |
Status: | RESOLVED FIXED | ||
Severity: | normal | CC: | austinenglish, dlehman25, dougvj, eeknaak |
Priority: | NOR | ||
Version: | 3.14 SVN | ||
Target Milestone: | --- | ||
Platform: | Arch Linux | ||
OS: | Linux | ||
See Also: | https://bugs.kde.org/show_bug.cgi?id=253657 | ||
Latest Commit: | Version Fixed In: | ||
Sentry Crash Report: | |||
Attachments: |
IRETQ Test Case
iretq implementation updated iretq implementation |
Description
Alex Henrie
2018-11-01 02:31:14 UTC
0x48 0xCF is IRETQ (return from interrupt) and it segfaults when run even natively (not on V) on my Fedora 29 box. So I'm kinda surprised that you expect it to work when running on V. But maybe I misunderstand what's going on here? My test case is int main ( void ) { __asm__ __volatile__(".byte 0x48, 0xCF" ::: "cc","memory"); return 0; } IRETQ appears to be used by wine to start executing a CPU context. In normal operation this context is generated by the CPU when it is interrupted and pushed onto the stack, which is picked up by IRETQ when the interrupt is done being handled. Wine appears to generate this context on the stack itself so it's not using one generated by the CPU for IRETQ. Simply executing IRETQ without a valid CPU context on the stack will surely cause a segfault as the stack doesn't contain a valid instruction pointer and other CPU state. The segfault may even be caused by a stack underflow in this case, I am not sure. See the wine source here for usage of IRETQ: https://github.com/wine-mirror/wine/blob/master/dlls/ntdll/signal_x86_64.c Wine has been using IRETQ since May 2009: https://source.winehq.org/git/wine.git/commitdiff/880d00fb43de924a3543b0ad53b5aaf0ad63d0cb The first reference I could find to IRETQ in Wine causing a problem with Valgrind was in January 2013: https://sourceforge.net/p/valgrind/mailman/message/30422124/ Created attachment 118834 [details]
IRETQ Test Case
I went ahead and implemented a minimal test case which is attached. I confirmed the code runs fine on metal but chokes in valgrind producing a similar error message: unhandled instruction bytes: 0x48 0xCF 0xDE 0xAD 0xBE 0xEF
Comment on attachment 118834 [details] IRETQ Test Case >#include <stdio.h> >#include <stdlib.h> > >void return_from_iret() { > printf("Hello From IRETQ\n"); > exit(0); >} > > >int main() { > asm ( > "pushfq\n" > "movq 0(%%rsp), %%rbx\n" //rbx contains eflags > "popfq\n" > "subq $40, %%rsp\n" //Allocate our stack area for iret > "movq %%ss, %%rax\n" > "movq %%rax, 32(%%rsp)\n" //SS > "movq %%rsp, %%rax\n" > "movq %%rax, 24(%%rsp)\n" //SP > "movq %%rbx, 16(%%rsp)\n" //EFLAGS > "movq %%cs, %%rax\n" > "movq %%rax, 8(%%rsp)\n" //CS > "movq %0, 0(%%rsp)\n" //RIP > "iretq\n" > ".byte 0xDE, 0xAD, 0xBE, 0xEF\n" > : //no outputs > : "r" (return_from_iret) > : "rax", "rbx" //clobber list > ); > return 1; >} Okay, I can reproduce this, it needs a couple more valgrind arguments. # First, start a wine process (so that wineserver is running before valgrind starts): $ wine64 start /min winemine # Then, start notepad under valgrind: $ austin@laptop:~/src/valgrind$ valgrind --trace-children=yes --vex-iropt-register-updates=allregs-at-mem-access /opt/oldwow64/wine-4.5/bin/wine64 notepad ==2874== Memcheck, a memory error detector ==2874== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. ==2874== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info ==2874== Command: /opt/oldwow64/wine-4.5/bin/wine64 notepad ==2874== ==2874== Memcheck, a memory error detector ==2874== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. ==2874== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info ==2874== Command: /opt/oldwow64/wine-4.5/bin/wine64-preloader /opt/oldwow64/wine-4.5/bin/wine64 notepad ==2874== preloader: Warning: failed to reserve range 0000000000110000-0000000068000000 ==2874== vex amd64->IR: unhandled instruction bytes: 0x48 0xCF 0xF 0x1F 0x0 0xFF 0xD2 0xCC 0x90 0x55 vex amd64->IR: REX=1 REX.W=1 REX.R=0 REX.X=0 REX.B=0 vex amd64->IR: VEX=0 VEX.L=0 VEX.nVVVV=0x0 ESC=NONE vex amd64->IR: PFX.66=0 PFX.F2=0 PFX.F3=0 vex amd64->IR: unhandled instruction bytes: 0x48 0xCF 0xF 0x1F 0x0 0xFF 0xD2 0xCC 0x90 0x55 vex amd64->IR: REX=1 REX.W=1 REX.R=0 REX.X=0 REX.B=0 vex amd64->IR: VEX=0 VEX.L=0 VEX.nVVVV=0x0 ESC=NONE vex amd64->IR: PFX.66=0 PFX.F2=0 PFX.F3=0 ==2874== valgrind: Unrecognised instruction at address 0x7bc9bff3. ==2874== at 0x7BC9BFF3: ??? (in /opt/oldwow64/wine-4.5/lib64/wine/ntdll.dll.so) ==2874== by 0x7BC9C0CA: ??? (in /opt/oldwow64/wine-4.5/lib64/wine/ntdll.dll.so) ==2874== Your program just tried to execute an instruction that Valgrind ==2874== did not recognise. There are two possible reasons for this. ==2874== 1. Your program has a bug and erroneously jumped to a non-code ==2874== location. If you are running Memcheck and you just saw a ==2874== warning about a bad jump, it's probably your program's fault. ==2874== 2. The instruction is legitimate but Valgrind doesn't handle it, ==2874== i.e. it's Valgrind's fault. If you think this is the case or ==2874== you are not sure, please let us know and we'll try to fix it. ==2874== Either way, Valgrind will now raise a SIGILL signal which will ==2874== probably kill your program. 005d:err:seh:segv_handler Got unexpected trap 0 ==2874== Invalid write of size 8 ==2874== at 0x7BC9BFF8: ??? (in /opt/oldwow64/wine-4.5/lib64/wine/ntdll.dll.so) ==2874== by 0x7BC9BFF2: ??? (in /opt/oldwow64/wine-4.5/lib64/wine/ntdll.dll.so) ==2874== by 0x7BC9C0CA: ??? (in /opt/oldwow64/wine-4.5/lib64/wine/ntdll.dll.so) ==2874== Address 0x7ffffe20f4b8 is in a rw- anonymous segment ==2874== 005d:err:seh:NtRaiseException Unhandled exception code c000001d flags 0 addr 0x7bc9bff3 ==2874== ==2874== HEAP SUMMARY: ==2874== in use at exit: 731,905 bytes in 6,501 blocks ==2874== total heap usage: 13,837 allocs, 7,336 frees, 2,963,926 bytes allocated ==2874== ==2874== LEAK SUMMARY: ==2874== definitely lost: 318 bytes in 2 blocks ==2874== indirectly lost: 0 bytes in 0 blocks ==2874== possibly lost: 0 bytes in 0 blocks ==2874== still reachable: 731,587 bytes in 6,499 blocks ==2874== suppressed: 0 bytes in 0 blocks ==2874== Rerun with --leak-check=full to see details of leaked memory ==2874== ==2874== For counts of detected and suppressed errors, rerun with: -v ==2874== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0) Tested with 3.15-rc1 / wine-4.5 Created attachment 119759 [details] iretq implementation updated version of the iretq implementation i included in the tarball in https://bugs.kde.org/show_bug.cgi?id=253657 (In reply to Daniel Lehman from comment #8) > Created attachment 119759 [details] > iretq implementation > > updated version of the iretq implementation i included in the tarball in > https://bugs.kde.org/show_bug.cgi?id=253657 Daniel, all, sorry to have been so slow looking at this. Thank you for the patch. The patch ignores the new values for %CS and %SS, which seems reasonable to me, given that Vex doesn't model segment registers on x86_64 anyway (per comment above dis_mov_S_E() in guest_amd64_toIR.c). However, afaics, the patch also ignores the new value for %rflags.d, which iirc is the string-operation direction flag. We do need to restore that in order that any pending string operations continue in the right direction, I think. See the implementation for POPF in that same file, for how to set it. The Intel docs for IRETQ have this in a couple of places: RETURN-TO-SAME-PRIVILEGE-LEVEL: (* PE = 1, RPL = CPL *) ... EFLAGS (CF, PF, AF, ZF, SF, TF, DF, OF, NT) ← tempEFLAGS; which is why I think at least D should be restored. I notice that Vex also models the ID and AC flags (see, again, the POPF implementation) but from the Intel docs it's not clear to me whether these also need to be restoired from 'tempEFLAGS' above. Created attachment 121516 [details] updated iretq implementation > Vex also models the ID and AC flags (see, again, the POPF implementation) > but from the Intel docs it's not clear to me whether these also need > to be restoired from 'tempEFLAGS' above from the docs, it does look like they need to be restored. using the attached iretq test case in a debugger, i can see that the ID and AC are saved across iretq > EFLAGS (CF, PF, AF, ZF, SF, TF, DF, OF, NT) ← tempEFLAGS; it doesn't look like VEX models certain flags like NT or TF > See the implementation for POPF in that same file, for how to set it the attached uses the code from popf. i retested with the latest wine 4.12.1 Committed, e7dde4bc20bf57b4c1e25801f8462d1519c4fa41. Thanks for the patch. I took the liberty of adding an extra condition which disallows decoding if there is an 0x66, 0xF2 or 0xF3 prefix present, which I think should make it a little safer. Thank you Julian, having this patch committed is a big help to the Wine project! *** Bug 414659 has been marked as a duplicate of this bug. *** |