pex: move rx header check to callback function
authorFelix Fietkau <nbd@nbd.name>
Thu, 15 Sep 2022 19:18:42 +0000 (21:18 +0200)
committerFelix Fietkau <nbd@nbd.name>
Fri, 16 Sep 2022 16:55:17 +0000 (18:55 +0200)
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 <nbd@nbd.name>
cli.c
pex-msg.c
pex-msg.h
pex.c

diff --git a/cli.c b/cli.c
index 34050ff45d177d088f4154981805772bafb17b8a..24a06b31bbfee228187403958f8e75bc9f920050 100644 (file)
--- 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 &&
index 4f0b19538ffd7c7e61837cbcf1aff16243669126..f6cbd71179e6e0a8b0c8155010c0e0e69e7927ff 100644 (file)
--- 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)
 {
index e8e4f11e48d6970641787c3f6cfc65d1ec022269..c777a6adf0021951079c73107aa0ec736a10e1a5 100644 (file)
--- 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 7a76cf7e4f76f842a541aee270099ffaadd99627..1f831a0e1da3bc27e71e406045f5d41588b4b762 100644 (file)
--- 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;