From afec41f9d80cb1f923d0d4f76af832b036dc2f4f Mon Sep 17 00:00:00 2001 From: LD Date: Sat, 9 Mar 2024 15:02:44 +0100 Subject: move x86 copy_user.[ch] to ipc/ and make it arch-indipendent Message-ID: <20240309140244.347835-3-luca@orpolo.org> --- Makefrag.am | 2 + i386/Makefrag.am | 1 - i386/i386/copy_user.h | 100 -------- ipc/copy_user.c | 616 ++++++++++++++++++++++++++++++++++++++++++++++++++ ipc/copy_user.h | 100 ++++++++ ipc/ipc_kmsg.c | 2 +- ipc/ipc_mqueue.c | 2 +- ipc/mach_msg.c | 2 +- kern/ipc_mig.c | 2 +- x86_64/Makefrag.am | 1 - x86_64/copy_user.c | 613 ------------------------------------------------- 11 files changed, 722 insertions(+), 719 deletions(-) delete mode 100644 i386/i386/copy_user.h create mode 100644 ipc/copy_user.c create mode 100644 ipc/copy_user.h delete mode 100644 x86_64/copy_user.c diff --git a/Makefrag.am b/Makefrag.am index 5b61a1d6..82fce628 100644 --- a/Makefrag.am +++ b/Makefrag.am @@ -76,6 +76,8 @@ endif # libkernel_a_SOURCES += \ + ipc/copy_user.c \ + ipc/copy_user.h \ ipc/ipc_entry.c \ ipc/ipc_entry.h \ ipc/ipc_init.c \ diff --git a/i386/Makefrag.am b/i386/Makefrag.am index 58ee3273..5e7d4740 100644 --- a/i386/Makefrag.am +++ b/i386/Makefrag.am @@ -91,7 +91,6 @@ endif # libkernel_a_SOURCES += \ - i386/i386/copy_user.h \ i386/i386/cswitch.S \ i386/i386/debug_trace.S \ i386/i386/idt_inittab.S \ diff --git a/i386/i386/copy_user.h b/i386/i386/copy_user.h deleted file mode 100644 index 3d1c7278..00000000 --- a/i386/i386/copy_user.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (C) 2023 Free Software Foundation - * - * This program is free software ; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation ; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY ; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with the program ; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef COPY_USER_H -#define COPY_USER_H - -#include -#include - -#include -#include - -/* - * The copyin_32to64() and copyout_64to32() routines are meant for data types - * that have different size in kernel and user space. They should be independent - * of endianness and hopefully can be reused in the future on other archs. - * These types are e.g.: - * - port names vs port pointers, on a 64-bit kernel - * - memory addresses, on a 64-bit kernel and 32-bit user - */ - -static inline int copyin_32to64(const uint32_t *uaddr, uint64_t *kaddr) -{ - uint32_t rkaddr; - int ret; - ret = copyin(uaddr, &rkaddr, sizeof(uint32_t)); - if (ret) - return ret; - *kaddr = rkaddr; - return 0; -} - -static inline int copyout_64to32(const uint64_t *kaddr, uint32_t *uaddr) -{ - uint32_t rkaddr=*kaddr; - return copyout(&rkaddr, uaddr, sizeof(uint32_t)); -} - -static inline int copyin_address(const rpc_vm_offset_t *uaddr, vm_offset_t *kaddr) -{ -#ifdef USER32 - return copyin_32to64(uaddr, kaddr); -#else /* USER32 */ - return copyin(uaddr, kaddr, sizeof(*uaddr)); -#endif /* USER32 */ -} - -static inline int copyout_address(const vm_offset_t *kaddr, rpc_vm_offset_t *uaddr) -{ -#ifdef USER32 - return copyout_64to32(kaddr, uaddr); -#else /* USER32 */ - return copyout(kaddr, uaddr, sizeof(*kaddr)); -#endif /* USER32 */ -} - -static inline int copyin_port(const mach_port_name_t *uaddr, mach_port_t *kaddr) -{ -#ifdef __x86_64__ - return copyin_32to64(uaddr, kaddr); -#else /* __x86_64__ */ - return copyin(uaddr, kaddr, sizeof(*uaddr)); -#endif /* __x86_64__ */ -} - -static inline int copyout_port(const mach_port_t *kaddr, mach_port_name_t *uaddr) -{ -#ifdef __x86_64__ - return copyout_64to32(kaddr, uaddr); -#else /* __x86_64__ */ - return copyout(kaddr, uaddr, sizeof(*kaddr)); -#endif /* __x86_64__ */ -} - -#if defined(__x86_64__) && defined(USER32) -/* For 32 bit userland, kernel and user land messages are not the same size. */ -size_t msg_usize(const mach_msg_header_t *kmsg); -#else -static inline size_t msg_usize(const mach_msg_header_t *kmsg) -{ - return kmsg->msgh_size; -} -#endif /* __x86_64__ && USER32 */ - -#endif /* COPY_USER_H */ diff --git a/ipc/copy_user.c b/ipc/copy_user.c new file mode 100644 index 00000000..5c6329d3 --- /dev/null +++ b/ipc/copy_user.c @@ -0,0 +1,616 @@ +/* + * Copyright (C) 2023 Free Software Foundation + * + * This program is free software ; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation ; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY ; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the program ; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifdef __LP64__ + +#include +#include + +#include +#include +#include + + +/* Mach field descriptors measure size in bits */ +#define descsize_to_bytes(n) (n / 8) +#define bytes_to_descsize(n) (n * 8) + +#ifdef USER32 +/* Versions of mach_msg_type_t and mach_msg_type_long that are expected from the 32 bit userland. */ +typedef struct { + unsigned int msgt_name : 8, + msgt_size : 8, + msgt_number : 12, + msgt_inline : 1, + msgt_longform : 1, + msgt_deallocate : 1, + msgt_unused : 1; +} mach_msg_user_type_t; +_Static_assert(sizeof(mach_msg_user_type_t) == 4); + +typedef struct { + mach_msg_user_type_t msgtl_header; + unsigned short msgtl_name; + unsigned short msgtl_size; + natural_t msgtl_number; +} mach_msg_user_type_long_t; +_Static_assert(sizeof(mach_msg_user_type_long_t) == 12); +#else +typedef mach_msg_type_t mach_msg_user_type_t; +typedef mach_msg_type_long_t mach_msg_user_type_long_t; +#endif /* USER32 */ + +/* +* Helper to unpack the relevant fields of a msg type; the fields are different +* depending on whether is long form or not. +.*/ +static inline void unpack_msg_type(vm_offset_t addr, + mach_msg_type_name_t *name, + mach_msg_type_size_t *size, + mach_msg_type_number_t *number, + boolean_t *is_inline, + vm_size_t *user_amount, + vm_size_t *kernel_amount) +{ + mach_msg_type_t* kmt = (mach_msg_type_t*)addr; + *is_inline = kmt->msgt_inline; + if (kmt->msgt_longform) + { + mach_msg_type_long_t* kmtl = (mach_msg_type_long_t*)addr; + *name = kmtl->msgtl_name; + *size = kmtl->msgtl_size; + *number = kmtl->msgtl_number; + *kernel_amount = sizeof(mach_msg_type_long_t); + *user_amount = sizeof(mach_msg_user_type_long_t); + } + else + { + *name = kmt->msgt_name; + *size = kmt->msgt_size; + *number = kmt->msgt_number; + *kernel_amount = sizeof(mach_msg_type_t); + *user_amount = sizeof(mach_msg_user_type_t); + } +} + +#ifdef USER32 +static inline void mach_msg_user_type_to_kernel(const mach_msg_user_type_t *u, + mach_msg_type_t* k) { + k->msgt_name = u->msgt_name; + k->msgt_size = u->msgt_size; + k->msgt_number = u->msgt_number; + k->msgt_inline = u->msgt_inline; + k->msgt_longform = u->msgt_longform; + k->msgt_deallocate = u->msgt_deallocate; + k->msgt_unused = 0; +} + +static inline void mach_msg_user_type_to_kernel_long(const mach_msg_user_type_long_t *u, + mach_msg_type_long_t* k) { + const mach_msg_type_long_t kernel = { + .msgtl_header = { + .msgt_name = u->msgtl_name, + .msgt_size = u->msgtl_size, + .msgt_number = u->msgtl_number, + .msgt_inline = u->msgtl_header.msgt_inline, + .msgt_longform = u->msgtl_header.msgt_longform, + .msgt_deallocate = u->msgtl_header.msgt_deallocate, + .msgt_unused = 0 + } + }; + *k = kernel; +} + +static inline void mach_msg_kernel_type_to_user(const mach_msg_type_t *k, + mach_msg_user_type_t *u) { + u->msgt_name = k->msgt_name; + u->msgt_size = k->msgt_size; + u->msgt_number = k->msgt_number; + u->msgt_inline = k->msgt_inline; + u->msgt_longform = k->msgt_longform; + u->msgt_deallocate = k->msgt_deallocate; + u->msgt_unused = 0; +} + +static inline void mach_msg_kernel_type_to_user_long(const mach_msg_type_long_t *k, + mach_msg_user_type_long_t *u) { + const mach_msg_user_type_long_t user = { + .msgtl_header = { + .msgt_name = 0, + .msgt_size = 0, + .msgt_number = 0, + .msgt_inline = k->msgtl_header.msgt_inline, + .msgt_longform = k->msgtl_header.msgt_longform, + .msgt_deallocate = k->msgtl_header.msgt_deallocate, + .msgt_unused = 0 + }, + .msgtl_name = k->msgtl_header.msgt_name, + .msgtl_size = k->msgtl_header.msgt_size, + .msgtl_number = k->msgtl_header.msgt_number + }; + *u = user; +} +#endif + +static inline int copyin_mach_msg_type(const rpc_vm_offset_t *uaddr, mach_msg_type_t *kaddr) { +#ifdef USER32 + mach_msg_user_type_t user; + int ret = copyin(uaddr, &user, sizeof(mach_msg_user_type_t)); + if (ret) { + return ret; + } + mach_msg_user_type_to_kernel(&user, kaddr); + return 0; +#else + return copyin(uaddr, kaddr, sizeof(mach_msg_type_t)); +#endif +} + +static inline int copyout_mach_msg_type(const mach_msg_type_t *kaddr, rpc_vm_offset_t *uaddr) { +#ifdef USER32 + mach_msg_user_type_t user; + mach_msg_kernel_type_to_user(kaddr, &user); + return copyout(&user, uaddr, sizeof(mach_msg_user_type_t)); +#else + return copyout(kaddr, uaddr, sizeof(mach_msg_type_t)); +#endif +} + +static inline int copyin_mach_msg_type_long(const rpc_vm_offset_t *uaddr, mach_msg_type_long_t *kaddr) { +#ifdef USER32 + mach_msg_user_type_long_t user; + int ret = copyin(uaddr, &user, sizeof(mach_msg_user_type_long_t)); + if (ret) + return ret; + mach_msg_user_type_to_kernel_long(&user, kaddr); + return 0; +#else + return copyin(uaddr, kaddr, sizeof(mach_msg_type_long_t)); +#endif +} + +static inline int copyout_mach_msg_type_long(const mach_msg_type_long_t *kaddr, rpc_vm_offset_t *uaddr) { +#ifdef USER32 + mach_msg_user_type_long_t user; + mach_msg_kernel_type_to_user_long(kaddr, &user); + return copyout(&user, uaddr, sizeof(mach_msg_user_type_long_t)); +#else + return copyout(kaddr, uaddr, sizeof(mach_msg_type_long_t)); +#endif +} + +/* Optimized version of unpack_msg_type(), including proper copyin() */ +static inline int copyin_unpack_msg_type(vm_offset_t uaddr, + vm_offset_t kaddr, + mach_msg_type_name_t *name, + mach_msg_type_size_t *size, + mach_msg_type_number_t *number, + boolean_t *is_inline, + vm_size_t *user_amount, + vm_size_t *kernel_amount) +{ + mach_msg_type_t *kmt = (mach_msg_type_t*)kaddr; + if (copyin_mach_msg_type((void *)uaddr, kmt)) + return 1; + *is_inline = kmt->msgt_inline; + if (kmt->msgt_longform) + { + mach_msg_type_long_t* kmtl = (mach_msg_type_long_t*)kaddr; + if (copyin_mach_msg_type_long((void *)uaddr, kmtl)) + return 1; + *name = kmtl->msgtl_name; + *size = kmtl->msgtl_size; + *number = kmtl->msgtl_number; + *user_amount = sizeof(mach_msg_user_type_long_t); + *kernel_amount = sizeof(mach_msg_type_long_t); + } + else + { + *name = kmt->msgt_name; + *size = kmt->msgt_size; + *number = kmt->msgt_number; + *user_amount = sizeof(mach_msg_user_type_t); + *kernel_amount = sizeof(mach_msg_type_t); + } + return 0; +} + +/* + * The msg type has a different size field depending on whether is long or not, + * and we also need to convert from bytes to bits + */ +static inline void adjust_msg_type_size(vm_offset_t addr, int amount) +{ + mach_msg_type_t* kmt = (mach_msg_type_t*)addr; + if (kmt->msgt_longform) + { + mach_msg_type_long_t* kmtl = (mach_msg_type_long_t*)addr; + kmtl->msgtl_size += bytes_to_descsize(amount); + } + else + { + kmt->msgt_size += bytes_to_descsize(amount); + } +} + +/* Optimized version of unpack_msg_type(), including proper copyout() */ +static inline int copyout_unpack_msg_type(vm_offset_t kaddr, + vm_offset_t uaddr, + mach_msg_type_name_t *name, + mach_msg_type_size_t *size, + mach_msg_type_number_t *number, + boolean_t *is_inline, + vm_size_t *user_amount, + vm_size_t *kernel_amount) +{ + mach_msg_type_t *kmt = (mach_msg_type_t*)kaddr; + *is_inline = kmt->msgt_inline; + if (kmt->msgt_longform) + { + mach_msg_type_long_t* kmtl = (mach_msg_type_long_t*)kaddr; + mach_msg_type_size_t orig_size = kmtl->msgtl_size; + int ret; + + if (MACH_MSG_TYPE_PORT_ANY(kmtl->msgtl_name)) { +#ifdef USER32 + kmtl->msgtl_size = bytes_to_descsize(sizeof(mach_port_name_t)); +#else + /* 64 bit ABI uses mach_port_name_inlined_t for inlined ports. */ + if (!kmt->msgt_inline) + kmtl->msgtl_size = bytes_to_descsize(sizeof(mach_port_name_t)); +#endif + } + ret = copyout_mach_msg_type_long(kmtl, (void*)uaddr); + kmtl->msgtl_size = orig_size; + if (ret) + return 1; + + *name = kmtl->msgtl_name; + *size = kmtl->msgtl_size; + *number = kmtl->msgtl_number; + *user_amount = sizeof(mach_msg_user_type_long_t); + *kernel_amount = sizeof(mach_msg_type_long_t); + } + else + { + mach_msg_type_size_t orig_size = kmt->msgt_size; + int ret; + + if (MACH_MSG_TYPE_PORT_ANY(kmt->msgt_name)) { +#ifdef USER32 + kmt->msgt_size = bytes_to_descsize(sizeof(mach_port_name_t)); +#else + /* 64 bit ABI uses mach_port_name_inlined_t for inlined ports. */ + if (!kmt->msgt_inline) + kmt->msgt_size = bytes_to_descsize(sizeof(mach_port_name_t)); +#endif + } + ret = copyout_mach_msg_type(kmt, (void *)uaddr); + kmt->msgt_size = orig_size; + if (ret) + return 1; + + *name = kmt->msgt_name; + *size = kmt->msgt_size; + *number = kmt->msgt_number; + *user_amount = sizeof(mach_msg_user_type_t); + *kernel_amount = sizeof(mach_msg_type_t); + } + return 0; +} + +#ifdef USER32 +/* + * Compute the user-space size of a message still in the kernel when processing + * messages from 32bit userland. + * The message may be originating from userspace (in which case we could + * optimize this by keeping the usize around) or from kernel space (we could + * optimize if the message structure is fixed and known in advance). + * For now just handle the most general case, iterating over the msg body. + */ +size_t msg_usize(const mach_msg_header_t *kmsg) +{ + size_t ksize = kmsg->msgh_size; + size_t usize = sizeof(mach_msg_user_header_t); + if (ksize > sizeof(mach_msg_header_t)) + { + // iterate over body compute the user-space message size + vm_offset_t saddr, eaddr; + saddr = (vm_offset_t)(kmsg + 1); + eaddr = saddr + ksize - sizeof(mach_msg_header_t); + while (saddr < (eaddr - sizeof(mach_msg_type_t))) + { + vm_size_t user_amount, kernel_amount; + mach_msg_type_name_t name; + mach_msg_type_size_t size; + mach_msg_type_number_t number; + boolean_t is_inline; + unpack_msg_type(saddr, &name, &size, &number, &is_inline, &user_amount, &kernel_amount); + saddr += kernel_amount; + saddr = mach_msg_kernel_align(saddr); + usize += user_amount; + usize = mach_msg_user_align(usize); + + if (is_inline) + { + if (MACH_MSG_TYPE_PORT_ANY(name)) + { + const vm_size_t length = sizeof(mach_port_t) * number; + saddr += length; + usize += sizeof(mach_port_name_t) * number; + } + else + { + size_t n = descsize_to_bytes(size); + saddr += n*number; + usize += n*number; + } + } + else + { + // advance one pointer + saddr += sizeof(vm_offset_t); + usize += sizeof(rpc_vm_offset_t); + } + saddr = mach_msg_kernel_align(saddr); + usize = mach_msg_user_align(usize); + } + } + return usize; +} +#endif /* USER32 */ + +/* + * Expand the msg header and, if required, the msg body (ports, pointers) + * + * To not make the code too complicated, we use the fact that some fields of + * mach_msg_header have the same size in the kernel and user variant (basically + * all fields except ports and addresses) +*/ +int copyinmsg (const void *userbuf, void *kernelbuf, const size_t usize, const size_t ksize) +{ + 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; + if (copyin_port(&umsg->msgh_local_port, &kmsg->msgh_local_port)) + return 1; + 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; + kmsg->msgh_remote_port &= 0xFFFFFFFF; // FIXME: still have port names here + kmsg->msgh_local_port &= 0xFFFFFFFF; // also, this assumes little-endian +#endif + + vm_offset_t usaddr, ueaddr, ksaddr; + ksaddr = (vm_offset_t)(kmsg + 1); + usaddr = (vm_offset_t)(umsg + 1); + ueaddr = (vm_offset_t)umsg + usize; + + _Static_assert(!mach_msg_user_is_misaligned(sizeof(mach_msg_user_header_t)), + "mach_msg_user_header_t needs to be MACH_MSG_USER_ALIGNMENT aligned."); + + if (usize > sizeof(mach_msg_user_header_t)) + { + /* check we have at least space for an empty descryptor */ + while (usaddr <= (ueaddr - sizeof(mach_msg_user_type_t))) + { + vm_size_t user_amount, kernel_amount; + mach_msg_type_name_t name; + mach_msg_type_size_t size; + mach_msg_type_number_t number; + boolean_t is_inline; + if (copyin_unpack_msg_type(usaddr, ksaddr, &name, &size, &number, + &is_inline, &user_amount, &kernel_amount)) + return 1; + + // keep a reference to the current field descriptor, we + // might need to adjust it later depending on the type + vm_offset_t ktaddr = ksaddr; + usaddr += user_amount; + usaddr = mach_msg_user_align(usaddr); + ksaddr += kernel_amount; + ksaddr = mach_msg_kernel_align(ksaddr); + + if (is_inline) + { + if (MACH_MSG_TYPE_PORT_ANY(name)) + { +#ifdef USER32 + if (size != bytes_to_descsize(sizeof(mach_port_name_t))) + return 1; + if ((usaddr + sizeof(mach_port_name_t)*number) > ueaddr) + return 1; + adjust_msg_type_size(ktaddr, sizeof(mach_port_t) - sizeof(mach_port_name_t)); + for (int i=0; i ueaddr) + return 1; + if (copyin((void*)usaddr, (void*)ksaddr, length)) + return 1; + usaddr += length; + ksaddr += length; +#endif + } + else + { + // type that doesn't need change + size_t n = descsize_to_bytes(size); + if ((usaddr + n*number) > ueaddr) + return 1; + if (copyin((void*)usaddr, (void*)ksaddr, n*number)) + return 1; + usaddr += n*number; + ksaddr += n*number; + } + } + else + { + if ((usaddr + sizeof(rpc_vm_offset_t)) > ueaddr) + return 1; + + /* out-of-line port arrays are always arrays of mach_port_name_t (4 bytes) + * and are expanded in ipc_kmsg_copyin_body() */ + if (MACH_MSG_TYPE_PORT_ANY(name)) { + if (size != bytes_to_descsize(sizeof(mach_port_name_t))) + return 1; + adjust_msg_type_size(ktaddr, sizeof(mach_port_t) - sizeof(mach_port_name_t)); + } + + if (copyin_address((rpc_vm_offset_t*)usaddr, (vm_offset_t*)ksaddr)) + return 1; + // Advance one pointer. + ksaddr += sizeof(vm_offset_t); + usaddr += sizeof(rpc_vm_offset_t); + } + // Note that we have to align because mach_port_name_t might not align + // with the required user alignment. + usaddr = mach_msg_user_align(usaddr); + ksaddr = mach_msg_kernel_align(ksaddr); + } + } + + kmsg->msgh_size = sizeof(mach_msg_header_t) + ksaddr - (vm_offset_t)(kmsg + 1); + assert(kmsg->msgh_size <= ksize); +#ifndef USER32 + if (kmsg->msgh_size != usize) + return 1; +#endif + return 0; +} + +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; + if (copyout_port(&kmsg->msgh_local_port, &umsg->msgh_local_port)) + return 1; + 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); + usaddr = (vm_offset_t)(umsg + 1); + keaddr = ksaddr + ksize - sizeof(mach_msg_header_t); + + if (ksize > sizeof(mach_msg_header_t)) + { + while (ksaddr < keaddr) + { + vm_size_t user_amount, kernel_amount; + mach_msg_type_name_t name; + mach_msg_type_size_t size; + mach_msg_type_number_t number; + boolean_t is_inline; + if (copyout_unpack_msg_type(ksaddr, usaddr, &name, &size, &number, + &is_inline, &user_amount, &kernel_amount)) + return 1; + usaddr += user_amount; + usaddr = mach_msg_user_align(usaddr); + ksaddr += kernel_amount; + ksaddr = mach_msg_kernel_align(ksaddr); + + if (is_inline) + { + if (MACH_MSG_TYPE_PORT_ANY(name)) + { +#ifdef USER32 + for (int i=0; imsgh_size, sizeof(umsg->msgh_size))) + return 1; +#ifndef USER32 + if (usize != ksize) + return 1; +#endif + + return 0; + +} + +#endif /* __LP64__ */ diff --git a/ipc/copy_user.h b/ipc/copy_user.h new file mode 100644 index 00000000..a57b3ee5 --- /dev/null +++ b/ipc/copy_user.h @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2023 Free Software Foundation + * + * This program is free software ; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation ; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY ; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the program ; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef COPY_USER_H +#define COPY_USER_H + +#include +#include + +#include +#include + +/* + * The copyin_32to64() and copyout_64to32() routines are meant for data types + * that have different size in kernel and user space. They should be independent + * of endianness and hopefully can be reused on all archs. + * These types are e.g.: + * - port names vs port pointers, on a 64-bit kernel + * - memory addresses, on a 64-bit kernel and 32-bit user + */ + +static inline int copyin_32to64(const uint32_t *uaddr, uint64_t *kaddr) +{ + uint32_t rkaddr; + int ret; + ret = copyin(uaddr, &rkaddr, sizeof(uint32_t)); + if (ret) + return ret; + *kaddr = rkaddr; + return 0; +} + +static inline int copyout_64to32(const uint64_t *kaddr, uint32_t *uaddr) +{ + uint32_t rkaddr=*kaddr; + return copyout(&rkaddr, uaddr, sizeof(uint32_t)); +} + +static inline int copyin_address(const rpc_vm_offset_t *uaddr, vm_offset_t *kaddr) +{ +#ifdef USER32 + return copyin_32to64(uaddr, kaddr); +#else /* USER32 */ + return copyin(uaddr, kaddr, sizeof(*uaddr)); +#endif /* USER32 */ +} + +static inline int copyout_address(const vm_offset_t *kaddr, rpc_vm_offset_t *uaddr) +{ +#ifdef USER32 + return copyout_64to32(kaddr, uaddr); +#else /* USER32 */ + return copyout(kaddr, uaddr, sizeof(*kaddr)); +#endif /* USER32 */ +} + +static inline int copyin_port(const mach_port_name_t *uaddr, mach_port_t *kaddr) +{ +#ifdef __LP64__ + return copyin_32to64(uaddr, kaddr); +#else /* __LP64__ */ + return copyin(uaddr, kaddr, sizeof(*uaddr)); +#endif /* __LP64__ */ +} + +static inline int copyout_port(const mach_port_t *kaddr, mach_port_name_t *uaddr) +{ +#ifdef __LP64__ + return copyout_64to32(kaddr, uaddr); +#else /* __LP64__ */ + return copyout(kaddr, uaddr, sizeof(*kaddr)); +#endif /* __LP64__ */ +} + +#if defined(__LP64__) && defined(USER32) +/* For 32 bit userland, kernel and user land messages are not the same size. */ +size_t msg_usize(const mach_msg_header_t *kmsg); +#else +static inline size_t msg_usize(const mach_msg_header_t *kmsg) +{ + return kmsg->msgh_size; +} +#endif /* __LP64__ && USER32 */ + +#endif /* COPY_USER_H */ diff --git a/ipc/ipc_kmsg.c b/ipc/ipc_kmsg.c index bd843804..8bd645ff 100644 --- a/ipc/ipc_kmsg.c +++ b/ipc/ipc_kmsg.c @@ -42,7 +42,6 @@ #include #include #include -#include #include #include #include @@ -51,6 +50,7 @@ #include #include #include +#include #include #include #include diff --git a/ipc/ipc_mqueue.c b/ipc/ipc_mqueue.c index 44e1eb98..95308f35 100644 --- a/ipc/ipc_mqueue.c +++ b/ipc/ipc_mqueue.c @@ -36,13 +36,13 @@ #include #include -#include #include #include #include #include #include #include +#include #include #include #include diff --git a/ipc/mach_msg.c b/ipc/mach_msg.c index 6194ef7b..ff5e5b09 100644 --- a/ipc/mach_msg.c +++ b/ipc/mach_msg.c @@ -39,7 +39,6 @@ #include #include #include -#include #include #include #include @@ -49,6 +48,7 @@ #include #include #include +#include #include #include #include diff --git a/kern/ipc_mig.c b/kern/ipc_mig.c index d26d2c6d..b753a25f 100644 --- a/kern/ipc_mig.c +++ b/kern/ipc_mig.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include @@ -42,6 +41,7 @@ #include #include #include +#include #include #include #include diff --git a/x86_64/Makefrag.am b/x86_64/Makefrag.am index b0bc45c2..2bbed986 100644 --- a/x86_64/Makefrag.am +++ b/x86_64/Makefrag.am @@ -90,7 +90,6 @@ libkernel_a_SOURCES += \ i386/i386/percpu.h \ i386/i386/percpu.c \ x86_64/cswitch.S \ - x86_64/copy_user.c \ x86_64/debug_trace.S \ x86_64/idt_inittab.S \ x86_64/locore.S \ diff --git a/x86_64/copy_user.c b/x86_64/copy_user.c deleted file mode 100644 index c6e125d9..00000000 --- a/x86_64/copy_user.c +++ /dev/null @@ -1,613 +0,0 @@ -/* - * Copyright (C) 2023 Free Software Foundation - * - * This program is free software ; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation ; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY ; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with the program ; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include - -#include -#include - -#include - - -/* Mach field descriptors measure size in bits */ -#define descsize_to_bytes(n) (n / 8) -#define bytes_to_descsize(n) (n * 8) - -#ifdef USER32 -/* Versions of mach_msg_type_t and mach_msg_type_long that are expected from the 32 bit userland. */ -typedef struct { - unsigned int msgt_name : 8, - msgt_size : 8, - msgt_number : 12, - msgt_inline : 1, - msgt_longform : 1, - msgt_deallocate : 1, - msgt_unused : 1; -} mach_msg_user_type_t; -_Static_assert(sizeof(mach_msg_user_type_t) == 4); - -typedef struct { - mach_msg_user_type_t msgtl_header; - unsigned short msgtl_name; - unsigned short msgtl_size; - natural_t msgtl_number; -} mach_msg_user_type_long_t; -_Static_assert(sizeof(mach_msg_user_type_long_t) == 12); -#else -typedef mach_msg_type_t mach_msg_user_type_t; -typedef mach_msg_type_long_t mach_msg_user_type_long_t; -#endif /* USER32 */ - -/* -* Helper to unpack the relevant fields of a msg type; the fields are different -* depending on whether is long form or not. -.*/ -static inline void unpack_msg_type(vm_offset_t addr, - mach_msg_type_name_t *name, - mach_msg_type_size_t *size, - mach_msg_type_number_t *number, - boolean_t *is_inline, - vm_size_t *user_amount, - vm_size_t *kernel_amount) -{ - mach_msg_type_t* kmt = (mach_msg_type_t*)addr; - *is_inline = kmt->msgt_inline; - if (kmt->msgt_longform) - { - mach_msg_type_long_t* kmtl = (mach_msg_type_long_t*)addr; - *name = kmtl->msgtl_name; - *size = kmtl->msgtl_size; - *number = kmtl->msgtl_number; - *kernel_amount = sizeof(mach_msg_type_long_t); - *user_amount = sizeof(mach_msg_user_type_long_t); - } - else - { - *name = kmt->msgt_name; - *size = kmt->msgt_size; - *number = kmt->msgt_number; - *kernel_amount = sizeof(mach_msg_type_t); - *user_amount = sizeof(mach_msg_user_type_t); - } -} - -#ifdef USER32 -static inline void mach_msg_user_type_to_kernel(const mach_msg_user_type_t *u, - mach_msg_type_t* k) { - k->msgt_name = u->msgt_name; - k->msgt_size = u->msgt_size; - k->msgt_number = u->msgt_number; - k->msgt_inline = u->msgt_inline; - k->msgt_longform = u->msgt_longform; - k->msgt_deallocate = u->msgt_deallocate; - k->msgt_unused = 0; -} - -static inline void mach_msg_user_type_to_kernel_long(const mach_msg_user_type_long_t *u, - mach_msg_type_long_t* k) { - const mach_msg_type_long_t kernel = { - .msgtl_header = { - .msgt_name = u->msgtl_name, - .msgt_size = u->msgtl_size, - .msgt_number = u->msgtl_number, - .msgt_inline = u->msgtl_header.msgt_inline, - .msgt_longform = u->msgtl_header.msgt_longform, - .msgt_deallocate = u->msgtl_header.msgt_deallocate, - .msgt_unused = 0 - } - }; - *k = kernel; -} - -static inline void mach_msg_kernel_type_to_user(const mach_msg_type_t *k, - mach_msg_user_type_t *u) { - u->msgt_name = k->msgt_name; - u->msgt_size = k->msgt_size; - u->msgt_number = k->msgt_number; - u->msgt_inline = k->msgt_inline; - u->msgt_longform = k->msgt_longform; - u->msgt_deallocate = k->msgt_deallocate; - u->msgt_unused = 0; -} - -static inline void mach_msg_kernel_type_to_user_long(const mach_msg_type_long_t *k, - mach_msg_user_type_long_t *u) { - const mach_msg_user_type_long_t user = { - .msgtl_header = { - .msgt_name = 0, - .msgt_size = 0, - .msgt_number = 0, - .msgt_inline = k->msgtl_header.msgt_inline, - .msgt_longform = k->msgtl_header.msgt_longform, - .msgt_deallocate = k->msgtl_header.msgt_deallocate, - .msgt_unused = 0 - }, - .msgtl_name = k->msgtl_header.msgt_name, - .msgtl_size = k->msgtl_header.msgt_size, - .msgtl_number = k->msgtl_header.msgt_number - }; - *u = user; -} -#endif - -static inline int copyin_mach_msg_type(const rpc_vm_offset_t *uaddr, mach_msg_type_t *kaddr) { -#ifdef USER32 - mach_msg_user_type_t user; - int ret = copyin(uaddr, &user, sizeof(mach_msg_user_type_t)); - if (ret) { - return ret; - } - mach_msg_user_type_to_kernel(&user, kaddr); - return 0; -#else - return copyin(uaddr, kaddr, sizeof(mach_msg_type_t)); -#endif -} - -static inline int copyout_mach_msg_type(const mach_msg_type_t *kaddr, rpc_vm_offset_t *uaddr) { -#ifdef USER32 - mach_msg_user_type_t user; - mach_msg_kernel_type_to_user(kaddr, &user); - return copyout(&user, uaddr, sizeof(mach_msg_user_type_t)); -#else - return copyout(kaddr, uaddr, sizeof(mach_msg_type_t)); -#endif -} - -static inline int copyin_mach_msg_type_long(const rpc_vm_offset_t *uaddr, mach_msg_type_long_t *kaddr) { -#ifdef USER32 - mach_msg_user_type_long_t user; - int ret = copyin(uaddr, &user, sizeof(mach_msg_user_type_long_t)); - if (ret) - return ret; - mach_msg_user_type_to_kernel_long(&user, kaddr); - return 0; -#else - return copyin(uaddr, kaddr, sizeof(mach_msg_type_long_t)); -#endif -} - -static inline int copyout_mach_msg_type_long(const mach_msg_type_long_t *kaddr, rpc_vm_offset_t *uaddr) { -#ifdef USER32 - mach_msg_user_type_long_t user; - mach_msg_kernel_type_to_user_long(kaddr, &user); - return copyout(&user, uaddr, sizeof(mach_msg_user_type_long_t)); -#else - return copyout(kaddr, uaddr, sizeof(mach_msg_type_long_t)); -#endif -} - -/* Optimized version of unpack_msg_type(), including proper copyin() */ -static inline int copyin_unpack_msg_type(vm_offset_t uaddr, - vm_offset_t kaddr, - mach_msg_type_name_t *name, - mach_msg_type_size_t *size, - mach_msg_type_number_t *number, - boolean_t *is_inline, - vm_size_t *user_amount, - vm_size_t *kernel_amount) -{ - mach_msg_type_t *kmt = (mach_msg_type_t*)kaddr; - if (copyin_mach_msg_type((void *)uaddr, kmt)) - return 1; - *is_inline = kmt->msgt_inline; - if (kmt->msgt_longform) - { - mach_msg_type_long_t* kmtl = (mach_msg_type_long_t*)kaddr; - if (copyin_mach_msg_type_long((void *)uaddr, kmtl)) - return 1; - *name = kmtl->msgtl_name; - *size = kmtl->msgtl_size; - *number = kmtl->msgtl_number; - *user_amount = sizeof(mach_msg_user_type_long_t); - *kernel_amount = sizeof(mach_msg_type_long_t); - } - else - { - *name = kmt->msgt_name; - *size = kmt->msgt_size; - *number = kmt->msgt_number; - *user_amount = sizeof(mach_msg_user_type_t); - *kernel_amount = sizeof(mach_msg_type_t); - } - return 0; -} - -/* - * The msg type has a different size field depending on whether is long or not, - * and we also need to convert from bytes to bits - */ -static inline void adjust_msg_type_size(vm_offset_t addr, int amount) -{ - mach_msg_type_t* kmt = (mach_msg_type_t*)addr; - if (kmt->msgt_longform) - { - mach_msg_type_long_t* kmtl = (mach_msg_type_long_t*)addr; - kmtl->msgtl_size += bytes_to_descsize(amount); - } - else - { - kmt->msgt_size += bytes_to_descsize(amount); - } -} - -/* Optimized version of unpack_msg_type(), including proper copyout() */ -static inline int copyout_unpack_msg_type(vm_offset_t kaddr, - vm_offset_t uaddr, - mach_msg_type_name_t *name, - mach_msg_type_size_t *size, - mach_msg_type_number_t *number, - boolean_t *is_inline, - vm_size_t *user_amount, - vm_size_t *kernel_amount) -{ - mach_msg_type_t *kmt = (mach_msg_type_t*)kaddr; - *is_inline = kmt->msgt_inline; - if (kmt->msgt_longform) - { - mach_msg_type_long_t* kmtl = (mach_msg_type_long_t*)kaddr; - mach_msg_type_size_t orig_size = kmtl->msgtl_size; - int ret; - - if (MACH_MSG_TYPE_PORT_ANY(kmtl->msgtl_name)) { -#ifdef USER32 - kmtl->msgtl_size = bytes_to_descsize(sizeof(mach_port_name_t)); -#else - /* 64 bit ABI uses mach_port_name_inlined_t for inlined ports. */ - if (!kmt->msgt_inline) - kmtl->msgtl_size = bytes_to_descsize(sizeof(mach_port_name_t)); -#endif - } - ret = copyout_mach_msg_type_long(kmtl, (void*)uaddr); - kmtl->msgtl_size = orig_size; - if (ret) - return 1; - - *name = kmtl->msgtl_name; - *size = kmtl->msgtl_size; - *number = kmtl->msgtl_number; - *user_amount = sizeof(mach_msg_user_type_long_t); - *kernel_amount = sizeof(mach_msg_type_long_t); - } - else - { - mach_msg_type_size_t orig_size = kmt->msgt_size; - int ret; - - if (MACH_MSG_TYPE_PORT_ANY(kmt->msgt_name)) { -#ifdef USER32 - kmt->msgt_size = bytes_to_descsize(sizeof(mach_port_name_t)); -#else - /* 64 bit ABI uses mach_port_name_inlined_t for inlined ports. */ - if (!kmt->msgt_inline) - kmt->msgt_size = bytes_to_descsize(sizeof(mach_port_name_t)); -#endif - } - ret = copyout_mach_msg_type(kmt, (void *)uaddr); - kmt->msgt_size = orig_size; - if (ret) - return 1; - - *name = kmt->msgt_name; - *size = kmt->msgt_size; - *number = kmt->msgt_number; - *user_amount = sizeof(mach_msg_user_type_t); - *kernel_amount = sizeof(mach_msg_type_t); - } - return 0; -} - -#ifdef USER32 -/* - * Compute the user-space size of a message still in the kernel when processing - * messages from 32bit userland. - * The message may be originating from userspace (in which case we could - * optimize this by keeping the usize around) or from kernel space (we could - * optimize if the message structure is fixed and known in advance). - * For now just handle the most general case, iterating over the msg body. - */ -size_t msg_usize(const mach_msg_header_t *kmsg) -{ - size_t ksize = kmsg->msgh_size; - size_t usize = sizeof(mach_msg_user_header_t); - if (ksize > sizeof(mach_msg_header_t)) - { - // iterate over body compute the user-space message size - vm_offset_t saddr, eaddr; - saddr = (vm_offset_t)(kmsg + 1); - eaddr = saddr + ksize - sizeof(mach_msg_header_t); - while (saddr < (eaddr - sizeof(mach_msg_type_t))) - { - vm_size_t user_amount, kernel_amount; - mach_msg_type_name_t name; - mach_msg_type_size_t size; - mach_msg_type_number_t number; - boolean_t is_inline; - unpack_msg_type(saddr, &name, &size, &number, &is_inline, &user_amount, &kernel_amount); - saddr += kernel_amount; - saddr = mach_msg_kernel_align(saddr); - usize += user_amount; - usize = mach_msg_user_align(usize); - - if (is_inline) - { - if (MACH_MSG_TYPE_PORT_ANY(name)) - { - const vm_size_t length = sizeof(mach_port_t) * number; - saddr += length; - usize += sizeof(mach_port_name_t) * number; - } - else - { - size_t n = descsize_to_bytes(size); - saddr += n*number; - usize += n*number; - } - } - else - { - // advance one pointer - saddr += sizeof(vm_offset_t); - usize += sizeof(rpc_vm_offset_t); - } - saddr = mach_msg_kernel_align(saddr); - usize = mach_msg_user_align(usize); - } - } - return usize; -} -#endif /* USER32 */ - -/* - * Expand the msg header and, if required, the msg body (ports, pointers) - * - * To not make the code too complicated, we use the fact that some fields of - * mach_msg_header have the same size in the kernel and user variant (basically - * all fields except ports and addresses) -*/ -int copyinmsg (const void *userbuf, void *kernelbuf, const size_t usize, const size_t ksize) -{ - 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; - if (copyin_port(&umsg->msgh_local_port, &kmsg->msgh_local_port)) - return 1; - 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; - kmsg->msgh_remote_port &= 0xFFFFFFFF; // FIXME: still have port names here - kmsg->msgh_local_port &= 0xFFFFFFFF; // also, this assumes little-endian -#endif - - vm_offset_t usaddr, ueaddr, ksaddr; - ksaddr = (vm_offset_t)(kmsg + 1); - usaddr = (vm_offset_t)(umsg + 1); - ueaddr = (vm_offset_t)umsg + usize; - - _Static_assert(!mach_msg_user_is_misaligned(sizeof(mach_msg_user_header_t)), - "mach_msg_user_header_t needs to be MACH_MSG_USER_ALIGNMENT aligned."); - - if (usize > sizeof(mach_msg_user_header_t)) - { - /* check we have at least space for an empty descryptor */ - while (usaddr <= (ueaddr - sizeof(mach_msg_user_type_t))) - { - vm_size_t user_amount, kernel_amount; - mach_msg_type_name_t name; - mach_msg_type_size_t size; - mach_msg_type_number_t number; - boolean_t is_inline; - if (copyin_unpack_msg_type(usaddr, ksaddr, &name, &size, &number, - &is_inline, &user_amount, &kernel_amount)) - return 1; - - // keep a reference to the current field descriptor, we - // might need to adjust it later depending on the type - vm_offset_t ktaddr = ksaddr; - usaddr += user_amount; - usaddr = mach_msg_user_align(usaddr); - ksaddr += kernel_amount; - ksaddr = mach_msg_kernel_align(ksaddr); - - if (is_inline) - { - if (MACH_MSG_TYPE_PORT_ANY(name)) - { -#ifdef USER32 - if (size != bytes_to_descsize(sizeof(mach_port_name_t))) - return 1; - if ((usaddr + sizeof(mach_port_name_t)*number) > ueaddr) - return 1; - adjust_msg_type_size(ktaddr, sizeof(mach_port_t) - sizeof(mach_port_name_t)); - for (int i=0; i ueaddr) - return 1; - if (copyin((void*)usaddr, (void*)ksaddr, length)) - return 1; - usaddr += length; - ksaddr += length; -#endif - } - else - { - // type that doesn't need change - size_t n = descsize_to_bytes(size); - if ((usaddr + n*number) > ueaddr) - return 1; - if (copyin((void*)usaddr, (void*)ksaddr, n*number)) - return 1; - usaddr += n*number; - ksaddr += n*number; - } - } - else - { - if ((usaddr + sizeof(rpc_vm_offset_t)) > ueaddr) - return 1; - - /* out-of-line port arrays are always arrays of mach_port_name_t (4 bytes) - * and are expanded in ipc_kmsg_copyin_body() */ - if (MACH_MSG_TYPE_PORT_ANY(name)) { - if (size != bytes_to_descsize(sizeof(mach_port_name_t))) - return 1; - adjust_msg_type_size(ktaddr, sizeof(mach_port_t) - sizeof(mach_port_name_t)); - } - - if (copyin_address((rpc_vm_offset_t*)usaddr, (vm_offset_t*)ksaddr)) - return 1; - // Advance one pointer. - ksaddr += sizeof(vm_offset_t); - usaddr += sizeof(rpc_vm_offset_t); - } - // Note that we have to align because mach_port_name_t might not align - // with the required user alignment. - usaddr = mach_msg_user_align(usaddr); - ksaddr = mach_msg_kernel_align(ksaddr); - } - } - - kmsg->msgh_size = sizeof(mach_msg_header_t) + ksaddr - (vm_offset_t)(kmsg + 1); - assert(kmsg->msgh_size <= ksize); -#ifndef USER32 - if (kmsg->msgh_size != usize) - return 1; -#endif - return 0; -} - -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; - if (copyout_port(&kmsg->msgh_local_port, &umsg->msgh_local_port)) - return 1; - 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); - usaddr = (vm_offset_t)(umsg + 1); - keaddr = ksaddr + ksize - sizeof(mach_msg_header_t); - - if (ksize > sizeof(mach_msg_header_t)) - { - while (ksaddr < keaddr) - { - vm_size_t user_amount, kernel_amount; - mach_msg_type_name_t name; - mach_msg_type_size_t size; - mach_msg_type_number_t number; - boolean_t is_inline; - if (copyout_unpack_msg_type(ksaddr, usaddr, &name, &size, &number, - &is_inline, &user_amount, &kernel_amount)) - return 1; - usaddr += user_amount; - usaddr = mach_msg_user_align(usaddr); - ksaddr += kernel_amount; - ksaddr = mach_msg_kernel_align(ksaddr); - - if (is_inline) - { - if (MACH_MSG_TYPE_PORT_ANY(name)) - { -#ifdef USER32 - for (int i=0; imsgh_size, sizeof(umsg->msgh_size))) - return 1; -#ifndef USER32 - if (usize != ksize) - return 1; -#endif - - return 0; - -} -- cgit v1.2.3