[libsoup/websockets-fixes-2.66: 9/19] WebSockets: server must close the connection when receiving an unmasked frame




commit 4e7b45a512d3374212ac8238de01928a568d1427
Author: Carlos Garcia Campos <cgarcia igalia com>
Date:   Thu Jul 4 10:13:57 2019 +0200

    WebSockets: server must close the connection when receiving an unmasked frame
    
    RFC 6455:
    
    The server MUST close the connection upon receiving a
    frame that is not masked.

 libsoup/soup-websocket-connection.c |  9 +++++++
 tests/websocket-test.c              | 49 ++++++++++++++++++++++++++++++++++---
 2 files changed, 55 insertions(+), 3 deletions(-)
---
diff --git a/libsoup/soup-websocket-connection.c b/libsoup/soup-websocket-connection.c
index a41f05cd..03647413 100644
--- a/libsoup/soup-websocket-connection.c
+++ b/libsoup/soup-websocket-connection.c
@@ -921,6 +921,15 @@ process_frame (SoupWebsocketConnection *self)
                return FALSE;
        }
 
+       if (self->pv->connection_type == SOUP_WEBSOCKET_CONNECTION_SERVER && !masked) {
+               /* The server MUST close the connection upon receiving a frame
+                * that is not masked.
+                */
+               g_debug ("The client should always mask frames");
+               protocol_error_and_close (self);
+                return FALSE;
+        }
+
        /* We do not support extensions, reserved bits must be 0 */
        if (header[0] & 0x70) {
                protocol_error_and_close (self);
diff --git a/tests/websocket-test.c b/tests/websocket-test.c
index 59cbba39..890f358c 100644
--- a/tests/websocket-test.c
+++ b/tests/websocket-test.c
@@ -507,11 +507,11 @@ test_send_bad_data (Test *test,
        io = soup_websocket_connection_get_io_stream (test->client);
 
        /* Bad UTF-8 frame */
-       frame = "\x81\x04\xEE\xEE\xEE\xEE";
+       frame = "\x81\x84\x00\x00\x00\x00\xEE\xEE\xEE\xEE";
        if (!g_output_stream_write_all (g_io_stream_get_output_stream (io),
-                                       frame, 6, &written, NULL, NULL))
+                                       frame, 10, &written, NULL, NULL))
                g_assert_not_reached ();
-       g_assert_cmpuint (written, ==, 6);
+       g_assert_cmpuint (written, ==, 10);
 
        WAIT_UNTIL (error != NULL);
        g_assert_error (error, SOUP_WEBSOCKET_ERROR, SOUP_WEBSOCKET_CLOSE_BAD_DATA);
@@ -1027,6 +1027,40 @@ test_client_receive_masked_frame (Test *test,
        WAIT_UNTIL (soup_websocket_connection_get_state (test->client) == SOUP_WEBSOCKET_STATE_CLOSED);
 }
 
+static void
+test_server_receive_unmasked_frame (Test *test,
+                                   gconstpointer data)
+{
+       GError *error = NULL;
+       GIOStream *io;
+       gsize written;
+       const char *frame;
+       gboolean close_event = FALSE;
+
+       g_signal_handlers_disconnect_by_func (test->server, on_error_not_reached, NULL);
+       g_signal_connect (test->server, "error", G_CALLBACK (on_error_copy), &error);
+       g_signal_connect (test->client, "closed", G_CALLBACK (on_close_set_flag), &close_event);
+
+       io = soup_websocket_connection_get_io_stream (test->client);
+
+       /* Unmasked frame */
+       frame = "\x81\x0bHello World";
+       if (!g_output_stream_write_all (g_io_stream_get_output_stream (io),
+                                       frame, 13, &written, NULL, NULL))
+               g_assert_not_reached ();
+       g_assert_cmpuint (written, ==, 13);
+
+       WAIT_UNTIL (error != NULL);
+       g_assert_error (error, SOUP_WEBSOCKET_ERROR, SOUP_WEBSOCKET_CLOSE_PROTOCOL_ERROR);
+       g_clear_error (&error);
+
+       WAIT_UNTIL (soup_websocket_connection_get_state (test->client) == SOUP_WEBSOCKET_STATE_CLOSED);
+       g_assert (close_event);
+
+       g_assert_cmpuint (soup_websocket_connection_get_close_code (test->client), ==, 
SOUP_WEBSOCKET_CLOSE_PROTOCOL_ERROR);
+
+}
+
 static void
 test_client_context_got_server_connection (SoupServer              *server,
                                           SoupWebsocketConnection *connection,
@@ -1214,6 +1248,15 @@ main (int argc,
                    test_client_receive_masked_frame,
                    teardown_direct_connection);
 
+       g_test_add ("/websocket/direct/server-receive-unmasked-frame", Test, NULL,
+                   setup_direct_connection,
+                   test_server_receive_unmasked_frame,
+                   teardown_direct_connection);
+       g_test_add ("/websocket/soup/server-receive-unmasked-frame", Test, NULL,
+                   setup_soup_connection,
+                   test_server_receive_unmasked_frame,
+                   teardown_soup_connection);
+
        if (g_test_slow ()) {
                g_test_add ("/websocket/direct/close-after-timeout", Test, NULL,
                            setup_half_direct_connection,


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