Skip to content

Commit b63d16f

Browse files
authored
Merge pull request #22056 from opensourcerouting/fix/bgp_issue_22043
bgpd: Fix stack overflow when debug printing label information & BMP code
2 parents 531b2db + 08ebbd8 commit b63d16f

6 files changed

Lines changed: 44 additions & 14 deletions

File tree

bgpd/bgp_bmp.c

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1106,7 +1106,15 @@ static struct stream *bmp_update(const struct prefix *p, struct prefix_rd *prd,
11061106

11071107
bpacket_attr_vec_arr_reset(&vecarr);
11081108

1109-
s = stream_new(BGP_MAX_PACKET_SIZE);
1109+
/*
1110+
* Use an expandable stream so that an oversized re-encoded UPDATE
1111+
* (large unknown-transitive attribute plus route-map additions) does
1112+
* not silently truncate via CHECK_SIZE or assert in stream_put_prefix.
1113+
* The on-wire UPDATE inside a BMP Route-Monitoring message must still
1114+
* fit BGP's 16-bit length field, so we drop the route if the encoded
1115+
* size exceeds BGP_MAX_PACKET_SIZE.
1116+
*/
1117+
s = stream_new_expandable(BGP_MAX_PACKET_SIZE);
11101118
bgp_packet_set_marker(s, BGP_MSG_UPDATE);
11111119

11121120
/* 2: withdrawn routes length */
@@ -1120,8 +1128,6 @@ static struct stream *bmp_update(const struct prefix *p, struct prefix_rd *prd,
11201128
total_attr_len = bgp_packet_attribute(NULL, peer, s, attr, &vecarr, NULL, afi, safi, peer,
11211129
NULL, NULL, 0, 0, 0, 0, NULL, NULL);
11221130

1123-
/* space check? */
1124-
11251131
/* peer_cap_enhe & add-path removed */
11261132
if (afi == AFI_IP && safi == SAFI_UNICAST)
11271133
stream_put_prefix(s, p);
@@ -1137,6 +1143,13 @@ static struct stream *bmp_update(const struct prefix *p, struct prefix_rd *prd,
11371143
total_attr_len += stream_get_endp(s) - p1;
11381144
}
11391145

1146+
if (stream_get_endp(s) > BGP_MAX_PACKET_SIZE) {
1147+
zlog_warn("bmp: skipping route-monitoring for %pFX: re-encoded UPDATE exceeds %u bytes",
1148+
p, BGP_MAX_PACKET_SIZE);
1149+
stream_free(s);
1150+
return NULL;
1151+
}
1152+
11401153
/* set the total attribute length correctly */
11411154
stream_putw_at(s, attrlen_pos, total_attr_len);
11421155
bgp_packet_set_size(s);
@@ -1152,7 +1165,7 @@ static struct stream *bmp_withdraw(const struct prefix *p,
11521165
bgp_size_t total_attr_len = 0;
11531166
bgp_size_t unfeasible_len;
11541167

1155-
s = stream_new(BGP_MAX_PACKET_SIZE);
1168+
s = stream_new_expandable(BGP_MAX_PACKET_SIZE);
11561169

11571170
bgp_packet_set_marker(s, BGP_MSG_UPDATE);
11581171
stream_putw(s, 0);
@@ -1179,6 +1192,13 @@ static struct stream *bmp_withdraw(const struct prefix *p,
11791192
stream_putw_at(s, attrlen_pos, total_attr_len);
11801193
}
11811194

1195+
if (stream_get_endp(s) > BGP_MAX_PACKET_SIZE) {
1196+
zlog_warn("bmp: skipping route-monitoring withdraw for %pFX: encoded UPDATE exceeds %u bytes",
1197+
p, BGP_MAX_PACKET_SIZE);
1198+
stream_free(s);
1199+
return NULL;
1200+
}
1201+
11821202
bgp_packet_set_size(s);
11831203
return s;
11841204
}
@@ -1208,6 +1228,9 @@ static void bmp_monitor(struct bmp *bmp, struct peer *peer, uint8_t flags,
12081228
else
12091229
msg = bmp_withdraw(p, prd, afi, safi);
12101230

1231+
if (!msg)
1232+
return;
1233+
12111234
hdr = stream_new(BGP_MAX_PACKET_SIZE);
12121235
bmp_common_hdr(hdr, BMP_VERSION_3, BMP_TYPE_ROUTE_MONITORING);
12131236
bmp_per_peer_hdr(hdr, peer->bgp, peer, flags, peer_type_flag, peer_distinguisher,

bgpd/bgp_debug.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2951,7 +2951,7 @@ const char *bgp_debug_rdpfxpath2str(afi_t afi, safi_t safi,
29512951
struct bgp_route_evpn *overlay_index,
29522952
char *str, int size)
29532953
{
2954-
char tag_buf[30];
2954+
char tag_buf[sizeof(" label ") + BGP_MAX_LABEL_DIGITS];
29552955
char overlay_index_buf[INET6_ADDRSTRLEN + 14];
29562956
const struct prefix_evpn *evp;
29572957
int len = 0;

bgpd/bgp_label.c

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -681,24 +681,30 @@ char *mpls_labels2str(mpls_label_t *labels, uint8_t num_labels, const char *pref
681681
int size)
682682
{
683683
uint32_t label_value;
684-
uint32_t len = 0;
684+
int len = 0;
685+
int ret;
685686
uint8_t i;
686687

688+
if (size <= 0)
689+
return buf;
690+
687691
buf[0] = '\0';
688692
if (!num_labels)
689693
return buf;
690694

691695
if (prefix) {
692-
strlcat(buf + len, prefix, size - len);
696+
strlcat(buf, prefix, size);
693697
len = strlen(buf);
698+
if (len >= size - 1)
699+
return buf;
694700
}
695701

696-
label_value = decode_label(&labels[0]);
697-
len += snprintf(buf + len, size - len, "%u", label_value);
698-
699-
for (i = 1; i < num_labels; i++) {
702+
for (i = 0; i < num_labels; i++) {
700703
label_value = decode_label(&labels[i]);
701-
len += snprintf(buf + len, size - len, "/%u", label_value);
704+
ret = snprintf(buf + len, size - len, "%s%u", i == 0 ? "" : "/", label_value);
705+
if (ret < 0 || ret >= size - len)
706+
return buf;
707+
len += ret;
702708
}
703709

704710
return buf;

bgpd/bgp_label.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ struct peer;
2323
* It is impossible to pass more than 10 labels by BGP-LU
2424
*/
2525
#define BGP_MAX_LABELS 10
26+
#define BGP_MAX_LABEL_DIGITS (9 * BGP_MAX_LABELS)
2627

2728
/* MPLS label(s) - VNI(s) for EVPN-VxLAN */
2829
struct bgp_labels {

bgpd/bgp_route.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12436,7 +12436,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
1243612436
struct attr *pattr, uint16_t show_opts)
1243712437
{
1243812438
char buf[INET6_ADDRSTRLEN];
12439-
char labels_buf[9 * BGP_MAX_LABELS]; /* 8 per label + / or \0 for each */
12439+
char labels_buf[BGP_MAX_LABEL_DIGITS]; /* 8 per label + / or \0 for each */
1244012440
char vni_buf[30] = {};
1244112441
struct attr *attr = pattr ? pattr : path->attr;
1244212442
time_t tbuf;

bgpd/bgp_zebra.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1545,7 +1545,7 @@ static void bgp_debug_zebra_nh(struct zapi_route *api)
15451545
char eth_buf[ETHER_ADDR_STRLEN + 7] = { '\0' };
15461546
char buf1[ETHER_ADDR_STRLEN];
15471547
/* strlen("label ") + 8 chars per label + '/' or '\0' for each label */
1548-
char label_buf[6 + 9 * BGP_MAX_LABELS];
1548+
char label_buf[6 + BGP_MAX_LABEL_DIGITS];
15491549
char sid_buf[20];
15501550
char segs_buf[256];
15511551
struct zapi_nexthop *api_nh;

0 commit comments

Comments
 (0)