diff --git a/ospfd/ospf_api.c b/ospfd/ospf_api.c index 7e7236a3b6..81de882754 100644 --- a/ospfd/ospf_api.c +++ b/ospfd/ospf_api.c @@ -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; diff --git a/ospfd/ospf_api.h b/ospfd/ospf_api.h index 0fc683a5db..c20284aed5 100644 --- a/ospfd/ospf_api.h +++ b/ospfd/ospf_api.h @@ -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, diff --git a/ospfd/ospf_apiserver.c b/ospfd/ospf_apiserver.c index c01ecdd1d4..cbd03441ef 100644 --- a/ospfd/ospf_apiserver.c +++ b/ospfd/ospf_apiserver.c @@ -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); diff --git a/ospfd/ospf_dump.c b/ospfd/ospf_dump.c index 8f31f90346..e490070d03 100644 --- a/ospfd/ospf_dump.c +++ b/ospfd/ospf_dump.c @@ -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; - nl = (struct network_lsa *)stream_pnt(s); - cnt = (ntohs(nl->header.length) - (OSPF_LSA_HEADER_SIZE + 4)) / 4; - zlog_debug(" Network-LSA"); + + nl = (struct network_lsa *)stream_pnt(s); + cnt = (length - (OSPF_LSA_HEADER_SIZE + 4)) / 4; + /* 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--; } diff --git a/ospfd/ospf_ext.c b/ospfd/ospf_ext.c index 754e2bcbab..2d08eeece2 100644 --- a/ospfd/ospf_ext.c +++ b/ospfd/ospf_ext.c @@ -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; } } diff --git a/ospfd/ospf_gr_helper.c b/ospfd/ospf_gr_helper.c index d818878cf5..a25057a27f 100644 --- a/ospfd/ospf_gr_helper.c +++ b/ospfd/ospf_gr_helper.c @@ -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) { diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index 6e9df77fb8..72dc699bd9 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -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; diff --git a/ospfd/ospf_lsa.h b/ospfd/ospf_lsa.h index 3c1f94e628..3808700ccc 100644 --- a/ospfd/ospf_lsa.h +++ b/ospfd/ospf_lsa.h @@ -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; diff --git a/ospfd/ospf_opaque.c b/ospfd/ospf_opaque.c index ae9ab48d4a..42bf914f67 100644 --- a/ospfd/ospf_opaque.c +++ b/ospfd/ospf_opaque.c @@ -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; } diff --git a/ospfd/ospf_opaque.h b/ospfd/ospf_opaque.h index c63b8ebdaf..7d401c3dcc 100644 --- a/ospfd/ospf_opaque.h +++ b/ospfd/ospf_opaque.h @@ -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)) /* diff --git a/ospfd/ospf_ri.c b/ospfd/ospf_ri.c index 4083ea9332..c87a00a0d4 100644 --- a/ospfd/ospf_ri.c +++ b/ospfd/ospf_ri.c @@ -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; } } diff --git a/ospfd/ospf_ri.h b/ospfd/ospf_ri.h index 4729677bca..bbad896280 100644 --- a/ospfd/ospf_ri.h +++ b/ospfd/ospf_ri.h @@ -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 diff --git a/ospfd/ospf_sr.c b/ospfd/ospf_sr.c index d003f3bf7c..3ce177618f 100644 --- a/ospfd/ospf_sr.c +++ b/ospfd/ospf_sr.c @@ -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); } } diff --git a/ospfd/ospf_sr.h b/ospfd/ospf_sr.h index ce13457484..4ded6ee3b6 100644 --- a/ospfd/ospf_sr.h +++ b/ospfd/ospf_sr.h @@ -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 */ diff --git a/ospfd/ospf_te.c b/ospfd/ospf_te.c index 1929e3dea4..0946e51077 100644 --- a/ospfd/ospf_te.c +++ b/ospfd/ospf_te.c @@ -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) diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 50943c4ccf..04b6bdd961 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -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); } }