All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Bastien Roucariès" <rouca@debian.org>
To: libc-alpha@sourceware.org, Alejandro Colomar <alx.manpages@gmail.com>
Cc: Alejandro Colomar <alx@kernel.org>,
	linux-man@vger.kernel.org, Eric Blake <eblake@redhat.com>,
	Zack Weinberg <zack@owlfolio.org>,
	Stefan Puiu <stefan.puiu@gmail.com>, Igor Sysoev <igor@sysoev.ru>
Subject: Re: [PATCH v2] socket: Implement sockaddr_storage with an anonymous union
Date: Fri, 20 Jan 2023 20:32:35 +0000	[thread overview]
Message-ID: <5187043.CeDsVVrsAm@portable-bastien> (raw)
In-Reply-To: <20230120134043.10247-1-alx@kernel.org>

[-- Attachment #1: Type: text/plain, Size: 4638 bytes --]

Le vendredi 20 janvier 2023, 13:40:44 UTC Alejandro Colomar a écrit :
> The historical design of `sockaddr_storage` makes it impossible to use
> without breaking strict aliasing rules.  Not only this type is unusable,
> but even the use of other `sockaddr_*` structures directly (when the
> programmer only cares about a single address family) is also incorrect,
> since at some point the structure will be accessed as a `sockaddr`, and
> that breaks strict aliasing rules too.
> 
> So, the only way for a programmer to not invoke Undefined Behavior is to
> declare a union that includes `sockaddr` and any `sockaddr_*` structures
> that are of interest, which allows later accessing as either the correct
> structure or plain `sockaddr` for the sa_family.
> 
> This patch fixes sockaddr_storage to remove UB on its uses and make it
> that structure that everybody should be using.  It also allows removing
> many casts in code that needs to pass a sockaddr as a side effect.
> 
> The following is an example of how this improves both existing code and
> new code:
> 
> void
> foo(foo)
> {
>     struct old_sockaddr_storage  oss;
>     struct new_sockaddr_storage  nss;
> 
>     // ... (initialize oss and nss)
> 
>     inet_sockaddr2str(&nss.sa);  // correct (and has no casts)
>     inet_sockaddr2str((struct sockaddr *)&oss);  // UB
>     inet_sockaddr2str((struct sockaddr *)&nss);  // correct
> }
> 
> /* This function is correct, as far as the accessed object has the
>  * type we're using.  That's only possible through a `union`, since
>  * we're accessing it with 2 different types: `sockaddr` for the
>  * `sa_family` and then the appropriate subtype for the address
>  * itself.
>  */
> const char *
> inet_sockaddr2str(const struct sockaddr *sa)
> {
>     struct sockaddr_in   *sin;
>     struct sockaddr_in6  *sin6;
> 
>     static char          buf[MAXHOSTNAMELEN];
> 
>     switch (sa->sa_family) {
>     case AF_INET:
>         sin = (struct sockaddr_in *) sa;
>         inet_ntop(AF_INET, &sin->sin_addr, buf, NITEMS(buf));
>         return buf;
>     case AF_INET6:
>         sin6 = (struct sockaddr_in6 *) sa;
>         inet_ntop(AF_INET6, &sin6->sin6_addr, buf, NITEMS(buf));
>         return buf;
>     default:
>         errno = EAFNOSUPPORT;
>         return NULL;
>     }
> }
> 
> While it's not necessary to do the same for `sockaddr`, it might still
> be interesting to so, since it will allow removing many casts in the
> implementation of many libc functions.
> 
> Link: <https://lore.kernel.org/linux-man/2860541.uBSZ6KuyZf@portable-bastien/T/>
> Link: <https://inbox.sourceware.org/libc-alpha/0f25d60f-f183-b518-b6c1-6d46aa63ee57@gmail.com/T/>
> Link: <https://stackoverflow.com/a/42190913/6872717>
> Link: <https://software.codidact.com/posts/287748>
> Cc: Bastien Roucariès <rouca@debian.org>
> Cc: Eric Blake <eblake@redhat.com>
> Cc: Zack Weinberg <zack@owlfolio.org>
> Cc: Stefan Puiu <stefan.puiu@gmail.com>
> Cc: Igor Sysoev <igor@sysoev.ru>
> Signed-off-by: Alejandro Colomar <alx@kernel.org>
> ---
> 
> v2:
> 
> -  Fix incorrect cast in commit message.
> 
>  bits/socket.h | 11 ++++++++---
>  1 file changed, 8 insertions(+), 3 deletions(-)
> 
> diff --git a/bits/socket.h b/bits/socket.h
> index aac8c49b00..c0c23b4e84 100644
> --- a/bits/socket.h
> +++ b/bits/socket.h
> @@ -168,9 +168,14 @@ struct sockaddr
>  
>  struct sockaddr_storage
>    {
> -    __SOCKADDR_COMMON (ss_);	/* Address family, etc.  */
> -    char __ss_padding[_SS_PADSIZE];
> -    __ss_aligntype __ss_align;	/* Force desired alignment.  */
no this is not correct you break ABI by reducing size
> +    union
> +      {
> +        __SOCKADDR_COMMON (ss_);	/* Address family, etc.  */
> +        struct sockaddr      sa;
> +        struct sockaddr_in   sin;
> +        struct sockaddr_in6  sin6;
> +        struct sockaddr_un   sun;
> +      };
>    };

Correct one structure is

struct __private_sock_storage {
    __SOCKADDR_COMMON (ssprivate_);   /* Address family, etc. */
    char __ss_padding[_SS_PADSIZE];
    __ss_aligntype __ss_align; /* Force desired alignment. */
}

 struct sockaddr_storage
   {
       union
      {
         __SOCKADDR_COMMON (ss_);       /* Address family, etc. */
        struct sockaddr      sa;
         struct sockaddr_in   sin;
        struct sockaddr_in6  sin6;
        struct sockaddr_un   sun;
        struct __private_sock_storage _private;
      };
};

May it could be dropped later using align construct for modern C and padding

Bastien
>  
>  
> 


[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

  parent reply	other threads:[~2023-01-20 20:32 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-01-20 13:40 [PATCH v2] socket: Implement sockaddr_storage with an anonymous union Alejandro Colomar
2023-01-20 17:49 ` Joseph Myers
2023-01-20 19:26   ` Alejandro Colomar
2023-01-20 18:04 ` Zack Weinberg
2023-01-20 19:25   ` Alejandro Colomar
2023-01-21  2:38     ` Alejandro Colomar
2023-01-21  3:17       ` Alejandro Colomar
2023-01-21 13:30         ` Bastien Roucariès
2023-01-21 14:30           ` Alejandro Colomar
2023-01-22 14:12             ` Bastien Roucariès
2023-01-20 20:32 ` Bastien Roucariès [this message]
2023-01-20 20:38   ` Alejandro Colomar
2023-01-20 20:46     ` Bastien Roucariès
2023-01-20 20:51       ` Alejandro Colomar

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=5187043.CeDsVVrsAm@portable-bastien \
    --to=rouca@debian.org \
    --cc=alx.manpages@gmail.com \
    --cc=alx@kernel.org \
    --cc=eblake@redhat.com \
    --cc=igor@sysoev.ru \
    --cc=libc-alpha@sourceware.org \
    --cc=linux-man@vger.kernel.org \
    --cc=stefan.puiu@gmail.com \
    --cc=zack@owlfolio.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.