[Bug 24081] Garena crashes (ntoskrnl: out buf length from driver ioctl dispatch used despite error condition)

wine-bugs at winehq.org wine-bugs at winehq.org
Sun Aug 22 11:24:17 CDT 2010


http://bugs.winehq.org/show_bug.cgi?id=24081


Anastasius Focht <focht at gmx.net> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |focht at gmx.net
          Component|-unknown                    |ntoskrnl
            Summary|Garena crashes              |Garena crashes (ntoskrnl:
                   |                            |out buf length from driver
                   |                            |ioctl dispatch used despite
                   |                            |error condition)




--- Comment #4 from Anastasius Focht <focht at gmx.net>  2010-08-22 11:24:16 ---
Hello,

looks like some anti-cheat software protection.
There is a kernel service "GarenaPEngine" dynamically loaded and started: 

--- snip ---
0016:Call KERNEL32.CreateProcessW(00000000,00118548
L"C:\\windows\\system32\\winedevice.exe
GarenaPEngine",00000000,00000000,00000000,00000000,00000000,00000000,0073e55c,0073e5a0)
ret=68340f38 
...
0026:Call KERNEL32.LoadLibraryW(0011a610
L"C:\\users\\focht\\Temp\\HDR24d4.tmp") ret=6833c7f9 
...
0026:Ret  KERNEL32.LoadLibraryW() retval=00540000 ret=6833c7f9 
...
0026:Call ntdll.RtlInitUnicodeString(0053e72c,005415bc
L"\\Device\\GG_Protector") ret=005407f8
0026:Ret  ntdll.RtlInitUnicodeString() retval=00000028 ret=005407f8
...
ntoskrnl.exe.IoCreateDevice(6833e5c0,00000100,0053e72c,00008fc7,00000000,00000000,0053e734)
ret=00540823 
...
0026:Call ntoskrnl.exe.MmGetSystemRoutineAddress(0053e710) ret=00540914
...
0026:Call KERNEL32.GetProcAddress(683a0000,0011d178
"PsGetProcessImageFileName") ret=683bb5b0
0026:Ret  KERNEL32.GetProcAddress() retval=683b4294 ret=683bb5b0
...
0026:Ret  ntoskrnl.exe.MmGetSystemRoutineAddress() retval=683b4294 ret=00540914 
...
0026:Call ntoskrnl.exe.PsSetCreateProcessNotifyRoutine(00540614,00000000)
ret=00540861
0026:fixme:ntoskrnl:PsSetCreateProcessNotifyRoutine stub: 0x540614 0
0026:Ret  ntoskrnl.exe.PsSetCreateProcessNotifyRoutine() retval=00000000
ret=00540861 
...
--- snip ---

Client opens the device link and issues initial ioctl (0x8FC7A244):

--- snip ---
0009:Call KERNEL32.CreateFileW(02b14700
L"\\\\.\\GG_PROTECTOR",c0000000,00000000,00000000,00000003,00000004,00000000)
ret=02b05af3
0009:Ret  KERNEL32.CreateFileW() retval=0000013c ret=02b05af3 
...
0009:Call
KERNEL32.DeviceIoControl(0000013c,8fc7a244,02b36c30,00000008,00000000,00000000,00328a14,00000000)
ret=02b05c55
0026:Ret  KERNEL32.WaitForMultipleObjects() retval=00000001 ret=683baf76 
...
0026:Call driver dispatch 0x540486 (device=0x11d558,irp=0x53e7e0)
0026:Call hal.KeGetCurrentIrql() ret=005404a3
0026:fixme:ntoskrnl:KeGetCurrentIrql  stub!
0026:Ret  hal.KeGetCurrentIrql() retval=00000000 ret=005404a3
0026:Call
ntoskrnl.exe.KeWaitForSingleObject(005437e0,00000000,00000000,00000000,00000000)
ret=00540a4f
0026:fixme:ntoskrnl:KeWaitForSingleObject stub: 0x5437e0, 0, 0, 0, (nil)
0026:Ret  ntoskrnl.exe.KeWaitForSingleObject() retval=c0000002 ret=00540a4f
0026:trace:ntoskrnl:__regs_IofCompleteRequest 0x53e7e0 0
0026:trace:ntoskrnl:IoCompleteRequest 0x53e7e0 0
0026:Ret  driver dispatch 0x540486 (device=0x11d558,irp=0x53e7e0)
retval=00000000
0026: get_next_device_request( manager=003c, prev=0000, status=c0000005,
prev_data={} )
0026: get_next_device_request() = PENDING { next=0000, code=00000000,
user_ptr=00000000, in_size=0, out_size=0, next_data={} }
0026:Call KERNEL32.WaitForMultipleObjects(00000002,0053e908,00000000,ffffffff)
ret=68215f76
0026: select( flags=4, cookie=0053e4fc, signal=0000, prev_apc=0000,
timeout=infinite, result={}, handles={0034,003c} )
0026: select() = PENDING { timeout=infinite, call={APC_NONE}, apc_handle=0000 }
001d:err:ntdll:RtlpWaitForCriticalSection section 0x7bca2604
"../../../wine-git/dlls/ntdll/loader.c: loader_section" wait timed out in
thread 001d, blocked by 0009, retrying (60 sec)
--- snip ---

After return from driver dispatch, get_next_device_request() should unblock the
waiting ioctl request from client.
This fails, resulting in another get_next_device_request() round-trip (see the
one with status=c0000005), finally getting stuck on STATUS_PENDING.
Because the client never returns from device ioctl call (ioctl data not set ->
pending request not satisfied), the whole thing hangs.

Took me a while to find out the cause .. this driver stuff isn't easy to debug
because the client will continue to go further when the service start is
delayed, not issuing device i/o controls (you have to attach fast and set bp
into driver entry with some magic O_o).

The server call (the one with status=c0000005) after driver dispatch return is
actually the result of an earlier server call failing.
I noticed that when doing an strace on the whole thing.
Ntdll's send_request() -> wineserver pipe write failed with -EFAULT.
Going back I noticed the request header size had an insane value of 1431655765.
Converting to hex gives: 0x55555555 ... ring a bell? Sure, its the IRP magic
filler value.

--- snip dlls/ntoskrnl.exe/ntoskrnl.c ---
static NTSTATUS process_ioctl( DEVICE_OBJECT *device, ULONG code, void
*in_buff, ULONG in_size,
                               void *out_buff, ULONG *out_size )
...
    *out_size = (irp.IoStatus.u.Status >= 0) ? irp.IoStatus.Information : 0;
...
--- snip dlls/ntoskrnl.exe/ntoskrnl.c ---

The driver returns ntstatus 0xc0000002 from its dispatcher (due to stubs).
As you see in code snippet this results in unmodified out length field being
taken for real (the driver did not touch it).
This value is passed further, resulting in failing wine_server_call() finally
ending up blocking the client.

With that problem fixed, the client starts up and gives login.

=========



More information about the wine-bugs mailing list