diff mbox series

[meta-networking,kirkstone] frr: fix CVE-2024-55553

Message ID 20250422102107.80070-1-peng.zhang1.cn@windriver.com
State New
Headers show
Series [meta-networking,kirkstone] frr: fix CVE-2024-55553 | expand

Commit Message

Peng Zhang April 22, 2025, 10:21 a.m. UTC
From: Zhang Peng <peng.zhang1.cn@windriver.com>

CVE-2024-55553:
In FRRouting (FRR) before 10.3 from 6.0 onward, all routes are re-validated if the
total size of an update received via RTR exceeds the internal socket's buffer size,
default 4K on most OSes. An attacker can use this to trigger re-parsing of the RIB
for FRR routers using RTR by causing more than this number of updates during an update
interval (usually 30 minutes). Additionally, this effect regularly occurs organically.
Furthermore, an attacker can use this to trigger route validation continuously.
Given that routers with large full tables may need more than 30 minutes to fully
re-validate the table, continuous issuance/withdrawal of large numbers of ROA may be
used to impact the route handling performance of all FRR instances using RPKI globally.
Additionally, the re-validation will cause heightened BMP traffic to ingestors.
Fixed Versions: 10.0.3, 10.1.2, 10.2.1, >= 10.3.

Reference: [https://nvd.nist.gov/vuln/detail/CVE-2024-55553]
           [https://frrouting.org/security/cve-2024-55553/]

Upstream patch: backport [https://github.com/FRRouting/frr/commit/b0800bfdf04b4fcf48504737ebfe4ba7f05268d3]

Signed-off-by: Zhang Peng <peng.zhang1.cn@windriver.com>
---
 .../frr/frr/CVE-2024-55553.patch              | 304 ++++++++++++++++++
 .../recipes-protocols/frr/frr_8.2.2.bb        |   1 +
 2 files changed, 305 insertions(+)
 create mode 100644 meta-networking/recipes-protocols/frr/frr/CVE-2024-55553.patch
diff mbox series

Patch

diff --git a/meta-networking/recipes-protocols/frr/frr/CVE-2024-55553.patch b/meta-networking/recipes-protocols/frr/frr/CVE-2024-55553.patch
new file mode 100644
index 0000000000..1183b1e58b
--- /dev/null
+++ b/meta-networking/recipes-protocols/frr/frr/CVE-2024-55553.patch
@@ -0,0 +1,304 @@ 
+From fc6837ad68e9724d7c15db6cb01bf9bb5beea8e5 Mon Sep 17 00:00:00 2001
+From: Donatas Abraitis <donatas@opensourcerouting.org>
+Date: Tue, 21 Jan 2025 16:07:10 +0200
+Subject: [PATCH] bgpd: Validate only affected RPKI prefixes instead of a full
+ RIB
+
+This is backport of https://github.com/FRRouting/frr/commit/b0800bfdf04b4fcf48504737ebfe4ba7f05268d3 for 8.4.
+
+Signed-off-by: Donatas Abraitis <donatas@opensourcerouting.org>
+
+CVE: CVE-2024-55553
+Upstream-Status: Backport [https://github.com/opensourcerouting/frr/commit/cc1c66a7e8dd31c681f396f6635192c0d60a543c]
+
+The original patch is adjusted to fit for the current version.(8.2.2)
+
+Signed-off-by: Zhang Peng <peng.zhang1.cn@windriver.com>
+---
+ bgpd/bgp_rpki.c | 184 +++++++++++++++++++++---------------------------
+ bgpd/bgpd.c     |   4 ++
+ bgpd/bgpd.h     |   1 +
+ 3 files changed, 87 insertions(+), 102 deletions(-)
+
+diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c
+index 0a51269d9b..69c5f44fac 100644
+--- a/bgpd/bgp_rpki.c
++++ b/bgpd/bgp_rpki.c
+@@ -67,6 +67,12 @@ static struct thread *t_rpki;
+ 
+ DEFINE_MTYPE_STATIC(BGPD, BGP_RPKI_CACHE, "BGP RPKI Cache server");
+ DEFINE_MTYPE_STATIC(BGPD, BGP_RPKI_CACHE_GROUP, "BGP RPKI Cache server group");
++
++DEFINE_MTYPE_STATIC(BGPD, BGP_RPKI_REVALIDATE, "BGP RPKI Revalidation");
++
++#define RPKI_VALID 1
++#define RPKI_NOTFOUND 2
++#define RPKI_INVALID 3
+ 
+ #define POLLING_PERIOD_DEFAULT 3600
+ #define EXPIRE_INTERVAL_DEFAULT 7200
+@@ -129,7 +135,6 @@ static enum route_map_cmd_result_t route_match(void *rule,
+ 					       void *object);
+ static void *route_match_compile(const char *arg);
+ static void revalidate_bgp_node(struct bgp_dest *dest, afi_t afi, safi_t safi);
+-static void revalidate_all_routes(void);
+ 
+ static struct rtr_mgr_config *rtr_config;
+ static struct list *cache_list;
+@@ -339,10 +344,9 @@ inline int is_running(void)
+ 	return rtr_is_running;
+ }
+ 
+-static struct prefix *pfx_record_to_prefix(struct pfx_record *record)
++static void pfx_record_to_prefix(struct pfx_record *record,
++				 struct prefix *prefix)
+ {
+-	struct prefix *prefix = prefix_new();
+-
+ 	prefix->prefixlen = record->min_len;
+ 
+ 	if (record->prefix.ver == LRTR_IPV4) {
+@@ -353,75 +357,102 @@ static struct prefix *pfx_record_to_prefix(struct pfx_record *record)
+ 		ipv6_addr_to_network_byte_order(record->prefix.u.addr6.addr,
+ 						prefix->u.prefix6.s6_addr32);
+ 	}
+-
+-	return prefix;
+ }
+ 
+-static int bgpd_sync_callback(struct thread *thread)
+-{
++struct rpki_revalidate_prefix {
+ 	struct bgp *bgp;
+-	struct listnode *node;
+-	struct prefix *prefix;
+-	struct pfx_record rec;
+-	int retval;
+-	int socket = THREAD_FD(thread);
++	struct prefix prefix;
++	afi_t afi;
++	safi_t safi;
++};
+ 
+-	thread_add_read(bm->master, bgpd_sync_callback, NULL, socket, &t_rpki);
++static void rpki_revalidate_prefix(struct thread *thread)
++{
++	struct rpki_revalidate_prefix *rrp = THREAD_ARG(thread);
++	struct bgp_dest *match, *node;
+ 
+-	if (atomic_load_explicit(&rtr_update_overflow, memory_order_seq_cst)) {
+-		while (read(socket, &rec, sizeof(struct pfx_record)) != -1)
+-			;
++	match = bgp_table_subtree_lookup(rrp->bgp->rib[rrp->afi][rrp->safi],
++					 &rrp->prefix);
+ 
+-		atomic_store_explicit(&rtr_update_overflow, 0,
+-				      memory_order_seq_cst);
+-		revalidate_all_routes();
+-		return 0;
+-	}
++	node = match;
+ 
+-	retval = read(socket, &rec, sizeof(struct pfx_record));
+-	if (retval != sizeof(struct pfx_record)) {
+-		RPKI_DEBUG("Could not read from socket");
+-		return retval;
+-	}
++	while (node) {
++		if (bgp_dest_has_bgp_path_info_data(node)) {
++			revalidate_bgp_node(node, rrp->afi, rrp->safi);
++		}
+ 
+-	/* RTR-Server crashed/terminated, let's handle and switch
+-	 * to the second available RTR-Server according to preference.
+-	 */
+-	if (rec.socket && rec.socket->state == RTR_ERROR_FATAL) {
+-		reset(true);
+-		return 0;
++		node = bgp_route_next_until(node, match);
+ 	}
+ 
+-	prefix = pfx_record_to_prefix(&rec);
++	XFREE(MTYPE_BGP_RPKI_REVALIDATE, rrp);
++}
+ 
+-	afi_t afi = (rec.prefix.ver == LRTR_IPV4) ? AFI_IP : AFI_IP6;
++static void revalidate_single_prefix(struct prefix prefix, afi_t afi)
++{
++	struct bgp *bgp;
++	struct listnode *node;
+ 
+ 	for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp)) {
+ 		safi_t safi;
+ 
+ 		for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) {
+-			if (!bgp->rib[afi][safi])
++			struct bgp_table *table = bgp->rib[afi][safi];
++			struct rpki_revalidate_prefix *rrp;
++
++			if (!table)
+ 				continue;
+ 
+-			struct bgp_dest *match;
+-			struct bgp_dest *node;
++			rrp = XCALLOC(MTYPE_BGP_RPKI_REVALIDATE, sizeof(*rrp));
++			rrp->bgp = bgp;
++			rrp->prefix = prefix;
++			rrp->afi = afi;
++			rrp->safi = safi;
++			thread_add_event(bm->master, rpki_revalidate_prefix,
++					 rrp, 0, &bgp->t_revalidate[afi][safi]);
++		}
++	}
++}
++
++static void bgpd_sync_callback(struct thread *thread)
++{
++	struct prefix prefix;
++	struct pfx_record rec;
++	afi_t afi;
++	int retval;
++
++	if (atomic_load_explicit(&rtr_update_overflow, memory_order_seq_cst)) {
++		ssize_t size = 0;
+ 
+-			match = bgp_table_subtree_lookup(bgp->rib[afi][safi],
+-							 prefix);
+-			node = match;
++		retval = read(rpki_sync_socket_bgpd, &rec,
++			      sizeof(struct pfx_record));
++		while (retval != -1) {
++			if (retval != sizeof(struct pfx_record))
++				break;
+ 
+-			while (node) {
+-				if (bgp_dest_has_bgp_path_info_data(node)) {
+-					revalidate_bgp_node(node, afi, safi);
+-				}
++			size += retval;
++			pfx_record_to_prefix(&rec, &prefix);
++			afi = (rec.prefix.ver == LRTR_IPV4) ? AFI_IP : AFI_IP6;
++			revalidate_single_prefix(prefix, afi);
+ 
+-				node = bgp_route_next_until(node, match);
+-			}
++			retval = read(rpki_sync_socket_bgpd, &rec,
++				      sizeof(struct pfx_record));
+ 		}
++
++		atomic_store_explicit(&rtr_update_overflow, 0,
++				      memory_order_seq_cst);
++		return;
+ 	}
+ 
+-	prefix_free(&prefix);
+-	return 0;
++	retval = read(rpki_sync_socket_bgpd, &rec, sizeof(struct pfx_record));
++	if (retval != sizeof(struct pfx_record)) {
++		RPKI_DEBUG("Could not read from rpki_sync_socket_bgpd");
++		return;
++	}
++	pfx_record_to_prefix(&rec, &prefix);
++
++	afi = (rec.prefix.ver == LRTR_IPV4) ? AFI_IP : AFI_IP6;
++
++	revalidate_single_prefix(prefix, afi);
+ }
+ 
+ static void revalidate_bgp_node(struct bgp_dest *bgp_dest, afi_t afi,
+@@ -446,63 +477,12 @@ static void revalidate_bgp_node(struct bgp_dest *bgp_dest, afi_t afi,
+ 	}
+ }
+ 
+-static void revalidate_all_routes(void)
+-{
+-	struct bgp *bgp;
+-	struct listnode *node;
+-	afi_t afi;
+-	safi_t safi;
+-
+-	for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp)) {
+-		struct peer *peer;
+-		struct listnode *peer_listnode;
+-
+-		for (ALL_LIST_ELEMENTS_RO(bgp->peer, peer_listnode, peer)) {
+-			FOREACH_AFI_SAFI (afi, safi) {
+-				if (!peer->afc_nego[afi][safi])
+-					continue;
+-
+-				if (!peer->bgp->rib[afi][safi])
+-					continue;
+-
+-				bgp_soft_reconfig_in(peer, afi, safi);
+-			}
+-		}
+-	}
+-}
+-
+-static void rpki_connection_status_cb(const struct rtr_mgr_group *group
+-				      __attribute__((unused)),
+-				      enum rtr_mgr_status status,
+-				      const struct rtr_socket *socket
+-				      __attribute__((unused)),
+-				      void *data __attribute__((unused)))
+-{
+-	struct pfx_record rec = {0};
+-	int retval;
+-
+-	if (rtr_is_stopping ||
+-	    atomic_load_explicit(&rtr_update_overflow, memory_order_seq_cst))
+-		return;
+-
+-	if (status == RTR_MGR_ERROR)
+-		rec.socket = socket;
+-
+-	retval = write(rpki_sync_socket_rtr, &rec, sizeof(rec));
+-	if (retval == -1 && (errno == EAGAIN || errno == EWOULDBLOCK))
+-		atomic_store_explicit(&rtr_update_overflow, 1,
+-				      memory_order_seq_cst);
+-
+-	else if (retval != sizeof(rec))
+-		RPKI_DEBUG("Could not write to rpki_sync_socket_rtr");
+-}
+-
+ static void rpki_update_cb_sync_rtr(struct pfx_table *p __attribute__((unused)),
+ 				    const struct pfx_record rec,
+ 				    const bool added __attribute__((unused)))
+ {
+-	if (rtr_is_stopping
+-	    || atomic_load_explicit(&rtr_update_overflow, memory_order_seq_cst))
++	if (rtr_is_stopping ||
++	    atomic_load_explicit(&rtr_update_overflow, memory_order_seq_cst))
+ 		return;
+ 
+ 	int retval =
+diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
+index 7e528b2191..bfe96f0f01 100644
+--- a/bgpd/bgpd.c
++++ b/bgpd/bgpd.c
+@@ -3579,6 +3579,10 @@ int bgp_delete(struct bgp *bgp)
+ 
+ 	hook_call(bgp_inst_delete, bgp);
+ 
++	THREAD_OFF(bgp->t_condition_check);
++	FOREACH_AFI_SAFI (afi, safi)
++		THREAD_OFF(bgp->t_revalidate[afi][safi]);
++
+ 	THREAD_OFF(bgp->t_startup);
+ 	THREAD_OFF(bgp->t_maxmed_onstartup);
+ 	THREAD_OFF(bgp->t_update_delay);
+diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
+index 8b93c450e8..45db4752f4 100644
+--- a/bgpd/bgpd.h
++++ b/bgpd/bgpd.h
+@@ -426,6 +426,7 @@ struct bgp {
+ 	/* BGP update delay on startup */
+ 	struct thread *t_update_delay;
+ 	struct thread *t_establish_wait;
++	struct thread *t_revalidate[AFI_MAX][SAFI_MAX];
+ 	uint8_t update_delay_over;
+ 	uint8_t main_zebra_update_hold;
+ 	uint8_t main_peers_update_hold;
+-- 
+2.35.5
+
diff --git a/meta-networking/recipes-protocols/frr/frr_8.2.2.bb b/meta-networking/recipes-protocols/frr/frr_8.2.2.bb
index facc655e29..975607f5af 100644
--- a/meta-networking/recipes-protocols/frr/frr_8.2.2.bb
+++ b/meta-networking/recipes-protocols/frr/frr_8.2.2.bb
@@ -34,6 +34,7 @@  SRC_URI = "git://github.com/FRRouting/frr.git;protocol=https;branch=stable/8.2 \
            file://CVE-2024-31950.patch \
            file://CVE-2024-31951.patch \
            file://CVE-2024-31948.patch \
+           file://CVE-2024-55553.patch \
 	      "
 
 SRCREV = "79188bf710e92acf42fb5b9b0a2e9593a5ee9b05"