]> git.puffer.fish Git - mirror/frr.git/commitdiff
ospfd: Correct Coverity defects 8408/head
authorOlivier Dugeon <olivier.dugeon@orange.com>
Tue, 6 Apr 2021 10:09:25 +0000 (12:09 +0200)
committerOlivier Dugeon <olivier.dugeon@orange.com>
Wed, 19 May 2021 07:48:54 +0000 (09:48 +0200)
When browsing or parsing OSPF LSA TLVs, we need to use the LSA length which is
part of the LSA header. This length, encoded in 16 bits, must be first
converted to host byte order with ntohs() function. However, Coverity Scan
considers that ntohs() function return TAINTED data. Thus, when the length is
used to control for() loop, Coverity Scan marks this part of the code as defect
with "Untrusted Loop Bound" due to the usage of Tainted variable. Similar
problems occur when browsing sub-TLV where length is extracted with ntohs().

To overcome this limitation, a size attribute has been added to the ospf_lsa
structure. The size is set when lsa->data buffer is allocated. In addition,
when an OSPF packet is received, the size of the payload is controlled before
contains is processed. For OSPF LSA, this allow a secure buffer allocation.
Thus, new size attribute contains the exact buffer allocation allowing a
strict control during TLV browsing.

This patch adds extra control to bound for() loop during TLV browsing to
avoid potential problem as suggested by Coverity Scan. Controls are based
on new size attribute of the ospf_lsa structure to avoid any ambiguity.

Signed-off-by: Olivier Dugeon <olivier.dugeon@orange.com>
16 files changed:
ospfd/ospf_api.c
ospfd/ospf_api.h
ospfd/ospf_apiserver.c
ospfd/ospf_dump.c
ospfd/ospf_ext.c
ospfd/ospf_gr_helper.c
ospfd/ospf_lsa.c
ospfd/ospf_lsa.h
ospfd/ospf_opaque.c
ospfd/ospf_opaque.h
ospfd/ospf_ri.c
ospfd/ospf_ri.h
ospfd/ospf_sr.c
ospfd/ospf_sr.h
ospfd/ospf_te.c
ospfd/ospf_vty.c

index 7e7236a3b69eec3da9540a70e4708f0bf54ea379..81de8827548b75fbd674cc6cf36d4c226e5332bb 100644 (file)
@@ -58,7 +58,7 @@
 
 
 /* For debugging only, will be removed */
-void api_opaque_lsa_print(struct lsa_header *data)
+void api_opaque_lsa_print(struct ospf_lsa *lsa)
 {
        struct opaque_lsa {
                struct lsa_header header;
@@ -69,11 +69,11 @@ void api_opaque_lsa_print(struct lsa_header *data)
        int opaquelen;
        int i;
 
-       ospf_lsa_header_dump(data);
+       ospf_lsa_header_dump(lsa->data);
 
-       olsa = (struct opaque_lsa *)data;
+       olsa = (struct opaque_lsa *)lsa->data;
 
-       opaquelen = ntohs(data->length) - OSPF_LSA_HEADER_SIZE;
+       opaquelen = lsa->size - OSPF_LSA_HEADER_SIZE;
        zlog_debug("apiserver_lsa_print: opaquelen=%d", opaquelen);
 
        for (i = 0; i < opaquelen; i++) {
@@ -111,11 +111,16 @@ struct msg *msg_new(uint8_t msgtype, void *msgbody, uint32_t seqnum,
 struct msg *msg_dup(struct msg *msg)
 {
        struct msg *new;
+       size_t size;
 
        assert(msg);
 
+       size = ntohs(msg->hdr.msglen);
+       if (size > OSPF_MAX_LSA_SIZE)
+               return NULL;
+
        new = msg_new(msg->hdr.msgtype, STREAM_DATA(msg->s),
-                     ntohl(msg->hdr.msgseq), ntohs(msg->hdr.msglen));
+                     ntohl(msg->hdr.msgseq), size);
        return new;
 }
 
@@ -400,7 +405,7 @@ struct msg *msg_read(int fd)
        }
 
        /* Allocate new message */
-       msg = msg_new(hdr.msgtype, buf, ntohl(hdr.msgseq), ntohs(hdr.msglen));
+       msg = msg_new(hdr.msgtype, buf, ntohl(hdr.msgseq), bodylen);
 
        return msg;
 }
@@ -408,29 +413,34 @@ struct msg *msg_read(int fd)
 int msg_write(int fd, struct msg *msg)
 {
        uint8_t buf[OSPF_API_MAX_MSG_SIZE];
-       int l;
+       uint16_t l;
        int wlen;
 
        assert(msg);
        assert(msg->s);
 
-       /* Length of message including header */
-       l = sizeof(struct apimsghdr) + ntohs(msg->hdr.msglen);
+       /* Length of OSPF LSA payload */
+       l = ntohs(msg->hdr.msglen);
+       if (l > OSPF_MAX_LSA_SIZE) {
+               zlog_warn("%s: wrong LSA size %d", __func__, l);
+               return -1;
+       }
 
        /* Make contiguous memory buffer for message */
        memcpy(buf, &msg->hdr, sizeof(struct apimsghdr));
-       memcpy(buf + sizeof(struct apimsghdr), STREAM_DATA(msg->s),
-              ntohs(msg->hdr.msglen));
+       memcpy(buf + sizeof(struct apimsghdr), STREAM_DATA(msg->s), l);
 
+       /* Total length of OSPF API Message */
+       l += sizeof(struct apimsghdr);
        wlen = writen(fd, buf, l);
        if (wlen < 0) {
-               zlog_warn("msg_write: writen %s", safe_strerror(errno));
+               zlog_warn("%s: writen %s", __func__, safe_strerror(errno));
                return -1;
        } else if (wlen == 0) {
-               zlog_warn("msg_write: Connection closed by peer");
+               zlog_warn("%s: Connection closed by peer", __func__);
                return -1;
        } else if (wlen != l) {
-               zlog_warn("msg_write: Cannot write API message");
+               zlog_warn("%s: Cannot write API message", __func__);
                return -1;
        }
        return 0;
index 0fc683a5dbfe73c40972914a37df4b42ceacab2b..c20284aed5d808ad3296acdec474dd3636443874 100644 (file)
@@ -276,7 +276,7 @@ struct apimsg {
  */
 
 /* For debugging only. */
-extern void api_opaque_lsa_print(struct lsa_header *data);
+extern void api_opaque_lsa_print(struct ospf_lsa *lsa);
 
 /* Messages sent by client */
 extern struct msg *new_msg_register_opaque_type(uint32_t seqnum, uint8_t ltype,
index c01ecdd1d4d7a017448e07e1e4fad57a7b4164b9..cbd03441ef9415bdd8036161be336cf1ee81859c 100644 (file)
@@ -1156,6 +1156,7 @@ int ospf_apiserver_handle_register_event(struct ospf_apiserver *apiserv,
        struct msg_register_event *rmsg;
        int rc;
        uint32_t seqnum;
+       size_t size;
 
        rmsg = (struct msg_register_event *)STREAM_DATA(msg->s);
 
@@ -1165,13 +1166,16 @@ int ospf_apiserver_handle_register_event(struct ospf_apiserver *apiserv,
        /* Free existing filter in apiserv. */
        XFREE(MTYPE_OSPF_APISERVER_MSGFILTER, apiserv->filter);
        /* Alloc new space for filter. */
+       size = ntohs(msg->hdr.msglen);
+       if (size < OSPF_MAX_LSA_SIZE) {
 
-       apiserv->filter =
-               XMALLOC(MTYPE_OSPF_APISERVER_MSGFILTER, ntohs(msg->hdr.msglen));
+               apiserv->filter = XMALLOC(MTYPE_OSPF_APISERVER_MSGFILTER, size);
 
-       /* copy it over. */
-       memcpy(apiserv->filter, &rmsg->filter, ntohs(msg->hdr.msglen));
-       rc = OSPF_API_OK;
+               /* copy it over. */
+               memcpy(apiserv->filter, &rmsg->filter, size);
+               rc = OSPF_API_OK;
+       } else
+               rc = OSPF_API_NOMEMORY;
 
        /* Send a reply back to client with return code */
        rc = ospf_apiserver_send_reply(apiserv, seqnum, rc);
index 8f31f90346effa1f9b0654406f4abb1247b917e8..e490070d036c5d5636f09f9e081e352b05475b1a 100644 (file)
@@ -241,7 +241,7 @@ const char *ospf_timer_dump(struct thread *t, char *buf, size_t size)
 static void ospf_packet_hello_dump(struct stream *s, uint16_t length)
 {
        struct ospf_hello *hello;
-       int i;
+       int i, len;
 
        hello = (struct ospf_hello *)stream_pnt(s);
 
@@ -256,9 +256,9 @@ static void ospf_packet_hello_dump(struct stream *s, uint16_t length)
        zlog_debug("  DRouter %pI4", &hello->d_router);
        zlog_debug("  BDRouter %pI4", &hello->bd_router);
 
-       length -= OSPF_HEADER_SIZE + OSPF_HELLO_MIN_SIZE;
-       zlog_debug("  # Neighbors %d", length / 4);
-       for (i = 0; length > 0; i++, length -= sizeof(struct in_addr))
+       len = length - OSPF_HEADER_SIZE - OSPF_HELLO_MIN_SIZE;
+       zlog_debug("  # Neighbors %d", len / 4);
+       for (i = 0; len > 0; i++, len -= sizeof(struct in_addr))
                zlog_debug("    Neighbor %pI4", &hello->neighbors[i]);
 }
 
@@ -285,7 +285,8 @@ static void ospf_router_lsa_dump(struct stream *s, uint16_t length)
 {
        char buf[BUFSIZ];
        struct router_lsa *rl;
-       int i, len;
+       struct router_link *rlnk;
+       int i, len, sum;
 
        rl = (struct router_lsa *)stream_pnt(s);
 
@@ -294,16 +295,15 @@ static void ospf_router_lsa_dump(struct stream *s, uint16_t length)
                   ospf_router_lsa_flags_dump(rl->flags, buf, BUFSIZ));
        zlog_debug("    # links %d", ntohs(rl->links));
 
-       len = ntohs(rl->header.length) - OSPF_LSA_HEADER_SIZE - 4;
-       for (i = 0; len > 0; i++) {
-               zlog_debug("    Link ID %pI4", &rl->link[i].link_id);
-               zlog_debug("    Link Data %pI4",
-                          &rl->link[i].link_data);
-               zlog_debug("    Type %d", (uint8_t)rl->link[i].type);
-               zlog_debug("    TOS %d", (uint8_t)rl->link[i].tos);
-               zlog_debug("    metric %d", ntohs(rl->link[i].metric));
-
-               len -= 12;
+       len = length - OSPF_LSA_HEADER_SIZE - 4;
+       rlnk = &rl->link[0];
+       sum = 0;
+       for (i = 0; sum < len && rlnk; sum += 12, rlnk = &rl->link[++i]) {
+               zlog_debug("    Link ID %pI4", &rlnk->link_id);
+               zlog_debug("    Link Data %pI4", &rlnk->link_data);
+               zlog_debug("    Type %d", (uint8_t)rlnk->type);
+               zlog_debug("    TOS %d", (uint8_t)rlnk->tos);
+               zlog_debug("    metric %d", ntohs(rlnk->metric));
        }
 }
 
@@ -312,10 +312,11 @@ static void ospf_network_lsa_dump(struct stream *s, uint16_t length)
        struct network_lsa *nl;
        int i, cnt;
 
+       zlog_debug("  Network-LSA");
+
        nl = (struct network_lsa *)stream_pnt(s);
-       cnt = (ntohs(nl->header.length) - (OSPF_LSA_HEADER_SIZE + 4)) / 4;
+       cnt = (length - (OSPF_LSA_HEADER_SIZE + 4)) / 4;
 
-       zlog_debug("  Network-LSA");
        /*
        zlog_debug ("LSA total size %d", ntohs (nl->header.length));
        zlog_debug ("Network-LSA size %d",
@@ -331,55 +332,53 @@ static void ospf_network_lsa_dump(struct stream *s, uint16_t length)
 static void ospf_summary_lsa_dump(struct stream *s, uint16_t length)
 {
        struct summary_lsa *sl;
-       int size;
-       int i;
 
        sl = (struct summary_lsa *)stream_pnt(s);
 
        zlog_debug("  Summary-LSA");
        zlog_debug("    Network Mask %pI4", &sl->mask);
-
-       size = ntohs(sl->header.length) - OSPF_LSA_HEADER_SIZE - 4;
-       for (i = 0; size > 0; size -= 4, i++)
-               zlog_debug("    TOS=%d metric %d", sl->tos,
-                          GET_METRIC(sl->metric));
+       zlog_debug("    TOS=%d metric %d", sl->tos, GET_METRIC(sl->metric));
 }
 
 static void ospf_as_external_lsa_dump(struct stream *s, uint16_t length)
 {
        struct as_external_lsa *al;
-       int size;
+       struct as_route *asr;
+       int size, sum;
        int i;
 
        al = (struct as_external_lsa *)stream_pnt(s);
        zlog_debug("  %s", ospf_lsa_type_msg[al->header.type].str);
        zlog_debug("    Network Mask %pI4", &al->mask);
 
-       size = ntohs(al->header.length) - OSPF_LSA_HEADER_SIZE - 4;
-       for (i = 0; size > 0; size -= 12, i++) {
+       size = length - OSPF_LSA_HEADER_SIZE - 4;
+       asr = &al->e[0];
+       sum = 0;
+       for (i = 0; sum < size && asr; sum += 12, asr = &al->e[++i]) {
                zlog_debug("    bit %s TOS=%d metric %d",
-                          IS_EXTERNAL_METRIC(al->e[i].tos) ? "E" : "-",
-                          al->e[i].tos & 0x7f, GET_METRIC(al->e[i].metric));
-               zlog_debug("    Forwarding address %pI4",
-                          &al->e[i].fwd_addr);
+                          IS_EXTERNAL_METRIC(asr->tos) ? "E" : "-",
+                          asr->tos & 0x7f, GET_METRIC(asr->metric));
+               zlog_debug("    Forwarding address %pI4", &asr->fwd_addr);
                zlog_debug("    External Route Tag %" ROUTE_TAG_PRI,
-                          al->e[i].route_tag);
+                          asr->route_tag);
        }
 }
 
 static void ospf_lsa_header_list_dump(struct stream *s, uint16_t length)
 {
        struct lsa_header *lsa;
+       int len;
 
        zlog_debug("  # LSA Headers %d", length / OSPF_LSA_HEADER_SIZE);
 
        /* LSA Headers. */
-       while (length > 0) {
+       len = length;
+       while (len > 0) {
                lsa = (struct lsa_header *)stream_pnt(s);
                ospf_lsa_header_dump(lsa);
 
                stream_forward_getp(s, OSPF_LSA_HEADER_SIZE);
-               length -= OSPF_LSA_HEADER_SIZE;
+               len -= OSPF_LSA_HEADER_SIZE;
        }
 }
 
@@ -417,6 +416,7 @@ static void ospf_packet_ls_req_dump(struct stream *s, uint16_t length)
        uint32_t ls_type;
        struct in_addr ls_id;
        struct in_addr adv_router;
+       int sum;
 
        sp = stream_get_getp(s);
 
@@ -425,7 +425,8 @@ static void ospf_packet_ls_req_dump(struct stream *s, uint16_t length)
        zlog_debug("Link State Request");
        zlog_debug("  # Requests %d", length / 12);
 
-       for (; length > 0; length -= 12) {
+       sum = 0;
+       for (; sum < length; sum += 12) {
                ls_type = stream_getl(s);
                ls_id.s_addr = stream_get_ipv4(s);
                adv_router.s_addr = stream_get_ipv4(s);
@@ -442,23 +443,23 @@ static void ospf_packet_ls_upd_dump(struct stream *s, uint16_t length)
 {
        uint32_t sp;
        struct lsa_header *lsa;
-       int lsa_len;
+       int lsa_len, len;
        uint32_t count;
 
-       length -= OSPF_HEADER_SIZE;
+       len = length - OSPF_HEADER_SIZE;
 
        sp = stream_get_getp(s);
 
        count = stream_getl(s);
-       length -= 4;
+       len -= 4;
 
        zlog_debug("Link State Update");
        zlog_debug("  # LSAs %d", count);
 
-       while (length > 0 && count > 0) {
-               if (length < OSPF_HEADER_SIZE || length % 4 != 0) {
+       while (len > 0 && count > 0) {
+               if ((uint16_t)len < OSPF_LSA_HEADER_SIZE || len % 4 != 0) {
                        zlog_debug("  Remaining %d bytes; Incorrect length.",
-                                  length);
+                                  len);
                        break;
                }
 
@@ -466,34 +467,39 @@ static void ospf_packet_ls_upd_dump(struct stream *s, uint16_t length)
                lsa_len = ntohs(lsa->length);
                ospf_lsa_header_dump(lsa);
 
+               /* Check that LSA length is valid */
+               if (lsa_len > len || lsa_len % 4 != 0) {
+                       zlog_debug("  LSA length %d is incorrect!", lsa_len);
+                       break;
+               }
                switch (lsa->type) {
                case OSPF_ROUTER_LSA:
-                       ospf_router_lsa_dump(s, length);
+                       ospf_router_lsa_dump(s, lsa_len);
                        break;
                case OSPF_NETWORK_LSA:
-                       ospf_network_lsa_dump(s, length);
+                       ospf_network_lsa_dump(s, lsa_len);
                        break;
                case OSPF_SUMMARY_LSA:
                case OSPF_ASBR_SUMMARY_LSA:
-                       ospf_summary_lsa_dump(s, length);
+                       ospf_summary_lsa_dump(s, lsa_len);
                        break;
                case OSPF_AS_EXTERNAL_LSA:
-                       ospf_as_external_lsa_dump(s, length);
+                       ospf_as_external_lsa_dump(s, lsa_len);
                        break;
                case OSPF_AS_NSSA_LSA:
-                       ospf_as_external_lsa_dump(s, length);
+                       ospf_as_external_lsa_dump(s, lsa_len);
                        break;
                case OSPF_OPAQUE_LINK_LSA:
                case OSPF_OPAQUE_AREA_LSA:
                case OSPF_OPAQUE_AS_LSA:
-                       ospf_opaque_lsa_dump(s, length);
+                       ospf_opaque_lsa_dump(s, lsa_len);
                        break;
                default:
                        break;
                }
 
                stream_forward_getp(s, lsa_len);
-               length -= lsa_len;
+               len -= lsa_len;
                count--;
        }
 
index 754e2bcbab9ceead8b195ba0c020a9848dadf202..2d08eeece23427f715a674e24a366baf973198fb 100644 (file)
@@ -1715,13 +1715,23 @@ static void ospf_ext_lsa_schedule(struct ext_itf *exti, enum lsa_opcode op)
  * ------------------------------------
  */
 
+#define check_tlv_size(size, msg)                                              \
+       do {                                                                   \
+               if (ntohs(tlvh->length) != size) {                             \
+                       vty_out(vty, "  Wrong %s TLV size: %d(%d). Abort!\n",  \
+                               msg, ntohs(tlvh->length), size);               \
+                       return size + TLV_HDR_SIZE;                            \
+               }                                                              \
+       } while (0)
+
 /* Cisco experimental SubTLV */
 static uint16_t show_vty_ext_link_rmt_itf_addr(struct vty *vty,
                                               struct tlv_header *tlvh)
 {
-       struct ext_subtlv_rmt_itf_addr *top;
+       struct ext_subtlv_rmt_itf_addr *top =
+               (struct ext_subtlv_rmt_itf_addr *)tlvh;
 
-       top = (struct ext_subtlv_rmt_itf_addr *)tlvh;
+       check_tlv_size(EXT_SUBTLV_RMT_ITF_ADDR_SIZE, "Remote Itf. Address");
 
        vty_out(vty,
                "  Remote Interface Address Sub-TLV: Length %u\n        Address: %pI4\n",
@@ -1736,6 +1746,8 @@ static uint16_t show_vty_ext_link_adj_sid(struct vty *vty,
 {
        struct ext_subtlv_adj_sid *top = (struct ext_subtlv_adj_sid *)tlvh;
 
+       check_tlv_size(EXT_SUBTLV_ADJ_SID_SIZE, "Adjacency SID");
+
        vty_out(vty,
                "  Adj-SID Sub-TLV: Length %u\n\tFlags: 0x%x\n\tMT-ID:0x%x\n\tWeight: 0x%x\n\t%s: %u\n",
                ntohs(top->header.length), top->flags, top->mtid, top->weight,
@@ -1755,6 +1767,8 @@ static uint16_t show_vty_ext_link_lan_adj_sid(struct vty *vty,
        struct ext_subtlv_lan_adj_sid *top =
                (struct ext_subtlv_lan_adj_sid *)tlvh;
 
+       check_tlv_size(EXT_SUBTLV_LAN_ADJ_SID_SIZE, "Lan-Adjacency SID");
+
        vty_out(vty,
                "  LAN-Adj-SID Sub-TLV: Length %u\n\tFlags: 0x%x\n\tMT-ID:0x%x\n\tWeight: 0x%x\n\tNeighbor ID: %pI4\n\t%s: %u\n",
                ntohs(top->header.length), top->flags, top->mtid, top->weight,
@@ -1768,8 +1782,15 @@ static uint16_t show_vty_ext_link_lan_adj_sid(struct vty *vty,
        return TLV_SIZE(tlvh);
 }
 
-static uint16_t show_vty_unknown_tlv(struct vty *vty, struct tlv_header *tlvh)
+static uint16_t show_vty_unknown_tlv(struct vty *vty, struct tlv_header *tlvh,
+                                    size_t buf_size)
 {
+       if (TLV_SIZE(tlvh) > buf_size) {
+               vty_out(vty, "    TLV size %d exceeds buffer size. Abort!",
+                       TLV_SIZE(tlvh));
+               return buf_size;
+       }
+
        vty_out(vty, "    Unknown TLV: [type(0x%x), length(0x%x)]\n",
                ntohs(tlvh->type), ntohs(tlvh->length));
 
@@ -1777,13 +1798,22 @@ static uint16_t show_vty_unknown_tlv(struct vty *vty, struct tlv_header *tlvh)
 }
 
 /* Extended Link Sub TLVs */
-static uint16_t show_vty_link_info(struct vty *vty, struct tlv_header *ext)
+static uint16_t show_vty_link_info(struct vty *vty, struct tlv_header *ext,
+                                  size_t buf_size)
 {
        struct ext_tlv_link *top = (struct ext_tlv_link *)ext;
        struct tlv_header *tlvh;
-       uint16_t length = ntohs(top->header.length) - 3 * sizeof(uint32_t);
+       uint16_t length = ntohs(top->header.length);
        uint16_t sum = 0;
 
+       /* Verify that TLV length is valid against remaining buffer size */
+       if (length > buf_size) {
+               vty_out(vty,
+                       "  Extended Link TLV size %d exceeds buffer size. Abort!\n",
+                       length);
+               return buf_size;
+       }
+
        vty_out(vty,
                "  Extended Link TLV: Length %u\n       Link Type: 0x%x\n"
                "       Link ID: %pI4\n",
@@ -1791,9 +1821,11 @@ static uint16_t show_vty_link_info(struct vty *vty, struct tlv_header *ext)
                &top->link_id);
        vty_out(vty, "  Link data: %pI4\n", &top->link_data);
 
+       /* Skip Extended TLV and parse sub-TLVs */
+       length -= EXT_TLV_LINK_SIZE;
        tlvh = (struct tlv_header *)((char *)(ext) + TLV_HDR_SIZE
                                     + EXT_TLV_LINK_SIZE);
-       for (; sum < length; tlvh = TLV_HDR_NEXT(tlvh)) {
+       for (; sum < length && tlvh; tlvh = TLV_HDR_NEXT(tlvh)) {
                switch (ntohs(tlvh->type)) {
                case EXT_SUBTLV_ADJ_SID:
                        sum += show_vty_ext_link_adj_sid(vty, tlvh);
@@ -1805,7 +1837,7 @@ static uint16_t show_vty_link_info(struct vty *vty, struct tlv_header *ext)
                        sum += show_vty_ext_link_rmt_itf_addr(vty, tlvh);
                        break;
                default:
-                       sum += show_vty_unknown_tlv(vty, tlvh);
+                       sum += show_vty_unknown_tlv(vty, tlvh, length - sum);
                        break;
                }
        }
@@ -1821,16 +1853,16 @@ static void ospf_ext_link_show_info(struct vty *vty, struct ospf_lsa *lsa)
        uint16_t length = 0, sum = 0;
 
        /* Initialize TLV browsing */
-       length = ntohs(lsah->length) - OSPF_LSA_HEADER_SIZE;
+       length = lsa->size - OSPF_LSA_HEADER_SIZE;
 
-       for (tlvh = TLV_HDR_TOP(lsah); sum < length;
+       for (tlvh = TLV_HDR_TOP(lsah); sum < length && tlvh;
             tlvh = TLV_HDR_NEXT(tlvh)) {
                switch (ntohs(tlvh->type)) {
                case EXT_TLV_LINK:
-                       sum += show_vty_link_info(vty, tlvh);
+                       sum += show_vty_link_info(vty, tlvh, length - sum);
                        break;
                default:
-                       sum += show_vty_unknown_tlv(vty, tlvh);
+                       sum += show_vty_unknown_tlv(vty, tlvh, length - sum);
                        break;
                }
        }
@@ -1843,6 +1875,8 @@ static uint16_t show_vty_ext_pref_pref_sid(struct vty *vty,
        struct ext_subtlv_prefix_sid *top =
                (struct ext_subtlv_prefix_sid *)tlvh;
 
+       check_tlv_size(EXT_SUBTLV_PREFIX_SID_SIZE, "Prefix SID");
+
        vty_out(vty,
                "  Prefix SID Sub-TLV: Length %u\n\tAlgorithm: %u\n\tFlags: 0x%x\n\tMT-ID:0x%x\n\t%s: %u\n",
                ntohs(top->header.length), top->algorithm, top->flags,
@@ -1857,28 +1891,39 @@ static uint16_t show_vty_ext_pref_pref_sid(struct vty *vty,
 }
 
 /* Extended Prefix SubTLVs */
-static uint16_t show_vty_pref_info(struct vty *vty, struct tlv_header *ext)
+static uint16_t show_vty_pref_info(struct vty *vty, struct tlv_header *ext,
+                                  size_t buf_size)
 {
        struct ext_tlv_prefix *top = (struct ext_tlv_prefix *)ext;
        struct tlv_header *tlvh;
-       uint16_t length = ntohs(top->header.length) - 2 * sizeof(uint32_t);
+       uint16_t length = ntohs(top->header.length);
        uint16_t sum = 0;
 
+       /* Verify that TLV length is valid against remaining buffer size */
+       if (length > buf_size) {
+               vty_out(vty,
+                       "  Extended Link TLV size %d exceeds buffer size. Abort!\n",
+                       length);
+               return buf_size;
+       }
+
        vty_out(vty,
                "  Extended Prefix TLV: Length %u\n\tRoute Type: %u\n"
                "\tAddress Family: 0x%x\n\tFlags: 0x%x\n\tAddress: %pI4/%u\n",
                ntohs(top->header.length), top->route_type, top->af, top->flags,
                &top->address, top->pref_length);
 
+       /* Skip Extended Prefix TLV and parse sub-TLVs */
+       length -= EXT_TLV_PREFIX_SIZE;
        tlvh = (struct tlv_header *)((char *)(ext) + TLV_HDR_SIZE
                                     + EXT_TLV_PREFIX_SIZE);
-       for (; sum < length; tlvh = TLV_HDR_NEXT(tlvh)) {
+       for (; sum < length && tlvh; tlvh = TLV_HDR_NEXT(tlvh)) {
                switch (ntohs(tlvh->type)) {
                case EXT_SUBTLV_PREFIX_SID:
                        sum += show_vty_ext_pref_pref_sid(vty, tlvh);
                        break;
                default:
-                       sum += show_vty_unknown_tlv(vty, tlvh);
+                       sum += show_vty_unknown_tlv(vty, tlvh, length - sum);
                        break;
                }
        }
@@ -1894,16 +1939,16 @@ static void ospf_ext_pref_show_info(struct vty *vty, struct ospf_lsa *lsa)
        uint16_t length = 0, sum = 0;
 
        /* Initialize TLV browsing */
-       length = ntohs(lsah->length) - OSPF_LSA_HEADER_SIZE;
+       length = lsa->size - OSPF_LSA_HEADER_SIZE;
 
-       for (tlvh = TLV_HDR_TOP(lsah); sum < length;
+       for (tlvh = TLV_HDR_TOP(lsah); sum < length && tlvh;
             tlvh = TLV_HDR_NEXT(tlvh)) {
                switch (ntohs(tlvh->type)) {
                case EXT_TLV_PREFIX:
-                       sum += show_vty_pref_info(vty, tlvh);
+                       sum += show_vty_pref_info(vty, tlvh, length - sum);
                        break;
                default:
-                       sum += show_vty_unknown_tlv(vty, tlvh);
+                       sum += show_vty_unknown_tlv(vty, tlvh, length - sum);
                        break;
                }
        }
index d818878cf5f3ac67eee87479d7474e37c7791390..a25057a27f54514ea2a9fc0595d33e045a68bb3e 100644 (file)
@@ -233,19 +233,17 @@ static int ospf_extract_grace_lsa_fields(struct ospf_lsa *lsa,
 
        lsah = (struct lsa_header *)lsa->data;
 
-       length = ntohs(lsah->length);
-
        /* Check LSA len */
-       if (length <= OSPF_LSA_HEADER_SIZE) {
+       if (lsa->size <= OSPF_LSA_HEADER_SIZE) {
                if (IS_DEBUG_OSPF_GR_HELPER)
                        zlog_debug("%s: Malformed packet: Invalid LSA len:%d",
                                   __func__, length);
                return OSPF_GR_FAILURE;
        }
 
-       length -= OSPF_LSA_HEADER_SIZE;
+       length = lsa->size - OSPF_LSA_HEADER_SIZE;
 
-       for (tlvh = TLV_HDR_TOP(lsah); sum < length;
+       for (tlvh = TLV_HDR_TOP(lsah); sum < length && tlvh;
             tlvh = TLV_HDR_NEXT(tlvh)) {
 
                /* Check TLV len against overall LSA */
@@ -996,18 +994,16 @@ static void show_ospf_grace_lsa_info(struct vty *vty, struct ospf_lsa *lsa)
 
        lsah = (struct lsa_header *)lsa->data;
 
-       length = ntohs(lsah->length);
-
-       if (length <= OSPF_LSA_HEADER_SIZE) {
+       if (lsa->size <= OSPF_LSA_HEADER_SIZE) {
                vty_out(vty, "%% Invalid LSA length: %d\n", length);
                return;
        }
 
-       length -= OSPF_LSA_HEADER_SIZE;
+       length = lsa->size - OSPF_LSA_HEADER_SIZE;
 
        vty_out(vty, "  TLV info:\n");
 
-       for (tlvh = TLV_HDR_TOP(lsah); sum < length;
+       for (tlvh = TLV_HDR_TOP(lsah); sum < length && tlvh;
             tlvh = TLV_HDR_NEXT(tlvh)) {
                /* Check TLV len */
                if (sum + TLV_SIZE(tlvh) > length) {
index 6e9df77fb879db8fb5099cfcdac9cc930a901a69..72dc699bd989fd5ea5a47a6f4b35b35ec0e92e53 100644 (file)
@@ -175,6 +175,7 @@ struct ospf_lsa *ospf_lsa_new_and_data(size_t size)
 
        new = ospf_lsa_new();
        new->data = ospf_lsa_data_new(size);
+       new->size = size;
 
        return new;
 }
@@ -3241,22 +3242,22 @@ int ospf_lsa_different(struct ospf_lsa *l1, struct ospf_lsa *l2)
        if (IS_LSA_MAXAGE(l2) && !IS_LSA_MAXAGE(l1))
                return 1;
 
-       if (l1->data->length != l2->data->length)
+       if (l1->size != l2->size)
                return 1;
 
-       if (l1->data->length == 0)
+       if (l1->size == 0)
                return 1;
 
        if (CHECK_FLAG((l1->flags ^ l2->flags), OSPF_LSA_RECEIVED))
                return 1; /* May be a stale LSA in the LSBD */
 
-       assert(ntohs(l1->data->length) > OSPF_LSA_HEADER_SIZE);
+       assert(l1->size > OSPF_LSA_HEADER_SIZE);
 
        p1 = (char *)l1->data;
        p2 = (char *)l2->data;
 
        if (memcmp(p1 + OSPF_LSA_HEADER_SIZE, p2 + OSPF_LSA_HEADER_SIZE,
-                  ntohs(l1->data->length) - OSPF_LSA_HEADER_SIZE)
+                  l1->size - OSPF_LSA_HEADER_SIZE)
            != 0)
                return 1;
 
index 3c1f94e6282b6ba5684bb9dd878d4325dc79b353..3808700cccc9e17b0b87ef55f18b8ee57477429b 100644 (file)
@@ -84,8 +84,9 @@ struct ospf_lsa {
 #define OSPF_LSA_PREMATURE_AGE   0x40
 #define OSPF_LSA_IN_MAXAGE       0x80
 
-       /* LSA data. */
+       /* LSA data. and size */
        struct lsa_header *data;
+       size_t size;
 
        /* Received time stamp. */
        struct timeval tv_recv;
@@ -168,7 +169,7 @@ struct router_lsa {
        uint8_t flags;
        uint8_t zero;
        uint16_t links;
-       struct {
+       struct router_link {
                struct in_addr link_id;
                struct in_addr link_data;
                uint8_t type;
@@ -199,7 +200,7 @@ struct summary_lsa {
 struct as_external_lsa {
        struct lsa_header header;
        struct in_addr mask;
-       struct {
+       struct as_route {
                uint8_t tos;
                uint8_t metric[3];
                struct in_addr fwd_addr;
index ae9ab48d4a262a2c54f8e2919462d0972131e212..42bf914f6755f3eed63de27858f5add4cf31a045 100644 (file)
@@ -1204,9 +1204,10 @@ void show_opaque_info_detail(struct vty *vty, struct ospf_lsa *lsa,
 
 void ospf_opaque_lsa_dump(struct stream *s, uint16_t length)
 {
-       struct ospf_lsa lsa;
+       struct ospf_lsa lsa = {};
 
        lsa.data = (struct lsa_header *)stream_pnt(s);
+       lsa.size = length;
        show_opaque_info_detail(NULL, &lsa, NULL);
        return;
 }
index c63b8ebdafa5026807a7cd743b9e978cf58758c5..7d401c3dcc18a5adf074af0a602672caf74a29d0 100644 (file)
@@ -79,6 +79,7 @@
 
 #define VALID_OPAQUE_INFO_LEN(lsahdr)                                          \
        ((ntohs((lsahdr)->length) >= sizeof(struct lsa_header))                \
+        && ((ntohs((lsahdr)->length) < OSPF_MAX_LSA_SIZE))                    \
         && ((ntohs((lsahdr)->length) % sizeof(uint32_t)) == 0))
 
 /*
index 4083ea9332a206e2a1919ca84e0854af7d94d2e3..c87a00a0d4867369beaf0c0c428ebb1e6285c7fb 100644 (file)
@@ -294,8 +294,8 @@ static void set_pce_address(struct in_addr ipv4, struct ospf_pce_info *pce)
        pce->pce_header.header.type = htons(RI_TLV_PCE);
        /* Set PCE Address */
        pce->pce_address.header.type = htons(RI_PCE_SUBTLV_ADDRESS);
-       pce->pce_address.header.length = htons(PCE_ADDRESS_LENGTH_IPV4);
-       pce->pce_address.address.type = htons(PCE_ADDRESS_TYPE_IPV4);
+       pce->pce_address.header.length = htons(PCE_ADDRESS_IPV4_SIZE);
+       pce->pce_address.address.type = htons(PCE_ADDRESS_IPV4);
        pce->pce_address.address.value = ipv4;
 
        return;
@@ -323,7 +323,7 @@ static void set_pce_domain(uint16_t type, uint32_t domain,
                      sizeof(struct ri_pce_subtlv_domain));
 
        new->header.type = htons(RI_PCE_SUBTLV_DOMAIN);
-       new->header.length = htons(PCE_ADDRESS_LENGTH_IPV4);
+       new->header.length = htons(PCE_ADDRESS_IPV4_SIZE);
        new->type = htons(type);
        new->value = htonl(domain);
 
@@ -369,7 +369,7 @@ static void set_pce_neighbor(uint16_t type, uint32_t domain,
                      sizeof(struct ri_pce_subtlv_neighbor));
 
        new->header.type = htons(RI_PCE_SUBTLV_NEIGHBOR);
-       new->header.length = htons(PCE_ADDRESS_LENGTH_IPV4);
+       new->header.length = htons(PCE_ADDRESS_IPV4_SIZE);
        new->type = htons(type);
        new->value = htonl(domain);
 
@@ -1226,10 +1226,25 @@ static int ospf_router_info_lsa_update(struct ospf_lsa *lsa)
  * Followings are vty session control functions.
  *------------------------------------------------------------------------*/
 
+#define check_tlv_size(size, msg)                                              \
+       do {                                                                   \
+               if (ntohs(tlvh->length) > size) {                              \
+                       if (vty != NULL)                                       \
+                               vty_out(vty, "  Wrong %s TLV size: %d(%d)\n",  \
+                                       msg, ntohs(tlvh->length), size);       \
+                       else                                                   \
+                               zlog_debug("    Wrong %s TLV size: %d(%d)\n",  \
+                                          msg, ntohs(tlvh->length), size);    \
+                       return size + TLV_HDR_SIZE;                            \
+               }                                                              \
+       } while (0)
+
 static uint16_t show_vty_router_cap(struct vty *vty, struct tlv_header *tlvh)
 {
        struct ri_tlv_router_cap *top = (struct ri_tlv_router_cap *)tlvh;
 
+       check_tlv_size(RI_TLV_CAPABILITIES_SIZE, "Router Capabilities");
+
        if (vty != NULL)
                vty_out(vty, "  Router Capabilities: 0x%x\n",
                        ntohl(top->value));
@@ -1245,21 +1260,30 @@ static uint16_t show_vty_pce_subtlv_address(struct vty *vty,
        struct ri_pce_subtlv_address *top =
                (struct ri_pce_subtlv_address *)tlvh;
 
-       if (ntohs(top->address.type) == PCE_ADDRESS_TYPE_IPV4) {
+       if (ntohs(top->address.type) == PCE_ADDRESS_IPV4) {
+               check_tlv_size(PCE_ADDRESS_IPV4_SIZE, "PCE Address");
                if (vty != NULL)
                        vty_out(vty, "  PCE Address: %pI4\n",
                                &top->address.value);
                else
                        zlog_debug("    PCE Address: %pI4",
                                   &top->address.value);
-       } else {
+       } else if (ntohs(top->address.type) == PCE_ADDRESS_IPV6) {
                /* TODO: Add support to IPv6 with inet_ntop() */
+               check_tlv_size(PCE_ADDRESS_IPV6_SIZE, "PCE Address");
                if (vty != NULL)
                        vty_out(vty, "  PCE Address: 0x%x\n",
                                ntohl(top->address.value.s_addr));
                else
                        zlog_debug("    PCE Address: 0x%x",
                                   ntohl(top->address.value.s_addr));
+       } else {
+               if (vty != NULL)
+                       vty_out(vty, "  Wrong PCE Address type: 0x%x\n",
+                               ntohl(top->address.type));
+               else
+                       zlog_debug("    Wrong PCE Address type: 0x%x",
+                                  ntohl(top->address.type));
        }
 
        return TLV_SIZE(tlvh);
@@ -1271,6 +1295,8 @@ static uint16_t show_vty_pce_subtlv_path_scope(struct vty *vty,
        struct ri_pce_subtlv_path_scope *top =
                (struct ri_pce_subtlv_path_scope *)tlvh;
 
+       check_tlv_size(RI_PCE_SUBTLV_PATH_SCOPE_SIZE, "PCE Path Scope");
+
        if (vty != NULL)
                vty_out(vty, "  PCE Path Scope: 0x%x\n", ntohl(top->value));
        else
@@ -1285,19 +1311,29 @@ static uint16_t show_vty_pce_subtlv_domain(struct vty *vty,
        struct ri_pce_subtlv_domain *top = (struct ri_pce_subtlv_domain *)tlvh;
        struct in_addr tmp;
 
+       check_tlv_size(RI_PCE_SUBTLV_DOMAIN_SIZE, "PCE Domain");
+
        if (ntohs(top->type) == PCE_DOMAIN_TYPE_AREA) {
                tmp.s_addr = top->value;
                if (vty != NULL)
-                       vty_out(vty, "  PCE domain Area: %pI4\n", &tmp);
+                       vty_out(vty, "  PCE Domain Area: %pI4\n", &tmp);
                else
-                       zlog_debug("    PCE domain Area: %pI4", &tmp);
-       } else {
+                       zlog_debug("    PCE Domain Area: %pI4", &tmp);
+       } else if (ntohs(top->type) == PCE_DOMAIN_TYPE_AS) {
                if (vty != NULL)
-                       vty_out(vty, "  PCE domain AS: %d\n",
+                       vty_out(vty, "  PCE Domain AS: %d\n",
                                ntohl(top->value));
                else
-                       zlog_debug("    PCE domain AS: %d", ntohl(top->value));
+                       zlog_debug("    PCE Domain AS: %d", ntohl(top->value));
+       } else {
+               if (vty != NULL)
+                       vty_out(vty, "  Wrong PCE Domain type: %d\n",
+                               ntohl(top->type));
+               else
+                       zlog_debug("    Wrong PCE Domain type: %d",
+                                  ntohl(top->type));
        }
+
        return TLV_SIZE(tlvh);
 }
 
@@ -1309,21 +1345,30 @@ static uint16_t show_vty_pce_subtlv_neighbor(struct vty *vty,
                (struct ri_pce_subtlv_neighbor *)tlvh;
        struct in_addr tmp;
 
+       check_tlv_size(RI_PCE_SUBTLV_NEIGHBOR_SIZE, "PCE Neighbor");
+
        if (ntohs(top->type) == PCE_DOMAIN_TYPE_AREA) {
                tmp.s_addr = top->value;
                if (vty != NULL)
-                       vty_out(vty, "  PCE neighbor Area: %pI4\n",
-                               &tmp);
+                       vty_out(vty, "  PCE Neighbor Area: %pI4\n", &tmp);
                else
-                       zlog_debug("    PCE neighbor Area: %pI4", &tmp);
-       } else {
+                       zlog_debug("    PCE Neighbor Area: %pI4", &tmp);
+       } else if (ntohs(top->type) == PCE_DOMAIN_TYPE_AS) {
                if (vty != NULL)
-                       vty_out(vty, "  PCE neighbor AS: %d\n",
+                       vty_out(vty, "  PCE Neighbor AS: %d\n",
                                ntohl(top->value));
                else
-                       zlog_debug("    PCE neighbor AS: %d",
+                       zlog_debug("    PCE Neighbor AS: %d",
                                   ntohl(top->value));
+       } else {
+               if (vty != NULL)
+                       vty_out(vty, "  Wrong PCE Neighbor type: %d\n",
+                               ntohl(top->type));
+               else
+                       zlog_debug("    Wrong PCE Neighbor type: %d",
+                                  ntohl(top->type));
        }
+
        return TLV_SIZE(tlvh);
 }
 
@@ -1333,6 +1378,8 @@ static uint16_t show_vty_pce_subtlv_cap_flag(struct vty *vty,
        struct ri_pce_subtlv_cap_flag *top =
                (struct ri_pce_subtlv_cap_flag *)tlvh;
 
+       check_tlv_size(RI_PCE_SUBTLV_CAP_FLAG_SIZE, "PCE Capabilities");
+
        if (vty != NULL)
                vty_out(vty, "  PCE Capabilities Flag: 0x%x\n",
                        ntohl(top->value));
@@ -1343,8 +1390,21 @@ static uint16_t show_vty_pce_subtlv_cap_flag(struct vty *vty,
        return TLV_SIZE(tlvh);
 }
 
-static uint16_t show_vty_unknown_tlv(struct vty *vty, struct tlv_header *tlvh)
+static uint16_t show_vty_unknown_tlv(struct vty *vty, struct tlv_header *tlvh,
+                                    size_t buf_size)
 {
+       if (TLV_SIZE(tlvh) > buf_size) {
+               if (vty != NULL)
+                       vty_out(vty,
+                               "    TLV size %d exceeds buffer size. Abort!",
+                               TLV_SIZE(tlvh));
+               else
+                       zlog_debug(
+                               "    TLV size %d exceeds buffer size. Abort!",
+                               TLV_SIZE(tlvh));
+               return buf_size;
+       }
+
        if (vty != NULL)
                vty_out(vty, "  Unknown TLV: [type(0x%x), length(0x%x)]\n",
                        ntohs(tlvh->type), ntohs(tlvh->length));
@@ -1356,12 +1416,21 @@ static uint16_t show_vty_unknown_tlv(struct vty *vty, struct tlv_header *tlvh)
 }
 
 static uint16_t show_vty_pce_info(struct vty *vty, struct tlv_header *ri,
-                                 uint32_t total)
+                                 size_t buf_size)
 {
        struct tlv_header *tlvh;
+       uint16_t length = ntohs(ri->length);
        uint16_t sum = 0;
 
-       for (tlvh = ri; sum < total; tlvh = TLV_HDR_NEXT(tlvh)) {
+       /* Verify that TLV length is valid against remaining buffer size */
+       if (length > buf_size) {
+               vty_out(vty,
+                       "  PCE Info TLV size %d exceeds buffer size. Abort!\n",
+                       length);
+               return buf_size;
+       }
+
+       for (tlvh = ri; sum < length; tlvh = TLV_HDR_NEXT(tlvh)) {
                switch (ntohs(tlvh->type)) {
                case RI_PCE_SUBTLV_ADDRESS:
                        sum += show_vty_pce_subtlv_address(vty, tlvh);
@@ -1379,7 +1448,7 @@ static uint16_t show_vty_pce_info(struct vty *vty, struct tlv_header *ri,
                        sum += show_vty_pce_subtlv_cap_flag(vty, tlvh);
                        break;
                default:
-                       sum += show_vty_unknown_tlv(vty, tlvh);
+                       sum += show_vty_unknown_tlv(vty, tlvh, length - sum);
                        break;
                }
        }
@@ -1393,6 +1462,8 @@ static uint16_t show_vty_sr_algorithm(struct vty *vty, struct tlv_header *tlvh)
                (struct ri_sr_tlv_sr_algorithm *)tlvh;
        int i;
 
+       check_tlv_size(ALGORITHM_COUNT, "Segment Routing Algorithm");
+
        if (vty != NULL) {
                vty_out(vty, "  Segment Routing Algorithm TLV:\n");
                for (i = 0; i < ntohs(algo->header.length); i++) {
@@ -1411,9 +1482,7 @@ static uint16_t show_vty_sr_algorithm(struct vty *vty, struct tlv_header *tlvh)
                                break;
                        }
                }
-       }
-
-       else {
+       } else {
                zlog_debug("  Segment Routing Algorithm TLV:");
                for (i = 0; i < ntohs(algo->header.length); i++)
                        switch (algo->value[i]) {
@@ -1439,6 +1508,8 @@ static uint16_t show_vty_sr_range(struct vty *vty, struct tlv_header *tlvh)
        struct ri_sr_tlv_sid_label_range *range =
                (struct ri_sr_tlv_sid_label_range *)tlvh;
 
+       check_tlv_size(RI_SR_TLV_LABEL_RANGE_SIZE, "SR Label Range");
+
        if (vty != NULL) {
                vty_out(vty,
                        "  Segment Routing %s Range TLV:\n"
@@ -1467,6 +1538,8 @@ static uint16_t show_vty_sr_msd(struct vty *vty, struct tlv_header *tlvh)
 {
        struct ri_sr_tlv_node_msd *msd = (struct ri_sr_tlv_node_msd *)tlvh;
 
+       check_tlv_size(RI_SR_TLV_NODE_MSD_SIZE, "Node Maximum Stack Depth");
+
        if (vty != NULL) {
                vty_out(vty,
                        "  Segment Routing MSD TLV:\n"
@@ -1488,9 +1561,9 @@ static void ospf_router_info_show_info(struct vty *vty, struct ospf_lsa *lsa)
        uint16_t length = 0, sum = 0;
 
        /* Initialize TLV browsing */
-       length = ntohs(lsah->length) - OSPF_LSA_HEADER_SIZE;
+       length = lsa->size - OSPF_LSA_HEADER_SIZE;
 
-       for (tlvh = TLV_HDR_TOP(lsah); sum < length;
+       for (tlvh = TLV_HDR_TOP(lsah); sum < length && tlvh;
             tlvh = TLV_HDR_NEXT(tlvh)) {
                switch (ntohs(tlvh->type)) {
                case RI_TLV_CAPABILITIES:
@@ -1513,7 +1586,7 @@ static void ospf_router_info_show_info(struct vty *vty, struct ospf_lsa *lsa)
                        break;
 
                default:
-                       sum += show_vty_unknown_tlv(vty, tlvh);
+                       sum += show_vty_unknown_tlv(vty, tlvh, length);
                        break;
                }
        }
index 4729677bcaf2ca3b242c4be2e8c39d9b177eedf4..bbad896280d39cb35a267a2422b8b48f52c97d68 100644 (file)
@@ -75,7 +75,7 @@
 
 /* RFC4970: Router Information Capabilities TLV */ /* Mandatory */
 #define RI_TLV_CAPABILITIES            1
-
+#define RI_TLV_CAPABILITIES_SIZE       4
 struct ri_tlv_router_cap {
        struct tlv_header header; /* Value length is 4 bytes. */
        uint32_t value;
@@ -105,12 +105,12 @@ struct ri_tlv_pce {
 struct ri_pce_subtlv_address {
        /* Type = 1; Length is 8 (IPv4) or 20 (IPv6) bytes. */
        struct tlv_header header;
-#define        PCE_ADDRESS_LENGTH_IPV4         8
-#define        PCE_ADDRESS_LENGTH_IPV6         20
+#define        PCE_ADDRESS_IPV4_SIZE           8
+#define        PCE_ADDRESS_IPV6_SIZE           20
        struct {
                uint16_t type; /* Address type: 1 = IPv4, 2 = IPv6 */
-#define        PCE_ADDRESS_TYPE_IPV4           1
-#define        PCE_ADDRESS_TYPE_IPV6           2
+#define        PCE_ADDRESS_IPV4                1
+#define        PCE_ADDRESS_IPV6                2
                uint16_t reserved;
                struct in_addr value; /* PCE address */
        } address;
@@ -118,6 +118,7 @@ struct ri_pce_subtlv_address {
 
 /* PCE Path-Scope Sub-TLV */ /* Mandatory */
 #define        RI_PCE_SUBTLV_PATH_SCOPE        2
+#define        RI_PCE_SUBTLV_PATH_SCOPE_SIZE   4
 struct ri_pce_subtlv_path_scope {
        struct tlv_header header; /* Type = 2; Length = 4 bytes. */
        /*
@@ -128,11 +129,11 @@ struct ri_pce_subtlv_path_scope {
 };
 
 /* PCE Domain Sub-TLV */ /* Optional */
-#define        RI_PCE_SUBTLV_DOMAIN            3
-
 #define        PCE_DOMAIN_TYPE_AREA            1
-#define        PCE_DOMAIN_TYPE_AS                      2
+#define        PCE_DOMAIN_TYPE_AS              2
 
+#define        RI_PCE_SUBTLV_DOMAIN            3
+#define        RI_PCE_SUBTLV_DOMAIN_SIZE       8
 struct ri_pce_subtlv_domain {
        struct tlv_header header; /* Type = 3; Length = 8 bytes. */
        uint16_t type; /* Domain type: 1 = OSPF Area ID, 2 = AS Number */
@@ -142,6 +143,7 @@ struct ri_pce_subtlv_domain {
 
 /* PCE Neighbor Sub-TLV */ /* Mandatory if R or S bit is set */
 #define RI_PCE_SUBTLV_NEIGHBOR         4
+#define RI_PCE_SUBTLV_NEIGHBOR_SIZE    8
 struct ri_pce_subtlv_neighbor {
        struct tlv_header header; /* Type = 4; Length = 8 bytes. */
        uint16_t type; /* Domain type: 1 = OSPF Area ID, 2 = AS Number */
@@ -151,6 +153,7 @@ struct ri_pce_subtlv_neighbor {
 
 /* PCE Capabilities Flags Sub-TLV */ /* Optional */
 #define RI_PCE_SUBTLV_CAP_FLAG         5
+#define RI_PCE_SUBTLV_CAP_FLAG_SIZE    4
 
 #define PCE_CAP_GMPLS_LINK             0x0001
 #define PCE_CAP_BIDIRECTIONAL          0x0002
index d003f3bf7cde438eaab9249db66e41391844c88e..3ce177618f39b0d96789a17b90008c52bef755ad 100644 (file)
@@ -954,7 +954,7 @@ static inline void update_adj_sid(struct sr_nhlfe n1, struct sr_nhlfe n2)
  */
 
 /* Extended Link SubTLVs Getter */
-static struct sr_link *get_ext_link_sid(struct tlv_header *tlvh)
+static struct sr_link *get_ext_link_sid(struct tlv_header *tlvh, size_t size)
 {
 
        struct sr_link *srl;
@@ -966,13 +966,20 @@ static struct sr_link *get_ext_link_sid(struct tlv_header *tlvh)
        struct tlv_header *sub_tlvh;
        uint16_t length = 0, sum = 0, i = 0;
 
+       /* Check TLV size */
+       if ((ntohs(tlvh->length) > size)
+           || ntohs(tlvh->length) < EXT_TLV_LINK_SIZE) {
+               zlog_warn("Wrong Extended Link TLV size. Abort!");
+               return NULL;
+       }
+
        srl = XCALLOC(MTYPE_OSPF_SR_PARAMS, sizeof(struct sr_link));
 
        /* Initialize TLV browsing */
        length = ntohs(tlvh->length) - EXT_TLV_LINK_SIZE;
        sub_tlvh = (struct tlv_header *)((char *)(tlvh) + TLV_HDR_SIZE
                                         + EXT_TLV_LINK_SIZE);
-       for (; sum < length; sub_tlvh = TLV_HDR_NEXT(sub_tlvh)) {
+       for (; sum < length && sub_tlvh; sub_tlvh = TLV_HDR_NEXT(sub_tlvh)) {
                switch (ntohs(sub_tlvh->type)) {
                case EXT_SUBTLV_ADJ_SID:
                        adj_sid = (struct ext_subtlv_adj_sid *)sub_tlvh;
@@ -1025,7 +1032,8 @@ static struct sr_link *get_ext_link_sid(struct tlv_header *tlvh)
 }
 
 /* Extended Prefix SubTLVs Getter */
-static struct sr_prefix *get_ext_prefix_sid(struct tlv_header *tlvh)
+static struct sr_prefix *get_ext_prefix_sid(struct tlv_header *tlvh,
+                                           size_t size)
 {
 
        struct sr_prefix *srp;
@@ -1035,13 +1043,20 @@ static struct sr_prefix *get_ext_prefix_sid(struct tlv_header *tlvh)
        struct tlv_header *sub_tlvh;
        uint16_t length = 0, sum = 0;
 
+       /* Check TLV size */
+       if ((ntohs(tlvh->length) > size)
+           || ntohs(tlvh->length) < EXT_TLV_PREFIX_SIZE) {
+               zlog_warn("Wrong Extended Link TLV size. Abort!");
+               return NULL;
+       }
+
        srp = XCALLOC(MTYPE_OSPF_SR_PARAMS, sizeof(struct sr_prefix));
 
        /* Initialize TLV browsing */
        length = ntohs(tlvh->length) - EXT_TLV_PREFIX_SIZE;
        sub_tlvh = (struct tlv_header *)((char *)(tlvh) + TLV_HDR_SIZE
                                         + EXT_TLV_PREFIX_SIZE);
-       for (; sum < length; sub_tlvh = TLV_HDR_NEXT(sub_tlvh)) {
+       for (; sum < length && sub_tlvh; sub_tlvh = TLV_HDR_NEXT(sub_tlvh)) {
                switch (ntohs(sub_tlvh->type)) {
                case EXT_SUBTLV_PREFIX_SID:
                        psid = (struct ext_subtlv_prefix_sid *)sub_tlvh;
@@ -1353,7 +1368,7 @@ void ospf_sr_ri_lsa_update(struct ospf_lsa *lsa)
 
        /* Collect Router Information Sub TLVs */
        /* Initialize TLV browsing */
-       length = ntohs(lsah->length) - OSPF_LSA_HEADER_SIZE;
+       length = lsa->size - OSPF_LSA_HEADER_SIZE;
        srgb.range_size = 0;
        srgb.lower_bound = 0;
 
@@ -1362,24 +1377,20 @@ void ospf_sr_ri_lsa_update(struct ospf_lsa *lsa)
                switch (ntohs(tlvh->type)) {
                case RI_SR_TLV_SR_ALGORITHM:
                        algo = (struct ri_sr_tlv_sr_algorithm *)tlvh;
-                       sum += TLV_SIZE(tlvh);
                        break;
                case RI_SR_TLV_SRGB_LABEL_RANGE:
                        ri_srgb = (struct ri_sr_tlv_sid_label_range *)tlvh;
-                       sum += TLV_SIZE(tlvh);
                        break;
                case RI_SR_TLV_SRLB_LABEL_RANGE:
                        ri_srlb = (struct ri_sr_tlv_sid_label_range *)tlvh;
-                       sum += TLV_SIZE(tlvh);
                        break;
                case RI_SR_TLV_NODE_MSD:
                        msd = ((struct ri_sr_tlv_node_msd *)(tlvh))->value;
-                       sum += TLV_SIZE(tlvh);
                        break;
                default:
-                       sum += TLV_SIZE(tlvh);
                        break;
                }
+               sum += TLV_SIZE(tlvh);
        }
 
        /* Check if Segment Routing Capabilities has been found */
@@ -1519,7 +1530,7 @@ void ospf_sr_ext_link_lsa_update(struct ospf_lsa *lsa)
        struct lsa_header *lsah = lsa->data;
        struct sr_link *srl;
 
-       uint16_t length, sum;
+       int length;
 
        osr_debug("SR (%s): Process Extended Link LSA 8.0.0.%u from %pI4",
                  __func__, GET_OPAQUE_ID(ntohl(lsah->id.s_addr)),
@@ -1546,20 +1557,19 @@ void ospf_sr_ext_link_lsa_update(struct ospf_lsa *lsa)
        }
 
        /* Initialize TLV browsing */
-       length = ntohs(lsah->length) - OSPF_LSA_HEADER_SIZE;
-       sum = 0;
-       for (tlvh = TLV_HDR_TOP(lsah); (sum < length) && (tlvh != NULL);
+       length = lsa->size - OSPF_LSA_HEADER_SIZE;
+       for (tlvh = TLV_HDR_TOP(lsah); length > 0 && tlvh;
             tlvh = TLV_HDR_NEXT(tlvh)) {
                if (ntohs(tlvh->type) == EXT_TLV_LINK) {
                        /* Got Extended Link information */
-                       srl = get_ext_link_sid(tlvh);
+                       srl = get_ext_link_sid(tlvh, length);
                        /* Update SID if not null */
                        if (srl != NULL) {
                                srl->instance = ntohl(lsah->id.s_addr);
                                update_ext_link_sid(srn, srl, lsa->flags);
                        }
                }
-               sum += TLV_SIZE(tlvh);
+               length -= TLV_SIZE(tlvh);
        }
 }
 
@@ -1753,7 +1763,7 @@ void ospf_sr_ext_prefix_lsa_update(struct ospf_lsa *lsa)
        struct lsa_header *lsah = (struct lsa_header *)lsa->data;
        struct sr_prefix *srp;
 
-       uint16_t length, sum;
+       int length;
 
        osr_debug("SR (%s): Process Extended Prefix LSA 7.0.0.%u from %pI4",
                  __func__, GET_OPAQUE_ID(ntohl(lsah->id.s_addr)),
@@ -1780,20 +1790,19 @@ void ospf_sr_ext_prefix_lsa_update(struct ospf_lsa *lsa)
        }
 
        /* Initialize TLV browsing */
-       length = ntohs(lsah->length) - OSPF_LSA_HEADER_SIZE;
-       sum = 0;
-       for (tlvh = TLV_HDR_TOP(lsah); sum < length;
+       length = lsa->size - OSPF_LSA_HEADER_SIZE;
+       for (tlvh = TLV_HDR_TOP(lsah); length > 0 && tlvh;
             tlvh = TLV_HDR_NEXT(tlvh)) {
                if (ntohs(tlvh->type) == EXT_TLV_LINK) {
                        /* Got Extended Link information */
-                       srp = get_ext_prefix_sid(tlvh);
+                       srp = get_ext_prefix_sid(tlvh, length);
                        /* Update SID if not null */
                        if (srp != NULL) {
                                srp->instance = ntohl(lsah->id.s_addr);
                                update_ext_prefix_sid(srn, srp);
                        }
                }
-               sum += TLV_SIZE(tlvh);
+               length -= TLV_SIZE(tlvh);
        }
 }
 
index ce13457484080071daaa0e8ef8f3e28a5b775920..4ded6ee3b6d33704a9168e35c009253f63d52bb6 100644 (file)
@@ -88,6 +88,7 @@ struct ri_sr_tlv_sr_algorithm {
 /* RI SID/Label Range TLV used for SRGB & SRLB - section 3.2 & 3.3 */
 #define RI_SR_TLV_SRGB_LABEL_RANGE     9
 #define RI_SR_TLV_SRLB_LABEL_RANGE     14
+#define RI_SR_TLV_LABEL_RANGE_SIZE     12
 struct ri_sr_tlv_sid_label_range {
        struct tlv_header header;
 /* Only 24 upper most bits are significant */
@@ -99,6 +100,7 @@ struct ri_sr_tlv_sid_label_range {
 
 /* RI Node/MSD TLV as per RFC 8476 */
 #define RI_SR_TLV_NODE_MSD             12
+#define RI_SR_TLV_NODE_MSD_SIZE                4
 struct ri_sr_tlv_node_msd {
        struct tlv_header header;
        uint8_t subtype; /* always = 1 */
index 1929e3dea40b948fb2cf60c3f72ea7d0be9edac5..0946e510775244f43a3bf3d0f666243c44f4102a 100644 (file)
@@ -1882,7 +1882,7 @@ static int ospf_te_parse_router_lsa(struct ls_ted *ted, struct ospf_lsa *lsa)
        struct ls_edge *edge;
        struct ls_subnet *subnet;
        struct listnode *node;
-       int len;
+       int len, links;
 
        /* Sanity Check */
        if (!ted || !lsa || !lsa->data)
@@ -1932,8 +1932,9 @@ static int ospf_te_parse_router_lsa(struct ls_ted *ted, struct ospf_lsa *lsa)
                subnet->status = ORPHAN;
 
        /* Then, process Link Information */
-       len = ntohs(rl->header.length) - 4;
-       for (int i = 0; i < ntohs(rl->links) && len > 0; len -= 12, i++) {
+       len = lsa->size - OSPF_LSA_HEADER_SIZE - OSPF_ROUTER_LSA_MIN_SIZE;
+       links = ntohs(rl->links);
+       for (int i = 0; i < links && len > 0; len -= 12, i++) {
                struct prefix p;
                uint32_t metric;
 
@@ -2152,20 +2153,20 @@ static int ospf_te_parse_te(struct ls_ted *ted, struct ospf_lsa *lsa)
 
        /* Initialize TLV browsing */
        tlvh = TLV_HDR_TOP(lsa->data);
+       len = lsa->size - OSPF_LSA_HEADER_SIZE;
 
-       uint32_t total_len = TLV_BODY_SIZE(lsa->data) - OSPF_LSA_HEADER_SIZE;
+       /* Check if TE Router-ID TLV is present */
+       if (ntohs(tlvh->type) == TE_TLV_ROUTER_ADDR) {
+               /* if TE Router-ID is alone, we are done ... */
+               if (len == TE_LINK_SUBTLV_DEF_SIZE)
+                       return 0;
 
-       /* If TE Router-ID is only TLV we are done */
-       if (ntohs(tlvh->type) == TE_TLV_ROUTER_ADDR
-           && total_len == sizeof(struct te_tlv_router_addr))
-               return 0;
-
-       /* Skip TE Router-ID if present */
-       if (ntohs(tlvh->type) == TE_TLV_ROUTER_ADDR)
+               /* ... otherwise, skip it */
+               len -= TE_LINK_SUBTLV_DEF_SIZE + TLV_HDR_SIZE;
                tlvh = TLV_HDR_NEXT(tlvh);
+       }
 
-       /* Check if we have a TE Link TLV */
-       len = TLV_BODY_SIZE(tlvh);
+       /* Check if we have a valid TE Link TLV */
        if ((len == 0) || (ntohs(tlvh->type) != TE_TLV_LINK))
                return 0;
 
@@ -2467,8 +2468,9 @@ static int ospf_te_parse_ri(struct ls_ted *ted, struct ospf_lsa *lsa)
                  &lsa->data->id, &node->router_id);
 
        /* Initialize TLV browsing */
-       len = ntohs(lsah->length) - OSPF_LSA_HEADER_SIZE;
-       for (tlvh = TLV_HDR_TOP(lsah); sum < len; tlvh = TLV_HDR_NEXT(tlvh)) {
+       len = lsa->size - OSPF_LSA_HEADER_SIZE;
+       for (tlvh = TLV_HDR_TOP(lsah); sum < len && tlvh;
+            tlvh = TLV_HDR_NEXT(tlvh)) {
                struct ri_sr_tlv_sr_algorithm *algo;
                struct ri_sr_tlv_sid_label_range *range;
                struct ri_sr_tlv_node_msd *msd;
@@ -3152,11 +3154,25 @@ static void ospf_te_init_ted(struct ls_ted *ted, struct ospf *ospf)
 /*------------------------------------------------------------------------*
  * Followings are vty session control functions.
  *------------------------------------------------------------------------*/
+#define check_tlv_size(size, msg)                                              \
+       do {                                                                   \
+               if (ntohs(tlvh->length) > size) {                              \
+                       if (vty != NULL)                                       \
+                               vty_out(vty, "  Wrong %s TLV size: %d(%d)\n",  \
+                                       msg, ntohs(tlvh->length), size);       \
+                       else                                                   \
+                               zlog_debug("    Wrong %s TLV size: %d(%d)\n",  \
+                                          msg, ntohs(tlvh->length), size);    \
+                       return size + TLV_HDR_SIZE;                            \
+               }                                                              \
+       } while(0)
 
 static uint16_t show_vty_router_addr(struct vty *vty, struct tlv_header *tlvh)
 {
        struct te_tlv_router_addr *top = (struct te_tlv_router_addr *)tlvh;
 
+       check_tlv_size(TE_LINK_SUBTLV_DEF_SIZE, "Router Address");
+
        if (vty != NULL)
                vty_out(vty, "  Router-Address: %pI4\n", &top->value);
        else
@@ -3165,10 +3181,23 @@ static uint16_t show_vty_router_addr(struct vty *vty, struct tlv_header *tlvh)
        return TLV_SIZE(tlvh);
 }
 
-static uint16_t show_vty_link_header(struct vty *vty, struct tlv_header *tlvh)
+static uint16_t show_vty_link_header(struct vty *vty, struct tlv_header *tlvh,
+                                    size_t buf_size)
 {
        struct te_tlv_link *top = (struct te_tlv_link *)tlvh;
 
+       if (TLV_SIZE(tlvh) > buf_size) {
+               if (vty != NULL)
+                       vty_out(vty,
+                               "    TLV size %d exceeds buffer size. Abort!",
+                               TLV_SIZE(tlvh));
+               else
+                       zlog_debug(
+                               "    TLV size %d exceeds buffer size. Abort!",
+                               TLV_SIZE(tlvh));
+               return buf_size;
+       }
+
        if (vty != NULL)
                vty_out(vty, "  Link: %u octets of data\n",
                        ntohs(top->header.length));
@@ -3185,6 +3214,8 @@ static uint16_t show_vty_link_subtlv_link_type(struct vty *vty,
        struct te_link_subtlv_link_type *top;
        const char *cp = "Unknown";
 
+       check_tlv_size(TE_LINK_SUBTLV_TYPE_SIZE, "Link Type");
+
        top = (struct te_link_subtlv_link_type *)tlvh;
        switch (top->link_type.value) {
        case LINK_TYPE_SUBTLV_VALUE_PTP:
@@ -3211,6 +3242,8 @@ static uint16_t show_vty_link_subtlv_link_id(struct vty *vty,
 {
        struct te_link_subtlv_link_id *top;
 
+       check_tlv_size(TE_LINK_SUBTLV_DEF_SIZE, "Link ID");
+
        top = (struct te_link_subtlv_link_id *)tlvh;
        if (vty != NULL)
                vty_out(vty, "  Link-ID: %pI4\n", &top->value);
@@ -3221,11 +3254,24 @@ static uint16_t show_vty_link_subtlv_link_id(struct vty *vty,
 }
 
 static uint16_t show_vty_link_subtlv_lclif_ipaddr(struct vty *vty,
-                                                 struct tlv_header *tlvh)
+                                                 struct tlv_header *tlvh,
+                                                 size_t buf_size)
 {
        struct te_link_subtlv_lclif_ipaddr *top;
        int i, n;
 
+       if (TLV_SIZE(tlvh) > buf_size) {
+               if (vty != NULL)
+                       vty_out(vty,
+                               "    TLV size %d exceeds buffer size. Abort!",
+                               TLV_SIZE(tlvh));
+               else
+                       zlog_debug(
+                               "    TLV size %d exceeds buffer size. Abort!",
+                               TLV_SIZE(tlvh));
+               return buf_size;
+       }
+
        top = (struct te_link_subtlv_lclif_ipaddr *)tlvh;
        n = ntohs(tlvh->length) / sizeof(top->value[0]);
 
@@ -3244,11 +3290,24 @@ static uint16_t show_vty_link_subtlv_lclif_ipaddr(struct vty *vty,
 }
 
 static uint16_t show_vty_link_subtlv_rmtif_ipaddr(struct vty *vty,
-                                                 struct tlv_header *tlvh)
+                                                 struct tlv_header *tlvh,
+                                                 size_t buf_size)
 {
        struct te_link_subtlv_rmtif_ipaddr *top;
        int i, n;
 
+       if (TLV_SIZE(tlvh) > buf_size) {
+               if (vty != NULL)
+                       vty_out(vty,
+                               "    TLV size %d exceeds buffer size. Abort!",
+                               TLV_SIZE(tlvh));
+               else
+                       zlog_debug(
+                               "    TLV size %d exceeds buffer size. Abort!",
+                               TLV_SIZE(tlvh));
+               return buf_size;
+       }
+
        top = (struct te_link_subtlv_rmtif_ipaddr *)tlvh;
        n = ntohs(tlvh->length) / sizeof(top->value[0]);
        if (vty != NULL)
@@ -3270,6 +3329,8 @@ static uint16_t show_vty_link_subtlv_te_metric(struct vty *vty,
 {
        struct te_link_subtlv_te_metric *top;
 
+       check_tlv_size(TE_LINK_SUBTLV_DEF_SIZE, "TE Metric");
+
        top = (struct te_link_subtlv_te_metric *)tlvh;
        if (vty != NULL)
                vty_out(vty, "  Traffic Engineering Metric: %u\n",
@@ -3287,6 +3348,8 @@ static uint16_t show_vty_link_subtlv_max_bw(struct vty *vty,
        struct te_link_subtlv_max_bw *top;
        float fval;
 
+       check_tlv_size(TE_LINK_SUBTLV_DEF_SIZE, "Maximum Bandwidth");
+
        top = (struct te_link_subtlv_max_bw *)tlvh;
        fval = ntohf(top->value);
 
@@ -3304,6 +3367,8 @@ static uint16_t show_vty_link_subtlv_max_rsv_bw(struct vty *vty,
        struct te_link_subtlv_max_rsv_bw *top;
        float fval;
 
+       check_tlv_size(TE_LINK_SUBTLV_DEF_SIZE, "Maximum Reservable Bandwidth");
+
        top = (struct te_link_subtlv_max_rsv_bw *)tlvh;
        fval = ntohf(top->value);
 
@@ -3324,6 +3389,8 @@ static uint16_t show_vty_link_subtlv_unrsv_bw(struct vty *vty,
        float fval1, fval2;
        int i;
 
+       check_tlv_size(TE_LINK_SUBTLV_UNRSV_SIZE, "Unreserved Bandwidth");
+
        top = (struct te_link_subtlv_unrsv_bw *)tlvh;
        if (vty != NULL)
                vty_out(vty,
@@ -3353,6 +3420,8 @@ static uint16_t show_vty_link_subtlv_rsc_clsclr(struct vty *vty,
 {
        struct te_link_subtlv_rsc_clsclr *top;
 
+       check_tlv_size(TE_LINK_SUBTLV_DEF_SIZE, "Resource class/color");
+
        top = (struct te_link_subtlv_rsc_clsclr *)tlvh;
        if (vty != NULL)
                vty_out(vty, "  Resource class/color: 0x%x\n",
@@ -3369,6 +3438,8 @@ static uint16_t show_vty_link_subtlv_lrrid(struct vty *vty,
 {
        struct te_link_subtlv_lrrid *top;
 
+       check_tlv_size(TE_LINK_SUBTLV_LRRID_SIZE, "Local/Remote Router ID");
+
        top = (struct te_link_subtlv_lrrid *)tlvh;
 
        if (vty != NULL) {
@@ -3391,6 +3462,8 @@ static uint16_t show_vty_link_subtlv_llri(struct vty *vty,
 {
        struct te_link_subtlv_llri *top;
 
+       check_tlv_size(TE_LINK_SUBTLV_LLRI_SIZE, "Link Local/Remote ID");
+
        top = (struct te_link_subtlv_llri *)tlvh;
 
        if (vty != NULL) {
@@ -3413,6 +3486,8 @@ static uint16_t show_vty_link_subtlv_rip(struct vty *vty,
 {
        struct te_link_subtlv_rip *top;
 
+       check_tlv_size(TE_LINK_SUBTLV_DEF_SIZE, "Remote ASBR Address");
+
        top = (struct te_link_subtlv_rip *)tlvh;
 
        if (vty != NULL)
@@ -3430,6 +3505,8 @@ static uint16_t show_vty_link_subtlv_ras(struct vty *vty,
 {
        struct te_link_subtlv_ras *top;
 
+       check_tlv_size(TE_LINK_SUBTLV_DEF_SIZE, "Remote AS number");
+
        top = (struct te_link_subtlv_ras *)tlvh;
 
        if (vty != NULL)
@@ -3449,6 +3526,8 @@ static uint16_t show_vty_link_subtlv_av_delay(struct vty *vty,
        uint32_t delay;
        uint32_t anomalous;
 
+       check_tlv_size(TE_LINK_SUBTLV_DEF_SIZE, "Average Link Delay");
+
        top = (struct te_link_subtlv_av_delay *)tlvh;
        delay = (uint32_t)ntohl(top->value) & TE_EXT_MASK;
        anomalous = (uint32_t)ntohl(top->value) & TE_EXT_ANORMAL;
@@ -3470,6 +3549,8 @@ static uint16_t show_vty_link_subtlv_mm_delay(struct vty *vty,
        uint32_t low, high;
        uint32_t anomalous;
 
+       check_tlv_size(TE_LINK_SUBTLV_MM_DELAY_SIZE, "Min/Max Link Delay");
+
        top = (struct te_link_subtlv_mm_delay *)tlvh;
        low = (uint32_t)ntohl(top->low) & TE_EXT_MASK;
        anomalous = (uint32_t)ntohl(top->low) & TE_EXT_ANORMAL;
@@ -3491,6 +3572,8 @@ static uint16_t show_vty_link_subtlv_delay_var(struct vty *vty,
        struct te_link_subtlv_delay_var *top;
        uint32_t jitter;
 
+       check_tlv_size(TE_LINK_SUBTLV_DEF_SIZE, "Link Delay Variation");
+
        top = (struct te_link_subtlv_delay_var *)tlvh;
        jitter = (uint32_t)ntohl(top->value) & TE_EXT_MASK;
 
@@ -3510,6 +3593,8 @@ static uint16_t show_vty_link_subtlv_pkt_loss(struct vty *vty,
        uint32_t anomalous;
        float fval;
 
+       check_tlv_size(TE_LINK_SUBTLV_DEF_SIZE, "Link Loss");
+
        top = (struct te_link_subtlv_pkt_loss *)tlvh;
        loss = (uint32_t)ntohl(top->value) & TE_EXT_MASK;
        fval = (float)(loss * LOSS_PRECISION);
@@ -3531,6 +3616,8 @@ static uint16_t show_vty_link_subtlv_res_bw(struct vty *vty,
        struct te_link_subtlv_res_bw *top;
        float fval;
 
+       check_tlv_size(TE_LINK_SUBTLV_DEF_SIZE, "Residual Bandwidth");
+
        top = (struct te_link_subtlv_res_bw *)tlvh;
        fval = ntohf(top->value);
 
@@ -3552,6 +3639,8 @@ static uint16_t show_vty_link_subtlv_ava_bw(struct vty *vty,
        struct te_link_subtlv_ava_bw *top;
        float fval;
 
+       check_tlv_size(TE_LINK_SUBTLV_DEF_SIZE, "Available Bandwidth");
+
        top = (struct te_link_subtlv_ava_bw *)tlvh;
        fval = ntohf(top->value);
 
@@ -3573,6 +3662,8 @@ static uint16_t show_vty_link_subtlv_use_bw(struct vty *vty,
        struct te_link_subtlv_use_bw *top;
        float fval;
 
+       check_tlv_size(TE_LINK_SUBTLV_DEF_SIZE, "Utilized Bandwidth");
+
        top = (struct te_link_subtlv_use_bw *)tlvh;
        fval = ntohf(top->value);
 
@@ -3588,8 +3679,21 @@ static uint16_t show_vty_link_subtlv_use_bw(struct vty *vty,
        return TLV_SIZE(tlvh);
 }
 
-static uint16_t show_vty_unknown_tlv(struct vty *vty, struct tlv_header *tlvh)
+static uint16_t show_vty_unknown_tlv(struct vty *vty, struct tlv_header *tlvh,
+                                    size_t buf_size)
 {
+       if (TLV_SIZE(tlvh) > buf_size) {
+               if (vty != NULL)
+                       vty_out(vty,
+                               "    TLV size %d exceeds buffer size. Abort!",
+                               TLV_SIZE(tlvh));
+               else
+                       zlog_debug(
+                               "    TLV size %d exceeds buffer size. Abort!",
+                               TLV_SIZE(tlvh));
+               return buf_size;
+       }
+
        if (vty != NULL)
                vty_out(vty, "  Unknown TLV: [type(0x%x), length(0x%x)]\n",
                        ntohs(tlvh->type), ntohs(tlvh->length));
@@ -3607,8 +3711,7 @@ static uint16_t ospf_mpls_te_show_link_subtlv(struct vty *vty,
        struct tlv_header *tlvh;
        uint16_t sum = subtotal;
 
-       for (tlvh = tlvh0; sum < total;
-            tlvh = TLV_HDR_NEXT(tlvh)) {
+       for (tlvh = tlvh0; sum < total; tlvh = TLV_HDR_NEXT(tlvh)) {
                switch (ntohs(tlvh->type)) {
                case TE_LINK_SUBTLV_LINK_TYPE:
                        sum += show_vty_link_subtlv_link_type(vty, tlvh);
@@ -3617,10 +3720,12 @@ static uint16_t ospf_mpls_te_show_link_subtlv(struct vty *vty,
                        sum += show_vty_link_subtlv_link_id(vty, tlvh);
                        break;
                case TE_LINK_SUBTLV_LCLIF_IPADDR:
-                       sum += show_vty_link_subtlv_lclif_ipaddr(vty, tlvh);
+                       sum += show_vty_link_subtlv_lclif_ipaddr(vty, tlvh,
+                                                                total - sum);
                        break;
                case TE_LINK_SUBTLV_RMTIF_IPADDR:
-                       sum += show_vty_link_subtlv_rmtif_ipaddr(vty, tlvh);
+                       sum += show_vty_link_subtlv_rmtif_ipaddr(vty, tlvh,
+                                                                total - sum);
                        break;
                case TE_LINK_SUBTLV_TE_METRIC:
                        sum += show_vty_link_subtlv_te_metric(vty, tlvh);
@@ -3671,7 +3776,7 @@ static uint16_t ospf_mpls_te_show_link_subtlv(struct vty *vty,
                        sum += show_vty_link_subtlv_use_bw(vty, tlvh);
                        break;
                default:
-                       sum += show_vty_unknown_tlv(vty, tlvh);
+                       sum += show_vty_unknown_tlv(vty, tlvh, total - sum);
                        break;
                }
        }
@@ -3687,9 +3792,9 @@ static void ospf_mpls_te_show_info(struct vty *vty, struct ospf_lsa *lsa)
                            uint16_t subtotal, uint16_t total) = NULL;
 
        sum = 0;
-       total = ntohs(lsah->length) - OSPF_LSA_HEADER_SIZE;
+       total = lsa->size - OSPF_LSA_HEADER_SIZE;
 
-       for (tlvh = TLV_HDR_TOP(lsah); sum < total;
+       for (tlvh = TLV_HDR_TOP(lsah); sum < total && tlvh;
             tlvh = (next ? next : TLV_HDR_NEXT(tlvh))) {
                if (subfunc != NULL) {
                        sum = (*subfunc)(vty, tlvh, sum, total);
@@ -3704,12 +3809,12 @@ static void ospf_mpls_te_show_info(struct vty *vty, struct ospf_lsa *lsa)
                        sum += show_vty_router_addr(vty, tlvh);
                        break;
                case TE_TLV_LINK:
-                       sum += show_vty_link_header(vty, tlvh);
+                       sum += show_vty_link_header(vty, tlvh, total - sum);
                        subfunc = ospf_mpls_te_show_link_subtlv;
                        next = TLV_DATA(tlvh);
                        break;
                default:
-                       sum += show_vty_unknown_tlv(vty, tlvh);
+                       sum += show_vty_unknown_tlv(vty, tlvh, total - sum);
                        break;
                }
        }
@@ -4081,10 +4186,12 @@ static void show_mpls_te_link_sub(struct vty *vty, struct interface *ifp)
                        show_vty_link_subtlv_link_id(vty, &lp->link_id.header);
                if (TLV_TYPE(lp->lclif_ipaddr) != 0)
                        show_vty_link_subtlv_lclif_ipaddr(
-                               vty, &lp->lclif_ipaddr.header);
+                               vty, &lp->lclif_ipaddr.header,
+                               lp->lclif_ipaddr.header.length);
                if (TLV_TYPE(lp->rmtif_ipaddr) != 0)
                        show_vty_link_subtlv_rmtif_ipaddr(
-                               vty, &lp->rmtif_ipaddr.header);
+                               vty, &lp->rmtif_ipaddr.header,
+                               lp->rmtif_ipaddr.header.length);
                if (TLV_TYPE(lp->rip) != 0)
                        show_vty_link_subtlv_rip(vty, &lp->rip.header);
                if (TLV_TYPE(lp->ras) != 0)
index 50943c4ccf0543b5a112e7892c2ec16f7df89da6..04b6bdd9613c7a9cdac603a8eef3a78b9c70f486 100644 (file)
@@ -6400,6 +6400,7 @@ static int show_network_lsa_detail(struct vty *vty, struct ospf_lsa *lsa,
 
        if (lsa != NULL) {
                struct network_lsa *nl = (struct network_lsa *)lsa->data;
+               struct in_addr *addr;
 
                show_ip_ospf_database_header(vty, lsa, json);
 
@@ -6410,24 +6411,25 @@ static int show_network_lsa_detail(struct vty *vty, struct ospf_lsa *lsa,
                        json_object_int_add(json, "networkMask",
                                            ip_masklen(nl->mask));
 
-               length = ntohs(lsa->data->length) - OSPF_LSA_HEADER_SIZE - 4;
-
-               for (i = 0; length > 0; i++, length -= 4)
+               length = lsa->size - OSPF_LSA_HEADER_SIZE - 4;
+               addr = &nl->routers[0];
+               for (i = 0; length > 0 && addr;
+                    length -= 4, addr = &nl->routers[++i])
                        if (!json) {
                                vty_out(vty, "        Attached Router: %pI4\n",
-                                       &nl->routers[i]);
+                                       addr);
                                vty_out(vty, "\n");
                        } else {
                                json_router = json_object_new_object();
                                json_object_string_add(
                                        json_router, "attachedRouterId",
-                                       inet_ntop(AF_INET, &nl->routers[i],
-                                                 buf, sizeof(buf)));
-                               json_object_object_add(
-                                       json_attached_rt,
-                                       inet_ntop(AF_INET, &(nl->routers[i]),
-                                                 buf, sizeof(buf)),
-                                       json_router);
+                                       inet_ntop(AF_INET, addr, buf,
+                                                 sizeof(buf)));
+                               json_object_object_add(json_attached_rt,
+                                                      inet_ntop(AF_INET, addr,
+                                                                buf,
+                                                                sizeof(buf)),
+                                                      json_router);
                        }
        }