Module: wine Branch: master Commit: 64ddb263d25dfceeeae8457a0131f1a2af292383 URL: http://source.winehq.org/git/wine.git/?a=commit;h=64ddb263d25dfceeeae8457a01...
Author: Alexandre Julliard julliard@winehq.org Date: Tue Feb 12 15:21:15 2013 +0100
ntdll: Check for invalid %gs value in 32-bit code.
Suggested by Alessandro Pignotti.
---
dlls/ntdll/signal_i386.c | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 43 insertions(+), 0 deletions(-)
diff --git a/dlls/ntdll/signal_i386.c b/dlls/ntdll/signal_i386.c index 18fe3da..05ede34 100644 --- a/dlls/ntdll/signal_i386.c +++ b/dlls/ntdll/signal_i386.c @@ -1507,6 +1507,47 @@ static inline DWORD is_privileged_instr( CONTEXT *context ) } }
+/*********************************************************************** + * check_invalid_gs + * + * Check for fault caused by invalid %gs value (some copy protection schemes mess with it). + */ +static inline BOOL check_invalid_gs( CONTEXT *context ) +{ + unsigned int prefix_count = 0; + const BYTE *instr = (BYTE *)context->Eip; + WORD system_gs = ntdll_get_thread_data()->gs; + + if (context->SegGs == system_gs) return FALSE; + if (!wine_ldt_is_system( context->SegCs )) return FALSE; + /* only handle faults in system libraries */ + if (virtual_is_valid_code_address( instr, 1 )) return FALSE; + + for (;;) switch(*instr) + { + /* instruction prefixes */ + case 0x2e: /* %cs: */ + case 0x36: /* %ss: */ + case 0x3e: /* %ds: */ + case 0x26: /* %es: */ + case 0x64: /* %fs: */ + case 0x66: /* opcode size */ + case 0x67: /* addr size */ + case 0xf0: /* lock */ + case 0xf2: /* repne */ + case 0xf3: /* repe */ + if (++prefix_count >= 15) return FALSE; + instr++; + continue; + case 0x65: /* %gs: */ + TRACE( "%04x/%04x at %p, fixing up\n", context->SegGs, system_gs, instr ); + context->SegGs = system_gs; + return TRUE; + default: + return FALSE; + } +} +
#include "pshpack1.h" struct atl_thunk @@ -1716,6 +1757,8 @@ static void WINAPI raise_segv_exception( EXCEPTION_RECORD *rec, CONTEXT *context { if (rec->ExceptionInformation[0] == EXCEPTION_EXECUTE_FAULT && check_atl_thunk( rec, context )) goto done; + if (rec->ExceptionInformation[1] == 0xffffffff && check_invalid_gs( context )) + goto done; if (!(rec->ExceptionCode = virtual_handle_fault( (void *)rec->ExceptionInformation[1], rec->ExceptionInformation[0] ))) goto done;