Skip to content

Commit 7edaa88

Browse files
authored
Merge pull request FRRouting#20811 from FRRouting/mergify/bp/stable/10.1/pr-20796
bgpd: validate incoming NOTIFICATION messages (backport FRRouting#20796)
2 parents 8fa0701 + 843d128 commit 7edaa88

File tree

3 files changed

+39
-16
lines changed

3 files changed

+39
-16
lines changed

bgpd/bgp_debug.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -545,7 +545,7 @@ const char *bgp_notify_admin_message(char *buf, size_t bufsz, uint8_t *data,
545545
}
546546

547547
/* dump notify packet */
548-
void bgp_notify_print(struct peer *peer, struct bgp_notify *bgp_notify,
548+
void bgp_notify_print(const struct peer *peer, const struct bgp_notify *bgp_notify,
549549
const char *direct, bool hard_reset)
550550
{
551551
const char *subcode_str;

bgpd/bgp_debug.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ extern bool bgp_dump_attr(struct attr *attr, char *buf, size_t size);
162162
extern bool bgp_debug_peer_updout_enabled(char *host);
163163
extern const char *bgp_notify_code_str(char code);
164164
extern const char *bgp_notify_subcode_str(char code, char subcode);
165-
extern void bgp_notify_print(struct peer *peer, struct bgp_notify *bgp_notify,
165+
extern void bgp_notify_print(const struct peer *peer, const struct bgp_notify *bgp_notify,
166166
const char *direct, bool hard_reset);
167167

168168
extern const struct message bgp_status_msg[];

bgpd/bgp_packet.c

Lines changed: 37 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -820,13 +820,19 @@ struct bgp_notify bgp_notify_decapsulate_hard_reset(struct bgp_notify *notify)
820820
{
821821
struct bgp_notify bn = {};
822822

823+
/* Validate inner length */
824+
if (notify->length < 2)
825+
goto done;
826+
823827
bn.code = notify->raw_data[0];
824828
bn.subcode = notify->raw_data[1];
825829
bn.length = notify->length - 2;
830+
if (bn.length > 0) {
831+
bn.raw_data = XMALLOC(MTYPE_BGP_NOTIFICATION, bn.length);
832+
memcpy(bn.raw_data, notify->raw_data + 2, bn.length);
833+
}
826834

827-
bn.raw_data = XMALLOC(MTYPE_BGP_NOTIFICATION, bn.length);
828-
memcpy(bn.raw_data, notify->raw_data + 2, bn.length);
829-
835+
done:
830836
return bn;
831837
}
832838

@@ -2515,6 +2521,14 @@ static int bgp_notify_receive(struct peer_connection *connection,
25152521
struct bgp_notify inner = {};
25162522
bool hard_reset = false;
25172523

2524+
/* Validate message size */
2525+
if (size < 2) {
2526+
flog_err(EC_BGP_NOTIFY_RCV,
2527+
"%s [Error] Notify packet error (packet length is short)",
2528+
peer->host);
2529+
return BGP_Stop;
2530+
}
2531+
25182532
if (peer->notify.data) {
25192533
XFREE(MTYPE_BGP_NOTIFICATION, peer->notify.data);
25202534
peer->notify.length = 0;
@@ -2526,16 +2540,24 @@ static int bgp_notify_receive(struct peer_connection *connection,
25262540
outer.length = size - 2;
25272541
outer.data = NULL;
25282542
outer.raw_data = NULL;
2529-
if (outer.length) {
2543+
if (outer.length > 0) {
25302544
outer.raw_data = XMALLOC(MTYPE_BGP_NOTIFICATION, outer.length);
25312545
memcpy(outer.raw_data, stream_pnt(peer->curr), outer.length);
25322546
}
25332547

25342548
hard_reset =
25352549
bgp_notify_received_hard_reset(peer, outer.code, outer.subcode);
2536-
if (hard_reset && outer.length) {
2537-
inner = bgp_notify_decapsulate_hard_reset(&outer);
2550+
if (hard_reset) {
2551+
/* Hard reset treatment: we expect but don't require inner error codes */
25382552
peer->notify.hard_reset = true;
2553+
/* If we have at least an inner code and subcode, capture them */
2554+
if (outer.length > 1) {
2555+
inner = bgp_notify_decapsulate_hard_reset(&outer);
2556+
} else {
2557+
inner = outer;
2558+
inner.length = 0;
2559+
inner.raw_data = NULL;
2560+
}
25392561
} else {
25402562
inner = outer;
25412563
}
@@ -2544,7 +2566,7 @@ static int bgp_notify_receive(struct peer_connection *connection,
25442566
peer->notify.code = inner.code;
25452567
peer->notify.subcode = inner.subcode;
25462568
/* For further diagnostic record returned Data. */
2547-
if (inner.length) {
2569+
if (inner.length > 0) {
25482570
peer->notify.length = inner.length;
25492571
peer->notify.data =
25502572
XMALLOC(MTYPE_BGP_NOTIFICATION, inner.length);
@@ -2557,7 +2579,7 @@ static int bgp_notify_receive(struct peer_connection *connection,
25572579
int first = 0;
25582580
char c[4];
25592581

2560-
if (inner.length) {
2582+
if (inner.length > 0) {
25612583
inner.data = XMALLOC(MTYPE_BGP_NOTIFICATION,
25622584
inner.length * 3);
25632585
for (i = 0; i < inner.length; i++)
@@ -2579,19 +2601,20 @@ static int bgp_notify_receive(struct peer_connection *connection,
25792601
}
25802602

25812603
bgp_notify_print(peer, &inner, "received", hard_reset);
2582-
if (inner.length) {
2604+
if (inner.length > 0) {
25832605
XFREE(MTYPE_BGP_NOTIFICATION, inner.data);
25842606
inner.length = 0;
25852607
}
2586-
if (outer.length) {
2587-
XFREE(MTYPE_BGP_NOTIFICATION, outer.data);
2588-
XFREE(MTYPE_BGP_NOTIFICATION, outer.raw_data);
2589-
2608+
if (outer.length > 0) {
25902609
/* If this is a Hard Reset notification, we MUST free
25912610
* the inner (encapsulated) notification too.
25922611
*/
2593-
if (hard_reset)
2612+
if (hard_reset && (inner.raw_data != outer.raw_data))
25942613
XFREE(MTYPE_BGP_NOTIFICATION, inner.raw_data);
2614+
2615+
XFREE(MTYPE_BGP_NOTIFICATION, outer.data);
2616+
XFREE(MTYPE_BGP_NOTIFICATION, outer.raw_data);
2617+
25952618
outer.length = 0;
25962619
}
25972620
}

0 commit comments

Comments
 (0)