ipc_kmsg_copyin_body() updated OOL port arrays from 32-bit
mach_port_name_t elements to 64-bit mach_port_t elements only in the
non-empty path. For zero-length arrays, the code skipped that
normalization and left msgtl_size at 32.
On LP64 this causes MIG type checking to reject empty OOL port arrays,
because the kernel delivers MACH_MSG_TYPE_PORT_SEND with msgtl_size == 32
instead of 64. Apparently, those kind of messages are never delivered on
the current Hurd, as such, the bug went unnoticed.
Normalize the descriptor size for OOL port arrays before the length == 0
branch so empty and non-empty arrays are handled consistently.
---
ipc/ipc_kmsg.c | 59 ++++++++++++++++++++++++++++----------------------
1 file changed, 33 insertions(+), 26 deletions(-)
diff --git a/ipc/ipc_kmsg.c b/ipc/ipc_kmsg.c
index 54291a6e..2693db6f 100644
--- a/ipc/ipc_kmsg.c
+++ b/ipc/ipc_kmsg.c
@@ -1392,45 +1392,52 @@ ipc_kmsg_copyin_body(
addr = * (vm_offset_t *) saddr;
- if (length == 0)
- data = 0;
- else if (is_port) {
+ if (is_port) {
const vm_size_t user_length = length;
+
/*
* In 64 bit architectures, out of line port
names are
* represented as an array of mach_port_name_t
which are
* smaller than mach_port_t.
*/
if (sizeof(mach_port_name_t) !=
sizeof(mach_port_t)) {
+ if (longform)
+ type->msgtl_size =
sizeof(mach_port_t) * 8;
+ else
+ ((mach_msg_type_t
*)type)->msgt_size = sizeof(mach_port_t) * 8;
length = sizeof(mach_port_t) * number;
- type->msgtl_size = sizeof(mach_port_t)
* 8;
}
- data = kalloc(length);
- if (data == 0)
- goto invalid_memory;
-
- if (user_length != length)
- {
- 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;
+ if (length == 0) {
+ data = 0;
+ else {
+ data = kalloc(length);
+ if (data == 0)
+ goto invalid_memory;
+
+ if (user_length != length)
+ {
+ 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,
user_length) != KERN_SUCCESS)) {
+ 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, user_length) !=
KERN_SUCCESS)) {
- kfree(data, length);
- goto invalid_memory;
}
-
+ } else if (length == 0) { /* !is_port */
+ data = 0;
} else {
vm_map_copy_t copy;
--
2.53.0