void ExceptionThread(mach_port_t port) { Common::SetCurrentThreadName("Mach exception thread"); #pragma pack(4) struct { mach_msg_header_t Head; NDR_record_t NDR; exception_type_t exception; mach_msg_type_number_t codeCnt; int64_t code[2]; int flavor; mach_msg_type_number_t old_stateCnt; natural_t old_state[x86_THREAD_STATE64_COUNT]; mach_msg_trailer_t trailer; } msg_in; struct { mach_msg_header_t Head; NDR_record_t NDR; kern_return_t RetCode; int flavor; mach_msg_type_number_t new_stateCnt; natural_t new_state[x86_THREAD_STATE64_COUNT]; } msg_out; #pragma pack() memset(&msg_in, 0xee, sizeof(msg_in)); memset(&msg_out, 0xee, sizeof(msg_out)); mach_msg_header_t *send_msg = NULL; mach_msg_size_t send_size = 0; mach_msg_option_t option = MACH_RCV_MSG; while (1) { // If this isn't the first run, send the reply message. Then, receive // a message: either a mach_exception_raise_state RPC due to // thread_set_exception_ports, or MACH_NOTIFY_NO_SENDERS due to // mach_port_request_notification. CheckKR("mach_msg_overwrite", mach_msg_overwrite(send_msg, option, send_size, sizeof(msg_in), port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL, &msg_in.Head, 0)); if (msg_in.Head.msgh_id == MACH_NOTIFY_NO_SENDERS) { // the other thread exited mach_port_destroy(mach_task_self(), port); return; } if (msg_in.Head.msgh_id != 2406) { PanicAlertT("unknown message received"); return; } if (msg_in.flavor != x86_THREAD_STATE64) { PanicAlertT("unknown flavor %d (expected %d)", msg_in.flavor, x86_THREAD_STATE64); return; } x86_thread_state64_t *state = (x86_thread_state64_t *) msg_in.old_state; bool ok = DoFault(msg_in.code[1], state); // Set up the reply. msg_out.Head.msgh_bits = MACH_MSGH_BITS(MACH_MSGH_BITS_REMOTE(msg_in.Head.msgh_bits), 0); msg_out.Head.msgh_remote_port = msg_in.Head.msgh_remote_port; msg_out.Head.msgh_local_port = MACH_PORT_NULL; msg_out.Head.msgh_id = msg_in.Head.msgh_id + 100; msg_out.NDR = msg_in.NDR; if (ok) { msg_out.RetCode = KERN_SUCCESS; msg_out.flavor = x86_THREAD_STATE64; msg_out.new_stateCnt = x86_THREAD_STATE64_COUNT; memcpy(msg_out.new_state, msg_in.old_state, x86_THREAD_STATE64_COUNT * sizeof(natural_t)); } else { // Pass the exception to the next handler (debugger or crash). msg_out.RetCode = KERN_FAILURE; msg_out.flavor = 0; msg_out.new_stateCnt = 0; } msg_out.Head.msgh_size = offsetof(typeof(msg_out), new_state) + msg_out.new_stateCnt * sizeof(natural_t); send_msg = &msg_out.Head; send_size = msg_out.Head.msgh_size; option |= MACH_SEND_MSG; } }
ipc_kmsg_t ipc_kobject_server( ipc_kmsg_t request) { mach_msg_size_t reply_size; ipc_kmsg_t reply; kern_return_t kr; ipc_port_t *destp; mach_msg_format_0_trailer_t *trailer; register mig_hash_t *ptr; /* * Find out corresponding mig_hash entry if any */ { register int key = request->ikm_header->msgh_id; register int i = MIG_HASH(key); register int max_iter = mig_table_max_displ; do ptr = &mig_buckets[i++ % MAX_MIG_ENTRIES]; while (key != ptr->num && ptr->num && --max_iter); if (!ptr->routine || key != ptr->num) { ptr = (mig_hash_t *)0; reply_size = mig_reply_size; } else { reply_size = ptr->size; #if MACH_COUNTER ptr->callcount++; #endif } } /* round up for trailer size */ reply_size += MAX_TRAILER_SIZE; reply = ipc_kmsg_alloc(reply_size); if (reply == IKM_NULL) { printf("ipc_kobject_server: dropping request\n"); ipc_kmsg_destroy(request); return IKM_NULL; } /* * Initialize reply message. */ { #define InP ((mach_msg_header_t *) request->ikm_header) #define OutP ((mig_reply_error_t *) reply->ikm_header) /* * MIG should really assure no data leakage - * but until it does, pessimistically zero the * whole reply buffer. */ bzero((void *)OutP, reply_size); OutP->NDR = NDR_record; OutP->Head.msgh_size = sizeof(mig_reply_error_t); OutP->Head.msgh_bits = MACH_MSGH_BITS(MACH_MSGH_BITS_LOCAL(InP->msgh_bits), 0); OutP->Head.msgh_remote_port = InP->msgh_local_port; OutP->Head.msgh_local_port = MACH_PORT_NULL; OutP->Head.msgh_reserved = (mach_msg_size_t)InP->msgh_id; /* useful for debug */ OutP->Head.msgh_id = InP->msgh_id + 100; #undef InP #undef OutP } /* * Find the routine to call, and call it * to perform the kernel function */ { if (ptr) { (*ptr->routine)(request->ikm_header, reply->ikm_header); kernel_task->messages_received++; } else { if (!ipc_kobject_notify(request->ikm_header, reply->ikm_header)){ #if MACH_IPC_TEST printf("ipc_kobject_server: bogus kernel message, id=%d\n", request->ikm_header->msgh_id); #endif /* MACH_IPC_TEST */ _MIG_MSGID_INVALID(request->ikm_header->msgh_id); ((mig_reply_error_t *) reply->ikm_header)->RetCode = MIG_BAD_ID; } else kernel_task->messages_received++; } kernel_task->messages_sent++; } /* * Destroy destination. The following code differs from * ipc_object_destroy in that we release the send-once * right instead of generating a send-once notification * (which would bring us here again, creating a loop). * It also differs in that we only expect send or * send-once rights, never receive rights. * * We set msgh_remote_port to IP_NULL so that the kmsg * destroy routines don't try to destroy the port twice. */ destp = (ipc_port_t *) &request->ikm_header->msgh_remote_port; switch (MACH_MSGH_BITS_REMOTE(request->ikm_header->msgh_bits)) { case MACH_MSG_TYPE_PORT_SEND: ipc_port_release_send(*destp); break; case MACH_MSG_TYPE_PORT_SEND_ONCE: ipc_port_release_sonce(*destp); break; default: panic("ipc_kobject_server: strange destination rights"); } *destp = IP_NULL; if (!(reply->ikm_header->msgh_bits & MACH_MSGH_BITS_COMPLEX) && ((mig_reply_error_t *) reply->ikm_header)->RetCode != KERN_SUCCESS) kr = ((mig_reply_error_t *) reply->ikm_header)->RetCode; else kr = KERN_SUCCESS; if ((kr == KERN_SUCCESS) || (kr == MIG_NO_REPLY)) { /* * The server function is responsible for the contents * of the message. The reply port right is moved * to the reply message, and we have deallocated * the destination port right, so we just need * to free the kmsg. */ ipc_kmsg_free(request); } else { /* * The message contents of the request are intact. * Destroy everthing except the reply port right, * which is needed in the reply message. */ request->ikm_header->msgh_local_port = MACH_PORT_NULL; ipc_kmsg_destroy(request); } if (kr == MIG_NO_REPLY) { /* * The server function will send a reply message * using the reply port right, which it has saved. */ ipc_kmsg_free(reply); return IKM_NULL; } else if (!IP_VALID((ipc_port_t)reply->ikm_header->msgh_remote_port)) { /* * Can't queue the reply message if the destination * (the reply port) isn't valid. */ ipc_kmsg_destroy(reply); return IKM_NULL; } trailer = (mach_msg_format_0_trailer_t *) ((vm_offset_t)reply->ikm_header + (int)reply->ikm_header->msgh_size); trailer->msgh_sender = KERNEL_SECURITY_TOKEN; trailer->msgh_trailer_type = MACH_MSG_TRAILER_FORMAT_0; trailer->msgh_trailer_size = MACH_MSG_TRAILER_MINIMUM_SIZE; return reply; }
/* Routine substrated_mark */ mig_external kern_return_t substrated_mark ( mach_port_t server, vm_map_t task, mach_vm_address_t source_address, mach_vm_size_t source_size, mach_vm_address_t *target_address ) { #ifdef __MigPackStructs #pragma pack(4) #endif typedef struct { mach_msg_header_t Head; /* start of the kernel processed data */ mach_msg_body_t msgh_body; mach_msg_port_descriptor_t task; /* end of the kernel processed data */ NDR_record_t NDR; mach_vm_address_t source_address; mach_vm_size_t source_size; mach_vm_address_t target_address; } Request __attribute__((unused)); #ifdef __MigPackStructs #pragma pack() #endif #ifdef __MigPackStructs #pragma pack(4) #endif typedef struct { mach_msg_header_t Head; NDR_record_t NDR; kern_return_t RetCode; mach_vm_address_t target_address; mach_msg_trailer_t trailer; } Reply __attribute__((unused)); #ifdef __MigPackStructs #pragma pack() #endif #ifdef __MigPackStructs #pragma pack(4) #endif typedef struct { mach_msg_header_t Head; NDR_record_t NDR; kern_return_t RetCode; mach_vm_address_t target_address; } __Reply __attribute__((unused)); #ifdef __MigPackStructs #pragma pack() #endif /* * typedef struct { * mach_msg_header_t Head; * NDR_record_t NDR; * kern_return_t RetCode; * } mig_reply_error_t; */ union { Request In; Reply Out; } Mess; Request *InP = &Mess.In; Reply *Out0P = &Mess.Out; mach_msg_return_t msg_result; #ifdef __MIG_check__Reply__substrated_mark_t__defined kern_return_t check_result; #endif /* __MIG_check__Reply__substrated_mark_t__defined */ __DeclareSendRpc(9000, "substrated_mark") #if UseStaticTemplates const static mach_msg_port_descriptor_t taskTemplate = { /* name = */ MACH_PORT_NULL, /* pad1 = */ 0, /* pad2 = */ 0, /* disp = */ 19, /* type = */ MACH_MSG_PORT_DESCRIPTOR, }; #endif /* UseStaticTemplates */ InP->msgh_body.msgh_descriptor_count = 1; #if UseStaticTemplates InP->task = taskTemplate; InP->task.name = task; #else /* UseStaticTemplates */ InP->task.name = task; InP->task.disposition = 19; InP->task.type = MACH_MSG_PORT_DESCRIPTOR; #endif /* UseStaticTemplates */ InP->NDR = NDR_record; InP->source_address = source_address; InP->source_size = source_size; InP->target_address = *target_address; InP->Head.msgh_bits = MACH_MSGH_BITS_COMPLEX| MACH_MSGH_BITS(19, MACH_MSG_TYPE_MAKE_SEND_ONCE); /* msgh_size passed as argument */ InP->Head.msgh_request_port = server; InP->Head.msgh_reply_port = mig_get_reply_port(); InP->Head.msgh_id = 9000; InP->Head.msgh_reserved = 0; /* BEGIN VOUCHER CODE */ #ifdef USING_VOUCHERS if (voucher_mach_msg_set != NULL) { voucher_mach_msg_set(&InP->Head); } #endif // USING_VOUCHERS /* END VOUCHER CODE */ __BeforeSendRpc(9000, "substrated_mark") msg_result = mach_msg(&InP->Head, MACH_SEND_MSG|MACH_RCV_MSG|MACH_MSG_OPTION_NONE, (mach_msg_size_t)sizeof(Request), (mach_msg_size_t)sizeof(Reply), InP->Head.msgh_reply_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); __AfterSendRpc(9000, "substrated_mark") if (msg_result != MACH_MSG_SUCCESS) { __MachMsgErrorWithoutTimeout(msg_result); { return msg_result; } } #if defined(__MIG_check__Reply__substrated_mark_t__defined) check_result = __MIG_check__Reply__substrated_mark_t((__Reply__substrated_mark_t *)Out0P); if (check_result != MACH_MSG_SUCCESS) { return check_result; } #endif /* defined(__MIG_check__Reply__substrated_mark_t__defined) */ *target_address = Out0P->target_address; return KERN_SUCCESS; }
/* Routine mach_exception_raise_state */ mig_external kern_return_t mach_exception_raise_state ( mach_port_t exception_port, exception_type_t exception, const mach_exception_data_t code, mach_msg_type_number_t codeCnt, int *flavor, const thread_state_t old_state, mach_msg_type_number_t old_stateCnt, thread_state_t new_state, mach_msg_type_number_t *new_stateCnt ) { #ifdef __MigPackStructs #pragma pack(4) #endif typedef struct { mach_msg_header_t Head; NDR_record_t NDR; exception_type_t exception; mach_msg_type_number_t codeCnt; int64_t code[2]; int flavor; mach_msg_type_number_t old_stateCnt; natural_t old_state[224]; } Request __attribute__((unused)); #ifdef __MigPackStructs #pragma pack() #endif #ifdef __MigPackStructs #pragma pack(4) #endif typedef struct { mach_msg_header_t Head; NDR_record_t NDR; kern_return_t RetCode; int flavor; mach_msg_type_number_t new_stateCnt; natural_t new_state[224]; mach_msg_trailer_t trailer; } Reply __attribute__((unused)); #ifdef __MigPackStructs #pragma pack() #endif #ifdef __MigPackStructs #pragma pack(4) #endif typedef struct { mach_msg_header_t Head; NDR_record_t NDR; kern_return_t RetCode; int flavor; mach_msg_type_number_t new_stateCnt; natural_t new_state[224]; } __Reply __attribute__((unused)); #ifdef __MigPackStructs #pragma pack() #endif /* * typedef struct { * mach_msg_header_t Head; * NDR_record_t NDR; * kern_return_t RetCode; * } mig_reply_error_t; */ union { Request In; Reply Out; } Mess; Request *InP = &Mess.In; Reply *Out0P = &Mess.Out; mach_msg_return_t msg_result; unsigned int msgh_size; unsigned int msgh_size_delta; #ifdef __MIG_check__Reply__mach_exception_raise_state_t__defined kern_return_t check_result; #endif /* __MIG_check__Reply__mach_exception_raise_state_t__defined */ __DeclareSendRpc(2406, "mach_exception_raise_state") InP->NDR = NDR_record; InP->exception = exception; if (codeCnt > 2) { { return MIG_ARRAY_TOO_LARGE; } } (void)memcpy((char *) InP->code, (const char *) code, 8 * codeCnt); InP->codeCnt = codeCnt; msgh_size_delta = (8 * codeCnt); msgh_size = (mach_msg_size_t)(sizeof(Request) - 912) + msgh_size_delta; InP = (Request *) ((pointer_t) InP + msgh_size_delta - 16); InP->flavor = *flavor; if (old_stateCnt > 224) { { return MIG_ARRAY_TOO_LARGE; } } (void)memcpy((char *) InP->old_state, (const char *) old_state, 4 * old_stateCnt); InP->old_stateCnt = old_stateCnt; msgh_size += (4 * old_stateCnt); InP = &Mess.In; InP->Head.msgh_bits = MACH_MSGH_BITS(19, MACH_MSG_TYPE_MAKE_SEND_ONCE); /* msgh_size passed as argument */ InP->Head.msgh_request_port = exception_port; InP->Head.msgh_reply_port = mig_get_reply_port(); InP->Head.msgh_id = 2406; /* BEGIN VOUCHER CODE */ #ifdef USING_VOUCHERS if (voucher_mach_msg_set != NULL) { voucher_mach_msg_set(&InP->Head); } #endif // USING_VOUCHERS /* END VOUCHER CODE */ __BeforeSendRpc(2406, "mach_exception_raise_state") msg_result = mach_msg(&InP->Head, MACH_SEND_MSG|MACH_RCV_MSG|MACH_MSG_OPTION_NONE, msgh_size, (mach_msg_size_t)sizeof(Reply), InP->Head.msgh_reply_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); __AfterSendRpc(2406, "mach_exception_raise_state") if (msg_result != MACH_MSG_SUCCESS) { __MachMsgErrorWithoutTimeout(msg_result); { return msg_result; } } #if defined(__MIG_check__Reply__mach_exception_raise_state_t__defined) check_result = __MIG_check__Reply__mach_exception_raise_state_t((__Reply__mach_exception_raise_state_t *)Out0P); if (check_result != MACH_MSG_SUCCESS) { return check_result; } #endif /* defined(__MIG_check__Reply__mach_exception_raise_state_t__defined) */ *flavor = Out0P->flavor; if (Out0P->new_stateCnt > 224) { (void)memcpy((char *) new_state, (const char *) Out0P->new_state, 4 * 224); *new_stateCnt = Out0P->new_stateCnt; { return MIG_ARRAY_TOO_LARGE; } } (void)memcpy((char *) new_state, (const char *) Out0P->new_state, 4 * Out0P->new_stateCnt); *new_stateCnt = Out0P->new_stateCnt; return KERN_SUCCESS; }
/* Routine mach_exception_raise_state_identity */ mig_external kern_return_t mach_exception_raise_state_identity ( mach_port_t exception_port, mach_port_t thread, mach_port_t task, exception_type_t exception, mach_exception_data_t code, mach_msg_type_number_t codeCnt, int *flavor, thread_state_t old_state, mach_msg_type_number_t old_stateCnt, thread_state_t new_state, mach_msg_type_number_t *new_stateCnt ) { #ifdef __MigPackStructs #pragma pack(4) #endif typedef struct { mach_msg_header_t Head; /* start of the kernel processed data */ mach_msg_body_t msgh_body; mach_msg_port_descriptor_t thread; mach_msg_port_descriptor_t task; /* end of the kernel processed data */ NDR_record_t NDR; exception_type_t exception; mach_msg_type_number_t codeCnt; int64_t code[2]; int flavor; mach_msg_type_number_t old_stateCnt; natural_t old_state[224]; } Request __attribute__((unused)); #ifdef __MigPackStructs #pragma pack() #endif #ifdef __MigPackStructs #pragma pack(4) #endif typedef struct { mach_msg_header_t Head; NDR_record_t NDR; kern_return_t RetCode; int flavor; mach_msg_type_number_t new_stateCnt; natural_t new_state[224]; mach_msg_trailer_t trailer; } Reply __attribute__((unused)); #ifdef __MigPackStructs #pragma pack() #endif #ifdef __MigPackStructs #pragma pack(4) #endif typedef struct { mach_msg_header_t Head; NDR_record_t NDR; kern_return_t RetCode; int flavor; mach_msg_type_number_t new_stateCnt; natural_t new_state[224]; } __Reply __attribute__((unused)); #ifdef __MigPackStructs #pragma pack() #endif /* * typedef struct { * mach_msg_header_t Head; * NDR_record_t NDR; * kern_return_t RetCode; * } mig_reply_error_t; */ union { Request In; Reply Out; } Mess; Request *InP = &Mess.In; Reply *Out0P = &Mess.Out; mach_msg_return_t msg_result; unsigned int msgh_size; unsigned int msgh_size_delta; #ifdef __MIG_check__Reply__mach_exception_raise_state_identity_t__defined kern_return_t check_result; #endif /* __MIG_check__Reply__mach_exception_raise_state_identity_t__defined */ __DeclareSendRpc(2407, "mach_exception_raise_state_identity") #if UseStaticTemplates const static mach_msg_port_descriptor_t threadTemplate = { /* name = */ MACH_PORT_NULL, /* pad1 = */ 0, /* pad2 = */ 0, /* disp = */ 19, /* type = */ MACH_MSG_PORT_DESCRIPTOR, }; #endif /* UseStaticTemplates */ #if UseStaticTemplates const static mach_msg_port_descriptor_t taskTemplate = { /* name = */ MACH_PORT_NULL, /* pad1 = */ 0, /* pad2 = */ 0, /* disp = */ 19, /* type = */ MACH_MSG_PORT_DESCRIPTOR, }; #endif /* UseStaticTemplates */ InP->msgh_body.msgh_descriptor_count = 2; #if UseStaticTemplates InP->thread = threadTemplate; InP->thread.name = thread; #else /* UseStaticTemplates */ InP->thread.name = thread; InP->thread.disposition = 19; InP->thread.type = MACH_MSG_PORT_DESCRIPTOR; #endif /* UseStaticTemplates */ #if UseStaticTemplates InP->task = taskTemplate; InP->task.name = task; #else /* UseStaticTemplates */ InP->task.name = task; InP->task.disposition = 19; InP->task.type = MACH_MSG_PORT_DESCRIPTOR; #endif /* UseStaticTemplates */ InP->NDR = NDR_record; InP->exception = exception; if (codeCnt > 2) { { return MIG_ARRAY_TOO_LARGE; } } (void)memcpy((char *) InP->code, (const char *) code, 8 * codeCnt); InP->codeCnt = codeCnt; msgh_size_delta = (8 * codeCnt); msgh_size = (mach_msg_size_t)(sizeof(Request) - 912) + msgh_size_delta; InP = (Request *) ((pointer_t) InP + msgh_size_delta - 16); InP->flavor = *flavor; if (old_stateCnt > 224) { { return MIG_ARRAY_TOO_LARGE; } } (void)memcpy((char *) InP->old_state, (const char *) old_state, 4 * old_stateCnt); InP->old_stateCnt = old_stateCnt; msgh_size += (4 * old_stateCnt); InP = &Mess.In; InP->Head.msgh_bits = MACH_MSGH_BITS_COMPLEX| MACH_MSGH_BITS(19, MACH_MSG_TYPE_MAKE_SEND_ONCE); /* msgh_size passed as argument */ InP->Head.msgh_request_port = exception_port; InP->Head.msgh_reply_port = mig_get_reply_port(); InP->Head.msgh_id = 2407; /* BEGIN VOUCHER CODE */ #ifdef USING_VOUCHERS if (voucher_mach_msg_set != NULL) { voucher_mach_msg_set(&InP->Head); } #endif // USING_VOUCHERS /* END VOUCHER CODE */ __BeforeSendRpc(2407, "mach_exception_raise_state_identity") msg_result = mach_msg(&InP->Head, MACH_SEND_MSG|MACH_RCV_MSG|MACH_MSG_OPTION_NONE, msgh_size, (mach_msg_size_t)sizeof(Reply), InP->Head.msgh_reply_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); __AfterSendRpc(2407, "mach_exception_raise_state_identity") if (msg_result != MACH_MSG_SUCCESS) { __MachMsgErrorWithoutTimeout(msg_result); { return msg_result; } } #if defined(__MIG_check__Reply__mach_exception_raise_state_identity_t__defined) check_result = __MIG_check__Reply__mach_exception_raise_state_identity_t((__Reply__mach_exception_raise_state_identity_t *)Out0P); if (check_result != MACH_MSG_SUCCESS) { return check_result; } #endif /* defined(__MIG_check__Reply__mach_exception_raise_state_identity_t__defined) */ *flavor = Out0P->flavor; if (Out0P->new_stateCnt > 224) { (void)memcpy((char *) new_state, (const char *) Out0P->new_state, 4 * 224); *new_stateCnt = Out0P->new_stateCnt; { return MIG_ARRAY_TOO_LARGE; } } (void)memcpy((char *) new_state, (const char *) Out0P->new_state, 4 * Out0P->new_stateCnt); *new_stateCnt = Out0P->new_stateCnt; return KERN_SUCCESS; }
/* Send signal SIGNO to MSGPORT with REFPORT as reference. Don't block in any fashion. */ void send_signal (mach_port_t msgport, int signal, mach_port_t refport) { error_t err; /* This message buffer might be modified by mach_msg in some error cases, so we cannot safely use a shared static buffer. */ struct msg_sig_post_request message = { { /* Message header: */ (MACH_MSGH_BITS_COMPLEX | MACH_MSGH_BITS (MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE)), /* msgh_bits */ sizeof message, /* msgh_size */ msgport, /* msgh_remote_port */ MACH_PORT_NULL, /* msgh_local_port */ 0, /* msgh_seqno */ RPCID_SIG_POST, /* msgh_id */ }, { /* Type descriptor for signo */ MACH_MSG_TYPE_INTEGER_32, /* msgt_name */ 32, /* msgt_size */ 1, /* msgt_number */ 1, /* msgt_inline */ 0, /* msgt_longform */ 0, /* msgt_deallocate */ 0, /* msgt_unused */ }, /* Signal number */ signal, /* Type descriptor for sigcode */ { MACH_MSG_TYPE_INTEGER_32, /* msgt_name */ 32, /* msgt_size */ 1, /* msgt_number */ 1, /* msgt_inline */ 0, /* msgt_longform */ 0, /* msgt_deallocate */ 0, /* msgt_unused */ }, /* Sigcode */ 0, { /* Type descriptor for refport */ MACH_MSG_TYPE_COPY_SEND, /* msgt_name */ 32, /* msgt_size */ 1, /* msgt_number */ 1, /* msgt_inline */ 0, /* msgt_longform */ 0, /* msgt_deallocate */ 0, /* msgt_unused */ }, refport }; err = mach_msg ((mach_msg_header_t *)&message, MACH_SEND_MSG|MACH_SEND_TIMEOUT, sizeof message, 0, MACH_PORT_NULL, 0, MACH_PORT_NULL); switch (err) { case MACH_SEND_TIMED_OUT: /* The send could not complete immediately, and we do not want to block. We'll fork off another thread to do the blocking send. The message buffer was modified by a pseudo-receive operation, so we need to copy its modified contents into a malloc'd buffer. */ { struct msg_sig_post_request *copy = malloc (sizeof *copy); if (copy) { memcpy (copy, &message, sizeof message); cthread_detach (cthread_fork (blocking_message_send, copy)); } break; } /* These are the other codes that mean a pseudo-receive modified the message buffer and we might need to clean up the send rights. None of them should be possible in our usage. */ case MACH_SEND_INTERRUPTED: case MACH_SEND_INVALID_NOTIFY: case MACH_SEND_NO_NOTIFY: case MACH_SEND_NOTIFY_IN_PROGRESS: assert_perror (err); break; default: /* Other errors are safe to ignore. */ break; } }
static void* handleIPCMessage (void* aMsgParam, CFIndex aMessageSize, CFAllocatorRef anAllocator, void* aMachPort) { SystemStarterIPCMessage* aMessage = (SystemStarterIPCMessage*) aMsgParam; SystemStarterIPCMessage* aReplyMessage = NULL; CFDataRef aResult = NULL; CFDataRef aData = NULL; if (aMessage->aHeader.msgh_bits & MACH_MSGH_BITS_COMPLEX) { warning(CFSTR("Ignoring out-of-line IPC message.\n")); return NULL; } else { mach_msg_security_trailer_t* aSecurityTrailer = (mach_msg_security_trailer_t*) ((uint8_t*)aMessage + round_msg(sizeof(SystemStarterIPCMessage) + aMessage->aByteLength)); /* CFRunLoop includes the format 0 message trailer with the passed message. */ if (aSecurityTrailer->msgh_trailer_type == MACH_MSG_TRAILER_FORMAT_0 && aSecurityTrailer->msgh_sender.val[0] != 0) { warning(CFSTR("Ignoring IPC message sent from uid %d\n."), aSecurityTrailer->msgh_sender.val[0]); return NULL; } } if (aMessage->aProtocol != kIPCProtocolVersion) { warning(CFSTR("Unsupported IPC protocol version number: %d. Message ignored.\n"), aMessage->aProtocol); return NULL; } aData = CFDataCreateWithBytesNoCopy(NULL, (uint8_t*)aMessage + sizeof(SystemStarterIPCMessage), aMessage->aByteLength, kCFAllocatorNull); /* * Dispatch the IPC message. */ if (aData) { StartupContext aStartupContext = NULL; CFStringRef anErrorString = NULL; CFDictionaryRef anIPCMessage = (CFDictionaryRef) CFPropertyListCreateFromXMLData(NULL, aData, kCFPropertyListImmutable, &anErrorString); if (gDebugFlag == 2) debug(CFSTR("\nIPC message = %@\n"), anIPCMessage); if (aMachPort) { CFMachPortContext aMachPortContext; CFMachPortGetContext((CFMachPortRef)aMachPort, &aMachPortContext); aStartupContext = (StartupContext)aMachPortContext.info; } if (anIPCMessage && CFGetTypeID(anIPCMessage) == CFDictionaryGetTypeID()) { /* switch on the type of the IPC message */ CFStringRef anIPCMessageType = CFDictionaryGetValue(anIPCMessage, kIPCMessageKey); if (anIPCMessageType && CFGetTypeID(anIPCMessageType) == CFStringGetTypeID()) { if (CFEqual(anIPCMessageType, kIPCConsoleMessage)) { consoleMessage(aStartupContext, anIPCMessage); } else if (CFEqual(anIPCMessageType, kIPCStatusMessage)) { statusMessage(aStartupContext, anIPCMessage); } else if (CFEqual(anIPCMessageType, kIPCQueryMessage)) { aResult = queryConfigSetting(aStartupContext, anIPCMessage); } else if (CFEqual(anIPCMessageType, kIPCLoadDisplayBundleMessage)) { loadDisplayBundle(aStartupContext, anIPCMessage); } else if (CFEqual(anIPCMessageType, kIPCUnloadDisplayBundleMessage)) { unloadDisplayBundle(aStartupContext, anIPCMessage); } } } else { error(CFSTR("Unable to parse IPC message: %@\n"), anErrorString); } CFRelease(aData); } else { error(CFSTR("Out of memory. Could not allocate space for IPC message.\n")); } /* * Generate a Mach message for the result data. */ if (!aResult) aResult = CFDataCreateWithBytesNoCopy(NULL, "", 1, kCFAllocatorNull); if (aResult) { CFIndex aDataSize = CFDataGetLength(aResult); CFIndex aReplyMessageSize = round_msg(sizeof(SystemStarterIPCMessage) + aDataSize + 3); aReplyMessage = CFAllocatorAllocate(kCFAllocatorSystemDefault, aReplyMessageSize, 0); if (aReplyMessage) { aReplyMessage->aHeader.msgh_id = -1 * (SInt32)aMessage->aHeader.msgh_id; aReplyMessage->aHeader.msgh_size = aReplyMessageSize; aReplyMessage->aHeader.msgh_remote_port = aMessage->aHeader.msgh_remote_port; aReplyMessage->aHeader.msgh_local_port = MACH_PORT_NULL; aReplyMessage->aHeader.msgh_reserved = 0; aReplyMessage->aHeader.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE, 0); aReplyMessage->aBody.msgh_descriptor_count = 0; aReplyMessage->aProtocol = kIPCProtocolVersion; aReplyMessage->aByteLength = CFDataGetLength(aResult); memmove((uint8_t*)aReplyMessage + sizeof(SystemStarterIPCMessage), CFDataGetBytePtr(aResult), CFDataGetLength(aResult)); } CFRelease(aResult); } if (!aReplyMessage) { error(CFSTR("Out of memory. Could not allocate IPC result.\n")); } return aReplyMessage; }
void profile_thread() { struct message { mach_msg_header_t head; mach_msg_type_t type; int arg[SIZE_PROF_BUFFER+1]; } msg; register spl_t s; buf_to_send_t buf_entry; queue_entry_t prof_queue_entry; prof_data_t pbuf; simple_lock_t lock; msg_return_t mr; int j; /* Initialise the queue header for the prof_queue */ mpqueue_init(&prof_queue); /* Template initialisation of header and type structures */ msg.head.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE); msg.head.msgh_size = sizeof(msg); msg.head.msgh_local_port = MACH_PORT_NULL; msg.head.msgh_kind = MACH_MSGH_KIND_NORMAL; msg.head.msgh_id = 666666; msg.type.msgt_name = MACH_MSG_TYPE_INTEGER_32; msg.type.msgt_size = 32; msg.type.msgt_number = SIZE_PROF_BUFFER+1; msg.type.msgt_inline = TRUE; msg.type.msgt_longform = FALSE; msg.type.msgt_deallocate = FALSE; msg.type.msgt_unused = 0; while (TRUE) { /* Dequeue the first buffer. */ s = splsched(); mpdequeue_head(&prof_queue, &prof_queue_entry); splx(s); if ((buf_entry = (buf_to_send_t) prof_queue_entry) == NULLBTS) { thread_sleep((event_t) profile_thread, lock, TRUE); if (current_thread()->wait_result != THREAD_AWAKENED) break; } else { task_t curr_task; thread_t curr_th; register int *sample; int curr_buf; int imax; curr_th = (thread_t) buf_entry->thread; curr_buf = (int) buf_entry->number; pbuf = curr_th->profil_buffer; /* Set the remote port */ msg.head.msgh_remote_port = (mach_port_t) pbuf->prof_port; sample = pbuf->prof_area[curr_buf].p_zone; imax = pbuf->prof_area[curr_buf].p_index; for(j=0 ;j<imax; j++,sample++) msg.arg[j] = *sample; /* Let hardclock() know you've finished the dirty job */ pbuf->prof_area[curr_buf].p_full = FALSE; /* * Store the number of samples actually sent * as the last element of the array. */ msg.arg[SIZE_PROF_BUFFER] = imax; mr = mach_msg(&(msg.head), MACH_SEND_MSG, sizeof(struct message), 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); if (mr != MACH_MSG_SUCCESS) { printf("profile_thread: mach_msg failed returned %x\n",(int)mr); } if (buf_entry->wakeme) thread_wakeup((event_t) &buf_entry->wakeme); kmem_free(kernel_map, (buf_to_send_t) buf_entry, sizeof(struct buf_to_send)); } } /* The profile thread has been signalled to exit. There may still be sample data queued for us, which we must now throw away. Once we set profile_thread_id to null, hardclock() will stop queueing any additional samples, so we do not need to alter the interrupt level. */ profile_thread_id = THREAD_NULL; while (1) { mpdequeue_head(&prof_queue, &prof_queue_entry); if ((buf_entry = (buf_to_send_t) prof_queue_entry) == NULLBTS) break; if (buf_entry->wakeme) thread_wakeup((event_t) &buf_entry->wakeme); kmem_free(kernel_map, (buf_to_send_t) buf_entry, sizeof(struct buf_to_send)); } thread_halt_self(); }
bool Connection::sendOutgoingMessage(MessageID messageID, PassOwnPtr<MessageEncoder> encoder) { Vector<Attachment> attachments = encoder->releaseAttachments(); size_t numberOfPortDescriptors = 0; size_t numberOfOOLMemoryDescriptors = 0; for (size_t i = 0; i < attachments.size(); ++i) { Attachment::Type type = attachments[i].type(); if (type == Attachment::MachPortType) numberOfPortDescriptors++; else if (type == Attachment::MachOOLMemoryType) numberOfOOLMemoryDescriptors++; } size_t messageSize = machMessageSize(encoder->bufferSize(), numberOfPortDescriptors, numberOfOOLMemoryDescriptors); char buffer[inlineMessageMaxSize]; bool messageBodyIsOOL = false; if (messageSize > sizeof(buffer)) { messageBodyIsOOL = true; attachments.append(Attachment(encoder->buffer(), encoder->bufferSize(), MACH_MSG_VIRTUAL_COPY, false)); numberOfOOLMemoryDescriptors++; messageSize = machMessageSize(0, numberOfPortDescriptors, numberOfOOLMemoryDescriptors); } bool isComplex = (numberOfPortDescriptors + numberOfOOLMemoryDescriptors > 0); mach_msg_header_t* header = reinterpret_cast<mach_msg_header_t*>(&buffer); header->msgh_bits = isComplex ? MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND | MACH_MSGH_BITS_COMPLEX, 0) : MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0); header->msgh_size = messageSize; header->msgh_remote_port = m_sendPort; header->msgh_local_port = MACH_PORT_NULL; header->msgh_id = messageID.toInt(); if (messageBodyIsOOL) header->msgh_id |= MessageBodyIsOOL; uint8_t* messageData; if (isComplex) { mach_msg_body_t* body = reinterpret_cast<mach_msg_body_t*>(header + 1); body->msgh_descriptor_count = numberOfPortDescriptors + numberOfOOLMemoryDescriptors; uint8_t* descriptorData = reinterpret_cast<uint8_t*>(body + 1); for (size_t i = 0; i < attachments.size(); ++i) { Attachment attachment = attachments[i]; mach_msg_descriptor_t* descriptor = reinterpret_cast<mach_msg_descriptor_t*>(descriptorData); switch (attachment.type()) { case Attachment::MachPortType: descriptor->port.name = attachment.port(); descriptor->port.disposition = attachment.disposition(); descriptor->port.type = MACH_MSG_PORT_DESCRIPTOR; descriptorData += sizeof(mach_msg_port_descriptor_t); break; case Attachment::MachOOLMemoryType: descriptor->out_of_line.address = attachment.address(); descriptor->out_of_line.size = attachment.size(); descriptor->out_of_line.copy = attachment.copyOptions(); descriptor->out_of_line.deallocate = attachment.deallocate(); descriptor->out_of_line.type = MACH_MSG_OOL_DESCRIPTOR; descriptorData += sizeof(mach_msg_ool_descriptor_t); break; default: ASSERT_NOT_REACHED(); } } messageData = descriptorData; } else messageData = (uint8_t*)(header + 1); // Copy the data if it is not being sent out-of-line. if (!messageBodyIsOOL) memcpy(messageData, encoder->buffer(), encoder->bufferSize()); ASSERT(m_sendPort); // Send the message. kern_return_t kr = mach_msg(header, MACH_SEND_MSG, messageSize, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); if (kr != KERN_SUCCESS) { // FIXME: What should we do here? } return true; }
/* SimpleRoutine mach_notify_port_destroyed */ mig_external kern_return_t _dispatch_send_mach_notify_port_destroyed ( mach_port_t _notify, mach_port_t _rights ) { #ifdef __MigPackStructs #pragma pack(4) #endif typedef struct { mach_msg_header_t Head; /* start of the kernel processed data */ mach_msg_body_t msgh_body; mach_msg_port_descriptor_t _rights; /* end of the kernel processed data */ } Request; #ifdef __MigPackStructs #pragma pack() #endif /* * typedef struct { * mach_msg_header_t Head; * NDR_record_t NDR; * kern_return_t RetCode; * } mig_reply_error_t; */ union { Request In; } Mess; Request *InP = &Mess.In; mach_msg_return_t msg_result; #ifdef __MIG_check__Reply__mach_notify_port_destroyed_t__defined kern_return_t check_result; #endif /* __MIG_check__Reply__mach_notify_port_destroyed_t__defined */ __DeclareSendSimple(69, "mach_notify_port_destroyed") #if UseStaticTemplates const static mach_msg_port_descriptor_t _rightsTemplate = { /* name = */ MACH_PORT_NULL, /* pad1 = */ 0, /* pad2 = */ 0, /* disp = */ 16, /* type = */ MACH_MSG_PORT_DESCRIPTOR, }; #endif /* UseStaticTemplates */ InP->msgh_body.msgh_descriptor_count = 1; #if UseStaticTemplates InP->_rights = _rightsTemplate; InP->_rights.name = _rights; #else /* UseStaticTemplates */ InP->_rights.name = _rights; InP->_rights.disposition = 16; InP->_rights.type = MACH_MSG_PORT_DESCRIPTOR; #endif /* UseStaticTemplates */ InP->Head.msgh_bits = MACH_MSGH_BITS_COMPLEX| MACH_MSGH_BITS(18, 0); /* msgh_size passed as argument */ InP->Head.msgh_request_port = _notify; InP->Head.msgh_reply_port = MACH_PORT_NULL; InP->Head.msgh_id = 69; __BeforeSendSimple(69, "mach_notify_port_destroyed") msg_result = mach_msg(&InP->Head, MACH_SEND_MSG|MACH_MSG_OPTION_NONE, (mach_msg_size_t)sizeof(Request), 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); __AfterSendSimple(69, "mach_notify_port_destroyed") return msg_result; }