From 937be61ea987137b39fba9c97f2af82214f25db1 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Thu, 16 Oct 2014 16:43:31 +0100 Subject: [PATCH 5/8] Add a test-case for dbus-daemon kicking the sender of a corrupt message --- test/dbus-daemon.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/test/dbus-daemon.c b/test/dbus-daemon.c index 4b3b61e..4d55858 100644 --- a/test/dbus-daemon.c +++ b/test/dbus-daemon.c @@ -27,6 +27,7 @@ #include #include +#include #include @@ -332,6 +333,89 @@ test_echo (Fixture *f, count, elapsed); } +/* Enough bytes for it to be obvious that this connection is broken */ +#define CORRUPT_LEN 1024 + +/* All-zero is not a valid D-Bus message header - for a start, this is + * protocol version 1, not 0 */ +static const gchar not_a_dbus_message[CORRUPT_LEN] = { 0 }; + +static void +send_n_bytes (GSocket *socket, + const gchar *blob, + gssize blob_len) +{ + gssize len, total_sent; + GError *gerror = NULL; + + total_sent = 0; + + while (total_sent < blob_len) + { + len = g_socket_send (socket, + blob + total_sent, + blob_len - total_sent, + NULL, &gerror); + + /* this is NULL-safe: a NULL error does not match */ + if (g_error_matches (gerror, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) + { + /* we could wait for G_IO_OUT, but life's too short; just sleep */ + g_clear_error (&gerror); + g_usleep (G_USEC_PER_SEC / 10); + continue; + } + + g_assert_no_error (gerror); + g_assert (len >= 0); + total_sent += len; + } +} + +static void +test_corrupt (Fixture *f, + gconstpointer addr) +{ + GSocket *socket; + GError *gerror = NULL; + int fd; + + test_echo (f, NULL); + + dbus_connection_flush (f->left_conn); + + /* OK, now the connection is working, let's break it! Don't try this + * at home; splicing arbitrary bytes into the middle of the stream is + * specifically documented as not a valid thing to do. Who'd have thought? */ + if (!dbus_connection_get_socket (f->left_conn, &fd)) + g_error ("failed to steal fd from left connection"); + + socket = g_socket_new_from_fd (fd, &gerror); + g_assert_no_error (gerror); + g_assert (socket != NULL); + + send_n_bytes (socket, not_a_dbus_message, CORRUPT_LEN); + + /* Now spin on the client connection: the server just sent it complete + * rubbish, so it should disconnect */ + while (dbus_connection_get_is_connected (f->left_conn)) + { + g_print ("."); + test_main_context_iterate (f->ctx, TRUE); + } + + /* Free the DBusConnection before the GSocket, because GSocket is + * going to close our fd. GSocket tolerates closing an already-closed + * fd, whereas DBusLoop + DBusSocketSetEpoll doesn't. On Unix + * we could use dup() but that isn't portable to Windows :-( + */ + dbus_connection_close (f->left_conn); + dbus_connection_unref (f->left_conn); + f->left_conn = NULL; + + g_object_unref (socket); +} + static void pending_call_store_reply (DBusPendingCall *pc, void *data) @@ -514,6 +598,7 @@ main (int argc, g_test_add ("/echo/limited", Fixture, &limited_config, setup, test_echo, teardown); g_test_add ("/creds", Fixture, NULL, setup, test_creds, teardown); + g_test_add ("/corrupt", Fixture, NULL, setup, test_corrupt, teardown); return g_test_run (); } -- 2.1.1