Skip to content

Commit 9fa702b

Browse files
authored
Merge pull request FRRouting#20796 from mjstapp/fix_bgp_notify_validation
bgpd: validate incoming NOTIFICATION messages
2 parents b49d57f + fe28d25 commit 9fa702b

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
@@ -565,7 +565,7 @@ const char *bgp_notify_admin_message(char *buf, size_t bufsz, uint8_t *data,
565565
}
566566

567567
/* dump notify packet */
568-
void bgp_notify_print(struct peer *peer, struct bgp_notify *bgp_notify,
568+
void bgp_notify_print(const struct peer *peer, const struct bgp_notify *bgp_notify,
569569
const char *direct, bool hard_reset)
570570
{
571571
const char *subcode_str;

bgpd/bgp_debug.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ extern bool bgp_dump_attr(struct attr *attr, char *buf, size_t size);
168168
extern bool bgp_debug_peer_updout_enabled(char *host);
169169
extern const char *bgp_notify_code_str(char code);
170170
extern const char *bgp_notify_subcode_str(char code, char subcode);
171-
extern void bgp_notify_print(struct peer *peer, struct bgp_notify *bgp_notify,
171+
extern void bgp_notify_print(const struct peer *peer, const struct bgp_notify *bgp_notify,
172172
const char *direct, bool hard_reset);
173173

174174
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
@@ -803,13 +803,19 @@ struct bgp_notify bgp_notify_decapsulate_hard_reset(struct bgp_notify *notify)
803803
{
804804
struct bgp_notify bn = {};
805805

806+
/* Validate inner length */
807+
if (notify->length < 2)
808+
goto done;
809+
806810
bn.code = notify->raw_data[0];
807811
bn.subcode = notify->raw_data[1];
808812
bn.length = notify->length - 2;
813+
if (bn.length > 0) {
814+
bn.raw_data = XMALLOC(MTYPE_BGP_NOTIFICATION, bn.length);
815+
memcpy(bn.raw_data, notify->raw_data + 2, bn.length);
816+
}
809817

810-
bn.raw_data = XMALLOC(MTYPE_BGP_NOTIFICATION, bn.length);
811-
memcpy(bn.raw_data, notify->raw_data + 2, bn.length);
812-
818+
done:
813819
return bn;
814820
}
815821

@@ -2575,6 +2581,14 @@ static int bgp_notify_receive(struct peer_connection *connection,
25752581
struct bgp_notify inner = {};
25762582
bool hard_reset = false;
25772583

2584+
/* Validate message size */
2585+
if (size < 2) {
2586+
flog_err(EC_BGP_NOTIFY_RCV,
2587+
"%s [Error] Notify packet error (packet length is short)",
2588+
peer->host);
2589+
return BGP_Stop;
2590+
}
2591+
25782592
if (peer->notify.data) {
25792593
XFREE(MTYPE_BGP_NOTIFICATION, peer->notify.data);
25802594
peer->notify.length = 0;
@@ -2586,16 +2600,24 @@ static int bgp_notify_receive(struct peer_connection *connection,
25862600
outer.length = size - 2;
25872601
outer.data = NULL;
25882602
outer.raw_data = NULL;
2589-
if (outer.length) {
2603+
if (outer.length > 0) {
25902604
outer.raw_data = XMALLOC(MTYPE_BGP_NOTIFICATION, outer.length);
25912605
memcpy(outer.raw_data, stream_pnt(connection->curr), outer.length);
25922606
}
25932607

25942608
hard_reset =
25952609
bgp_notify_received_hard_reset(peer, outer.code, outer.subcode);
2596-
if (hard_reset && outer.length) {
2597-
inner = bgp_notify_decapsulate_hard_reset(&outer);
2610+
if (hard_reset) {
2611+
/* Hard reset treatment: we expect but don't require inner error codes */
25982612
peer->notify.hard_reset = true;
2613+
/* If we have at least an inner code and subcode, capture them */
2614+
if (outer.length > 1) {
2615+
inner = bgp_notify_decapsulate_hard_reset(&outer);
2616+
} else {
2617+
inner = outer;
2618+
inner.length = 0;
2619+
inner.raw_data = NULL;
2620+
}
25992621
} else {
26002622
inner = outer;
26012623
}
@@ -2604,7 +2626,7 @@ static int bgp_notify_receive(struct peer_connection *connection,
26042626
peer->notify.code = inner.code;
26052627
peer->notify.subcode = inner.subcode;
26062628
/* For further diagnostic record returned Data. */
2607-
if (inner.length) {
2629+
if (inner.length > 0) {
26082630
peer->notify.length = inner.length;
26092631
peer->notify.data =
26102632
XMALLOC(MTYPE_BGP_NOTIFICATION, inner.length);
@@ -2617,7 +2639,7 @@ static int bgp_notify_receive(struct peer_connection *connection,
26172639
int first = 0;
26182640
char c[4];
26192641

2620-
if (inner.length) {
2642+
if (inner.length > 0) {
26212643
inner.data = XMALLOC(MTYPE_BGP_NOTIFICATION,
26222644
inner.length * 3);
26232645
for (i = 0; i < inner.length; i++)
@@ -2639,19 +2661,20 @@ static int bgp_notify_receive(struct peer_connection *connection,
26392661
}
26402662

26412663
bgp_notify_print(peer, &inner, "received", hard_reset);
2642-
if (inner.length) {
2664+
if (inner.length > 0) {
26432665
XFREE(MTYPE_BGP_NOTIFICATION, inner.data);
26442666
inner.length = 0;
26452667
}
2646-
if (outer.length) {
2647-
XFREE(MTYPE_BGP_NOTIFICATION, outer.data);
2648-
XFREE(MTYPE_BGP_NOTIFICATION, outer.raw_data);
2649-
2668+
if (outer.length > 0) {
26502669
/* If this is a Hard Reset notification, we MUST free
26512670
* the inner (encapsulated) notification too.
26522671
*/
2653-
if (hard_reset)
2672+
if (hard_reset && (inner.raw_data != outer.raw_data))
26542673
XFREE(MTYPE_BGP_NOTIFICATION, inner.raw_data);
2674+
2675+
XFREE(MTYPE_BGP_NOTIFICATION, outer.data);
2676+
XFREE(MTYPE_BGP_NOTIFICATION, outer.raw_data);
2677+
26552678
outer.length = 0;
26562679
}
26572680
}

0 commit comments

Comments
 (0)