https://bugs.winehq.org/show_bug.cgi?id=48986
Bug ID: 48986 Summary: Riot Vanguard (Riot Games) 'vgk.sys' crashes on unimplemented function ntoskrnl.exe.KeAreAllApcsDisabled Product: Wine Version: 5.6 Hardware: x86-64 OS: Linux Status: NEW Severity: normal Priority: P2 Component: ntoskrnl Assignee: wine-bugs@winehq.org Reporter: focht@gmx.net Distribution: ---
Hello folks,
as it says. It lacks forward to 'ntdll.NtFlushBuffersFile'.
--- snip --- ... The vgk service is starting. 005e:trace:loaddll:load_native_dll Loaded L"C:\windows\system32\kernelbase.dll" at 0x7b000000: PE builtin 005e:trace:loaddll:load_so_dll Loaded L"C:\windows\system32\kernel32.dll" at 0x7b410000: builtin 005e:trace:loaddll:load_native_dll Loaded L"C:\windows\system32\winedevice.exe" at 0x140000000: PE builtin 005e:trace:loaddll:load_so_dll Loaded L"C:\windows\system32\advapi32.dll" at 0x7f4da3f80000: builtin 005e:trace:loaddll:load_so_dll Loaded L"C:\windows\system32\msvcrt.dll" at 0x7f4da3da0000: builtin 005e:trace:loaddll:load_native_dll Loaded L"C:\windows\system32\ntoskrnl.exe" at 0x180000000: PE builtin 005e:trace:loaddll:load_so_dll Loaded L"C:\windows\system32\ucrtbase.dll" at 0x7f4da3c70000: builtin 005e:trace:loaddll:load_native_dll Loaded L"C:\windows\system32\rpcrt4.dll" at 0x9b0000: PE builtin 0060:trace:loaddll:load_native_dll Loaded L"C:\windows\system32\cng.sys" at 0x1070000: native 0060:trace:loaddll:load_native_dll Loaded L"C:\Program Files\Riot Vanguard\vgk.sys" at 0xd60000: native wine: Call from 0x7bc6dd4c to unimplemented function ntoskrnl.exe.KeAreAllApcsDisabled, aborting wine: Unimplemented function ntoskrnl.exe.KeAreAllApcsDisabled called at address 000000007BC6DD4C (thread 0060), starting debugger... --- snip ---
--- snip --- $ winedump -j import vgk.sys Contents of vgk.sys: 3196560 bytes
Import Table size: 00000050 offset 0001e090 cng.sys Hint/Name Table: 00022108 TimeDateStamp: 00000000 (Thu Jan 1 01:00:00 1970) ForwarderChain: 00000000 First thunk RVA: 0001B028 Thunk Ordn Name 0001b028 8 BCryptDestroyHash 0001b030 1 BCryptCloseAlgorithmProvider
offset 0001e0a4 ntoskrnl.exe Hint/Name Table: 00022120 TimeDateStamp: 00000000 (Thu Jan 1 01:00:00 1970) ForwarderChain: 00000000 First thunk RVA: 0001B040 Thunk Ordn Name 0001b040 1081 KeIpiGenericCall 0001b048 2777 __C_specific_handler 0001b050 196 ExFreePoolWithTag 0001b058 2801 _stricmp 0001b060 2897 wcscat_s 0001b068 2901 wcscpy_s 0001b070 2060 RtlInitUnicodeString 0001b078 2571 ZwCreateFile 0001b080 2705 ZwReadFile 0001b088 2775 ZwWriteFile 0001b090 2560 ZwClose 0001b098 2604 ZwFlushBuffersFile 0001b0a0 2697 ZwQuerySystemInformation 0001b0a8 2259 RtlTimeToTimeFields 0001b0b0 986 KeAreAllApcsDisabled 0001b0b8 302 ExSystemTimeToLocalTime 0001b0c0 2885 swprintf_s 0001b0c8 2895 vswprintf_s 0001b0d0 2818 _vsnwprintf 0001b0d8 1049 KeInitializeApc 0001b0e0 1074 KeInsertQueueApc 0001b0e8 157 ExAllocatePoolWithTag 0001b0f0 990 KeBugCheckEx
Done dumping vgk.sys --- snip ---
Wine source:
https://source.winehq.org/git/wine.git/blob/f31a29b8d1ea478af28f14cdaf3db151...
Microsoft docs:
https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-kea...
Add a simple stub like 'KeAreApcsDisabled':
https://source.winehq.org/git/wine.git/blob/f31a29b8d1ea478af28f14cdaf3db151...
$ sha1sum setup.exe 08deca4c0b46a3481e706926c0217d1c944d22a3 setup.exe
$ du -sh setup.exe 15M setup.exe
$ wine --version wine-5.6-258-gf31a29b8d1
Regards
https://bugs.winehq.org/show_bug.cgi?id=48986
Anastasius Focht focht@gmx.net changed:
What |Removed |Added ---------------------------------------------------------------------------- URL| |https://riot-client.secure. | |dyn.riotcdn.net/channels/pu | |blic/rccontent/vanguard/0.3 | |.2.2/setup.exe Keywords| |download, obfuscation
https://bugs.winehq.org/show_bug.cgi?id=48986
--- Comment #1 from Anastasius Focht focht@gmx.net --- Hello folks,
some tidbits on why this API is called. Currently Wine doesn't implement the concept of Windows kernel IRQL (priority level) by design.
IRQL is a pretty important topic for all code that executes in kernel space. Kernel drivers need to follow general rules when/what code can be called, depending on current IRQL, usage of synchronization primitives etc. I'm not going repeat common knowledge here since you can read a lot about this topic in various online resources.
Windows x86_64 stores the current IRQL in control register CR8. A read of CR8 register equals to 'KeGetCurrentIrql()'.
With Vanguard's 'vgk.sys' you'll see a lot of this:
--- snip --- ... 00c8:trace:seh:raise_exception code=c0000096 flags=0 addr=0x11233c1 ip=11233c1 tid=00c8 00c8:trace:seh:raise_exception rax=000000005fd75f32 rbx=00000000000fccc8 rcx=0000000000000000 rdx=000000000000004a 00c8:trace:seh:raise_exception rsi=0000000000cef8dc rdi=00000000000fccc8 rbp=0000000000cef660 rsp=0000000000cef560 00c8:trace:seh:raise_exception r8=0000000000e2e320 r9=0000000000ceee92 r10=0000000000000000 r11=0000000000cef7b0 00c8:trace:seh:raise_exception r12=00000000000fcb60 r13=00007fffffea4000 r14=0000000000000004 r15=0000000000000000 00c8:trace:seh:call_vectored_handlers calling handler at 0x22ce30 code=c0000096 flags=0 00c8:trace:int:emulate_instruction mov cr8,rax at 11233c1 00c8:trace:int:vectored_handler next instruction rip=11233c5 00c8:trace:int:vectored_handler rax=0000000000000000 rbx=00000000000fccc8 rcx=0000000000000000 rdx=000000000000004a 00c8:trace:int:vectored_handler rsi=0000000000cef8dc rdi=00000000000fccc8 rbp=0000000000cef660 rsp=0000000000cef560 00c8:trace:int:vectored_handler r8=0000000000e2e320 r9=0000000000ceee92 r10=0000000000000000 r11=0000000000cef7b0 00c8:trace:int:vectored_handler r12=00000000000fcb60 r13=00000000ffea4000 r14=0000000000000004 r15=0000000000000000 00c8:trace:seh:call_vectored_handlers handler at 0x22ce30 returned ffffffff ... --- snip ---
Disassembly from exception site (with obfuscation in between):
--- snip --- ... 00000000011233C1 | mov rax,cr8 | KeGetCurrentIrql 00000000011233C5 | clc | 00000000011233C6 | cmp edx,ebx | 00000000011233C8 | sub r15d,r15d | 00000000011233CB | cmp cl,EE | 00000000011233CE | test al,al | >= APC_LEVEL? 00000000011233D0 | jne vgk.E1F250 | 00000000011233D6 | mov rax,FFFFF78000000014 | PASSIVE_LEVEL 00000000011233E0 | lea rdx,qword ptr ss:[rsp+68] | 00000000011233E5 | not cx | 00000000011233E8 | movsxd rcx,r8d | 00000000011233EB | lea rcx,qword ptr ss:[rsp+60] | 00000000011233F0 | jmp vgk.11233F5 | 00000000011233F5 | mov rax,qword ptr ds:[rax] | 00000000011233F8 | mov qword ptr ss:[rsp+60],rax | 00000000011233FD | call qword ptr ds:[<&RtlSystemTime...>] | ... 0000000000E1F250 | mov rcx,qword ptr ss:[rbp+130] | 0000000000E1F257 | xor rcx,rsp | 0000000000E1F25A | call vgk.E2D670 | 0000000000E1F25F | add rsp,248 | 0000000000E1F266 | pop r15 | 0000000000E1F268 | pop r14 | 0000000000E1F26A | pop r13 | 0000000000E1F26C | pop r12 | 0000000000E1F26E | pop rdi | 0000000000E1F26F | pop rsi | 0000000000E1F270 | pop rbx | 0000000000E1F271 | pop rbp | 0000000000E1F272 | ret | ... --- snip ---
It's used in the logging sequence, when the driver wants to write encrypted data to log file. I've found a kernel driver on github that shows how it's intended to be used in this case:
https://github.com/veracrypt/VeraCrypt/blob/94d3a1919c8eee4d7bfd7280ee496447...
--- snip --- NTSTATUS SendDeviceIoControlRequest (PDEVICE_OBJECT deviceObject, ULONG ioControlCode, void *inputBuffer, int inputBufferSize, void *outputBuffer, int outputBufferSize) { IO_STATUS_BLOCK ioStatusBlock; NTSTATUS status; PIRP irp; KEVENT event;
if ((KeGetCurrentIrql() >= APC_LEVEL) || VC_KeAreAllApcsDisabled()) { SendDeviceIoControlRequestWorkItemArgs args;
PIO_WORKITEM workItem = IoAllocateWorkItem (RootDeviceObject); if (!workItem) return STATUS_INSUFFICIENT_RESOURCES;
args.deviceObject = deviceObject; args.ioControlCode = ioControlCode; args.inputBuffer = inputBuffer; args.inputBufferSize = inputBufferSize; args.outputBuffer = outputBuffer; args.outputBufferSize = outputBufferSize;
KeInitializeEvent (&args.WorkItemCompletedEvent, SynchronizationEvent, FALSE); IoQueueWorkItem (workItem, SendDeviceIoControlRequestWorkItemRoutine, DelayedWorkQueue, &args);
KeWaitForSingleObject (&args.WorkItemCompletedEvent, Executive, KernelMode, FALSE, NULL); IoFreeWorkItem (workItem);
return args.Status; }
KeInitializeEvent (&event, NotificationEvent, FALSE);
irp = IoBuildDeviceIoControlRequest (ioControlCode, deviceObject, inputBuffer, inputBufferSize, outputBuffer, outputBufferSize, FALSE, &event, &ioStatusBlock);
if (!irp) return STATUS_INSUFFICIENT_RESOURCES;
ObReferenceObject (deviceObject);
status = IoCallDriver (deviceObject, irp); if (status == STATUS_PENDING) { KeWaitForSingleObject (&event, Executive, KernelMode, FALSE, NULL); status = ioStatusBlock.Status; }
ObDereferenceObject (deviceObject); return status; } --- snip ---
Wine currently returns hard-coded PASSIVE_LEVEL = KIRQL(0).
https://source.winehq.org/git/wine.git/blob/26b26a2e0efcb776e7b0115f15580d25...
This is ok and the code seems to work as intended. There will be cases in future where we probably need a tracking of "fake" KIRQL and sync with CR8 emulation.
If we would return APC_LEVEL = KIRQL(1) or even DISPATCH_LEVEL = KIRQL(2) in CR8 emulation, the call to KeAreAllApcsDisabled() wouldn't be made and no logging functions would be executed.
Regards
https://bugs.winehq.org/show_bug.cgi?id=48986
Anastasius Focht focht@gmx.net changed:
What |Removed |Added ---------------------------------------------------------------------------- URL|https://riot-client.secure. |https://web.archive.org/web |dyn.riotcdn.net/channels/pu |/20200421165713/https://rio |blic/rccontent/vanguard/0.3 |t-client.secure.dyn.riotcdn |.2.2/setup.exe |.net/channels/public/rccont | |ent/vanguard/0.3.2.2/setup. | |exe
https://bugs.winehq.org/show_bug.cgi?id=48986
--- Comment #2 from Anastasius Focht focht@gmx.net --- Hello folks,
revisiting, still present.
$ wine --version wine-6.20-61-gababea0fd70
Regards
https://bugs.winehq.org/show_bug.cgi?id=48986
Etaash Mathamsetty etaash.mathamsetty@gmail.com changed:
What |Removed |Added ---------------------------------------------------------------------------- CC| |etaash.mathamsetty@gmail.co | |m
--- Comment #3 from Etaash Mathamsetty etaash.mathamsetty@gmail.com --- fixed with https://gitlab.winehq.org/wine/wine/-/commit/bafb181c42a88e9cb847d589799d62f...
https://bugs.winehq.org/show_bug.cgi?id=48986
Anastasius Focht focht@gmx.net changed:
What |Removed |Added ---------------------------------------------------------------------------- Fixed by SHA1| |bafb181c42a88e9cb847d589799 | |d62ff0261a621 Resolution|--- |FIXED Status|NEW |RESOLVED
--- Comment #4 from Anastasius Focht focht@gmx.net --- Hello folks,
indeed fixed by commit https://source.winehq.org/git/wine.git/commitdiff/bafb181c42a88e9cb847d58979... ("ntoskrnl.exe: Implement KeAreAllApcsDisabled."). Part of Wine 7.16 release.
Thanks Etaash.
--- snip --- ... 00f0:Call ntoskrnl.exe.KeAreAllApcsDisabled() ret=022cf1f0 00f0:trace:ntoskrnl:KeAreApcsDisabled 0 00f0:Ret ntoskrnl.exe.KeAreAllApcsDisabled() retval=00000000 ret=022cf1f0 00f0:Call ntoskrnl.exe.ExAllocatePoolWithTag(00000200,0000005e,656e6f4e) ret=022cfcbe ... --- snip ---
$ wine --version wine-7.16
Regards
https://bugs.winehq.org/show_bug.cgi?id=48986
Alexandre Julliard julliard@winehq.org changed:
What |Removed |Added ---------------------------------------------------------------------------- Status|RESOLVED |CLOSED
--- Comment #5 from Alexandre Julliard julliard@winehq.org --- Closing bugs fixed in 7.17.