[glib: 1/2] gsocket: Fix credentials error-handling on Apple OSes
- From: Philip Withnall <pwithnall src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib: 1/2] gsocket: Fix credentials error-handling on Apple OSes
- Date: Mon, 4 Jan 2021 12:45:28 +0000 (UTC)
commit 9ac3a27f0360feb6eba78ba64270e1db827eb26d
Author: Ole André Vadla Ravnås <oleavr gmail com>
Date: Tue Dec 29 21:41:34 2020 +0100
gsocket: Fix credentials error-handling on Apple OSes
- When querying a TCP socket, getsockopt() may succeed but the resulting
`optlen` will be zero. This means we'd previously be reading
uninitialized stack memory in such cases.
- After a file-descriptor has gone through FD-passing, getsockopt() may
fail with EINVAL. At least this is the case with TCP sockets.
- While at it also use SOL_LOCAL instead of hard-coding its value.
gio/gsocket.c | 14 +++-
gio/tests/socket.c | 218 +++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 230 insertions(+), 2 deletions(-)
---
diff --git a/gio/gsocket.c b/gio/gsocket.c
index e911de781..5d8ecfb9c 100644
--- a/gio/gsocket.c
+++ b/gio/gsocket.c
@@ -5965,10 +5965,11 @@ g_socket_get_credentials (GSocket *socket,
socklen_t optlen = sizeof (cred);
if (getsockopt (socket->priv->fd,
- 0,
+ SOL_LOCAL,
LOCAL_PEERCRED,
&cred,
- &optlen) == 0)
+ &optlen) == 0
+ && optlen != 0)
{
if (cred.cr_version == XUCRED_VERSION)
{
@@ -5993,6 +5994,15 @@ g_socket_get_credentials (GSocket *socket,
return NULL;
}
}
+ else if (optlen == 0 || errno == EINVAL)
+ {
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ _("Unable to read socket credentials: %s"),
+ "unsupported socket type");
+ return NULL;
+ }
}
#elif G_CREDENTIALS_USE_NETBSD_UNPCBID
{
diff --git a/gio/tests/socket.c b/gio/tests/socket.c
index d6eecdc38..683866ede 100644
--- a/gio/tests/socket.c
+++ b/gio/tests/socket.c
@@ -18,6 +18,7 @@
#include <gio/gio.h>
+#include <gio/gcredentialsprivate.h>
#ifdef G_OS_UNIX
#include <errno.h>
#include <sys/wait.h>
@@ -1898,6 +1899,216 @@ test_read_write (gconstpointer user_data)
g_object_unref (client);
}
+#if G_CREDENTIALS_SUPPORTED
+static gpointer client_setup_thread (gpointer user_data);
+
+static void
+test_credentials_tcp_client (void)
+{
+ const GSocketFamily family = G_SOCKET_FAMILY_IPV4;
+ IPTestData *data;
+ GError *error = NULL;
+ GSocket *client;
+ GSocketAddress *addr;
+ GCredentials *creds;
+
+ data = create_server (family, echo_server_thread, FALSE, &error);
+ if (error != NULL)
+ {
+ gchar *message = g_strdup_printf ("Failed to create server: %s", error->message);
+ g_test_skip (message);
+ g_free (message);
+ g_clear_error (&error);
+ return;
+ }
+
+ addr = g_socket_get_local_address (data->server, &error);
+ g_assert_no_error (error);
+
+ client = g_socket_new (family,
+ G_SOCKET_TYPE_STREAM,
+ G_SOCKET_PROTOCOL_DEFAULT,
+ &error);
+ g_assert_no_error (error);
+
+ g_socket_set_blocking (client, TRUE);
+ g_socket_set_timeout (client, 1);
+
+ g_socket_connect (client, addr, NULL, &error);
+ g_assert_no_error (error);
+ g_object_unref (addr);
+
+ creds = g_socket_get_credentials (client, &error);
+ if (creds != NULL)
+ {
+ gchar *str = g_credentials_to_string (creds);
+ g_print ("Supported on this OS: %s\n", str);
+ g_free (str);
+ g_clear_object (&creds);
+ }
+ else
+ {
+ g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
+ g_print ("Unsupported on this OS: %s\n", error->message);
+ g_clear_error (&error);
+ }
+
+ g_socket_close (client, &error);
+ g_assert_no_error (error);
+
+ g_thread_join (data->thread);
+
+ g_socket_close (data->server, &error);
+ g_assert_no_error (error);
+
+ g_object_unref (data->server);
+ g_object_unref (client);
+
+ g_slice_free (IPTestData, data);
+}
+
+static void
+test_credentials_tcp_server (void)
+{
+ const GSocketFamily family = G_SOCKET_FAMILY_IPV4;
+ IPTestData *data;
+ GSocket *server;
+ GError *error = NULL;
+ GSocketAddress *addr = NULL;
+ GInetAddress *iaddr = NULL;
+ GSocket *sock = NULL;
+ GCredentials *creds;
+
+ data = g_slice_new0 (IPTestData);
+ data->family = family;
+ data->server = server = g_socket_new (family,
+ G_SOCKET_TYPE_STREAM,
+ G_SOCKET_PROTOCOL_DEFAULT,
+ &error);
+ if (error != NULL)
+ goto skip;
+
+ g_socket_set_blocking (server, TRUE);
+
+ iaddr = g_inet_address_new_loopback (family);
+ addr = g_inet_socket_address_new (iaddr, 0);
+
+ if (!g_socket_bind (server, addr, TRUE, &error))
+ goto skip;
+
+ if (!g_socket_listen (server, &error))
+ goto skip;
+
+ data->thread = g_thread_new ("client", client_setup_thread, data);
+
+ sock = g_socket_accept (server, NULL, &error);
+ g_assert_no_error (error);
+
+ creds = g_socket_get_credentials (sock, &error);
+ if (creds != NULL)
+ {
+ gchar *str = g_credentials_to_string (creds);
+ g_print ("Supported on this OS: %s\n", str);
+ g_free (str);
+ g_clear_object (&creds);
+ }
+ else
+ {
+ g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
+ g_print ("Unsupported on this OS: %s\n", error->message);
+ g_clear_error (&error);
+ }
+
+ goto beach;
+
+skip:
+ {
+ gchar *message = g_strdup_printf ("Failed to create server: %s", error->message);
+ g_test_skip (message);
+ g_free (message);
+
+ goto beach;
+ }
+beach:
+ {
+ g_clear_error (&error);
+
+ g_clear_object (&sock);
+ g_clear_object (&addr);
+ g_clear_object (&iaddr);
+
+ g_clear_pointer (&data->thread, g_thread_join);
+ g_clear_object (&data->server);
+ g_clear_object (&data->client);
+
+ g_slice_free (IPTestData, data);
+ }
+}
+
+static gpointer
+client_setup_thread (gpointer user_data)
+{
+ IPTestData *data = user_data;
+ GSocketAddress *addr;
+ GSocket *client;
+ GError *error = NULL;
+
+ addr = g_socket_get_local_address (data->server, &error);
+ g_assert_no_error (error);
+
+ data->client = client = g_socket_new (data->family,
+ G_SOCKET_TYPE_STREAM,
+ G_SOCKET_PROTOCOL_DEFAULT,
+ &error);
+ g_assert_no_error (error);
+
+ g_socket_set_blocking (client, TRUE);
+ g_socket_set_timeout (client, 1);
+
+ g_socket_connect (client, addr, NULL, &error);
+ g_assert_no_error (error);
+
+ g_object_unref (addr);
+
+ return NULL;
+}
+
+#ifdef G_OS_UNIX
+static void
+test_credentials_unix_socketpair (void)
+{
+ gint fds[2];
+ gint status;
+ GSocket *sock;
+ GError *error = NULL;
+ GCredentials *creds;
+
+ status = socketpair (PF_UNIX, SOCK_STREAM, 0, fds);
+ g_assert_cmpint (status, ==, 0);
+
+ sock = g_socket_new_from_fd (fds[0], &error);
+
+ creds = g_socket_get_credentials (sock, &error);
+ if (creds != NULL)
+ {
+ gchar *str = g_credentials_to_string (creds);
+ g_print ("Supported on this OS: %s\n", str);
+ g_free (str);
+ g_clear_object (&creds);
+ }
+ else
+ {
+ g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
+ g_print ("Unsupported on this OS: %s\n", error->message);
+ g_clear_error (&error);
+ }
+
+ g_object_unref (sock);
+ close (fds[1]);
+}
+#endif
+#endif
+
int
main (int argc,
char *argv[])
@@ -1954,6 +2165,13 @@ main (int argc,
test_read_write);
g_test_add_data_func ("/socket/read_writev", GUINT_TO_POINTER (TRUE),
test_read_write);
+#if G_CREDENTIALS_SUPPORTED
+ g_test_add_func ("/socket/credentials/tcp_client", test_credentials_tcp_client);
+ g_test_add_func ("/socket/credentials/tcp_server", test_credentials_tcp_server);
+#ifdef G_OS_UNIX
+ g_test_add_func ("/socket/credentials/unix_socketpair", test_credentials_unix_socketpair);
+#endif
+#endif
return g_test_run();
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]