NVIDIA Driver - Escape Code Leaks Uninitialised ExAllocatePoolWithTag Memory to Userspace Exploit

ID 1337DAY-ID-26190
Type zdt
Reporter Google Security Research
Modified 2016-11-01T00:00:00


Exploit for windows platform in category dos / poc

                                            Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=892
The handler for the DxgkDdiEscape escape code 0x70000D4 has the following pseudocode:
void __fastcall escape_70000D4(NvMiniportDeviceContext *a1, NvEscapeData *a2)
  Escape70000D4 *escape_data_; // [email protected]
  PVOID alloc_buf; // [email protected]
  unsigned int v4; // [email protected]
  __int64 user_ptr; // [email protected]
  DWORD *v6; // [email protected]
  __int128 v7; // [rsp+40h] [rbp-38h]@1
  __int128 v8; // [rsp+50h] [rbp-28h]@4
  PVOID alloc_buf_; // [rsp+60h] [rbp-18h]@4
  escape_data_ = (Escape70000D4 *)a2;
  a2->unknown_rest[6] = 1;
  LODWORD(v7) = 0;
  memset((char *)&v7 + 4, 0, 0x24ui64);
  alloc_buf = ExAllocatePoolWithTag_(PagedPool, escape_data_->user_ptr_size, 'paVN');
  v4 = 0;
  if ( !alloc_buf )
    v4 = 0xFFFF;
  if ( v4 )
    goto LABEL_12;
  HIDWORD(v8) = escape_data_->user_ptr_size;
  alloc_buf_ = alloc_buf;
  v4 = sub_625BC(0i64, dword_B1BB94, escape_data_->unknown_0, 0x83F30101, (__int64)&v7, 40);
  user_ptr = escape_data_->user_ptr;
  ProbeForWrite((PVOID)escape_data_->user_ptr, escape_data_->user_ptr_size, UserMode);
  memcpy((void *)escape_data_->user_ptr, alloc_buf, escape_data_->user_ptr_size);
  *(_OWORD *)&escape_data_->unknown_2 = v7;
  *(_OWORD *)&escape_data_->unknown_4 = v8;
  escape_data_->user_ptr = user_ptr;
  if ( v4 )
    v6 = &escape_data_->header.unknown_rest[6];
    if ( v6 )
      if ( v4 <= 0xFFFFF000 )
        *v6 = -4096 - v4;
  if ( alloc_buf )
    ExFreePoolWithTag_(alloc_buf, 0x7061564Eu);
ExAllocatePoolWithTag is called with a user provided size to allocate a buffer, but the subsequent copying of said buffer to the user provided pointer doesn't make sense since the buffer is never initialised with any values. This means that a user mode program can leak uninitialised memory from arbitrarily-sized pool allocations.
Looks like I made an oversimplified analysis of the pseudocode in the report. The allocated buffer pointer is indeed passed off to the sub_625BC function (as part of a struct member on the stack) which eventually passes it to a bunch of other functions.
However, this doesn't change the fact that with the provided PoC, the pool allocated buffer still isn't being initialised and is copied into the user buffer unchanged.
Proof of Concept:

#  0day.today [2018-01-04]  #