bug-hurd
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH gnumach] Align mach_msg_type_t and mach_msg_type_long_t with


From: Samuel Thibault
Subject: Re: [PATCH gnumach] Align mach_msg_type_t and mach_msg_type_long_t with the same alignment as uintptr_t.
Date: Wed, 8 Mar 2023 00:44:15 +0100
User-agent: NeoMutt/20170609 (1.8.3)

Applied, thanks!

Flavio Cruz, le mar. 07 mars 2023 02:01:13 -0500, a ecrit:
> With this change, any 64 bit code using the IPC subsystem without relying on
> MiG will work without any changes. We have a few examples of this inside 
> gnumach but
> also in the Hurd servers. For example, in hurd/console/display.c
> 
>   typedef struct
>   {
>     mach_msg_header_t Head;
>     mach_msg_type_t ticknoType;
>     natural_t tickno;
>     mach_msg_type_t changeType;
>     file_changed_type_t change;
>     mach_msg_type_t startType;
>     loff_t start;
>     mach_msg_type_t endType;
>     loff_t end;
>   } Request;
> 
> This will now work correctly in 64 bits, without requiring any explicit 
> padding.
> 
> As a follow up, we can simplify mach_msg_type_long_t so that we
> only need an 8 byte structure where the second field will include the
> number of elements for the long form. This is already included in
> mach_msg_type_t as unused_msgtl_number.
> ---
>  i386/i386/copy_user.h  |   4 +-
>  include/mach/message.h |  14 ++--
>  x86_64/copy_user.c     | 186 ++++++++++++++++++++++++++++++++---------
>  3 files changed, 156 insertions(+), 48 deletions(-)
> 
> diff --git a/i386/i386/copy_user.h b/i386/i386/copy_user.h
> index c7e8b4e1..5cdbfa80 100644
> --- a/i386/i386/copy_user.h
> +++ b/i386/i386/copy_user.h
> @@ -71,7 +71,7 @@ static inline int copyout_address(const vm_offset_t *kaddr, 
> rpc_vm_offset_t *uad
>  
>  static inline int copyin_port(const mach_port_name_t *uaddr, mach_port_t 
> *kaddr)
>  {
> -#ifdef __x86_64
> +#ifdef __x86_64__
>    return copyin_32to64(uaddr, kaddr);
>  #else /* __x86_64__ */
>    return copyin(uaddr, kaddr, sizeof(*uaddr));
> @@ -80,7 +80,7 @@ static inline int copyin_port(const mach_port_name_t 
> *uaddr, mach_port_t *kaddr)
>  
>  static inline int copyout_port(const mach_port_t *kaddr, mach_port_name_t 
> *uaddr)
>  {
> -#ifdef __x86_64
> +#ifdef __x86_64__
>    return copyout_64to32(kaddr, uaddr);
>  #else /* __x86_64__ */
>    return copyout(kaddr, uaddr, sizeof(*kaddr));
> diff --git a/include/mach/message.h b/include/mach/message.h
> index 22a17b03..0eab9d41 100644
> --- a/include/mach/message.h
> +++ b/include/mach/message.h
> @@ -132,9 +132,6 @@ typedef   unsigned int mach_msg_size_t;
>  typedef natural_t mach_msg_seqno_t;
>  typedef integer_t mach_msg_id_t;
>  
> -/* Force 4-byte alignment to simplify how the kernel parses the messages */
> -#pragma pack(push, 4)
> -
>  /* full header structure, may have different size in user/kernel spaces */
>  typedef      struct mach_msg_header {
>      mach_msg_bits_t  msgh_bits;
> @@ -232,16 +229,19 @@ typedef struct  {
>                       msgt_longform : 1,
>                       msgt_deallocate : 1,
>                       msgt_unused : 1;
> -} mach_msg_type_t;
> +#ifdef __x86_64__
> +    /* TODO: We want to eventually use this in favor of mach_msg_type_long_t
> +     * as it makes the mach_msg protocol require only mach_msg_type_t. */
> +    mach_msg_type_number_t   unused_msgtl_number;
> +#endif
> +} __attribute__ ((aligned (__alignof__ (uintptr_t)))) mach_msg_type_t;
>  
>  typedef      struct  {
>      mach_msg_type_t  msgtl_header;
>      unsigned short   msgtl_name;
>      unsigned short   msgtl_size;
>      natural_t                msgtl_number;
> -} mach_msg_type_long_t;
> -
> -#pragma pack(pop)
> +} __attribute__ ((aligned (__alignof__ (uintptr_t)))) mach_msg_type_long_t;
>  
>  /*
>   *   Known values for the msgt_name field.
> diff --git a/x86_64/copy_user.c b/x86_64/copy_user.c
> index e429f259..b5084996 100644
> --- a/x86_64/copy_user.c
> +++ b/x86_64/copy_user.c
> @@ -29,16 +29,42 @@
>  #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 vm_size_t 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)
> +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;
> @@ -48,17 +74,69 @@ static inline vm_size_t unpack_msg_type(vm_offset_t addr,
>        *name = kmtl->msgtl_name;
>        *size = kmtl->msgtl_size;
>        *number = kmtl->msgtl_number;
> -      return sizeof(mach_msg_type_long_t);
> +      *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;
> -      return sizeof(mach_msg_type_t);
> +      *kernel_amount = sizeof(mach_msg_type_t);
> +      *user_amount = sizeof(mach_msg_user_type_t);
>      }
>  }
>  
> +static inline int copyin_mach_msg_type(const rpc_vm_offset_t *uaddr, 
> mach_msg_type_t *kaddr) {
> +#ifdef USER32
> +  int ret;
> +  ret = copyin(uaddr, kaddr, sizeof(mach_msg_user_type_t));
> +  kaddr->unused_msgtl_number = 0;
> +  return ret;
> +#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
> +  return copyout(kaddr, 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;
> +  ret = copyin(uaddr, &user, sizeof(mach_msg_user_type_long_t));
> +  if (ret)
> +    return ret;
> +  /* The first 4 bytes are laid out in the same way. */
> +  memcpy(&kaddr->msgtl_header, &user.msgtl_header, 
> sizeof(mach_msg_user_type_t));
> +  kaddr->msgtl_name = user.msgtl_name;
> +  kaddr->msgtl_size = user.msgtl_size;
> +  kaddr->msgtl_number = user.msgtl_number;
> +  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;
> +  memcpy(&user.msgtl_header, &kaddr->msgtl_header, 
> sizeof(mach_msg_user_type_t));
> +  user.msgtl_name = kaddr->msgtl_name;
> +  user.msgtl_size = kaddr->msgtl_size;
> +  user.msgtl_number = kaddr->msgtl_number;
> +  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,
> @@ -66,28 +144,31 @@ static inline int copyin_unpack_msg_type(vm_offset_t 
> uaddr,
>                                           mach_msg_type_size_t *size,
>                                           mach_msg_type_number_t *number,
>                                           boolean_t *is_inline,
> -                                         vm_size_t *amount)
> +                                         vm_size_t *user_amount,
> +                                         vm_size_t *kernel_amount)
>  {
>    mach_msg_type_t *kmt = (mach_msg_type_t*)kaddr;
> -  if (copyin((void*)uaddr, kmt, sizeof(mach_msg_type_t)))
> +  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((void*)uaddr, kmtl, sizeof(mach_msg_type_long_t)))
> +      if (copyin_mach_msg_type_long((void *)uaddr, kmtl))
>          return 1;
>        *name = kmtl->msgtl_name;
>        *size = kmtl->msgtl_size;
>        *number = kmtl->msgtl_number;
> -      *amount = sizeof(mach_msg_type_long_t);
> +      *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;
> -      *amount = sizeof(mach_msg_type_t);
> +      *user_amount = sizeof(mach_msg_user_type_t);
> +      *kernel_amount = sizeof(mach_msg_type_t);
>      }
>    return 0;
>  }
> @@ -110,6 +191,46 @@ static inline void adjust_msg_type_size(vm_offset_t 
> addr, int 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;
> +      if (MACH_MSG_TYPE_PORT_ANY(kmtl->msgtl_name))
> +        kmtl->msgtl_size = bytes_to_descsize(sizeof(mach_port_name_t));
> +      if (copyout_mach_msg_type_long(kmtl, (void*)uaddr))
> +        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
> +    {
> +      if (MACH_MSG_TYPE_PORT_ANY(kmt->msgt_name))
> +        kmt->msgt_size = bytes_to_descsize(sizeof(mach_port_name_t));
> +      if (copyout_mach_msg_type(kmt, (void *)uaddr))
> +        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;
> +}
> +
>  /*
>   * Compute the user-space size of a message still in the kernel.
>   * The message may be originating from userspace (in which case we could
> @@ -129,15 +250,15 @@ size_t msg_usize(const mach_msg_header_t *kmsg)
>        eaddr = saddr + ksize - sizeof(mach_msg_header_t);
>        while (saddr < (eaddr - sizeof(mach_msg_type_t)))
>          {
> -          vm_size_t amount;
> +          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;
> -          amount = unpack_msg_type(saddr, &name, &size, &number, &is_inline);
> -          saddr += amount;
> +          unpack_msg_type(saddr, &name, &size, &number, &is_inline, 
> &user_amount, &kernel_amount);
> +          saddr += kernel_amount;
>            saddr = mach_msg_kernel_align(saddr);
> -          usize += amount;
> +          usize += user_amount;
>            usize = mach_msg_user_align(usize);
>  
>            if (is_inline)
> @@ -211,23 +332,23 @@ int copyinmsg (const void *userbuf, void *kernelbuf, 
> const size_t usize)
>    if (usize > sizeof(mach_msg_user_header_t))
>      {
>        /* check we have at least space for an empty descryptor */
> -      while (usaddr < (ueaddr - sizeof(mach_msg_type_t)))
> +      while (usaddr < (ueaddr - sizeof(mach_msg_user_type_t)))
>          {
> -          vm_size_t amount;
> +          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, &amount))
> +                                     &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 += amount;
> +          usaddr += user_amount;
>            usaddr = mach_msg_user_align(usaddr);
> -          ksaddr += amount;
> +          ksaddr += kernel_amount;
>            ksaddr = mach_msg_kernel_align(ksaddr);
>  
>            if (is_inline)
> @@ -313,28 +434,23 @@ int copyoutmsg (const void *kernelbuf, void *userbuf, 
> const size_t ksize)
>      {
>        while (ksaddr < keaddr)
>          {
> -          vm_size_t amount;
> +          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;
> -          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))
> +          if (copyout_unpack_msg_type(ksaddr, usaddr, &name, &size, &number,
> +                                      &is_inline, &user_amount, 
> &kernel_amount))
>              return 1;
> -          usaddr += amount;
> +          usaddr += user_amount;
>            usaddr = mach_msg_user_align(usaddr);
> -          ksaddr += amount;
> +          ksaddr += kernel_amount;
>            ksaddr = mach_msg_kernel_align(ksaddr);
>  
>            if (is_inline)
>              {
>                if (MACH_MSG_TYPE_PORT_ANY(name))
>                  {
> -                  adjust_msg_type_size(ktaddr, (int)sizeof(mach_port_name_t) 
> - (int)sizeof(mach_port_t));
> -                  if (copyout((void*)ktaddr, (void*)utaddr, amount))
> -                    return 1;
>                    for (int i=0; i<number; i++)
>                      {
>                        if (copyout_port((mach_port_t*)ksaddr, 
> (mach_port_name_t*)usaddr))
> @@ -355,14 +471,6 @@ int copyoutmsg (const void *kernelbuf, void *userbuf, 
> const size_t ksize)
>              }
>            else
>              {
> -              // out-of-line port arrays are shrinked in 
> ipc_kmsg_copyout_body()
> -              if (MACH_MSG_TYPE_PORT_ANY(name))
> -                {
> -                  adjust_msg_type_size(ktaddr, -4);
> -                  if (copyout((void*)ktaddr, (void*)utaddr, amount))
> -                    return 1;
> -                }
> -
>                if (copyout_address((vm_offset_t*)ksaddr, 
> (rpc_vm_offset_t*)usaddr))
>                  return 1;
>                // advance one pointer
> -- 
> 2.39.2
> 
> 

-- 
Samuel
---
Pour une évaluation indépendante, transparente et rigoureuse !
Je soutiens la Commission d'Évaluation de l'Inria.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]