NVIDIA Driver 375.70 – Buffer Overflow in Command Buffer Submission

  • 作者: Google Security Research
    日期: 2017-02-15
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/41365/
  • Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1012
    
    DxgkDdiSubmitCommandVirtual is the function implemented by the kernel mode driver
    responsible for submitting a command buffer to the GPU. One of the arguments passed
    contains vendor specific data from the user mode driver. The kernel allocates a single
    buffer for this purpose for all submit calls for the same context.
    
    NVIDIA implements this data as:
    
    struct NvPrivateHeader {
    DWORD magic;
    WORD unknown_4;
    WORD unknown_6;
    DWORD unknown_8;
    DWORD size;
    };
    
    struct NvPrivateData {
    NvPrivateHeader header;
    DWORD unknown_0;
    DWORD unknown_1;
    DWORD some_size;
    DWORD unknown_2;
    PVOID a_gpu_address_maybe;
    BYTE unknown[1220];
    };
    
    In one of the functions that process this data, there appears to be code to
    shift around the contents of this user private data.
    
    // |len| is controlled by the user. can come from the |some_size| field if the
    |a_gpu_address_maybe| field is 0.
    
    if ( len ) {
    if ( 8 * len >= pCommand_->DmaBufferPrivateDataSize - 0x4E8 )
    do_debug_thingo();// doesn't stop the memcpy
    
    priv_data = (NvSubmitPrivateData *)pCommand_->pDmaBufferPrivateData;
    
    src = (char *)priv_data + priv_data->header.size;// unchecked length
    priv_data = (NvSubmitPrivateData *)((char *)priv_data + 1256);
    *(_QWORD *)&v4->unknown_0[256] = priv_data;
    
    // potential bad memcpy
    memcpy(priv_data, src, 8 * len);
    }
    
    
    There are two main problems here: the |len| value is checked, but that appears
    to only call a debug logging function and not actually stop the memcpy that
    occurs afterwards.
    
    Also, the |size| field from the header is not properly
    checked to be smaller than the actual size of the data (this is also checked in
    the calling function but once again only calls do_debug_thingo()).
    
    This lets an attacker specify an arbitrary length for the copy, as well as
    specify an arbitrary 32-bit offset to copy from, leading to pool memory corruption.
    
    Crashing context with PoC (Win 10 x64, driver version 375.95):
    
    PAGE_FAULT_IN_NONPAGED_AREA (50)
    ...
    rax=0000000000000008 rbx=0000000000000000 rcx=ffffb2087fe8f4f0
    rdx=0000000041413c59 rsi=0000000000000000 rdi=0000000000000000
    rip=fffff8035fc15b00 rsp=ffffd88179edd1a8 rbp=0000000000000080
     r8=00000000020a0a08r9=0000000000105050 r10=0000000000000000
    r11=ffffb2087fe8f4f0 r12=0000000000000000 r13=0000000000000000
    r14=0000000000000000 r15=0000000000000000
    iopl=0 nv up ei ng nz na po nc
    nvlddmkm+0x5e5b00:
    fffff803`5fc15b00 f30f6f040amovdquxmm0,xmmword ptr [rdx+rcx] ds:ffffb208`c12a3149=????????????????????????????????
    Resetting default scope
    
    
    Proof of Concept:
    https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/41365.zip