Fix various strict aliasing problems with sockaddr

Fix various strict aliasing problems caused by casting between (struct
sockaddr *) and (struct sockaddr_storage *): the correct code here is to
keep the two in a union.

Signed-off-by: Philip Withnall <withnall@endlessm.com>

https://bugzilla.gnome.org/show_bug.cgi?id=791622
This commit is contained in:
Philip Withnall 2017-12-21 17:46:24 +00:00
parent 8f7cc8cb75
commit d8fe926ba4
3 changed files with 47 additions and 26 deletions

View File

@ -47,7 +47,10 @@
struct _GNativeSocketAddressPrivate struct _GNativeSocketAddressPrivate
{ {
struct sockaddr *sockaddr; struct sockaddr *sockaddr;
union {
struct sockaddr_storage storage; struct sockaddr_storage storage;
struct sockaddr sa;
} storage;
gsize sockaddr_len; gsize sockaddr_len;
}; };
@ -58,7 +61,7 @@ g_native_socket_address_dispose (GObject *object)
{ {
GNativeSocketAddress *address = G_NATIVE_SOCKET_ADDRESS (object); GNativeSocketAddress *address = G_NATIVE_SOCKET_ADDRESS (object);
if (address->priv->sockaddr != (struct sockaddr *)&address->priv->storage) if (address->priv->sockaddr != &address->priv->storage.sa)
g_free (address->priv->sockaddr); g_free (address->priv->sockaddr);
G_OBJECT_CLASS (g_native_socket_address_parent_class)->dispose (object); G_OBJECT_CLASS (g_native_socket_address_parent_class)->dispose (object);
@ -150,7 +153,7 @@ g_native_socket_address_new (gpointer native,
addr = g_object_new (G_TYPE_NATIVE_SOCKET_ADDRESS, NULL); addr = g_object_new (G_TYPE_NATIVE_SOCKET_ADDRESS, NULL);
if (len <= sizeof(addr->priv->storage)) if (len <= sizeof(addr->priv->storage))
addr->priv->sockaddr = (struct sockaddr*)&addr->priv->storage; addr->priv->sockaddr = &addr->priv->storage.sa;
else else
addr->priv->sockaddr = g_malloc (len); addr->priv->sockaddr = g_malloc (len);

View File

@ -421,7 +421,10 @@ check_timeout (GSocket *socket,
static void static void
g_socket_details_from_fd (GSocket *socket) g_socket_details_from_fd (GSocket *socket)
{ {
struct sockaddr_storage address; union {
struct sockaddr_storage storage;
struct sockaddr sa;
} address;
gint fd; gint fd;
guint addrlen; guint addrlen;
int value, family; int value, family;
@ -454,7 +457,7 @@ g_socket_details_from_fd (GSocket *socket)
} }
addrlen = sizeof address; addrlen = sizeof address;
if (getsockname (fd, (struct sockaddr *) &address, &addrlen) != 0) if (getsockname (fd, &address.sa, &addrlen) != 0)
{ {
errsv = get_socket_errno (); errsv = get_socket_errno ();
goto err; goto err;
@ -463,8 +466,8 @@ g_socket_details_from_fd (GSocket *socket)
if (addrlen > 0) if (addrlen > 0)
{ {
g_assert (G_STRUCT_OFFSET (struct sockaddr, sa_family) + g_assert (G_STRUCT_OFFSET (struct sockaddr, sa_family) +
sizeof address.ss_family <= addrlen); sizeof address.storage.ss_family <= addrlen);
family = address.ss_family; family = address.storage.ss_family;
} }
else else
{ {
@ -488,7 +491,7 @@ g_socket_details_from_fd (GSocket *socket)
{ {
case G_SOCKET_FAMILY_IPV4: case G_SOCKET_FAMILY_IPV4:
case G_SOCKET_FAMILY_IPV6: case G_SOCKET_FAMILY_IPV6:
socket->priv->family = address.ss_family; socket->priv->family = address.storage.ss_family;
switch (socket->priv->type) switch (socket->priv->type)
{ {
case G_SOCKET_TYPE_STREAM: case G_SOCKET_TYPE_STREAM:
@ -521,7 +524,7 @@ g_socket_details_from_fd (GSocket *socket)
if (socket->priv->family != G_SOCKET_FAMILY_INVALID) if (socket->priv->family != G_SOCKET_FAMILY_INVALID)
{ {
addrlen = sizeof address; addrlen = sizeof address;
if (getpeername (fd, (struct sockaddr *) &address, &addrlen) >= 0) if (getpeername (fd, &address.sa, &addrlen) >= 0)
{ {
socket->priv->connected_read = TRUE; socket->priv->connected_read = TRUE;
socket->priv->connected_write = TRUE; socket->priv->connected_write = TRUE;
@ -1936,12 +1939,15 @@ GSocketAddress *
g_socket_get_local_address (GSocket *socket, g_socket_get_local_address (GSocket *socket,
GError **error) GError **error)
{ {
struct sockaddr_storage buffer; union {
struct sockaddr_storage storage;
struct sockaddr sa;
} buffer;
guint len = sizeof (buffer); guint len = sizeof (buffer);
g_return_val_if_fail (G_IS_SOCKET (socket), NULL); g_return_val_if_fail (G_IS_SOCKET (socket), NULL);
if (getsockname (socket->priv->fd, (struct sockaddr *) &buffer, &len) < 0) if (getsockname (socket->priv->fd, &buffer.sa, &len) < 0)
{ {
int errsv = get_socket_errno (); int errsv = get_socket_errno ();
g_set_error (error, G_IO_ERROR, socket_io_error_from_errno (errsv), g_set_error (error, G_IO_ERROR, socket_io_error_from_errno (errsv),
@ -1949,7 +1955,7 @@ g_socket_get_local_address (GSocket *socket,
return NULL; return NULL;
} }
return g_socket_address_new_from_native (&buffer, len); return g_socket_address_new_from_native (&buffer.storage, len);
} }
/** /**
@ -1969,7 +1975,10 @@ GSocketAddress *
g_socket_get_remote_address (GSocket *socket, g_socket_get_remote_address (GSocket *socket,
GError **error) GError **error)
{ {
struct sockaddr_storage buffer; union {
struct sockaddr_storage storage;
struct sockaddr sa;
} buffer;
guint len = sizeof (buffer); guint len = sizeof (buffer);
g_return_val_if_fail (G_IS_SOCKET (socket), NULL); g_return_val_if_fail (G_IS_SOCKET (socket), NULL);
@ -1984,7 +1993,7 @@ g_socket_get_remote_address (GSocket *socket,
if (!socket->priv->remote_address) if (!socket->priv->remote_address)
{ {
if (getpeername (socket->priv->fd, (struct sockaddr *) &buffer, &len) < 0) if (getpeername (socket->priv->fd, &buffer.sa, &len) < 0)
{ {
int errsv = get_socket_errno (); int errsv = get_socket_errno ();
g_set_error (error, G_IO_ERROR, socket_io_error_from_errno (errsv), g_set_error (error, G_IO_ERROR, socket_io_error_from_errno (errsv),
@ -1992,7 +2001,7 @@ g_socket_get_remote_address (GSocket *socket,
return NULL; return NULL;
} }
socket->priv->remote_address = g_socket_address_new_from_native (&buffer, len); socket->priv->remote_address = g_socket_address_new_from_native (&buffer.storage, len);
} }
return g_object_ref (socket->priv->remote_address); return g_object_ref (socket->priv->remote_address);
@ -2104,7 +2113,10 @@ g_socket_bind (GSocket *socket,
gboolean reuse_address, gboolean reuse_address,
GError **error) GError **error)
{ {
struct sockaddr_storage addr; union {
struct sockaddr_storage storage;
struct sockaddr sa;
} addr;
gboolean so_reuseaddr; gboolean so_reuseaddr;
#ifdef SO_REUSEPORT #ifdef SO_REUSEPORT
gboolean so_reuseport; gboolean so_reuseport;
@ -2115,7 +2127,7 @@ g_socket_bind (GSocket *socket,
if (!check_socket (socket, error)) if (!check_socket (socket, error))
return FALSE; return FALSE;
if (!g_socket_address_to_native (address, &addr, sizeof addr, error)) if (!g_socket_address_to_native (address, &addr.storage, sizeof addr, error))
return FALSE; return FALSE;
/* On Windows, SO_REUSEADDR has the semantics we want for UDP /* On Windows, SO_REUSEADDR has the semantics we want for UDP
@ -2147,7 +2159,7 @@ g_socket_bind (GSocket *socket,
g_socket_set_option (socket, SOL_SOCKET, SO_REUSEPORT, so_reuseport, NULL); g_socket_set_option (socket, SOL_SOCKET, SO_REUSEPORT, so_reuseport, NULL);
#endif #endif
if (bind (socket->priv->fd, (struct sockaddr *) &addr, if (bind (socket->priv->fd, &addr.sa,
g_socket_address_get_native_size (address)) < 0) g_socket_address_get_native_size (address)) < 0)
{ {
int errsv = get_socket_errno (); int errsv = get_socket_errno ();
@ -2793,14 +2805,17 @@ g_socket_connect (GSocket *socket,
GCancellable *cancellable, GCancellable *cancellable,
GError **error) GError **error)
{ {
struct sockaddr_storage buffer; union {
struct sockaddr_storage storage;
struct sockaddr sa;
} buffer;
g_return_val_if_fail (G_IS_SOCKET (socket) && G_IS_SOCKET_ADDRESS (address), FALSE); g_return_val_if_fail (G_IS_SOCKET (socket) && G_IS_SOCKET_ADDRESS (address), FALSE);
if (!check_socket (socket, error)) if (!check_socket (socket, error))
return FALSE; return FALSE;
if (!g_socket_address_to_native (address, &buffer, sizeof buffer, error)) if (!g_socket_address_to_native (address, &buffer.storage, sizeof buffer, error))
return FALSE; return FALSE;
if (socket->priv->remote_address) if (socket->priv->remote_address)
@ -2811,7 +2826,7 @@ g_socket_connect (GSocket *socket,
{ {
win32_unset_event_mask (socket, FD_CONNECT); win32_unset_event_mask (socket, FD_CONNECT);
if (connect (socket->priv->fd, (struct sockaddr *) &buffer, if (connect (socket->priv->fd, &buffer.sa,
g_socket_address_get_native_size (address)) < 0) g_socket_address_get_native_size (address)) < 0)
{ {
int errsv = get_socket_errno (); int errsv = get_socket_errno ();

View File

@ -2167,12 +2167,15 @@ g_log_writer_is_journald (gint output_fd)
if (g_once_init_enter (&initialized)) if (g_once_init_enter (&initialized))
{ {
struct sockaddr_storage addr; union {
struct sockaddr_storage storage;
struct sockaddr sa;
struct sockaddr_un un;
} addr;
socklen_t addr_len = sizeof(addr); socklen_t addr_len = sizeof(addr);
int err = getpeername (output_fd, (struct sockaddr *) &addr, &addr_len); int err = getpeername (output_fd, &addr.sa, &addr_len);
if (err == 0 && addr.ss_family == AF_UNIX) if (err == 0 && addr.storage.ss_family == AF_UNIX)
fd_is_journal = g_str_has_prefix (((struct sockaddr_un *)&addr)->sun_path, fd_is_journal = g_str_has_prefix (addr.un.sun_path, "/run/systemd/journal/");
"/run/systemd/journal/");
g_once_init_leave (&initialized, TRUE); g_once_init_leave (&initialized, TRUE);
} }