From 543e4a3d2ed7c227c69b223116f7ba8c5b126cfe Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 15 Sep 2022 21:18:42 +0200 Subject: [PATCH] pex: move rx header check to callback function Fixes some length check bugs in the cli code and allows other protocols to be used on the global PEX port. Signed-off-by: Felix Fietkau --- cli.c | 22 +++++++++++++++------- pex-msg.c | 32 +++++++++++++++++++++++--------- pex-msg.h | 4 +++- pex.c | 21 +++++++++++++-------- 4 files changed, 54 insertions(+), 25 deletions(-) diff --git a/cli.c b/cli.c index 34050ff..24a06b3 100644 --- a/cli.c +++ b/cli.c @@ -165,12 +165,20 @@ pex_handle_update_request(struct sockaddr_in6 *addr, const uint8_t *id, void *da uloop_end(); } -static void pex_recv(struct pex_hdr *hdr, struct sockaddr_in6 *addr) +static void pex_recv(void *msg, size_t msg_len, struct sockaddr_in6 *addr) { - struct pex_ext_hdr *ehdr = (void *)(hdr + 1); - void *data = (void *)(ehdr + 1); - uint32_t len = be32_to_cpu(hdr->len); - uint64_t *msg_req_id = data; + struct pex_hdr *hdr; + struct pex_ext_hdr *ehdr; + uint64_t *msg_req_id; + void *data; + + hdr = pex_rx_accept(msg, msg_len, true); + if (!hdr) + return; + + ehdr = (void *)(hdr + 1); + data = (void *)(ehdr + 1); + msg_req_id = data; if (hdr->version != 0) return; @@ -185,12 +193,12 @@ static void pex_recv(struct pex_hdr *hdr, struct sockaddr_in6 *addr) if (cmd != CMD_UPLOAD) break; - pex_handle_update_request(addr, hdr->id, data, len); + pex_handle_update_request(addr, hdr->id, data, hdr->len); break; case PEX_MSG_UPDATE_RESPONSE: case PEX_MSG_UPDATE_RESPONSE_DATA: case PEX_MSG_UPDATE_RESPONSE_NO_DATA: - if (len < sizeof(*msg_req_id) || *msg_req_id != req_id) + if (hdr->len < sizeof(*msg_req_id) || *msg_req_id != req_id) break; if (cmd == CMD_DOWNLOAD && diff --git a/pex-msg.c b/pex-msg.c index 4f0b195..f6cbd71 100644 --- a/pex-msg.c +++ b/pex-msg.c @@ -137,7 +137,6 @@ pex_fd_cb(struct uloop_fd *fd, unsigned int events) { static struct sockaddr_in6 sin6; static char buf[PEX_RX_BUF_SIZE]; - struct pex_hdr *hdr = (struct pex_hdr *)buf; ssize_t len; while (1) { @@ -199,14 +198,7 @@ retry: } } - if (len < sizeof(*hdr) + sizeof(struct pex_ext_hdr)) - continue; - - hdr->len = ntohs(hdr->len); - if (len - sizeof(hdr) - sizeof(struct pex_ext_hdr) < hdr->len) - continue; - - pex_recv_cb(hdr, &sin6); + pex_recv_cb(buf, len, &sin6); } } @@ -666,6 +658,28 @@ error: return NULL; } +struct pex_hdr *pex_rx_accept(void *data, size_t len, bool ext) +{ + struct pex_hdr *hdr = data; + uint16_t hdr_len; + size_t min_size; + + min_size = sizeof(*hdr); + if (ext) + min_size += sizeof(struct pex_ext_hdr); + + if (len < min_size) + return NULL; + + hdr_len = ntohs(hdr->len); + if (len < min_size + hdr_len) + return NULL; + + hdr->len = hdr_len; + + return hdr; +} + static void pex_gc_cb(struct uloop_timeout *t) { diff --git a/pex-msg.h b/pex-msg.h index e8e4f11..c777a6a 100644 --- a/pex-msg.h +++ b/pex-msg.h @@ -94,7 +94,9 @@ struct pex_msg_local_control { int timeout; }; -typedef void (*pex_recv_cb_t)(struct pex_hdr *hdr, struct sockaddr_in6 *addr); +struct pex_hdr *pex_rx_accept(void *data, size_t len, bool ext); + +typedef void (*pex_recv_cb_t)(void *data, size_t len, struct sockaddr_in6 *addr); typedef void (*pex_recv_control_cb_t)(struct pex_msg_local_control *msg, int len); int pex_open(void *addr, size_t addr_len, pex_recv_cb_t cb, bool server); diff --git a/pex.c b/pex.c index 7a76cf7..1f831a0 100644 --- a/pex.c +++ b/pex.c @@ -652,11 +652,8 @@ network_pex_fd_cb(struct uloop_fd *fd, unsigned int events) if (!len) continue; - if (len < sizeof(*hdr)) - continue; - - hdr->len = ntohs(hdr->len); - if (len - sizeof(hdr) < hdr->len) + hdr = pex_rx_accept(buf, len, false); + if (!hdr) continue; peer = pex_msg_peer(net, hdr->id); @@ -856,15 +853,23 @@ global_pex_set_active(struct network *net, struct sockaddr_in6 *addr) } static void -global_pex_recv(struct pex_hdr *hdr, struct sockaddr_in6 *addr) +global_pex_recv(void *msg, size_t msg_len, struct sockaddr_in6 *addr) { - struct pex_ext_hdr *ehdr = (void *)(hdr + 1); + struct pex_hdr *hdr; + struct pex_ext_hdr *ehdr; struct network_peer *peer; struct network *net; - void *data = (void *)(ehdr + 1); char buf[INET6_ADDRSTRLEN]; + void *data; int addr_len; + hdr = pex_rx_accept(msg, msg_len, true); + if (!hdr) + return; + + ehdr = (void *)(hdr + 1); + data = (void *)(ehdr + 1); + if (hdr->version != 0) return; -- 2.30.2