diff mbox series

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

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

Commit Message

Peng Zhang Nov. 19, 2025, 5:58 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]

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

Signed-off-by: Zhang Peng <peng.zhang1.cn@windriver.com>
---
 .../frr/frr/CVE-2024-55553.patch              | 253 ++++++++++++++++++
 .../recipes-protocols/frr/frr_9.1.3.bb        |   1 +
 2 files changed, 254 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..ac8dbcc2ed
--- /dev/null
+++ b/meta-networking/recipes-protocols/frr/frr/CVE-2024-55553.patch
@@ -0,0 +1,253 @@ 
+From c66b72ef6d10f3f77d4bdddd849436a16270dfc4 Mon Sep 17 00:00:00 2001
+From: Donatas Abraitis <donatas@opensourcerouting.org>
+Date: Wed, 4 Dec 2024 23:38:34 +0200
+Subject: [PATCH] bgpd: Validate only affected RPKI prefixes instead of a full
+ RIB
+
+Before this fix, if rpki_sync_socket_rtr socket returns EAGAIN, then ALL routes
+in the RIB are revalidated which takes lots of CPU and some unnecessary traffic,
+e.g. if using BMP servers. With a full feed it would waste 50-80Mbps.
+
+Instead we should try to drain an existing pipe (another end), and revalidate
+only affected prefixes.
+
+Signed-off-by: Donatas Abraitis <donatas@opensourcerouting.org>
+
+CVE: CVE-2024-55553
+Upstream-Status: Backport [https://github.com/FRRouting/frr/commit/b0800bfdf04b4fcf48504737ebfe4ba7f05268d3]
+Signed-off-by: Zhang Peng <peng.zhang1.cn@windriver.com>
+---
+ bgpd/bgp_rpki.c | 148 ++++++++++++++++++------------------------------
+ bgpd/bgpd.c     |   4 --
+ bgpd/bgpd.h     |   1 -
+ 3 files changed, 55 insertions(+), 98 deletions(-)
+
+diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c
+index 375b041853..402ff24b50 100644
+--- a/bgpd/bgp_rpki.c
++++ b/bgpd/bgp_rpki.c
+@@ -116,7 +116,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;
+@@ -403,36 +402,10 @@ static void rpki_revalidate_prefix(struct event *thread)
+ 	XFREE(MTYPE_BGP_RPKI_REVALIDATE, rrp);
+ }
+ 
+-static void bgpd_sync_callback(struct event *thread)
++static void revalidate_single_prefix(struct vrf *vrf, struct prefix prefix, afi_t afi)
+ {
+ 	struct bgp *bgp;
+ 	struct listnode *node;
+-	struct prefix prefix;
+-	struct pfx_record rec;
+-
+-	event_add_read(bm->master, bgpd_sync_callback, NULL,
+-		       rpki_sync_socket_bgpd, NULL);
+-
+-	if (atomic_load_explicit(&rtr_update_overflow, memory_order_seq_cst)) {
+-		while (read(rpki_sync_socket_bgpd, &rec,
+-			    sizeof(struct pfx_record)) != -1)
+-			;
+-
+-		atomic_store_explicit(&rtr_update_overflow, 0,
+-				      memory_order_seq_cst);
+-		revalidate_all_routes();
+-		return;
+-	}
+-
+-	int 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_t afi = (rec.prefix.ver == LRTR_IPV4) ? AFI_IP : AFI_IP6;
+ 
+ 	for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp)) {
+ 		safi_t safi;
+@@ -455,87 +428,76 @@ static void bgpd_sync_callback(struct event *thread)
+ 	}
+ }
+ 
+-static void revalidate_bgp_node(struct bgp_dest *bgp_dest, afi_t afi,
+-				safi_t safi)
++static void bgpd_sync_callback(struct event *thread)
+ {
+-	struct bgp_adj_in *ain;
++	struct prefix prefix;
++	struct pfx_record rec;
++	struct rpki_vrf *rpki_vrf = EVENT_ARG(thread);
++	struct vrf *vrf = NULL;
++	afi_t afi;
++	int retval;
+ 
+-	for (ain = bgp_dest->adj_in; ain; ain = ain->next) {
+-		struct bgp_path_info *path =
+-			bgp_dest_get_bgp_path_info(bgp_dest);
+-		mpls_label_t *label = NULL;
+-		uint32_t num_labels = 0;
+-
+-		if (path && path->extra) {
+-			label = path->extra->label;
+-			num_labels = path->extra->num_labels;
++	event_add_read(bm->master, bgpd_sync_callback, rpki_vrf, rpki_vrf->rpki_sync_socket_bgpd,
++		       NULL);
++
++	if (rpki_vrf->vrfname) {
++		vrf = vrf_lookup_by_name(rpki_vrf->vrfname);
++		if (!vrf) {
++			zlog_err("%s(): vrf for rpki %s not found", __func__, rpki_vrf->vrfname);
++			return;
+ 		}
+-		(void)bgp_update(ain->peer, bgp_dest_get_prefix(bgp_dest),
+-				 ain->addpath_rx_id, ain->attr, afi, safi,
+-				 ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, label,
+-				 num_labels, 1, NULL);
+ 	}
+-}
+ 
+-/*
+- * The act of a soft reconfig in revalidation is really expensive
+- * coupled with the fact that the download of a full rpki state
+- * from a rpki server can be expensive, let's break up the revalidation
+- * to a point in time in the future to allow other bgp events
+- * to take place too.
+- */
+-struct rpki_revalidate_peer {
+-	afi_t afi;
+-	safi_t safi;
+-	struct peer *peer;
+-};
++	if (atomic_load_explicit(&rpki_vrf->rtr_update_overflow, memory_order_seq_cst)) {
++		ssize_t size = 0;
+ 
+-static void bgp_rpki_revalidate_peer(struct event *thread)
+-{
+-	struct rpki_revalidate_peer *rvp = EVENT_ARG(thread);
++		retval = read(rpki_vrf->rpki_sync_socket_bgpd, &rec, sizeof(struct pfx_record));
++		while (retval != -1) {
++			if (retval != sizeof(struct pfx_record))
++				break;
+ 
+-	/*
+-	 * Here's the expensive bit of gnomish deviousness
+-	 */
+-	bgp_soft_reconfig_in(rvp->peer, rvp->afi, rvp->safi);
++			size += retval;
++			pfx_record_to_prefix(&rec, &prefix);
++			afi = (rec.prefix.ver == LRTR_IPV4) ? AFI_IP : AFI_IP6;
++			revalidate_single_prefix(vrf, prefix, afi);
+ 
+-	XFREE(MTYPE_BGP_RPKI_REVALIDATE, rvp);
+-}
++			retval = read(rpki_vrf->rpki_sync_socket_bgpd, &rec,
++				      sizeof(struct pfx_record));
++		}
+ 
+-static void revalidate_all_routes(void)
+-{
+-	struct bgp *bgp;
+-	struct listnode *node;
++		RPKI_DEBUG("Socket overflow detected (%zu), revalidating affected prefixes", size);
+ 
+-	for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp)) {
+-		struct peer *peer;
+-		struct listnode *peer_listnode;
++		atomic_store_explicit(&rpki_vrf->rtr_update_overflow, 0, memory_order_seq_cst);
++		return;
++	}
+ 
+-		for (ALL_LIST_ELEMENTS_RO(bgp->peer, peer_listnode, peer)) {
+-			afi_t afi;
+-			safi_t safi;
++	retval = read(rpki_vrf->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);
+ 
+-			FOREACH_AFI_SAFI (afi, safi) {
+-				struct rpki_revalidate_peer *rvp;
++	afi = (rec.prefix.ver == LRTR_IPV4) ? AFI_IP : AFI_IP6;
+ 
+-				if (!bgp->rib[afi][safi])
+-					continue;
++	revalidate_single_prefix(vrf, prefix, afi);
++}
+ 
+-				if (!peer_established(peer->connection))
+-					continue;
++static void revalidate_bgp_node(struct bgp_dest *bgp_dest, afi_t afi, safi_t safi)
++{
++	struct bgp_adj_in *ain;
++	mpls_label_t *label;
++	uint8_t num_labels;
++
++	for (ain = bgp_dest->adj_in; ain; ain = ain->next) {
++		struct bgp_path_info *path = bgp_dest_get_bgp_path_info(bgp_dest);
+ 
+-				rvp = XCALLOC(MTYPE_BGP_RPKI_REVALIDATE,
+-					      sizeof(*rvp));
+-				rvp->peer = peer;
+-				rvp->afi = afi;
+-				rvp->safi = safi;
++		num_labels = BGP_PATH_INFO_NUM_LABELS(path);
++		label = num_labels ? path->extra->labels->label : NULL;
+ 
+-				event_add_event(
+-					bm->master, bgp_rpki_revalidate_peer,
+-					rvp, 0,
+-					&peer->t_revalidate_all[afi][safi]);
+-			}
+-		}
++		(void)bgp_update(ain->peer, bgp_dest_get_prefix(bgp_dest), ain->addpath_rx_id,
++				 ain->attr, afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL,
++				 label, num_labels, 1, NULL);
+ 	}
+ }
+ 
+diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
+index 4de5964c39..9bf964c45f 100644
+--- a/bgpd/bgpd.c
++++ b/bgpd/bgpd.c
+@@ -1248,8 +1248,6 @@ static void peer_free(struct peer *peer)
+ 	bgp_reads_off(peer->connection);
+ 	bgp_writes_off(peer->connection);
+ 	event_cancel_event_ready(bm->master, peer->connection);
+-	FOREACH_AFI_SAFI (afi, safi)
+-		EVENT_OFF(peer->t_revalidate_all[afi][safi]);
+ 	assert(!peer->connection->t_write);
+ 	assert(!peer->connection->t_read);
+ 	event_cancel_event_ready(bm->master, peer->connection);
+@@ -2640,8 +2638,6 @@ int peer_delete(struct peer *peer)
+ 	bgp_reads_off(peer->connection);
+ 	bgp_writes_off(peer->connection);
+ 	event_cancel_event_ready(bm->master, peer->connection);
+-	FOREACH_AFI_SAFI (afi, safi)
+-		EVENT_OFF(peer->t_revalidate_all[afi][safi]);
+ 	assert(!CHECK_FLAG(peer->connection->thread_flags,
+ 			   PEER_THREAD_WRITES_ON));
+ 	assert(!CHECK_FLAG(peer->connection->thread_flags,
+diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
+index b139b2c1b4..c4faacc6dc 100644
+--- a/bgpd/bgpd.h
++++ b/bgpd/bgpd.h
+@@ -1571,7 +1571,6 @@ struct peer {
+ 
+ 	/* Threads. */
+ 	struct event *t_llgr_stale[AFI_MAX][SAFI_MAX];
+-	struct event *t_revalidate_all[AFI_MAX][SAFI_MAX];
+ 	struct event *t_refresh_stalepath;
+ 
+ 	/* Thread flags. */
+-- 
+2.50.0
+
diff --git a/meta-networking/recipes-protocols/frr/frr_9.1.3.bb b/meta-networking/recipes-protocols/frr/frr_9.1.3.bb
index f3b4816941..c5f626a35a 100644
--- a/meta-networking/recipes-protocols/frr/frr_9.1.3.bb
+++ b/meta-networking/recipes-protocols/frr/frr_9.1.3.bb
@@ -13,6 +13,7 @@  LIC_FILES_CHKSUM = "file://doc/licenses/GPL-2.0;md5=b234ee4d69f5fce4486a80fdaf4a
 SRC_URI = "git://github.com/FRRouting/frr.git;protocol=https;branch=stable/9.1 \
            file://frr.pam \
            file://0001-zebra-Mimic-GNU-basename-API-for-non-glibc-library-e.patch \
+           file://CVE-2024-55553.patch \
            "
 
 SRCREV = "ad1766d17be022587fe05ebe1a7bf10e1b7dce19"