]> The Tcpdump Group git mirrors - libpcap/commitdiff
Check that values fit in findallif replies.
authorGuy Harris <[email protected]>
Thu, 3 Oct 2019 21:45:49 +0000 (14:45 -0700)
committerGuy Harris <[email protected]>
Thu, 3 Oct 2019 21:45:49 +0000 (14:45 -0700)
Fail if a name or description string's length doesn't fit in 16 bits, if
the count of interfaces doesn't fit in 16 bits, or if the entire reply
length doesn't fit in 32 bits.

rpcapd/daemon.c

index 7e5983947a30fd04905ad685619888c1dda2c207..4fa40e736b860b16b2dda30d8bab9b1207c731ee 100644 (file)
@@ -199,6 +199,17 @@ struct tls_alert {
 
 static int is_url(const char *source);
 
+/*
+ * Maximum sizes for fixed-bit-width values.
+ */
+#ifndef UINT16_MAX
+#define UINT16_MAX     65535U
+#endif
+
+#ifndef UINT32_MAX
+#define UINT32_MAX     4294967295U
+#endif
+
 int
 daemon_serviceloop(SOCKET sockctrl, int isactive, char *passiveClients,
     int nullAuthAllowed, int uses_ssl)
@@ -1560,6 +1571,18 @@ daemon_AuthUserPwd(char *username, char *password, char *errbuf)
 
 }
 
+/*
+ * Make sure that the reply length won't overflow 32 bits if we add the
+ * specified amount to it.  If it won't, add that amount to it.
+ */
+#define CHECK_AND_INCREASE_REPLY_LEN(itemlen) \
+       if (replylen + (itemlen) < replylen) { \
+               pcap_strlcpy(errmsgbuf, "Reply length doesn't fit in 32 bits", \
+                   sizeof (errmsgbuf)); \
+               goto error; \
+       } \
+       replylen += (uint32)itemlen;
+
 static int
 daemon_msg_findallif_req(uint8 ver, struct daemon_slpars *pars, uint32 plen)
 {
@@ -1606,13 +1629,30 @@ daemon_msg_findallif_req(uint8 ver, struct daemon_slpars *pars, uint32 plen)
        {
                nif++;
 
-               if (d->description)
-                       replylen += strlen(d->description);
-               if (d->name)
-                       replylen += strlen(d->name);
+               if (d->description) {
+                       size_t stringlen = strlen(d->description);
+                       if (stringlen > UINT16_MAX) {
+                               pcap_strlcpy(errmsgbuf,
+                                   "Description length doesn't fit in 16 bits",
+                                   sizeof (errmsgbuf));
+                               goto error;
+                       }
+                       CHECK_AND_INCREASE_REPLY_LEN(stringlen);
+               }
+               if (d->name) {
+                       size_t stringlen = strlen(d->name);
+                       if (stringlen > UINT16_MAX) {
+                               pcap_strlcpy(errmsgbuf,
+                                   "Name length doesn't fit in 16 bits",
+                                   sizeof (errmsgbuf));
+                               goto error;
+                       }
+                       CHECK_AND_INCREASE_REPLY_LEN(stringlen);
+               }
 
-               replylen += sizeof(struct rpcap_findalldevs_if);
+               CHECK_AND_INCREASE_REPLY_LEN(sizeof(struct rpcap_findalldevs_if));
 
+               uint16_t naddrs = 0;
                for (address = d->addresses; address != NULL; address = address->next)
                {
                        /*
@@ -1624,7 +1664,14 @@ daemon_msg_findallif_req(uint8 ver, struct daemon_slpars *pars, uint32 plen)
 #ifdef AF_INET6
                        case AF_INET6:
 #endif
-                               replylen += (sizeof(struct rpcap_sockaddr) * 4);
+                               CHECK_AND_INCREASE_REPLY_LEN(sizeof(struct rpcap_sockaddr) * 4);
+                               if (naddrs == UINT16_MAX) {
+                                       pcap_strlcpy(errmsgbuf,
+                                           "Number of interfaces doesn't fit in 16 bits",
+                                           sizeof (errmsgbuf));
+                                       goto error;
+                               }
+                               naddrs++;
                                break;
 
                        default:
@@ -1633,7 +1680,7 @@ daemon_msg_findallif_req(uint8 ver, struct daemon_slpars *pars, uint32 plen)
                }
        }
 
-       // RPCAP findalldevs command
+       // RPCAP findalldevs reply
        if (sock_bufferize(NULL, sizeof(struct rpcap_header), NULL,
            &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errmsgbuf,
            PCAP_ERRBUF_SIZE) == -1)
@@ -1655,10 +1702,18 @@ daemon_msg_findallif_req(uint8 ver, struct daemon_slpars *pars, uint32 plen)
 
                memset(findalldevs_if, 0, sizeof(struct rpcap_findalldevs_if));
 
-               if (d->description) ldescr = (short) strlen(d->description);
-               else ldescr = 0;
-               if (d->name) lname = (short) strlen(d->name);
-               else lname = 0;
+               /*
+                * We've already established that the string lengths
+                * fit in 16 bits.
+                */
+               if (d->description)
+                       ldescr = (uint16) strlen(d->description);
+               else
+                       ldescr = 0;
+               if (d->name)
+                       lname = (uint16) strlen(d->name);
+               else
+                       lname = 0;
 
                findalldevs_if->desclen = htons(ldescr);
                findalldevs_if->namelen = htons(lname);