new file mode 100644
@@ -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
+
@@ -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"