diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 808b98e41998..1ed111815059 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -1521,8 +1521,8 @@ bgp_attr_malformed(struct bgp_attr_parser_args *args, uint8_t subcode, case BGP_ATTR_PMSI_TUNNEL: case BGP_ATTR_ENCAP: case BGP_ATTR_OTC: - return BGP_ATTR_PARSE_WITHDRAW; case BGP_ATTR_LINK_STATE: + return BGP_ATTR_PARSE_WITHDRAW; case BGP_ATTR_MP_REACH_NLRI: case BGP_ATTR_MP_UNREACH_NLRI: bgp_notify_send_with_data(peer->connection, @@ -3417,6 +3417,14 @@ bgp_attr_linkstate(struct bgp_attr_parser_args *args) if (STREAM_READABLE(s) == 0) return BGP_ATTR_PARSE_PROCEED; + /* Length check. */ + if (STREAM_READABLE(s) < length) { + flog_err(EC_BGP_ATTR_LEN, + "BGP-LS attribute length is too big [%u]", length); + return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, + args->total); + } + attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_LINK_STATE); bgp_attr_ls = XCALLOC(MTYPE_BGP_ATTR_LS, sizeof(struct bgp_attr_ls)); @@ -4982,10 +4990,21 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer, } /* BGP Link-State */ - if (attr->link_state) { - stream_putc(s, BGP_ATTR_FLAG_OPTIONAL); + if (attr->link_state && + attr->link_state->length < peer->max_packet_size) { + uint8_t flags = BGP_ATTR_FLAG_OPTIONAL; + + if (attr->link_state->length > 255) + SET_FLAG(flags, BGP_ATTR_FLAG_EXTLEN); + + stream_putc(s, flags); stream_putc(s, BGP_ATTR_LINK_STATE); - stream_putc(s, attr->link_state->length); + + if (CHECK_FLAG(flags, BGP_ATTR_FLAG_EXTLEN)) + stream_putw(s, attr->link_state->length); + else + stream_putc(s, attr->link_state->length); + stream_put(s, attr->link_state->data, attr->link_state->length); } diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index e637b0efbfd3..817895fdaaae 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -139,7 +139,7 @@ struct bgp_attr_srv6_l3vpn { struct bgp_attr_ls { unsigned long refcnt; - uint8_t length; + uint16_t length; void *data; };