From 629a625422615ca38732452b2a54fd59882789d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Fri, 10 Jan 2020 19:27:17 +0100 Subject: [PATCH] server: be more resilient against bad behaving clients Make both the server listening socket and the connecting client sockets non-blocking. Then, when reading the initial length of the setup packet, handle read errors from partial reads separately. Assume the client writes all four bytes of the 'length' field at once, and bail out if we are unable to read those 4 bytes. Limit the maximum setup packet size to 128K. This is to prevent clients from pretending the setup packet is insanely large, causing us to fail to malloc. --- server.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/server.c b/server.c index 6542be68..92f326a0 100644 --- a/server.c +++ b/server.c @@ -124,11 +124,24 @@ fdm_client(struct fdm *fdm, int fd, int events, void *data) * data. */ uint32_t total_len; - if (recv(fd, &total_len, sizeof(total_len), 0) != sizeof(total_len)) { + ssize_t count = recv(fd, &total_len, sizeof(total_len), 0); + if (count < 0) { LOG_ERRNO("failed to read total length"); goto shutdown; } + if (count != sizeof(total_len)) { + LOG_ERR("client did not send setup packet size"); + goto shutdown; + } + + const uint32_t max_size = 128 * 1024; + if (total_len > max_size) { + LOG_ERR("client wants to send too large setup packet (%u > %u)", + total_len, max_size); + goto shutdown; + } + LOG_DBG("total len: %u", total_len); client->buffer.data = malloc(total_len + 1); client->buffer.left = total_len; @@ -262,7 +275,7 @@ fdm_server(struct fdm *fdm, int fd, int events, void *data) struct sockaddr_un addr; socklen_t addr_size = sizeof(addr); int client_fd = accept4( - server->fd, (struct sockaddr *)&addr, &addr_size, SOCK_CLOEXEC); + server->fd, (struct sockaddr *)&addr, &addr_size, SOCK_CLOEXEC | SOCK_NONBLOCK); if (client_fd == -1) { LOG_ERRNO("failed to accept client connection"); @@ -322,7 +335,7 @@ err: struct server * server_init(const struct config *conf, struct fdm *fdm, struct wayland *wayl) { - int fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); + int fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0); if (fd == -1) { LOG_ERRNO("failed to create UNIX socket"); return NULL;