aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/wayland-client.c22
-rw-r--r--src/wayland-private.h3
-rw-r--r--src/wayland-server.c23
-rw-r--r--src/wayland-util.h8
4 files changed, 56 insertions, 0 deletions
diff --git a/src/wayland-client.c b/src/wayland-client.c
index fe14a6b..c863304 100644
--- a/src/wayland-client.c
+++ b/src/wayland-client.c
@@ -1578,6 +1578,28 @@ queue_event(struct wl_display *display, int len)
id = p[0];
opcode = p[1] & 0xffff;
size = p[1] >> 16;
+
+ /*
+ * If the message is larger than the maximum size of the
+ * connection buffer, the connection buffer will fill to
+ * its max size and stay there, with no message ever
+ * successfully being processed. If the user of
+ * libwayland-client uses a level-triggered event loop,
+ * this will cause the client to enter a loop that
+ * consumes CPU. To avoid this, immediately drop the
+ * connection. Since the maximum size of a message should
+ * not depend on the max buffer size chosen by the client,
+ * always compare the message size against the
+ * limit enforced by libwayland 1.22 and below (4096),
+ * rather than the actual value the client chose.
+ */
+ if (size > WL_MAX_MESSAGE_SIZE) {
+ wl_log("Message length %u exceeds limit %d\n",
+ size, WL_MAX_MESSAGE_SIZE);
+ errno = E2BIG;
+ return -1;
+ }
+
if (len < size)
return 0;
diff --git a/src/wayland-private.h b/src/wayland-private.h
index 9aace67..d7ba9da 100644
--- a/src/wayland-private.h
+++ b/src/wayland-private.h
@@ -49,6 +49,9 @@
#define WL_CLOSURE_MAX_ARGS 20
#define WL_BUFFER_DEFAULT_SIZE_POT 12
#define WL_BUFFER_DEFAULT_MAX_SIZE (1 << WL_BUFFER_DEFAULT_SIZE_POT)
+#if WL_BUFFER_DEFAULT_MAX_SIZE < WL_MAX_MESSAGE_SIZE
+# error default buffer cannot hold maximum-sized message
+#endif
#define WL_DEBUG_COLOR_RESET "\e[0m"
#define WL_DEBUG_COLOR_RED "\e[31m"
diff --git a/src/wayland-server.c b/src/wayland-server.c
index 1566764..482743b 100644
--- a/src/wayland-server.c
+++ b/src/wayland-server.c
@@ -398,6 +398,29 @@ wl_client_connection_data(int fd, uint32_t mask, void *data)
wl_connection_copy(connection, p, sizeof p);
opcode = p[1] & 0xffff;
size = p[1] >> 16;
+
+ /*
+ * If the message is larger than the maximum size of the
+ * connection buffer, the connection buffer will fill to
+ * its max size and stay there, with no message ever
+ * successfully being processed. Since libwayland-server
+ * uses level-triggered epoll, it will cause the server to
+ * enter a loop that consumes CPU. To avoid this,
+ * immediately disconnect the client with a protocol
+ * error. Since the maximum size of a message should not
+ * depend on the buffer size chosen by the compositor,
+ * always compare the message size against the
+ * limit enforced by libwayland 1.22 and below (4096),
+ * rather than the actual value the compositor chose.
+ */
+ if (size > WL_MAX_MESSAGE_SIZE) {
+ wl_resource_post_error(client->display_resource,
+ WL_DISPLAY_ERROR_INVALID_METHOD,
+ "message length %u exceeds %d",
+ size, WL_MAX_MESSAGE_SIZE);
+ break;
+ }
+
if (len < size)
break;
diff --git a/src/wayland-util.h b/src/wayland-util.h
index 4540f04..98c72fd 100644
--- a/src/wayland-util.h
+++ b/src/wayland-util.h
@@ -91,6 +91,14 @@ extern "C" {
struct wl_object;
/**
+ * The maximum size of a protocol message.
+ *
+ * If a message size exceeds this value, the connection will be dropped.
+ * Servers will send an invalid_method error before disconnecting.
+ */
+#define WL_MAX_MESSAGE_SIZE 4096
+
+/**
* Protocol message signature
*
* A wl_message describes the signature of an actual protocol message, such as a