From: Martin Buck Date: Fri, 29 Jan 2021 15:40:04 +0000 (+0100) Subject: ospf6d: Fix LSA formatting out-of-bounds access X-Git-Tag: frr-7.5.1~7^2~8 X-Git-Url: https://git.puffer.fish/?a=commitdiff_plain;h=b9611f65a71adc0b8fa14a5a4d1a8f44e04dcd85;p=matthieu%2Ffrr.git ospf6d: Fix LSA formatting out-of-bounds access Check whether full struct ospf6_router_lsdesc/ospf6_prefix is accessible before accessing its contents. Previously, we only checked for the first byte in ospf6_router_lsa_get_nbr_id() or not even that (due to an additional off-by-one error) in ospf6_link_lsa_get_prefix_str() and ospf6_intra_prefix_lsa_get_prefix_str(). Also check *before* accessing the first prefix instead of starting the checks only at the 2nd prefix. The previous code could cause out-of-bounds accesses with valid LSAs in case of ospf6_link_lsa_get_prefix_str() and ospf6_intra_prefix_lsa_get_prefix_str() and with specially crafted LSAs (bad length field) in case of ospf6_router_lsa_get_nbr_id(). Signed-off-by: Martin Buck --- diff --git a/ospf6d/ospf6_intra.c b/ospf6d/ospf6_intra.c index 6a7a7ac751..909b7a6f59 100644 --- a/ospf6d/ospf6_intra.c +++ b/ospf6d/ospf6_intra.c @@ -76,7 +76,8 @@ static char *ospf6_router_lsa_get_nbr_id(struct ospf6_lsa *lsa, char *buf, *)(start + pos * (sizeof(struct ospf6_router_lsdesc))); - if ((char *)lsdesc < end) { + if ((char *)lsdesc + sizeof(struct ospf6_router_lsdesc) + <= end) { if (buf && (buflen > INET_ADDRSTRLEN * 2)) { inet_ntop(AF_INET, &lsdesc->neighbor_interface_id, buf1, @@ -604,7 +605,7 @@ static char *ospf6_link_lsa_get_prefix_str(struct ospf6_lsa *lsa, char *buf, end = (char *)lsa->header + ntohs(lsa->header->length); current = start; - do { + while (current + sizeof(struct ospf6_prefix) <= end) { prefix = (struct ospf6_prefix *)current; if (prefix->prefix_length == 0 || current + OSPF6_PREFIX_SIZE(prefix) > end) { @@ -622,7 +623,7 @@ static char *ospf6_link_lsa_get_prefix_str(struct ospf6_lsa *lsa, char *buf, inet_ntop(AF_INET6, &in6, buf, buflen); return (buf); } - } while (current <= end); + } } return NULL; } @@ -805,7 +806,7 @@ static char *ospf6_intra_prefix_lsa_get_prefix_str(struct ospf6_lsa *lsa, end = (char *)lsa->header + ntohs(lsa->header->length); current = start; - do { + while (current + sizeof(struct ospf6_prefix) <= end) { prefix = (struct ospf6_prefix *)current; if (prefix->prefix_length == 0 || current + OSPF6_PREFIX_SIZE(prefix) > end) { @@ -825,7 +826,7 @@ static char *ospf6_intra_prefix_lsa_get_prefix_str(struct ospf6_lsa *lsa, prefix->prefix_length); return (buf); } - } while (current <= end); + } } return NULL; }