From 56b3d9cd2d85ee8c6d0c3d012ae9b3f6ae1b3d25 Mon Sep 17 00:00:00 2001 From: Thomas Gschwantner Date: Tue, 8 Oct 2019 23:59:41 +0200 Subject: Fix parsing issue with split messages Previously this would trigger a BUG_ON() since the calculation of length & offset was wrong since we added the previous part of the buffer (req->buf) in parse_request(). This meant handle_request() couldn't know how much bytes where actually left in the buffer or their offset. --- common.c | 33 +++++++++++++++++---------------- wg-dynamic-client.c | 2 +- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/common.c b/common.c index 5dc229b..44c5562 100644 --- a/common.c +++ b/common.c @@ -207,7 +207,6 @@ static ssize_t parse_request(struct wg_dynamic_request *req, unsigned char *buf, size_t len) { ssize_t ret, offset = 0; - size_t addlen = 0; enum wg_dynamic_key key; union kvalues kv; void (*deserialize)(enum wg_dynamic_key key, union kvalues kv, @@ -216,17 +215,6 @@ static ssize_t parse_request(struct wg_dynamic_request *req, unsigned char *buf, if (memchr(buf, '\0', len)) return -EINVAL; /* don't allow null bytes */ - if (req->len > 0 && req->buf) { - len += req->len; - - memmove(buf + req->len, buf, len); - memcpy(buf, req->buf, req->len); - addlen = req->len; - free(req->buf); - req->buf = NULL; - req->len = 0; - } - if (req->cmd == WGKEY_UNKNOWN) { ret = parse_line(buf, len, req, &req->cmd, &kv); if (ret <= 0) @@ -255,7 +243,7 @@ static ssize_t parse_request(struct wg_dynamic_request *req, unsigned char *buf, offset += ret; if (key == WGKEY_EOMSG) - return offset - addlen; + return offset; else if (key == WGKEY_UNKNOWN) continue; else if (key <= WGKEY_ENDCMD) @@ -272,12 +260,16 @@ ssize_t handle_request(int fd, struct wg_dynamic_request *req, size_t *remaining) { ssize_t bytes, processed; + size_t leftover; + + BUG_ON((*remaining > 0 && req->buf) || (req->buf && !req->len)); do { + leftover = req->len; if (*remaining > 0) bytes = *remaining; else - bytes = read(fd, buf, RECV_BUFSIZE); + bytes = read(fd, buf + leftover, RECV_BUFSIZE); if (bytes < 0) { if (errno == EWOULDBLOCK || errno == EAGAIN || @@ -291,12 +283,21 @@ ssize_t handle_request(int fd, struct wg_dynamic_request *req, return -1; } - processed = parse_request(req, buf, bytes); + if (req->buf) { + memcpy(buf, req->buf, leftover); + free(req->buf); + req->buf = NULL; + req->len = 0; + } + + processed = parse_request(req, buf, bytes + leftover); if (processed < 0) return processed; /* Parsing error */ + if (!processed) + *remaining = 0; } while (processed == 0); - *remaining = bytes - processed; + *remaining = (bytes + leftover) - processed; memmove(buf, buf + processed, *remaining); return 1; diff --git a/wg-dynamic-client.c b/wg-dynamic-client.c index e425a27..2edb413 100644 --- a/wg-dynamic-client.c +++ b/wg-dynamic-client.c @@ -68,7 +68,7 @@ static void check_signal() static int request_ip(struct wg_dynamic_request_ip *rip) { unsigned char buf[RECV_BUFSIZE + MAX_LINESIZE]; - size_t msglen, remaining, off = 0; + size_t msglen, remaining = 0, off = 0; struct sockaddr_in6 dstaddr = { .sin6_family = AF_INET6, .sin6_addr = well_known, -- cgit v1.2.3-59-g8ed1b