This has several advantages: 1) We don't need to resize mach_msg_header_t, it is just a copy. 2) Mig won't require any changes because it statically computes the size of mach_msg_header_t, otherwise we would need two sizes (28 vs 32 bytes). --- include/mach/message.h | 15 +++++++++++++-- x86_64/copy_user.c | 35 +++++++++++++---------------------- 2 files changed, 26 insertions(+), 24 deletions(-)
diff --git a/include/mach/message.h b/include/mach/message.h index 63341e6f..eb3b34c0 100644 --- a/include/mach/message.h +++ b/include/mach/message.h @@ -139,7 +139,15 @@ typedef integer_t mach_msg_id_t; typedef struct mach_msg_header { mach_msg_bits_t msgh_bits; mach_msg_size_t msgh_size; - mach_port_t msgh_remote_port; + union { + mach_port_t msgh_remote_port; + /* + * Ensure msgh_remote_port is wide enough to hold a kernel pointer + * to avoid message resizing for the 64 bits case. This field should + * not be used since it is here just for padding purposes. + */ + rpc_uintptr_t msgh_remote_port_do_not_use; + }; union { mach_port_t msgh_local_port; rpc_uintptr_t msgh_protected_payload; @@ -153,7 +161,10 @@ typedef struct mach_msg_header { typedef struct { mach_msg_bits_t msgh_bits; mach_msg_size_t msgh_size; - mach_port_name_t msgh_remote_port; + union { + mach_port_name_t msgh_remote_port; + rpc_uintptr_t msgh_remote_port_do_not_use; + }; union { mach_port_name_t msgh_local_port; rpc_uintptr_t msgh_protected_payload; diff --git a/x86_64/copy_user.c b/x86_64/copy_user.c index ae062645..dd9fe2d7 100644 --- a/x86_64/copy_user.c +++ b/x86_64/copy_user.c @@ -177,29 +177,24 @@ int copyinmsg (const void *userbuf, void *kernelbuf, const size_t usize) const mach_msg_user_header_t *umsg = userbuf; mach_msg_header_t *kmsg = kernelbuf; +#ifdef USER32 if (copyin(&umsg->msgh_bits, &kmsg->msgh_bits, sizeof(kmsg->msgh_bits))) return 1; /* kmsg->msgh_size is filled in later */ if (copyin_port(&umsg->msgh_remote_port, &kmsg->msgh_remote_port)) return 1; -#ifdef USER32 - /* This could contain a payload, but for 32 bits it will be the same size as a mach_port_name_t */ - _Static_assert(sizeof(rpc_uintptr_t) == sizeof(mach_port_name_t), - "rpc_uintptr_t and mach_port_name_t expected to have the same size"); if (copyin_port(&umsg->msgh_local_port, &kmsg->msgh_local_port)) return 1; -#else - /* For pure 64 bits, the protected payload is as large as a port pointer. */ - _Static_assert(sizeof(rpc_uintptr_t) == sizeof(mach_port_t), - "rpc_uintptr_t and mach_port_t expected to have the same size"); - if (copyin((char*)umsg + offsetof(mach_msg_user_header_t, msgh_local_port), - (char*)kmsg + offsetof(mach_msg_header_t, msgh_local_port), - sizeof(rpc_uintptr_t))) - return 1; -#endif if (copyin(&umsg->msgh_seqno, &kmsg->msgh_seqno, sizeof(kmsg->msgh_seqno) + sizeof(kmsg->msgh_id))) return 1; +#else + /* The 64 bit interface ensures the header is the same size, so it does not need any resizing. */ + _Static_assert(sizeof(mach_msg_header_t) == sizeof(mach_msg_user_header_t), + "mach_msg_header_t and mach_msg_user_header_t expected to be of the same size"); + if (copyin(&umsg, &kmsg, sizeof(mach_msg_header_t))) + return 1; +#endif vm_offset_t usaddr, ueaddr, ksaddr; ksaddr = (vm_offset_t)(kmsg + 1); @@ -283,25 +278,21 @@ int copyoutmsg (const void *kernelbuf, void *userbuf, const size_t ksize) { const mach_msg_header_t *kmsg = kernelbuf; mach_msg_user_header_t *umsg = userbuf; - +#ifdef USER32 if (copyout(&kmsg->msgh_bits, &umsg->msgh_bits, sizeof(kmsg->msgh_bits))) return 1; /* umsg->msgh_size is filled in later */ if (copyout_port(&kmsg->msgh_remote_port, &umsg->msgh_remote_port)) return 1; -#ifdef USER32 if (copyout_port(&kmsg->msgh_local_port, &umsg->msgh_local_port)) return 1; -#else - /* Handle protected payloads correctly, same as copyinmsg. */ - if (copyout((char*)kmsg + offsetof(mach_msg_header_t, msgh_local_port), - (char*)umsg + offsetof(mach_msg_user_header_t, msgh_local_port), - sizeof(rpc_uintptr_t))) - return 1; -#endif if (copyout(&kmsg->msgh_seqno, &umsg->msgh_seqno, sizeof(kmsg->msgh_seqno) + sizeof(kmsg->msgh_id))) return 1; +#else + if (copyout(&kmsg, &umsg, sizeof(mach_msg_header_t))) + return 1; +#endif /* USER32 */ vm_offset_t ksaddr, keaddr, usaddr; ksaddr = (vm_offset_t)(kmsg + 1); -- 2.39.1