diff --git a/ospfd/ospf_sr.c b/ospfd/ospf_sr.c index fefb177937fd..9a7c4f92c763 100644 --- a/ospfd/ospf_sr.c +++ b/ospfd/ospf_sr.c @@ -987,6 +987,7 @@ static struct sr_link *get_ext_link_sid(struct tlv_header *tlvh, size_t size) struct tlv_header *sub_tlvh; uint32_t length = 0, sum = 0; uint16_t i = 0; + bool error_p = false; /* Check TLV size */ if ((ntohs(tlvh->length) > size) @@ -1012,6 +1013,12 @@ static struct sr_link *get_ext_link_sid(struct tlv_header *tlvh, size_t size) switch (ntohs(sub_tlvh->type)) { case EXT_SUBTLV_ADJ_SID: + /* Validate sub-TLV length */ + if (TLV_BODY_SIZE(sub_tlvh) != EXT_SUBTLV_ADJ_SID_SIZE) { + error_p = true; + break; + } + adj_sid = (struct ext_subtlv_adj_sid *)sub_tlvh; srl->type = ADJ_SID; i = CHECK_FLAG(adj_sid->flags, @@ -1027,6 +1034,12 @@ static struct sr_link *get_ext_link_sid(struct tlv_header *tlvh, size_t size) IPV4_ADDR_COPY(&srl->nhlfe[i].nexthop, &link->link_id); break; case EXT_SUBTLV_LAN_ADJ_SID: + /* Validate sub-TLV length */ + if (TLV_BODY_SIZE(sub_tlvh) != EXT_SUBTLV_LAN_ADJ_SID_SIZE) { + error_p = true; + break; + } + lan_sid = (struct ext_subtlv_lan_adj_sid *)sub_tlvh; srl->type = LAN_ADJ_SID; i = CHECK_FLAG(lan_sid->flags, @@ -1043,6 +1056,12 @@ static struct sr_link *get_ext_link_sid(struct tlv_header *tlvh, size_t size) &lan_sid->neighbor_id); break; case EXT_SUBTLV_RMT_ITF_ADDR: + /* Validate sub-TLV length */ + if (TLV_BODY_SIZE(sub_tlvh) != EXT_SUBTLV_RMT_ITF_ADDR_SIZE) { + error_p = true; + break; + } + rmt_itf = (struct ext_subtlv_rmt_itf_addr *)sub_tlvh; IPV4_ADDR_COPY(&srl->nhlfe[0].nexthop, &rmt_itf->value); IPV4_ADDR_COPY(&srl->nhlfe[1].nexthop, &rmt_itf->value); @@ -1050,11 +1069,24 @@ static struct sr_link *get_ext_link_sid(struct tlv_header *tlvh, size_t size) default: break; } + + if (error_p) + break; + sum += tlv_size; - if (sum < length) - sub_tlvh = TLV_HDR_NEXT(sub_tlvh); + if (sum >= length || ((length - sum) < TLV_HDR_SIZE)) + break; + + sub_tlvh = TLV_HDR_NEXT(sub_tlvh); } + if (error_p) { + zlog_warn("Invalid Extended Link sub-TLV!"); + XFREE(MTYPE_OSPF_SR_PARAMS, srl); + return NULL; + } + + IPV4_ADDR_COPY(&srl->itf_addr, &link->link_data); osr_debug(" |- Found primary %u and backup %u Adj/Lan Sid for %pI4", @@ -1389,10 +1421,22 @@ void ospf_sr_ri_lsa_update(struct ospf_lsa *lsa) struct lsa_header *lsah = lsa->data; struct ri_sr_tlv_sid_label_range *ri_srgb = NULL; struct ri_sr_tlv_sid_label_range *ri_srlb = NULL; - struct ri_sr_tlv_sr_algorithm *algo = NULL; struct sr_block srgb; uint32_t length = 0, sum = 0; uint8_t msd = 0; + bool error_p = false; + int i; + uint8_t *p; + /* Temp struct to copy flex-algo values from a TLV */ + struct algo_s { + uint16_t length; + uint8_t value[ALGORITHM_COUNT]; + } algo = {}; + + if (lsa->size <= OSPF_LSA_HEADER_SIZE) { + zlog_warn("Invalid SR Router-Information LSA"); + return; + } osr_debug("SR (%s): Process Router Information LSA 4.0.0.%u from %pI4", __func__, GET_OPAQUE_ID(ntohl(lsah->id.s_addr)), @@ -1416,6 +1460,11 @@ void ospf_sr_ri_lsa_update(struct ospf_lsa *lsa) /* Collect Router Information Sub TLVs */ /* Initialize TLV browsing */ length = lsa->size - OSPF_LSA_HEADER_SIZE; + if (length <= TLV_HDR_SIZE) { + zlog_warn("Malformed Router-Information TLV"); + return; + } + srgb.range_size = 0; srgb.lower_bound = 0; @@ -1425,28 +1474,80 @@ void ospf_sr_ri_lsa_update(struct ospf_lsa *lsa) if (tlv_size > length - sum) { zlog_warn("Malformed RI TLV size %u (remaining %u)", tlv_size, length - sum); + error_p = true; break; } switch (ntohs(tlvh->type)) { case RI_SR_TLV_SR_ALGORITHM: - algo = (struct ri_sr_tlv_sr_algorithm *)tlvh; + /* Validate sub-TLV length: variable-length, in octets */ + i = ntohs(tlvh->length); + if (i < 1 || i > ALGORITHM_COUNT) { + error_p = true; + break; + } + + /* Must only use first TLV, if multiple are present */ + if (algo.length > 0) + break; + + /* Init algo octets */ + for (i = 0; i < ALGORITHM_COUNT; i++) + algo.value[i] = SR_ALGORITHM_UNSET; + + /* Copy octets from TLV to local buffer. Note that length is + * in host-order. + */ + p = TLV_DATA(tlvh); + algo.length = ntohs(tlvh->length); + for (i = 0; i < algo.length; i++) + algo.value[i] = *(p + i); + break; case RI_SR_TLV_SRGB_LABEL_RANGE: + /* Validate sub-TLV length */ + if (TLV_BODY_SIZE(tlvh) < RI_SR_TLV_LABEL_RANGE_SIZE) { + error_p = true; + break; + } + ri_srgb = (struct ri_sr_tlv_sid_label_range *)tlvh; break; case RI_SR_TLV_SRLB_LABEL_RANGE: + /* Validate sub-TLV length */ + if (TLV_BODY_SIZE(tlvh) < RI_SR_TLV_LABEL_RANGE_SIZE) { + error_p = true; + break; + } + ri_srlb = (struct ri_sr_tlv_sid_label_range *)tlvh; break; case RI_SR_TLV_NODE_MSD: + /* Validate sub-TLV length */ + if (TLV_BODY_SIZE(tlvh) < RI_SR_TLV_NODE_MSD_SIZE) { + error_p = true; + break; + } + msd = ((struct ri_sr_tlv_node_msd *)(tlvh))->value; break; default: break; } + + if (error_p) + break; + sum += tlv_size; - if (sum < length) - tlvh = TLV_HDR_NEXT(tlvh); + if (sum >= length || ((length - sum) < TLV_HDR_SIZE)) + break; + + tlvh = TLV_HDR_NEXT(tlvh); + } + + if (error_p) { + zlog_warn("Invalid RI sub-TLV"); + return; } /* Check if Segment Routing Capabilities has been found */ @@ -1493,16 +1594,15 @@ void ospf_sr_ri_lsa_update(struct ospf_lsa *lsa) } /* Update Algorithm, SRLB and MSD if present */ - if (algo != NULL) { - int i; - for (i = 0; - i < ntohs(algo->header.length) && i < ALGORITHM_COUNT; i++) - srn->algo[i] = algo->value[0]; + if (algo.length > 0) { + for (i = 0; i < algo.length && i < ALGORITHM_COUNT; i++) + srn->algo[i] = algo.value[i]; for (; i < ALGORITHM_COUNT; i++) srn->algo[i] = SR_ALGORITHM_UNSET; } else { srn->algo[0] = SR_ALGORITHM_SPF; } + srn->msd = msd; if (ri_srlb != NULL) { srn->srlb.range_size = GET_RANGE_SIZE(ntohl(ri_srlb->size)); diff --git a/ospfd/ospf_te.c b/ospfd/ospf_te.c index 3787c05ccf49..385db1bda973 100644 --- a/ospfd/ospf_te.c +++ b/ospfd/ospf_te.c @@ -2124,6 +2124,7 @@ static int ospf_te_parse_te(struct ls_ted *ted, struct ospf_lsa *lsa) void *value; uint32_t len, sum; uint8_t lsa_id; + bool error_p = false; /* Initialize Attribute */ attr.adv.origin = OSPFv2; @@ -2131,8 +2132,12 @@ static int ospf_te_parse_te(struct ls_ted *ted, struct ospf_lsa *lsa) if (lsa->data->type != OSPF_OPAQUE_AS_LSA) attr.adv.id.ip.area_id = lsa->area->area_id; + if (lsa->size <= OSPF_LSA_HEADER_SIZE) + return -1; + /* Initialize TLV browsing */ tlvh = TLV_HDR_TOP(lsa->data); + len = lsa->size - OSPF_LSA_HEADER_SIZE; /* Check if TE Router-ID TLV is present */ @@ -2142,7 +2147,13 @@ static int ospf_te_parse_te(struct ls_ted *ted, struct ospf_lsa *lsa) return 0; /* ... otherwise, skip it */ + if (len < (TE_LINK_SUBTLV_DEF_SIZE + TLV_HDR_SIZE) || + TLV_BODY_SIZE(tlvh) != TE_LINK_SUBTLV_DEF_SIZE || + TLV_SIZE(tlvh) > len) + return -1; + len -= TE_LINK_SUBTLV_DEF_SIZE + TLV_HDR_SIZE; + tlvh = TLV_HDR_NEXT(tlvh); } @@ -2162,48 +2173,97 @@ static int ospf_te_parse_te(struct ls_ted *ted, struct ospf_lsa *lsa) if (tlv_size > len - sum) { zlog_warn("Malformed TE sub-TLV size %u (remaining %u)", tlv_size, len - sum); + error_p = true; break; } value = TLV_DATA(tlvh); switch (ntohs(tlvh->type)) { case TE_LINK_SUBTLV_LCLIF_IPADDR: + /* Validate sub-TLV length */ + if (TLV_BODY_SIZE(tlvh) < TE_LINK_SUBTLV_DEF_SIZE) { + error_p = true; + break; + } + memcpy(&addr, value, TE_LINK_SUBTLV_DEF_SIZE); attr.standard.local = addr; SET_FLAG(attr.flags, LS_ATTR_LOCAL_ADDR); break; case TE_LINK_SUBTLV_RMTIF_IPADDR: + /* Validate sub-TLV length */ + if (TLV_BODY_SIZE(tlvh) < TE_LINK_SUBTLV_DEF_SIZE) { + error_p = true; + break; + } + memcpy(&addr, value, TE_LINK_SUBTLV_DEF_SIZE); attr.standard.remote = addr; SET_FLAG(attr.flags, LS_ATTR_NEIGH_ADDR); break; case TE_LINK_SUBTLV_TE_METRIC: + /* Validate sub-TLV length */ + if (TLV_BODY_SIZE(tlvh) < TE_LINK_SUBTLV_DEF_SIZE) { + error_p = true; + break; + } + memcpy(&val32, value, TE_LINK_SUBTLV_DEF_SIZE); attr.standard.te_metric = ntohl(val32); SET_FLAG(attr.flags, LS_ATTR_TE_METRIC); break; case TE_LINK_SUBTLV_MAX_BW: + /* Validate sub-TLV length */ + if (TLV_BODY_SIZE(tlvh) < TE_LINK_SUBTLV_DEF_SIZE) { + error_p = true; + break; + } + memcpy(&valf, value, TE_LINK_SUBTLV_DEF_SIZE); attr.standard.max_bw = ntohf(valf); SET_FLAG(attr.flags, LS_ATTR_MAX_BW); break; case TE_LINK_SUBTLV_MAX_RSV_BW: + /* Validate sub-TLV length */ + if (TLV_BODY_SIZE(tlvh) < TE_LINK_SUBTLV_DEF_SIZE) { + error_p = true; + break; + } + memcpy(&valf, value, TE_LINK_SUBTLV_DEF_SIZE); attr.standard.max_rsv_bw = ntohf(valf); SET_FLAG(attr.flags, LS_ATTR_MAX_RSV_BW); break; case TE_LINK_SUBTLV_UNRSV_BW: + /* Validate sub-TLV length */ + if (TLV_BODY_SIZE(tlvh) < TE_LINK_SUBTLV_UNRSV_SIZE) { + error_p = true; + break; + } + memcpy(tabf, value, TE_LINK_SUBTLV_UNRSV_SIZE); for (int i = 0; i < MAX_CLASS_TYPE; i++) attr.standard.unrsv_bw[i] = ntohf(tabf[i]); SET_FLAG(attr.flags, LS_ATTR_UNRSV_BW); break; case TE_LINK_SUBTLV_RSC_CLSCLR: + /* Validate sub-TLV length */ + if (TLV_BODY_SIZE(tlvh) < TE_LINK_SUBTLV_DEF_SIZE) { + error_p = true; + break; + } + memcpy(&val32, value, TE_LINK_SUBTLV_DEF_SIZE); attr.standard.admin_group = ntohl(val32); SET_FLAG(attr.flags, LS_ATTR_ADM_GRP); break; case TE_LINK_SUBTLV_LLRI: + /* Validate sub-TLV length */ + if (TLV_BODY_SIZE(tlvh) < TE_LINK_SUBTLV_LLRI_SIZE) { + error_p = true; + break; + } + memcpy(tab32, value, TE_LINK_SUBTLV_LLRI_SIZE); attr.standard.local_id = ntohl(tab32[0]); attr.standard.remote_id = ntohl(tab32[1]); @@ -2211,47 +2271,102 @@ static int ospf_te_parse_te(struct ls_ted *ted, struct ospf_lsa *lsa) SET_FLAG(attr.flags, LS_ATTR_NEIGH_ID); break; case TE_LINK_SUBTLV_RIP: + /* Validate sub-TLV length */ + if (TLV_BODY_SIZE(tlvh) < TE_LINK_SUBTLV_DEF_SIZE) { + error_p = true; + break; + } + memcpy(&addr, value, TE_LINK_SUBTLV_DEF_SIZE); attr.standard.remote_addr = addr; SET_FLAG(attr.flags, LS_ATTR_REMOTE_ADDR); break; case TE_LINK_SUBTLV_RAS: + /* Validate sub-TLV length */ + if (TLV_BODY_SIZE(tlvh) < TE_LINK_SUBTLV_DEF_SIZE) { + error_p = true; + break; + } + memcpy(&val32, value, TE_LINK_SUBTLV_DEF_SIZE); attr.standard.remote_as = ntohl(val32); SET_FLAG(attr.flags, LS_ATTR_REMOTE_AS); break; case TE_LINK_SUBTLV_AV_DELAY: + /* Validate sub-TLV length */ + if (TLV_BODY_SIZE(tlvh) < TE_LINK_SUBTLV_DEF_SIZE) { + error_p = true; + break; + } + memcpy(&val32, value, TE_LINK_SUBTLV_DEF_SIZE); attr.extended.delay = ntohl(val32); SET_FLAG(attr.flags, LS_ATTR_DELAY); break; case TE_LINK_SUBTLV_MM_DELAY: + /* Validate sub-TLV length */ + if (TLV_BODY_SIZE(tlvh) < TE_LINK_SUBTLV_MM_DELAY_SIZE) { + error_p = true; + break; + } + memcpy(tab32, value, TE_LINK_SUBTLV_MM_DELAY_SIZE); attr.extended.min_delay = ntohl(tab32[0]); attr.extended.max_delay = ntohl(tab32[1]); SET_FLAG(attr.flags, LS_ATTR_MIN_MAX_DELAY); break; + case TE_LINK_SUBTLV_DELAY_VAR: + /* Validate sub-TLV length */ + if (TLV_BODY_SIZE(tlvh) < TE_LINK_SUBTLV_DEF_SIZE) { + error_p = true; + break; + } + memcpy(&val32, value, TE_LINK_SUBTLV_DEF_SIZE); attr.extended.jitter = ntohl(val32); SET_FLAG(attr.flags, LS_ATTR_JITTER); break; case TE_LINK_SUBTLV_PKT_LOSS: + /* Validate sub-TLV length */ + if (TLV_BODY_SIZE(tlvh) < TE_LINK_SUBTLV_DEF_SIZE) { + error_p = true; + break; + } + memcpy(&val32, value, TE_LINK_SUBTLV_DEF_SIZE); attr.extended.pkt_loss = ntohl(val32); SET_FLAG(attr.flags, LS_ATTR_PACKET_LOSS); break; case TE_LINK_SUBTLV_RES_BW: + /* Validate sub-TLV length */ + if (TLV_BODY_SIZE(tlvh) < TE_LINK_SUBTLV_DEF_SIZE) { + error_p = true; + break; + } + memcpy(&valf, value, TE_LINK_SUBTLV_DEF_SIZE); attr.extended.rsv_bw = ntohf(valf); SET_FLAG(attr.flags, LS_ATTR_RSV_BW); break; case TE_LINK_SUBTLV_AVA_BW: + /* Validate sub-TLV length */ + if (TLV_BODY_SIZE(tlvh) < TE_LINK_SUBTLV_DEF_SIZE) { + error_p = true; + break; + } + memcpy(&valf, value, TE_LINK_SUBTLV_DEF_SIZE); attr.extended.ava_bw = ntohf(valf); SET_FLAG(attr.flags, LS_ATTR_AVA_BW); break; case TE_LINK_SUBTLV_USE_BW: + /* Validate sub-TLV length */ + if (TLV_BODY_SIZE(tlvh) < TE_LINK_SUBTLV_DEF_SIZE) { + error_p = true; + break; + } + memcpy(&valf, value, TE_LINK_SUBTLV_DEF_SIZE); attr.extended.used_bw = ntohf(valf); SET_FLAG(attr.flags, LS_ATTR_USE_BW); @@ -2259,9 +2374,21 @@ static int ospf_te_parse_te(struct ls_ted *ted, struct ospf_lsa *lsa) default: break; } + + if (error_p) + break; + sum += tlv_size; - if (sum < len) - tlvh = TLV_HDR_NEXT(tlvh); + if (sum >= len || ((len - sum) < TLV_HDR_SIZE)) + break; + + tlvh = TLV_HDR_NEXT(tlvh); + } + + /* Error detected during parsing */ + if (error_p) { + zlog_warn("Malformed or invalid TE sub-TLV"); + return -1; } /* Get corresponding Edge from Link State Data Base */ @@ -2384,6 +2511,11 @@ static int ospf_te_delete_te(struct ls_ted *ted, struct ospf_lsa *lsa) } if (ntohs(tlvh->type) == TE_LINK_SUBTLV_LCLIF_IPADDR) { + if (TLV_BODY_SIZE(tlvh) < TE_LINK_SUBTLV_DEF_SIZE) { + zlog_warn("Invalid TE LCLIF sub-TLV"); + return 0; + } + memcpy(&addr, TLV_DATA(tlvh), TE_LINK_SUBTLV_DEF_SIZE); key.family = AF_INET; IPV4_ADDR_COPY(&key.k.addr, &addr); @@ -2467,16 +2599,27 @@ static int ospf_te_parse_ri(struct ls_ted *ted, struct ospf_lsa *lsa) struct lsa_header *lsah = lsa->data; struct tlv_header *tlvh; uint32_t len = 0, sum = 0; + int i; /* Get vertex / Node from LSA Advertised Router ID */ vertex = get_vertex(ted, lsa); node = vertex->node; + if (lsa->size <= OSPF_LSA_HEADER_SIZE) { + zlog_warn("Malformed RI TLV size %zu", lsa->size); + return -1; + } + ote_debug(" |- Process Router Information LSA %pI4 for Vertex %pI4", &lsa->data->id, &node->router_id); /* Initialize TLV browsing */ len = lsa->size - OSPF_LSA_HEADER_SIZE; + if (len <= TLV_HDR_SIZE) { + zlog_warn("Malformed RI TLV"); + return -1; + } + for (tlvh = TLV_HDR_TOP(lsah); sum < len && tlvh;) { uint32_t tlv_size = TLV_SIZE(tlvh); struct ri_sr_tlv_sr_algorithm *algo; @@ -2491,12 +2634,20 @@ static int ospf_te_parse_ri(struct ls_ted *ted, struct ospf_lsa *lsa) switch (ntohs(tlvh->type)) { case RI_SR_TLV_SR_ALGORITHM: - if (TLV_BODY_SIZE(tlvh) < 1 || - TLV_BODY_SIZE(tlvh) > ALGORITHM_COUNT) + /* This is variable-length, in octets */ + i = ntohs(tlvh->length); + if (i < 1 || i > ALGORITHM_COUNT) break; + algo = (struct ri_sr_tlv_sr_algorithm *)tlvh; - for (int i = 0; i < ntohs(algo->header.length); i++) { + /* Note that we're copying algo octets into a struct that has + * its own array size limit - have to respect that limit. + */ + for (i = 0; i < ntohs(algo->header.length); i++) { + if (i >= LIB_LS_SR_ALGO_COUNT) + break; + if (CHECK_FLAG(node->flags, LS_NODE_SR) && (node->algo[i] == algo->value[i])) continue; @@ -2508,7 +2659,7 @@ static int ospf_te_parse_ri(struct ls_ted *ted, struct ospf_lsa *lsa) } /* Reset other Algorithms */ - for (int i = ntohs(algo->header.length); i < 2; i++) { + for (i = ntohs(algo->header.length); i < LIB_LS_SR_ALGO_COUNT; i++) { if (vertex->status != NEW && node->algo[i] != SR_ALGORITHM_UNSET) vertex->status = UPDATE; @@ -2573,17 +2724,23 @@ static int ospf_te_parse_ri(struct ls_ted *ted, struct ospf_lsa *lsa) default: break; } + sum += tlv_size; - if (sum < len) - tlvh = TLV_HDR_NEXT(tlvh); + if (sum >= len || ((len - sum) < TLV_HDR_SIZE)) + break; + + tlvh = TLV_HDR_NEXT(tlvh); } /* Vertex has been created or updated: export it */ if (vertex->status == NEW || vertex->status == UPDATE) { - ote_debug(" |- %s SR info - SRGB[%d/%d] for Vertex %pI4", + ote_debug(" |- %s SRTE info - SRGB[%d/%d] SRLB[%u/%u] MSD[%u] for Vertex %pI4", vertex->status == NEW ? "Add" : "Update", vertex->node->srgb.lower_bound, vertex->node->srgb.range_size, + vertex->node->srlb.lower_bound, + vertex->node->srlb.range_size, + vertex->node->msd, &vertex->node->router_id); ospf_te_export(LS_MSG_TYPE_NODE, vertex); @@ -2654,16 +2811,36 @@ static int ospf_te_parse_ext_pref(struct ls_ted *ted, struct ospf_lsa *lsa) struct ls_subnet *subnet; struct ls_prefix *ls_pref; struct prefix pref; - struct ext_tlv_prefix *ext; + const struct ext_tlv_prefix *ext; struct ext_subtlv_prefix_sid *pref_sid; uint32_t label; uint16_t len, size; + struct tlv_header *tlvh; - /* Get corresponding Subnet from Link State Data Base */ - ext = (struct ext_tlv_prefix *)TLV_HDR_TOP(lsa->data); + /* Initialize TLV browsing */ + if (lsa->size < OSPF_LSA_HEADER_SIZE) { + zlog_warn("Invalid EXT Prefix LSA"); + return -1; + } + + len = lsa->size - OSPF_LSA_HEADER_SIZE; + if (len <= TLV_HDR_SIZE) { + zlog_warn("Malformed EXT Prefix LSA"); + return -1; + } + + tlvh = TLV_HDR_TOP(lsa->data); + if (TLV_BODY_SIZE(tlvh) < EXT_TLV_PREFIX_SIZE) { + zlog_warn("Malformed EXT Prefix TLV"); + return -1; + } + + ext = (const struct ext_tlv_prefix *)tlvh; pref.family = AF_INET; pref.prefixlen = ext->pref_length; pref.u.prefix4 = ext->address; + + /* Get corresponding Subnet from Link State Data Base */ subnet = ls_find_subnet(ted, &pref); /* Create new Link State Prefix if not found */ @@ -2742,13 +2919,32 @@ static int ospf_te_delete_ext_pref(struct ls_ted *ted, struct ospf_lsa *lsa) struct ls_subnet *subnet; struct ls_prefix *ls_pref; struct prefix pref; - struct ext_tlv_prefix *ext; + const struct ext_tlv_prefix *ext; + const struct tlv_header *tlvh; - /* Get corresponding Subnet from Link State Data Base */ - ext = (struct ext_tlv_prefix *)TLV_HDR_TOP(lsa->data); + /* Validate TLV buffer */ + if (lsa->size < OSPF_LSA_HEADER_SIZE) { + zlog_warn("Invalid EXT Prefix LSA"); + return -1; + } + + if ((lsa->size - OSPF_LSA_HEADER_SIZE) <= TLV_HDR_SIZE) { + zlog_warn("Malformed EXT Prefix LSA"); + return -1; + } + + tlvh = TLV_HDR_TOP(lsa->data); + if (TLV_BODY_SIZE(tlvh) < EXT_TLV_PREFIX_SIZE) { + zlog_warn("Malformed EXT Prefix TLV"); + return -1; + } + + ext = (const struct ext_tlv_prefix *)tlvh; pref.family = AF_INET; pref.prefixlen = ext->pref_length; pref.u.prefix4 = ext->address; + + /* Get corresponding Subnet from Link State Data Base */ subnet = ls_find_subnet(ted, &pref); /* Check if there is a corresponding subnet */ @@ -2783,19 +2979,32 @@ static int ospf_te_delete_ext_pref(struct ls_ted *ted, struct ospf_lsa *lsa) static int ospf_te_parse_ext_link(struct ls_ted *ted, struct ospf_lsa *lsa) { struct ls_node_id lnid; - struct tlv_header *tlvh; - struct ext_tlv_link *ext; + const struct tlv_header *tlvh; + const struct ext_tlv_link *ext; struct ls_edge *edge; struct ls_attributes *atr; uint32_t len = 0, sum = 0; uint16_t i; uint32_t label; + /* Validate LSA/TLV */ + if (lsa->size < OSPF_LSA_HEADER_SIZE + TLV_HDR_SIZE + EXT_TLV_LINK_SIZE) { + zlog_warn("Malformed EXT Link LSA"); + return -1; + } + + tlvh = TLV_HDR_TOP(lsa->data); + if (TLV_BODY_SIZE(tlvh) < EXT_TLV_LINK_SIZE) { + zlog_warn("Malformed EXT Link TLV"); + return -1; + } + + ext = (struct ext_tlv_link *)tlvh; + /* Get corresponding Edge from Link State Data Base */ lnid.origin = OSPFv2; lnid.id.ip.addr = lsa->data->adv_router; lnid.id.ip.area_id = lsa->area->area_id; - ext = (struct ext_tlv_link *)TLV_HDR_TOP(lsa->data); edge = get_edge(ted, lnid, ext->link_data); if (!edge) { ote_debug(" |- Found no edge from Extended Link Data. Abort!"); @@ -2946,11 +3155,24 @@ static int ospf_te_delete_ext_link(struct ls_ted *ted, struct ospf_lsa *lsa) { struct ls_edge *edge; struct ls_attributes *atr; - struct ext_tlv_link *ext; + const struct ext_tlv_link *ext; struct ls_edge_key key; + const struct tlv_header *tlvh; + + /* Validate LSA/TLV */ + if (lsa->size < OSPF_LSA_HEADER_SIZE + TLV_HDR_SIZE + EXT_TLV_LINK_SIZE) { + zlog_warn("Malformed EXT Link LSA"); + return -1; + } + + tlvh = TLV_HDR_TOP(lsa->data); + if (TLV_BODY_SIZE(tlvh) < EXT_TLV_LINK_SIZE) { + zlog_warn("Malformed EXT Link TLV"); + return -1; + } /* Search for corresponding Edge from Link State Data Base */ - ext = (struct ext_tlv_link *)TLV_HDR_TOP(lsa->data); + ext = (const struct ext_tlv_link *)tlvh; key.family = AF_INET; IPV4_ADDR_COPY(&key.k.addr, &ext->link_data); edge = ls_find_edge_by_key(ted, key);