diff options
author | Flavio Cruz <flaviocruz@gmail.com> | 2023-02-19 18:06:51 -0500 |
---|---|---|
committer | Samuel Thibault <samuel.thibault@ens-lyon.org> | 2023-02-27 23:17:03 +0100 |
commit | dac167f036465e9d7cca10c52d8345773d2e6c3f (patch) | |
tree | 0e8b8644bb217d4f95874f602224306e65979d59 /x86_64 | |
parent | d2880baef19991270cbcdbdb22622e91815faadc (diff) | |
download | gnumach-dac167f036465e9d7cca10c52d8345773d2e6c3f.tar.gz gnumach-dac167f036465e9d7cca10c52d8345773d2e6c3f.tar.bz2 gnumach-dac167f036465e9d7cca10c52d8345773d2e6c3f.zip |
Support alignment requirements for a 64 bit kernel.
We introduce both a user alignment and a kernel alignment. These are
separate requirements since for 64 bit with a 32 bit kernel we need to
ensure the kernel can consume messages that are 8-byte aligned. This
change removes any possibility of undefined behavior and also allows the
kernel to support 64 bit RPCs for the userland.
A lot of the code that performs alignment was simplified under the
assumption that the message headers are well aligned. To enforce that
going forward, a few static assertions were added.
Message-Id: <Y/KrixiC9Njmu7ef@jupiter.tail36e24.ts.net>
Diffstat (limited to 'x86_64')
-rw-r--r-- | x86_64/copy_user.c | 36 |
1 files changed, 22 insertions, 14 deletions
diff --git a/x86_64/copy_user.c b/x86_64/copy_user.c index ae17c368..e429f259 100644 --- a/x86_64/copy_user.c +++ b/x86_64/copy_user.c @@ -136,7 +136,9 @@ size_t msg_usize(const mach_msg_header_t *kmsg) boolean_t is_inline; amount = unpack_msg_type(saddr, &name, &size, &number, &is_inline); saddr += amount; + saddr = mach_msg_kernel_align(saddr); usize += amount; + usize = mach_msg_user_align(usize); if (is_inline) { @@ -150,8 +152,6 @@ size_t msg_usize(const mach_msg_header_t *kmsg) size_t n = descsize_to_bytes(size); saddr += n*number; usize += n*number; - saddr = mach_msg_align(saddr); - usize = mach_msg_align(usize); } } else @@ -160,6 +160,8 @@ size_t msg_usize(const mach_msg_header_t *kmsg) 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; @@ -168,7 +170,7 @@ size_t msg_usize(const mach_msg_header_t *kmsg) /* * Expand the msg header and, if required, the msg body (ports, pointers) * - * To not make the code too compicated, we use the fact that some fields of + * 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) */ @@ -202,6 +204,10 @@ int copyinmsg (const void *userbuf, void *kernelbuf, const size_t usize) 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 */ @@ -212,8 +218,6 @@ int copyinmsg (const void *userbuf, void *kernelbuf, const size_t usize) mach_msg_type_size_t size; mach_msg_type_number_t number; boolean_t is_inline; - usaddr = mach_msg_align(usaddr); - ksaddr = mach_msg_align(ksaddr); if (copyin_unpack_msg_type(usaddr, ksaddr, &name, &size, &number, &is_inline, &amount)) return 1; @@ -222,7 +226,9 @@ int copyinmsg (const void *userbuf, void *kernelbuf, const size_t usize) // might need to adjust it later depending on the type vm_offset_t ktaddr = ksaddr; usaddr += amount; + usaddr = mach_msg_user_align(usaddr); ksaddr += amount; + ksaddr = mach_msg_kernel_align(ksaddr); if (is_inline) { @@ -249,8 +255,6 @@ int copyinmsg (const void *userbuf, void *kernelbuf, const size_t usize) return 1; usaddr += n*number; ksaddr += n*number; - usaddr = mach_msg_align(usaddr); - ksaddr = mach_msg_align(ksaddr); } } else @@ -264,15 +268,19 @@ int copyinmsg (const void *userbuf, void *kernelbuf, const size_t usize) if (copyin_address((rpc_vm_offset_t*)usaddr, (vm_offset_t*)ksaddr)) return 1; - // advance one pointer + // 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); - kmsg->msgh_size = mach_msg_align(kmsg->msgh_size); + kmsg->msgh_size = kmsg->msgh_size; return 0; } @@ -310,15 +318,15 @@ int copyoutmsg (const void *kernelbuf, void *userbuf, const size_t ksize) mach_msg_type_size_t size; mach_msg_type_number_t number; boolean_t is_inline; - usaddr = mach_msg_align(usaddr); - ksaddr = mach_msg_align(ksaddr); amount = unpack_msg_type(ksaddr, &name, &size, &number, &is_inline); // TODO: optimize and bring here type adjustment?? vm_offset_t utaddr=usaddr, ktaddr=ksaddr; if (copyout((void*)ksaddr, (void*)usaddr, amount)) return 1; usaddr += amount; + usaddr = mach_msg_user_align(usaddr); ksaddr += amount; + ksaddr = mach_msg_kernel_align(ksaddr); if (is_inline) { @@ -343,8 +351,6 @@ int copyoutmsg (const void *kernelbuf, void *userbuf, const size_t ksize) return 1; usaddr += n*number; ksaddr += n*number; - usaddr = mach_msg_align(usaddr); - ksaddr = mach_msg_align(ksaddr); } } else @@ -363,12 +369,14 @@ int copyoutmsg (const void *kernelbuf, void *userbuf, const size_t ksize) ksaddr += sizeof(vm_offset_t); usaddr += sizeof(rpc_vm_offset_t); } + usaddr = mach_msg_user_align(usaddr); + ksaddr = mach_msg_kernel_align(ksaddr); } } mach_msg_size_t usize; usize = sizeof(mach_msg_user_header_t) + usaddr - (vm_offset_t)(umsg + 1); - usize = mach_msg_align(usize); + usize = usize; if (copyout(&usize, &umsg->msgh_size, sizeof(kmsg->msgh_size))) return 1; |