]> git.proxmox.com Git - mirror_frr.git/commitdiff
pimd: Various buffer overflow reads and crashes
authorDonald Sharp <sharpd@cumulusnetworks.com>
Wed, 20 Nov 2019 00:36:19 +0000 (19:36 -0500)
committerDonald Sharp <sharpd@cumulusnetworks.com>
Wed, 20 Nov 2019 01:30:24 +0000 (20:30 -0500)
A variety of buffer overflow reads and crashes
that could occur if you fed bad info into pim.

1) When type is setup incorrectly we were printing the first 8 bytes
of the pim_parse_addr_source, but the min encoding length is
4 bytes.  As such we will read beyond end of buffer.

2) The RP(pim, grp) macro can return a NULL value
Do not automatically assume that we can deref
the data.

3) BSM parsing was not properly sanitizing data input from wire
and we could enter into situations where we would read beyond
the end of the buffer.  Prevent this from happening, we are
probably left in a bad way.

4) The received bit length cannot be greater than 32 bits,
refuse to allow it to happen.

Signed-off-by: Donald Sharp <sharpd@cumulusnetworks.com>
pimd/pim_bsm.c
pimd/pim_join.c
pimd/pim_rp.c
pimd/pim_tlv.c

index 1383e3db116e41933e46b47f1b65c95917ae7d2f..65d602958514e86a1de90ba1bb5c27fd13a2bc87 100644 (file)
@@ -1111,6 +1111,13 @@ static bool pim_bsm_parse_install_g2rp(struct bsm_scope *scope, uint8_t *buf,
        int ins_count = 0;
 
        while (buflen > offset) {
+               if (offset + (int)sizeof(struct bsmmsg_grpinfo) > buflen) {
+                       if (PIM_DEBUG_BSM)
+                               zlog_debug(
+                                       "%s: buflen received %d is less than the internal data structure of the packet would suggest",
+                                       __PRETTY_FUNCTION__, buflen);
+                       return false;
+               }
                /* Extract Group tlv from BSM */
                memcpy(&grpinfo, buf, sizeof(struct bsmmsg_grpinfo));
 
@@ -1142,6 +1149,12 @@ static bool pim_bsm_parse_install_g2rp(struct bsm_scope *scope, uint8_t *buf,
                }
 
                group.family = AF_INET;
+               if (grpinfo.group.mask > IPV4_MAX_BITLEN) {
+                       if (PIM_DEBUG_BSM)
+                               zlog_debug("%s, v4 prefix length specified: %d is too long",
+                                          __PRETTY_FUNCTION__, grpinfo.group.mask);
+                       return false;
+               }
                group.prefixlen = grpinfo.group.mask;
                group.u.prefix4.s_addr = grpinfo.group.addr.s_addr;
 
@@ -1174,6 +1187,15 @@ static bool pim_bsm_parse_install_g2rp(struct bsm_scope *scope, uint8_t *buf,
                ins_count = 0;
 
                while (frag_rp_cnt--) {
+                       if (offset + (int)sizeof(struct bsmmsg_rpinfo)
+                           > buflen) {
+                               if (PIM_DEBUG_BSM)
+                                       zlog_debug(
+                                               "%s, buflen received: %u is less than the internal data structure of the packet would suggest",
+                                               __PRETTY_FUNCTION__, buflen);
+                               return false;
+                       }
+
                        /* Extract RP address tlv from BSM */
                        memcpy(&rpinfo, buf, sizeof(struct bsmmsg_rpinfo));
                        rpinfo.rp_holdtime = ntohs(rpinfo.rp_holdtime);
@@ -1245,6 +1267,13 @@ int pim_bsm_process(struct interface *ifp, struct ip *ip_hdr, uint8_t *buf,
                return -1;
        }
 
+       if (buf_size < sizeof(struct bsm_hdr)) {
+               if (PIM_DEBUG_BSM)
+                       zlog_debug("%s: received buffer length of %d which is too small to properly decode",
+                                  __PRETTY_FUNCTION__, buf_size);
+               return -1;
+       }
+
        bshdr = (struct bsm_hdr *)(buf + PIM_MSG_HEADER_LEN);
        pim_inet4_dump("<bsr?>", bshdr->bsr_addr.addr, bsr_str,
                       sizeof(bsr_str));
index 842d6684b53caba438ac34a715da3ce9aed7ea8b..89be42842ee32f1e5c23b046f2a5ea6fd6e1d0c9 100644 (file)
@@ -83,6 +83,11 @@ static void recv_join(struct interface *ifp, struct pim_neighbor *neigh,
            && (source_flags & PIM_WILDCARD_BIT_MASK)) {
                struct pim_rpf *rp = RP(pim_ifp->pim, sg->grp);
 
+               if (!rp) {
+                       zlog_warn("%s: Lookup of RP failed for %pSG4",
+                                 __PRETTY_FUNCTION__, sg);
+                       return;
+               }
                /*
                 * If the RP sent in the message is not
                 * our RP for the group, drop the message
@@ -136,6 +141,12 @@ static void recv_prune(struct interface *ifp, struct pim_neighbor *neigh,
            && (source_flags & PIM_WILDCARD_BIT_MASK)) {
                struct pim_rpf *rp = RP(pim_ifp->pim, sg->grp);
 
+               if (!rp) {
+                       if (PIM_DEBUG_PIM_TRACE)
+                               zlog_debug("%s: RP for %pSG4 completely failed lookup",
+                                          __PRETTY_FUNCTION__, sg);
+                       return;
+               }
                // Ignoring Prune *,G's at the moment.
                if (sg->src.s_addr != rp->rpf_addr.u.prefix4.s_addr)
                        return;
index 39493b189b20155ab714d3ae61a9f7ef3ca9737b..09529055e059b8bdeda25a69a2fce5559fa0cd28 100644 (file)
@@ -1192,8 +1192,8 @@ int pim_rp_set_upstream_addr(struct pim_instance *pim, struct in_addr *up,
 
        rp_info = pim_rp_find_match_group(pim, &g);
 
-       if ((pim_rpf_addr_is_inaddr_none(&rp_info->rp))
-           && (source.s_addr == INADDR_ANY)) {
+       if (!rp_info || ((pim_rpf_addr_is_inaddr_none(&rp_info->rp))
+                        && (source.s_addr == INADDR_ANY))) {
                if (PIM_DEBUG_PIM_NHT_RP)
                        zlog_debug("%s: Received a (*,G) with no RP configured",
                                   __PRETTY_FUNCTION__);
index 4fe3237395ec47a5db322cc904d1dae20c094f97..93e1cc1f8d5dbbc266f09009da2204d8d62570fa 100644 (file)
@@ -603,9 +603,9 @@ int pim_parse_addr_source(struct prefix_sg *sg, uint8_t *flags,
 
        if (type) {
                zlog_warn(
-                       "%s: unknown source address encoding type=%d: %02x%02x%02x%02x%02x%02x%02x%02x",
+                       "%s: unknown source address encoding type=%d: %02x%02x%02x%02x",
                        __PRETTY_FUNCTION__, type, buf[0], buf[1], buf[2],
-                       buf[3], buf[4], buf[5], buf[6], buf[7]);
+                       buf[3]);
                return -2;
        }
 
@@ -644,9 +644,9 @@ int pim_parse_addr_source(struct prefix_sg *sg, uint8_t *flags,
                break;
        default: {
                zlog_warn(
-                       "%s: unknown source address encoding family=%d: %02x%02x%02x%02x%02x%02x%02x%02x",
+                       "%s: unknown source address encoding family=%d: %02x%02x%02x%02x",
                        __PRETTY_FUNCTION__, family, buf[0], buf[1], buf[2],
-                       buf[3], buf[4], buf[5], buf[6], buf[7]);
+                       buf[3]);
                return -5;
        }
        }