[Bug 48986] Riot Vanguard (Riot Games) 'vgk.sys' crashes on unimplemented function ntoskrnl.exe.KeAreAllApcsDisabled
WineHQ Bugzilla
wine-bugs at winehq.org
Wed May 13 11:04:50 CDT 2020
https://bugs.winehq.org/show_bug.cgi?id=48986
--- Comment #1 from Anastasius Focht <focht at 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/94d3a1919c8eee4d7bfd7280ee4964477dee02e3/src/Driver/Ntdriver.c#L3596
--- 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/26b26a2e0efcb776e7b0115f15580d2507b10400:/dlls/ntoskrnl.exe/instr.c#l701
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
--
Do not reply to this email, post in Bugzilla using the
above URL to reply.
You are receiving this mail because:
You are watching all bug changes.
More information about the wine-bugs
mailing list