diff --git a/include/mach/mach_port.defs b/include/mach/mach_port.defs index e1f45e3..96a5987 100644 --- a/include/mach/mach_port.defs +++ b/include/mach/mach_port.defs @@ -342,5 +342,19 @@ routine mach_port_create_act( user_rbuf_size : vm_size_t; out new_act : thread_t); +#else /* MIGRATING_THREADS */ + +skip; /* mach_port_set_rpcinfo */ +skip; /* mach_port_create_act */ + #endif /* MIGRATING_THREADS */ +/* + * Only valid for receive rights. + * Set the protected payload for this right to the given value. + */ + +routine mach_port_set_protected_payload( + task : ipc_space_t; + name : mach_port_name_t; + payload : natural_t); diff --git a/include/mach/message.h b/include/mach/message.h index f78e978..0a7297e 100644 --- a/include/mach/message.h +++ b/include/mach/message.h @@ -136,7 +136,10 @@ typedef struct { mach_msg_bits_t msgh_bits; mach_msg_size_t msgh_size; mach_port_t msgh_remote_port; - mach_port_t msgh_local_port; + union { + mach_port_t msgh_local_port; + unsigned long msgh_protected_payload; + }; mach_port_seqno_t msgh_seqno; mach_msg_id_t msgh_id; } mach_msg_header_t; @@ -253,7 +256,9 @@ typedef struct { #define MACH_MSG_TYPE_PORT_SEND MACH_MSG_TYPE_MOVE_SEND #define MACH_MSG_TYPE_PORT_SEND_ONCE MACH_MSG_TYPE_MOVE_SEND_ONCE -#define MACH_MSG_TYPE_LAST 22 /* Last assigned */ +#define MACH_MSG_TYPE_PROTECTED_PAYLOAD 23 + +#define MACH_MSG_TYPE_LAST 23 /* Last assigned */ /* * A dummy value. Mostly used to indicate that the actual value diff --git a/ipc/ipc_init.c b/ipc/ipc_init.c index debda47..7627b4e 100644 --- a/ipc/ipc_init.c +++ b/ipc/ipc_init.c @@ -80,7 +80,7 @@ ipc_bootstrap(void) sizeof(struct ipc_tree_entry), 0, NULL, NULL, NULL, 0); kmem_cache_init(&ipc_object_caches[IOT_PORT], "ipc_port", - sizeof(struct ipc_port), 0, NULL, NULL, NULL, 0); + sizeof(struct ipc_port)+4, 0, NULL, NULL, NULL, 0); kmem_cache_init(&ipc_object_caches[IOT_PORT_SET], "ipc_pset", sizeof(struct ipc_pset), 0, NULL, NULL, NULL, 0); diff --git a/ipc/ipc_kmsg.c b/ipc/ipc_kmsg.c index 0e43410..aa51100 100644 --- a/ipc/ipc_kmsg.c +++ b/ipc/ipc_kmsg.c @@ -1802,9 +1802,17 @@ ipc_kmsg_copyout_header(msg, space, notify) } else ip_unlock(dest); - msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) | - MACH_MSGH_BITS(0, MACH_MSG_TYPE_PORT_SEND)); - msg->msgh_local_port = dest_name; + if (dest->ip_protected_payload == 0) { + msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) | + MACH_MSGH_BITS(0, MACH_MSG_TYPE_PORT_SEND)); + msg->msgh_local_port = dest_name; + } else { + msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) | + MACH_MSGH_BITS( + 0, MACH_MSG_TYPE_PROTECTED_PAYLOAD)); + msg->msgh_protected_payload = \ + dest->ip_protected_payload; + } msg->msgh_remote_port = MACH_PORT_NULL; return MACH_MSG_SUCCESS; } @@ -1900,10 +1908,18 @@ ipc_kmsg_copyout_header(msg, space, notify) } else ip_unlock(dest); - msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) | - MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE, - MACH_MSG_TYPE_PORT_SEND)); - msg->msgh_local_port = dest_name; + if (dest->ip_protected_payload == 0) { + msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) | + MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE, + MACH_MSG_TYPE_PORT_SEND)); + msg->msgh_local_port = dest_name; + } else { + msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) | + MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE, + MACH_MSG_TYPE_PROTECTED_PAYLOAD)); + msg->msgh_protected_payload = \ + dest->ip_protected_payload; + } msg->msgh_remote_port = reply_name; return MACH_MSG_SUCCESS; } @@ -1935,9 +1951,18 @@ ipc_kmsg_copyout_header(msg, space, notify) dest_name = MACH_PORT_NULL; } - msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) | - MACH_MSGH_BITS(0, MACH_MSG_TYPE_PORT_SEND_ONCE)); - msg->msgh_local_port = dest_name; + if (dest->ip_protected_payload == 0) { + msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) | + MACH_MSGH_BITS(0, + MACH_MSG_TYPE_PORT_SEND_ONCE)); + msg->msgh_local_port = dest_name; + } else { + msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) | + MACH_MSGH_BITS(0, + MACH_MSG_TYPE_PROTECTED_PAYLOAD)); + msg->msgh_protected_payload = \ + dest->ip_protected_payload; + } msg->msgh_remote_port = MACH_PORT_NULL; return MACH_MSG_SUCCESS; } @@ -2227,9 +2252,16 @@ ipc_kmsg_copyout_header(msg, space, notify) if (IP_VALID(reply)) ipc_port_release(reply); - msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) | - MACH_MSGH_BITS(reply_type, dest_type)); - msg->msgh_local_port = dest_name; + if (dest->ip_protected_payload == 0) { + msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) | + MACH_MSGH_BITS(reply_type, dest_type)); + msg->msgh_local_port = dest_name; + } else { + msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) | + MACH_MSGH_BITS(reply_type, + MACH_MSG_TYPE_PROTECTED_PAYLOAD)); + msg->msgh_protected_payload = dest->ip_protected_payload; + } msg->msgh_remote_port = reply_name; } diff --git a/ipc/ipc_object.c b/ipc/ipc_object.c index 982bd4e..59f5a67 100644 --- a/ipc/ipc_object.c +++ b/ipc/ipc_object.c @@ -481,6 +481,7 @@ ipc_object_copyin_from_kernel( port->ip_receiver_name = MACH_PORT_NULL; port->ip_destination = IP_NULL; + port->ip_protected_payload = 0; ip_unlock(port); break; } diff --git a/ipc/ipc_port.c b/ipc/ipc_port.c index d4ade8e..4051746 100644 --- a/ipc/ipc_port.c +++ b/ipc/ipc_port.c @@ -425,6 +425,25 @@ ipc_port_set_seqno(port, seqno) } /* + * Routine: ipc_port_set_protected_payload + * Purpose: + * Changes a port's protected payload. + * Conditions: + * The port is locked and active. + */ + +void +ipc_port_set_protected_payload(ipc_port_t port, unsigned long payload) +{ + ipc_mqueue_t mqueue; + + mqueue = ipc_port_lock_mqueue(port); + port->ip_protected_payload = payload; + imq_unlock(mqueue); +} + + +/* * Routine: ipc_port_clear_receiver * Purpose: * Prepares a receive right for transmission/destruction. @@ -493,6 +512,7 @@ ipc_port_init( port->ip_seqno = 0; port->ip_msgcount = 0; port->ip_qlimit = MACH_PORT_QLIMIT_DEFAULT; + port->ip_protected_payload = 0; ipc_mqueue_init(&port->ip_messages); ipc_thread_queue_init(&port->ip_blocked); @@ -615,6 +635,7 @@ ipc_port_destroy( /* make port be in limbo */ port->ip_receiver_name = MACH_PORT_NULL; port->ip_destination = IP_NULL; + port->ip_protected_payload = 0; ip_unlock(port); if (!ipc_port_check_circularity(port, pdrequest)) { @@ -1240,6 +1261,8 @@ ipc_port_print(port) printf(", sndrs=0x%x", port->ip_blocked.ithq_base); printf(", kobj=0x%x\n", port->ip_kobject); + iprintf("protected_payload=%p\n", (void *) port->ip_protected_payload); + indent -= 2; } diff --git a/ipc/ipc_port.h b/ipc/ipc_port.h index 27d2e49..a1a0943 100644 --- a/ipc/ipc_port.h +++ b/ipc/ipc_port.h @@ -96,6 +96,7 @@ struct ipc_port { mach_port_msgcount_t ip_msgcount; mach_port_msgcount_t ip_qlimit; struct ipc_thread_queue ip_blocked; + unsigned long ip_protected_payload; }; #define ip_object ip_target.ipt_object @@ -262,6 +263,9 @@ extern void ipc_port_set_seqno(ipc_port_t, mach_port_seqno_t); extern void +ipc_port_set_protected_payload(ipc_port_t, unsigned long); + +extern void ipc_port_clear_receiver(ipc_port_t); extern void diff --git a/ipc/ipc_right.c b/ipc/ipc_right.c index 41fe3de..1edbb47 100644 --- a/ipc/ipc_right.c +++ b/ipc/ipc_right.c @@ -1432,6 +1432,12 @@ ipc_right_copyin( port->ip_receiver_name = MACH_PORT_NULL; port->ip_destination = IP_NULL; + + /* + * Clear the protected payload field to retain + * the behavior of mach_msg. + */ + port->ip_protected_payload = 0; ip_unlock(port); *objectp = (ipc_object_t) port; @@ -1932,6 +1938,12 @@ ipc_right_copyout( port->ip_receiver_name = name; port->ip_receiver = space; + /* + * Clear the protected payload field to retain + * the behavior of mach_msg. + */ + port->ip_protected_payload = 0; + assert((bits & MACH_PORT_TYPE_RECEIVE) == 0); if (bits & MACH_PORT_TYPE_SEND) { diff --git a/ipc/mach_port.c b/ipc/mach_port.c index fbc5e69..d80d526 100644 --- a/ipc/mach_port.c +++ b/ipc/mach_port.c @@ -1564,3 +1564,40 @@ mach_port_set_syscall_right(task, name) } #endif #endif /* MIGRATING_THREADS */ + +/* + * Routine: mach_port_set_protected_payload [kernel call] + * Purpose: + * Changes a receive right's protected payload. + * Conditions: + * Nothing locked. + * Returns: + * KERN_SUCCESS Set protected payload. + * KERN_INVALID_TASK The space is null. + * KERN_INVALID_TASK The space is dead. + * KERN_INVALID_NAME The name doesn't denote a right. + * KERN_INVALID_RIGHT Name doesn't denote receive rights. + */ + +kern_return_t +mach_port_set_protected_payload( + ipc_space_t space, + mach_port_t name, + unsigned long payload) +{ + ipc_port_t port; + kern_return_t kr; + + if (space == IS_NULL) + return KERN_INVALID_TASK; + + kr = ipc_port_translate_receive(space, name, &port); + if (kr != KERN_SUCCESS) + return kr; + /* port is locked and active */ + + ipc_port_set_protected_payload(port, payload); + + ip_unlock(port); + return KERN_SUCCESS; +}