summaryrefslogtreecommitdiff
path: root/ipc/ipc_kmsg.c
diff options
context:
space:
mode:
Diffstat (limited to 'ipc/ipc_kmsg.c')
-rw-r--r--ipc/ipc_kmsg.c387
1 files changed, 201 insertions, 186 deletions
diff --git a/ipc/ipc_kmsg.c b/ipc/ipc_kmsg.c
index 28ed23c6..bd843804 100644
--- a/ipc/ipc_kmsg.c
+++ b/ipc/ipc_kmsg.c
@@ -42,7 +42,9 @@
#include <mach/message.h>
#include <mach/port.h>
#include <machine/locore.h>
+#include <machine/copy_user.h>
#include <kern/assert.h>
+#include <kern/debug.h>
#include <kern/kalloc.h>
#include <vm/vm_map.h>
#include <vm/vm_object.h>
@@ -68,9 +70,6 @@
#include <ipc/ipc_print.h>
#endif
-#define is_misaligned(x) ( ((vm_offset_t)(x)) & (sizeof(vm_offset_t)-1) )
-#define ptr_align(x) \
- ( ( ((vm_offset_t)(x)) + (sizeof(vm_offset_t)-1) ) & ~(sizeof(vm_offset_t)-1) )
ipc_kmsg_t ipc_kmsg_cache[NCPUS];
@@ -214,7 +213,7 @@ ipc_kmsg_destroy(
* No locks held.
*/
-void
+static void
ipc_kmsg_clean_body(
vm_offset_t saddr,
vm_offset_t eaddr)
@@ -230,28 +229,23 @@ ipc_kmsg_clean_body(
type = (mach_msg_type_long_t *) saddr;
is_inline = ((mach_msg_type_t*)type)->msgt_inline;
if (((mach_msg_type_t*)type)->msgt_longform) {
- /* This must be aligned */
- if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
- (is_misaligned(type))) {
- saddr = ptr_align(saddr);
- continue;
- }
name = type->msgtl_name;
size = type->msgtl_size;
number = type->msgtl_number;
saddr += sizeof(mach_msg_type_long_t);
+ if (mach_msg_kernel_is_misaligned(sizeof(mach_msg_type_long_t))) {
+ saddr = mach_msg_kernel_align(saddr);
+ }
} else {
name = ((mach_msg_type_t*)type)->msgt_name;
size = ((mach_msg_type_t*)type)->msgt_size;
number = ((mach_msg_type_t*)type)->msgt_number;
saddr += sizeof(mach_msg_type_t);
+ if (mach_msg_kernel_is_misaligned(sizeof(mach_msg_type_t))) {
+ saddr = mach_msg_kernel_align(saddr);
+ }
}
- /* padding (ptrs and ports) ? */
- if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
- ((size >> 3) == sizeof(natural_t)))
- saddr = ptr_align(saddr);
-
/* calculate length of data in bytes, rounding up */
length = ((number * size) + 7) >> 3;
@@ -284,9 +278,7 @@ ipc_kmsg_clean_body(
}
if (is_inline) {
- /* inline data sizes round up to int boundaries */
-
- saddr += (length + 3) &~ 3;
+ saddr += length;
} else {
vm_offset_t data = * (vm_offset_t *) saddr;
@@ -301,6 +293,7 @@ ipc_kmsg_clean_body(
saddr += sizeof(vm_offset_t);
}
+ saddr = mach_msg_kernel_align(saddr);
}
}
@@ -356,7 +349,7 @@ ipc_kmsg_clean(ipc_kmsg_t kmsg)
* Nothing locked.
*/
-void
+static void
ipc_kmsg_clean_partial(
ipc_kmsg_t kmsg,
vm_offset_t eaddr,
@@ -388,31 +381,26 @@ ipc_kmsg_clean_partial(
boolean_t is_inline, is_port;
vm_size_t length;
-xxx: type = (mach_msg_type_long_t *) eaddr;
+ type = (mach_msg_type_long_t *) eaddr;
is_inline = ((mach_msg_type_t*)type)->msgt_inline;
if (((mach_msg_type_t*)type)->msgt_longform) {
- /* This must be aligned */
- if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
- (is_misaligned(type))) {
- eaddr = ptr_align(eaddr);
- goto xxx;
- }
name = type->msgtl_name;
size = type->msgtl_size;
rnumber = type->msgtl_number;
eaddr += sizeof(mach_msg_type_long_t);
+ if (mach_msg_kernel_is_misaligned(sizeof(mach_msg_type_long_t))) {
+ eaddr = mach_msg_kernel_align(eaddr);
+ }
} else {
name = ((mach_msg_type_t*)type)->msgt_name;
size = ((mach_msg_type_t*)type)->msgt_size;
rnumber = ((mach_msg_type_t*)type)->msgt_number;
eaddr += sizeof(mach_msg_type_t);
+ if (mach_msg_kernel_is_misaligned(sizeof(mach_msg_type_t))) {
+ eaddr = mach_msg_kernel_align(eaddr);
+ }
}
- /* padding (ptrs and ports) ? */
- if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
- ((size >> 3) == sizeof(natural_t)))
- eaddr = ptr_align(eaddr);
-
/* calculate length of data in bytes, rounding up */
length = ((rnumber * size) + 7) >> 3;
@@ -496,39 +484,32 @@ ipc_kmsg_free(ipc_kmsg_t kmsg)
mach_msg_return_t
ipc_kmsg_get(
- mach_msg_header_t *msg,
+ mach_msg_user_header_t *msg,
mach_msg_size_t size,
ipc_kmsg_t *kmsgp)
{
ipc_kmsg_t kmsg;
+ mach_msg_size_t ksize = size * IKM_EXPAND_FACTOR;
- if ((size < sizeof(mach_msg_header_t)) || (size & 3))
+ if ((size < sizeof(mach_msg_user_header_t)) || mach_msg_user_is_misaligned(size))
return MACH_SEND_MSG_TOO_SMALL;
- if (size <= IKM_SAVED_MSG_SIZE) {
- kmsg = ikm_cache();
- if (kmsg != IKM_NULL) {
- ikm_cache() = IKM_NULL;
- ikm_check_initialized(kmsg, IKM_SAVED_KMSG_SIZE);
- } else {
- kmsg = ikm_alloc(IKM_SAVED_MSG_SIZE);
- if (kmsg == IKM_NULL)
- return MACH_SEND_NO_BUFFER;
- ikm_init(kmsg, IKM_SAVED_MSG_SIZE);
- }
+ if (ksize <= IKM_SAVED_MSG_SIZE) {
+ kmsg = ikm_cache_alloc();
+ if (kmsg == IKM_NULL)
+ return MACH_SEND_NO_BUFFER;
} else {
- kmsg = ikm_alloc(size);
+ kmsg = ikm_alloc(ksize);
if (kmsg == IKM_NULL)
return MACH_SEND_NO_BUFFER;
- ikm_init(kmsg, size);
+ ikm_init(kmsg, ksize);
}
- if (copyinmsg(msg, &kmsg->ikm_header, size)) {
+ if (copyinmsg(msg, &kmsg->ikm_header, size, kmsg->ikm_size)) {
ikm_free(kmsg);
return MACH_SEND_INVALID_DATA;
}
- kmsg->ikm_header.msgh_size = size;
*kmsgp = kmsg;
return MACH_MSG_SUCCESS;
}
@@ -555,7 +536,7 @@ ipc_kmsg_get_from_kernel(
ipc_kmsg_t kmsg;
assert(size >= sizeof(mach_msg_header_t));
- assert((size & 3) == 0);
+ assert(!mach_msg_kernel_is_misaligned(size));
kmsg = ikm_alloc(size);
if (kmsg == IKM_NULL)
@@ -585,7 +566,7 @@ ipc_kmsg_get_from_kernel(
mach_msg_return_t
ipc_kmsg_put(
- mach_msg_header_t *msg,
+ mach_msg_user_header_t *msg,
ipc_kmsg_t kmsg,
mach_msg_size_t size)
{
@@ -598,11 +579,7 @@ ipc_kmsg_put(
else
mr = MACH_MSG_SUCCESS;
- if ((kmsg->ikm_size == IKM_SAVED_KMSG_SIZE) &&
- (ikm_cache() == IKM_NULL))
- ikm_cache() = kmsg;
- else
- ikm_free(kmsg);
+ ikm_cache_free(kmsg);
return mr;
}
@@ -672,11 +649,21 @@ mach_msg_return_t
ipc_kmsg_copyin_header(
mach_msg_header_t *msg,
ipc_space_t space,
- mach_port_t notify)
+ mach_port_name_t notify)
{
mach_msg_bits_t mbits = msg->msgh_bits &~ MACH_MSGH_BITS_CIRCULAR;
- mach_port_t dest_name = msg->msgh_remote_port;
- mach_port_t reply_name = msg->msgh_local_port;
+ /*
+ * TODO: For 64 bits, msgh_remote_port as written by user space
+ * is 4 bytes long but here we assume it is the same size as a pointer.
+ * When copying the message to the kernel, we need to perform the
+ * conversion so that port names are parsed correctly.
+ *
+ * When copying the message out of the kernel to user space, we also need
+ * to be careful with the reverse translation.
+ */
+
+ mach_port_name_t dest_name = (mach_port_name_t)msg->msgh_remote_port;
+ mach_port_name_t reply_name = (mach_port_name_t)msg->msgh_local_port;
kern_return_t kr;
#ifndef MIGRATING_THREADS
@@ -699,7 +686,10 @@ ipc_kmsg_copyin_header(
entry = ipc_entry_lookup (space, dest_name);
if (entry == IE_NULL)
+ {
+ ipc_entry_lookup_failed (msg, dest_name);
goto abort_async;
+ }
bits = entry->ie_bits;
/* check type bits */
@@ -751,7 +741,10 @@ ipc_kmsg_copyin_header(
entry = ipc_entry_lookup (space, dest_name);
if (entry == IE_NULL)
+ {
+ ipc_entry_lookup_failed (msg, dest_name);
goto abort_request;
+ }
bits = entry->ie_bits;
/* check type bits */
@@ -765,7 +758,10 @@ ipc_kmsg_copyin_header(
entry = ipc_entry_lookup (space, reply_name);
if (entry == IE_NULL)
+ {
+ ipc_entry_lookup_failed (msg, reply_name);
goto abort_request;
+ }
bits = entry->ie_bits;
/* check type bits */
@@ -832,7 +828,10 @@ ipc_kmsg_copyin_header(
entry = ipc_entry_lookup (space, dest_name);
if (entry == IE_NULL)
+ {
+ ipc_entry_lookup_failed (msg, dest_name);
goto abort_reply;
+ }
bits = entry->ie_bits;
/* check and type bits */
@@ -905,6 +904,8 @@ ipc_kmsg_copyin_header(
if (((entry = ipc_entry_lookup(space, notify)) == IE_NULL) ||
((entry->ie_bits & MACH_PORT_TYPE_RECEIVE) == 0)) {
+ if (entry == IE_NULL)
+ ipc_entry_lookup_failed (msg, notify);
is_write_unlock(space);
return MACH_SEND_INVALID_NOTIFY;
}
@@ -914,7 +915,7 @@ ipc_kmsg_copyin_header(
if (dest_name == reply_name) {
ipc_entry_t entry;
- mach_port_t name = dest_name;
+ mach_port_name_t name = dest_name;
/*
* Destination and reply ports are the same!
@@ -929,8 +930,10 @@ ipc_kmsg_copyin_header(
*/
entry = ipc_entry_lookup(space, name);
- if (entry == IE_NULL)
+ if (entry == IE_NULL) {
+ ipc_entry_lookup_failed (msg, name);
goto invalid_dest;
+ }
assert(reply_type != 0); /* because name not null */
@@ -1071,7 +1074,7 @@ ipc_kmsg_copyin_header(
reply_soright = soright;
}
}
- } else if (!MACH_PORT_VALID(reply_name)) {
+ } else if (!MACH_PORT_NAME_VALID(reply_name)) {
ipc_entry_t entry;
/*
@@ -1080,8 +1083,10 @@ ipc_kmsg_copyin_header(
*/
entry = ipc_entry_lookup(space, dest_name);
- if (entry == IE_NULL)
+ if (entry == IE_NULL) {
+ ipc_entry_lookup_failed (msg, dest_name);
goto invalid_dest;
+ }
kr = ipc_right_copyin(space, dest_name, entry,
dest_type, FALSE,
@@ -1094,7 +1099,7 @@ ipc_kmsg_copyin_header(
if (IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE)
ipc_entry_dealloc(space, dest_name, entry);
- reply_port = (ipc_object_t) reply_name;
+ reply_port = (ipc_object_t) invalid_name_to_port(reply_name);
reply_soright = IP_NULL;
} else {
ipc_entry_t dest_entry, reply_entry;
@@ -1136,12 +1141,17 @@ ipc_kmsg_copyin_header(
*/
dest_entry = ipc_entry_lookup(space, dest_name);
- if (dest_entry == IE_NULL)
+ if (dest_entry == IE_NULL) {
+ ipc_entry_lookup_failed (msg, dest_name);
goto invalid_dest;
+ }
reply_entry = ipc_entry_lookup(space, reply_name);
if (reply_entry == IE_NULL)
+ {
+ ipc_entry_lookup_failed (msg, reply_name);
goto invalid_reply;
+ }
assert(dest_entry != reply_entry); /* names are not equal */
assert(reply_type != 0); /* because reply_name not null */
@@ -1280,7 +1290,7 @@ ipc_kmsg_copyin_header(
return MACH_SEND_INVALID_REPLY;
}
-mach_msg_return_t
+static mach_msg_return_t
ipc_kmsg_copyin_body(
ipc_kmsg_t kmsg,
ipc_space_t space,
@@ -1299,6 +1309,10 @@ ipc_kmsg_copyin_body(
saddr = (vm_offset_t) (&kmsg->ikm_header + 1);
eaddr = (vm_offset_t) &kmsg->ikm_header + kmsg->ikm_header.msgh_size;
+ // We make assumptions about the alignment of the header.
+ _Static_assert(!mach_msg_kernel_is_misaligned(sizeof(mach_msg_header_t)),
+ "mach_msg_header_t needs to be MACH_MSG_KERNEL_ALIGNMENT aligned.");
+
while (saddr < eaddr) {
vm_offset_t taddr = saddr;
mach_msg_type_long_t *type;
@@ -1322,50 +1336,44 @@ ipc_kmsg_copyin_body(
is_inline = ((mach_msg_type_t*)type)->msgt_inline;
dealloc = ((mach_msg_type_t*)type)->msgt_deallocate;
if (longform) {
- /* This must be aligned */
- if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
- (is_misaligned(type))) {
- saddr = ptr_align(saddr);
- continue;
- }
name = type->msgtl_name;
size = type->msgtl_size;
number = type->msgtl_number;
saddr += sizeof(mach_msg_type_long_t);
+ if (mach_msg_kernel_is_misaligned(sizeof(mach_msg_type_long_t))) {
+ saddr = mach_msg_kernel_align(saddr);
+ }
} else {
name = ((mach_msg_type_t*)type)->msgt_name;
size = ((mach_msg_type_t*)type)->msgt_size;
number = ((mach_msg_type_t*)type)->msgt_number;
saddr += sizeof(mach_msg_type_t);
+ if (mach_msg_kernel_is_misaligned(sizeof(mach_msg_type_t))) {
+ saddr = mach_msg_kernel_align(saddr);
+ }
}
is_port = MACH_MSG_TYPE_PORT_ANY(name);
if ((is_port && (size != PORT_T_SIZE_IN_BITS)) ||
+#ifndef __x86_64__
(longform && ((type->msgtl_header.msgt_name != 0) ||
(type->msgtl_header.msgt_size != 0) ||
(type->msgtl_header.msgt_number != 0))) ||
+#endif
(((mach_msg_type_t*)type)->msgt_unused != 0) ||
(dealloc && is_inline)) {
ipc_kmsg_clean_partial(kmsg, taddr, FALSE, 0);
return MACH_SEND_INVALID_TYPE;
}
- /* padding (ptrs and ports) ? */
- if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
- ((size >> 3) == sizeof(natural_t)))
- saddr = ptr_align(saddr);
-
/* calculate length of data in bytes, rounding up */
length = (((uint64_t) number * size) + 7) >> 3;
if (is_inline) {
- vm_size_t amount;
-
- /* inline data sizes round up to int boundaries */
+ vm_size_t amount = length;
- amount = (length + 3) &~ 3;
if ((eaddr - saddr) < amount) {
ipc_kmsg_clean_partial(kmsg, taddr, FALSE, 0);
return MACH_SEND_MSG_TOO_SMALL;
@@ -1376,9 +1384,6 @@ ipc_kmsg_copyin_body(
} else {
vm_offset_t addr;
- if (sizeof(vm_offset_t) > sizeof(mach_msg_type_t))
- saddr = ptr_align(saddr);
-
if ((eaddr - saddr) < sizeof(vm_offset_t)) {
ipc_kmsg_clean_partial(kmsg, taddr, FALSE, 0);
return MACH_SEND_MSG_TOO_SMALL;
@@ -1395,14 +1400,27 @@ ipc_kmsg_copyin_body(
if (data == 0)
goto invalid_memory;
- if (copyinmap(map, (char *) addr,
- (char *) data, length) ||
- (dealloc &&
- (vm_deallocate(map, addr, length) !=
- KERN_SUCCESS))) {
+ if (sizeof(mach_port_name_t) != sizeof(mach_port_t))
+ {
+ mach_port_name_t *src = (mach_port_name_t*)addr;
+ mach_port_t *dst = (mach_port_t*)data;
+ for (int i=0; i<number; i++) {
+ if (copyin_port(src + i, dst + i)) {
+ kfree(data, length);
+ goto invalid_memory;
+ }
+ }
+ } else if (copyinmap(map, (char *) addr,
+ (char *) data, length)) {
kfree(data, length);
goto invalid_memory;
}
+ if (dealloc &&
+ (vm_deallocate(map, addr, length) != KERN_SUCCESS)) {
+ kfree(data, length);
+ goto invalid_memory;
+ }
+
} else {
vm_map_copy_t copy;
@@ -1441,11 +1459,13 @@ ipc_kmsg_copyin_body(
((mach_msg_type_t*)type)->msgt_name = newname;
for (i = 0; i < number; i++) {
- mach_port_t port = (mach_port_t) objects[i];
+ mach_port_name_t port = ((mach_port_t*)data)[i];
ipc_object_t object;
- if (!MACH_PORT_VALID(port))
+ if (!MACH_PORT_NAME_VALID(port)) {
+ objects[i] = (ipc_object_t)invalid_name_to_port(port);
continue;
+ }
kr = ipc_object_copyin(space, port,
name, &object);
@@ -1467,6 +1487,7 @@ ipc_kmsg_copyin_body(
complex = TRUE;
}
+ saddr = mach_msg_kernel_align(saddr);
}
if (!complex)
@@ -1505,7 +1526,7 @@ ipc_kmsg_copyin(
ipc_kmsg_t kmsg,
ipc_space_t space,
vm_map_t map,
- mach_port_t notify)
+ mach_port_name_t notify)
{
mach_msg_return_t mr;
@@ -1589,28 +1610,23 @@ ipc_kmsg_copyin_from_kernel(ipc_kmsg_t kmsg)
longform = ((mach_msg_type_t*)type)->msgt_longform;
/* type->msgtl_header.msgt_deallocate not used */
if (longform) {
- /* This must be aligned */
- if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
- (is_misaligned(type))) {
- saddr = ptr_align(saddr);
- continue;
- }
name = type->msgtl_name;
size = type->msgtl_size;
number = type->msgtl_number;
saddr += sizeof(mach_msg_type_long_t);
+ if (mach_msg_kernel_is_misaligned(sizeof(mach_msg_type_long_t))) {
+ saddr = mach_msg_kernel_align(saddr);
+ }
} else {
name = ((mach_msg_type_t*)type)->msgt_name;
size = ((mach_msg_type_t*)type)->msgt_size;
number = ((mach_msg_type_t*)type)->msgt_number;
saddr += sizeof(mach_msg_type_t);
+ if (mach_msg_kernel_is_misaligned(sizeof(mach_msg_type_t))) {
+ saddr = mach_msg_kernel_align(saddr);
+ }
}
- /* padding (ptrs and ports) ? */
- if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
- ((size >> 3) == sizeof(natural_t)))
- saddr = ptr_align(saddr);
-
/* calculate length of data in bytes, rounding up */
length = ((number * size) + 7) >> 3;
@@ -1618,10 +1634,8 @@ ipc_kmsg_copyin_from_kernel(ipc_kmsg_t kmsg)
is_port = MACH_MSG_TYPE_PORT_ANY(name);
if (is_inline) {
- /* inline data sizes round up to int boundaries */
-
data = saddr;
- saddr += (length + 3) &~ 3;
+ saddr += length;
} else {
/*
* The sender should supply ready-made memory
@@ -1658,6 +1672,7 @@ ipc_kmsg_copyin_from_kernel(ipc_kmsg_t kmsg)
MACH_MSGH_BITS_CIRCULAR;
}
}
+ saddr = mach_msg_kernel_align(saddr);
}
}
@@ -1698,7 +1713,7 @@ mach_msg_return_t
ipc_kmsg_copyout_header(
mach_msg_header_t *msg,
ipc_space_t space,
- mach_port_t notify)
+ mach_port_name_t notify)
{
mach_msg_bits_t mbits = msg->msgh_bits;
ipc_port_t dest = (ipc_port_t) msg->msgh_remote_port;
@@ -1710,9 +1725,9 @@ ipc_kmsg_copyout_header(
if (notify == MACH_PORT_NULL) switch (MACH_MSGH_BITS_PORTS(mbits)) {
case MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND, 0): {
- mach_port_t dest_name;
+ mach_port_name_t dest_name;
ipc_port_t nsrequest;
- unsigned long payload;
+ rpc_uintptr_t payload;
/* receiving an asynchronous message */
@@ -1763,9 +1778,9 @@ ipc_kmsg_copyout_header(
MACH_MSG_TYPE_PORT_SEND_ONCE): {
ipc_entry_t entry;
ipc_port_t reply = (ipc_port_t) msg->msgh_local_port;
- mach_port_t dest_name, reply_name;
+ mach_port_name_t dest_name, reply_name;
ipc_port_t nsrequest;
- unsigned long payload;
+ rpc_uintptr_t payload;
/* receiving a request message */
@@ -1823,7 +1838,7 @@ ipc_kmsg_copyout_header(
entry->ie_bits = gen | (MACH_PORT_TYPE_SEND_ONCE | 1);
}
- assert(MACH_PORT_VALID(reply_name));
+ assert(MACH_PORT_NAME_VALID(reply_name));
entry->ie_object = (ipc_object_t) reply;
is_write_unlock(space);
@@ -1866,8 +1881,8 @@ ipc_kmsg_copyout_header(
}
case MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE, 0): {
- mach_port_t dest_name;
- unsigned long payload;
+ mach_port_name_t dest_name;
+ rpc_uintptr_t payload;
/* receiving a reply message */
@@ -1920,8 +1935,8 @@ ipc_kmsg_copyout_header(
mach_msg_type_name_t dest_type = MACH_MSGH_BITS_REMOTE(mbits);
mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits);
ipc_port_t reply = (ipc_port_t) msg->msgh_local_port;
- mach_port_t dest_name, reply_name;
- unsigned long payload;
+ mach_port_name_t dest_name, reply_name;
+ rpc_uintptr_t payload;
if (IP_VALID(reply)) {
ipc_port_t notify_port;
@@ -1998,7 +2013,7 @@ ipc_kmsg_copyout_header(
is_write_unlock(space);
reply = IP_DEAD;
- reply_name = MACH_PORT_DEAD;
+ reply_name = MACH_PORT_NAME_DEAD;
goto copyout_dest;
}
@@ -2101,6 +2116,8 @@ ipc_kmsg_copyout_header(
if (((entry = ipc_entry_lookup(space, notify))
== IE_NULL) ||
((entry->ie_bits & MACH_PORT_TYPE_RECEIVE) == 0)) {
+ if (entry == IE_NULL)
+ ipc_entry_lookup_failed (msg, notify);
is_read_unlock(space);
return MACH_RCV_INVALID_NOTIFY;
}
@@ -2109,7 +2126,7 @@ ipc_kmsg_copyout_header(
ip_lock(dest);
is_read_unlock(space);
- reply_name = (mach_port_t) reply;
+ reply_name = invalid_port_to_name(msg->msgh_local_port);
}
/*
@@ -2178,12 +2195,12 @@ ipc_kmsg_copyout_header(
if (ip_active(reply) ||
IP_TIMESTAMP_ORDER(timestamp,
reply->ip_timestamp))
- dest_name = MACH_PORT_DEAD;
+ dest_name = MACH_PORT_NAME_DEAD;
else
- dest_name = MACH_PORT_NULL;
+ dest_name = MACH_PORT_NAME_NULL;
ip_unlock(reply);
} else
- dest_name = MACH_PORT_DEAD;
+ dest_name = MACH_PORT_NAME_DEAD;
}
if (IP_VALID(reply))
@@ -2228,10 +2245,10 @@ ipc_kmsg_copyout_object(
ipc_space_t space,
ipc_object_t object,
mach_msg_type_name_t msgt_name,
- mach_port_t *namep)
+ mach_port_name_t *namep)
{
if (!IO_VALID(object)) {
- *namep = (mach_port_t) object;
+ *namep = invalid_port_to_name((mach_port_t)object);
return MACH_MSG_SUCCESS;
}
@@ -2301,9 +2318,9 @@ ipc_kmsg_copyout_object(
ipc_object_destroy(object, msgt_name);
if (kr == KERN_INVALID_CAPABILITY)
- *namep = MACH_PORT_DEAD;
+ *namep = MACH_PORT_NAME_DEAD;
else {
- *namep = MACH_PORT_NULL;
+ *namep = MACH_PORT_NAME_NULL;
if (kr == KERN_RESOURCE_SHORTAGE)
return MACH_MSG_IPC_KERNEL;
@@ -2336,13 +2353,17 @@ ipc_kmsg_copyout_object(
mach_msg_return_t
ipc_kmsg_copyout_body(
- vm_offset_t saddr,
- vm_offset_t eaddr,
+ ipc_kmsg_t kmsg,
ipc_space_t space,
vm_map_t map)
{
mach_msg_return_t mr = MACH_MSG_SUCCESS;
kern_return_t kr;
+ vm_offset_t saddr, eaddr;
+
+ saddr = (vm_offset_t) (&kmsg->ikm_header + 1);
+ eaddr = (vm_offset_t) &kmsg->ikm_header +
+ kmsg->ikm_header.msgh_size;
while (saddr < eaddr) {
vm_offset_t taddr = saddr;
@@ -2358,28 +2379,23 @@ ipc_kmsg_copyout_body(
is_inline = ((mach_msg_type_t*)type)->msgt_inline;
longform = ((mach_msg_type_t*)type)->msgt_longform;
if (longform) {
- /* This must be aligned */
- if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
- (is_misaligned(type))) {
- saddr = ptr_align(saddr);
- continue;
- }
name = type->msgtl_name;
size = type->msgtl_size;
number = type->msgtl_number;
saddr += sizeof(mach_msg_type_long_t);
+ if (mach_msg_kernel_is_misaligned(sizeof(mach_msg_type_long_t))) {
+ saddr = mach_msg_kernel_align(saddr);
+ }
} else {
name = ((mach_msg_type_t*)type)->msgt_name;
size = ((mach_msg_type_t*)type)->msgt_size;
number = ((mach_msg_type_t*)type)->msgt_number;
saddr += sizeof(mach_msg_type_t);
+ if (mach_msg_kernel_is_misaligned(sizeof(mach_msg_type_t))) {
+ saddr = mach_msg_kernel_align(saddr);
+ }
}
- /* padding (ptrs and ports) ? */
- if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
- ((size >> 3) == sizeof(natural_t)))
- saddr = ptr_align(saddr);
-
/* calculate length of data in bytes, rounding up */
length = (((uint64_t) number * size) + 7) >> 3;
@@ -2387,44 +2403,43 @@ ipc_kmsg_copyout_body(
is_port = MACH_MSG_TYPE_PORT_ANY(name);
if (is_port) {
- mach_port_t *objects;
+ ipc_object_t *objects;
mach_msg_type_number_t i;
if (!is_inline && (length != 0)) {
/* first allocate memory in the map */
+ uint64_t allocated = length;
+
+ _Static_assert(sizeof(mach_port_name_t) <= sizeof(mach_port_t),
+ "Size of mach_port_t should be equal or larger than mach_port_name_t.");
+ allocated -= (sizeof(mach_port_t) - sizeof(mach_port_name_t)) * number;
- kr = vm_allocate(map, &addr, length, TRUE);
+ kr = vm_allocate(map, &addr, allocated, TRUE);
if (kr != KERN_SUCCESS) {
ipc_kmsg_clean_body(taddr, saddr);
goto vm_copyout_failure;
}
}
- objects = (mach_port_t *)
+ objects = (ipc_object_t *)
(is_inline ? saddr : * (vm_offset_t *) saddr);
/* copyout port rights carried in the message */
for (i = 0; i < number; i++) {
- ipc_object_t object =
- (ipc_object_t) objects[i];
+ ipc_object_t object = objects[i];
- mr |= ipc_kmsg_copyout_object(space, object,
- name, &objects[i]);
+ mr |= ipc_kmsg_copyout_object_to_port(space, object,
+ name, (mach_port_t *)&objects[i]);
}
}
if (is_inline) {
- /* inline data sizes round up to int boundaries */
-
((mach_msg_type_t*)type)->msgt_deallocate = FALSE;
- saddr += (length + 3) &~ 3;
+ saddr += length;
} else {
vm_offset_t data;
- if (sizeof(vm_offset_t) > sizeof(mach_msg_type_t))
- saddr = ptr_align(saddr);
-
data = * (vm_offset_t *) saddr;
/* copyout memory carried in the message */
@@ -2435,8 +2450,19 @@ ipc_kmsg_copyout_body(
} else if (is_port) {
/* copyout to memory allocated above */
- (void) copyoutmap(map, (char *) data,
- (char *) addr, length);
+ if (sizeof(mach_port_name_t) != sizeof(mach_port_t)) {
+ mach_port_t *src = (mach_port_t*)data;
+ mach_port_name_t *dst = (mach_port_name_t*)addr;
+ for (int i=0; i<number; i++) {
+ if (copyout_port(src + i, dst + i)) {
+ kr = KERN_FAILURE;
+ goto vm_copyout_failure;
+ }
+ }
+ } else {
+ (void) copyoutmap(map, (char *) data,
+ (char *) addr, length);
+ }
kfree(data, length);
} else {
vm_map_copy_t copy = (vm_map_copy_t) data;
@@ -2464,6 +2490,9 @@ ipc_kmsg_copyout_body(
* (vm_offset_t *) saddr = addr;
saddr += sizeof(vm_offset_t);
}
+
+ /* Next element is always correctly aligned */
+ saddr = mach_msg_kernel_align(saddr);
}
return mr;
@@ -2492,7 +2521,7 @@ ipc_kmsg_copyout(
ipc_kmsg_t kmsg,
ipc_space_t space,
vm_map_t map,
- mach_port_t notify)
+ mach_port_name_t notify)
{
mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits;
mach_msg_return_t mr;
@@ -2502,13 +2531,7 @@ ipc_kmsg_copyout(
return mr;
if (mbits & MACH_MSGH_BITS_COMPLEX) {
- vm_offset_t saddr, eaddr;
-
- saddr = (vm_offset_t) (&kmsg->ikm_header + 1);
- eaddr = (vm_offset_t) &kmsg->ikm_header +
- kmsg->ikm_header.msgh_size;
-
- mr = ipc_kmsg_copyout_body(saddr, eaddr, space, map);
+ mr = ipc_kmsg_copyout_body(kmsg, space, map);
if (mr != MACH_MSG_SUCCESS)
mr |= MACH_RCV_BODY_ERROR;
}
@@ -2547,7 +2570,7 @@ ipc_kmsg_copyout_pseudo(
ipc_object_t reply = (ipc_object_t) kmsg->ikm_header.msgh_local_port;
mach_msg_type_name_t dest_type = MACH_MSGH_BITS_REMOTE(mbits);
mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits);
- mach_port_t dest_name, reply_name;
+ mach_port_name_t dest_name, reply_name;
mach_msg_return_t mr;
assert(IO_VALID(dest));
@@ -2560,13 +2583,7 @@ ipc_kmsg_copyout_pseudo(
kmsg->ikm_header.msgh_local_port = reply_name;
if (mbits & MACH_MSGH_BITS_COMPLEX) {
- vm_offset_t saddr, eaddr;
-
- saddr = (vm_offset_t) (&kmsg->ikm_header + 1);
- eaddr = (vm_offset_t) &kmsg->ikm_header +
- kmsg->ikm_header.msgh_size;
-
- mr |= ipc_kmsg_copyout_body(saddr, eaddr, space, map);
+ mr |= ipc_kmsg_copyout_body(kmsg, space, map);
}
return mr;
@@ -2591,7 +2608,7 @@ ipc_kmsg_copyout_dest(
ipc_object_t reply = (ipc_object_t) kmsg->ikm_header.msgh_local_port;
mach_msg_type_name_t dest_type = MACH_MSGH_BITS_REMOTE(mbits);
mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits);
- mach_port_t dest_name, reply_name;
+ mach_port_name_t dest_name, reply_name;
assert(IO_VALID(dest));
@@ -2602,14 +2619,14 @@ ipc_kmsg_copyout_dest(
} else {
io_release(dest);
io_check_unlock(dest);
- dest_name = MACH_PORT_DEAD;
+ dest_name = MACH_PORT_NAME_DEAD;
}
if (IO_VALID(reply)) {
ipc_object_destroy(reply, reply_type);
- reply_name = MACH_PORT_NULL;
+ reply_name = MACH_PORT_NAME_NULL;
} else
- reply_name = (mach_port_t) reply;
+ reply_name = invalid_port_to_name((mach_port_t)reply);
kmsg->ikm_header.msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
MACH_MSGH_BITS(reply_type, dest_type));
@@ -2629,7 +2646,7 @@ ipc_kmsg_copyout_dest(
#if MACH_KDB
-char *
+static char *
ipc_type_name(
int type_name,
boolean_t received)
@@ -2697,7 +2714,7 @@ ipc_type_name(
}
}
-void
+static void
ipc_print_type_name(
int type_name)
{
@@ -2801,21 +2818,21 @@ ipc_msg_print(mach_msg_header_t *msgh)
is_inline = ((mach_msg_type_t*)type)->msgt_inline;
dealloc = ((mach_msg_type_t*)type)->msgt_deallocate;
if (longform) {
- /* This must be aligned */
- if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
- (is_misaligned(type))) {
- saddr = ptr_align(saddr);
- continue;
- }
name = type->msgtl_name;
size = type->msgtl_size;
number = type->msgtl_number;
saddr += sizeof(mach_msg_type_long_t);
+ if (mach_msg_kernel_is_misaligned(sizeof(mach_msg_type_long_t))) {
+ saddr = mach_msg_kernel_align(saddr);
+ }
} else {
name = ((mach_msg_type_t*)type)->msgt_name;
size = ((mach_msg_type_t*)type)->msgt_size;
number = ((mach_msg_type_t*)type)->msgt_number;
saddr += sizeof(mach_msg_type_t);
+ if (mach_msg_kernel_is_misaligned(sizeof(mach_msg_type_t))) {
+ saddr = mach_msg_kernel_align(saddr);
+ }
}
db_printf("-- type=");
@@ -2837,20 +2854,17 @@ ipc_msg_print(mach_msg_header_t *msgh)
is_port = MACH_MSG_TYPE_PORT_ANY(name);
if ((is_port && (size != PORT_T_SIZE_IN_BITS)) ||
+#ifndef __x86_64__
(longform && ((type->msgtl_header.msgt_name != 0) ||
(type->msgtl_header.msgt_size != 0) ||
(type->msgtl_header.msgt_number != 0))) ||
+#endif
(((mach_msg_type_t*)type)->msgt_unused != 0) ||
(dealloc && is_inline)) {
db_printf("*** invalid type\n");
return;
}
- /* padding (ptrs and ports) ? */
- if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
- ((size >> 3) == sizeof(natural_t)))
- saddr = ptr_align(saddr);
-
/* calculate length of data in bytes, rounding up */
length = ((number * size) + 7) >> 3;
@@ -2859,7 +2873,7 @@ ipc_msg_print(mach_msg_header_t *msgh)
vm_size_t amount;
unsigned i, numwords;
- /* inline data sizes round up to int boundaries */
+ /* round up to int boundaries for printing */
amount = (length + 3) &~ 3;
if ((eaddr - saddr) < amount) {
db_printf("*** too small\n");
@@ -2884,6 +2898,7 @@ ipc_msg_print(mach_msg_header_t *msgh)
db_printf("0x%x\n", * (vm_offset_t *) saddr);
saddr += sizeof(vm_offset_t);
}
+ saddr = mach_msg_kernel_align(saddr);
}
}
#endif /* MACH_KDB */