Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=942
The DxgkDdiEscape handler for escape 0x100009a lacks proper bounds checks:
case 0x100009A:
...
size_0 = escape_data->size_1;
...
size_1 = 2 - (escape_data->unknown < 18);
...
size_2 = escape_data->size_2;
...
total_size = size_0 * size_1 * size_2;
...
if (total_size > 0x10)
do_debug_thingo();
if (total_size) {
DWORD* ptr = alloced_buf + 24;
DWORD* user_buf = escape_data->data;
...
while (total_size) {
*(ptr - 1) = *(user_buf - 1);
*ptr = *user_buf;
...
user_buf += 4;
ptr += 39;
--total_size;
}
There is a check that total_size > 0x10, which calls some kind of a
debug/logging function (do_debug_thingo in my pseudocode), but it does not
actually stop processing of the escape. This leads to buffer overflow on the
allocated pool buffer later on.
Note that there is also a potential integer overflow in the calculation of
|total_size|. Since the individual sizes (size_0, size_1, size_2) appear to be
stored in a struct and eventually passed off to another function, there may be
more problems later on too.
Crashing context with PoC (Win10 x64 with 372.54):
PAGE_FAULT_IN_NONPAGED_AREA (50)
Invalid system memory was referenced. This cannot be protected by try-except.
Typically the address is just plain bad or it is pointing at freed memory.
...
rax=00000000caa6ed30 rbx=0000000000000000 rcx=ffffc001cd337044
rdx=00000000000f41bd rsi=0000000000000000 rdi=0000000000000000
rip=fffff80102461188 rsp=ffffd000243bbed0 rbp=ffffd000243bbfd0
r8=0000000000000000 r9=0000000000000000 r10=0000000000000000
r11=0000000000000000 r12=0000000000000000 r13=0000000000000000
r14=0000000000000000 r15=0000000000000000
iopl=0 nv up ei pl nz na po nc
nvlddmkm!nvDumpConfig+0x12a2b0:
fffff801`02461188 8941fc mov dword ptr [rcx-4],eax ds:ffffc001`cd337040=????????
Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/40665.zip