summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDonald Sharp <sharpd@nvidia.com>2023-09-10 15:09:08 +0200
committerDonald Sharp <sharpd@nvidia.com>2023-09-11 18:45:59 +0200
commitb45925ad100c85404d15bce19a3e584ecb60f920 (patch)
tree10251aff2b512985d565cb6180ca0785cfb77bbc
parentbgpd: bgp_clear_adj_in|remove dest may be freed (diff)
downloadfrr-b45925ad100c85404d15bce19a3e584ecb60f920.tar.xz
frr-b45925ad100c85404d15bce19a3e584ecb60f920.zip
bgpd: evpn_cleanup_local_non_best_route could free dest
But never really does due to locking, but since it can we need to treat it like it does and ensure that FRR is not making a mistake, by using memory after it has been freed. Signed-off-by: Donald Sharp <sharpd@nvidia.com>
-rw-r--r--bgpd/bgp_evpn.c17
-rw-r--r--bgpd/bgp_route.c6
-rw-r--r--bgpd/bgp_route.h3
3 files changed, 16 insertions, 10 deletions
diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c
index e5d33e6d5..ff931e1f0 100644
--- a/bgpd/bgp_evpn.c
+++ b/bgpd/bgp_evpn.c
@@ -2035,10 +2035,10 @@ static void evpn_zebra_reinstall_best_route(struct bgp *bgp,
* additional handling to prevent bgp from injecting and holding on to a
* non-best local path.
*/
-static void evpn_cleanup_local_non_best_route(struct bgp *bgp,
- struct bgpevpn *vpn,
- struct bgp_dest *dest,
- struct bgp_path_info *local_pi)
+static struct bgp_dest *
+evpn_cleanup_local_non_best_route(struct bgp *bgp, struct bgpevpn *vpn,
+ struct bgp_dest *dest,
+ struct bgp_path_info *local_pi)
{
/* local path was not picked as the winner; kick it out */
if (bgp_debug_zebra(NULL))
@@ -2046,10 +2046,11 @@ static void evpn_cleanup_local_non_best_route(struct bgp *bgp,
dest);
evpn_delete_old_local_route(bgp, vpn, dest, local_pi, NULL);
- bgp_path_info_reap(dest, local_pi);
/* tell zebra to re-add the best remote path */
evpn_zebra_reinstall_best_route(bgp, vpn, dest);
+
+ return bgp_path_info_reap(dest, local_pi);
}
static inline bool bgp_evpn_route_add_l3_ecomm_ok(struct bgpevpn *vpn,
@@ -2186,7 +2187,8 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn,
} else {
if (!CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)) {
route_change = 0;
- evpn_cleanup_local_non_best_route(bgp, vpn, dest, pi);
+ dest = evpn_cleanup_local_non_best_route(bgp, vpn, dest,
+ pi);
} else {
bool new_is_sync;
@@ -2203,7 +2205,8 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn,
}
bgp_path_info_unlock(pi);
- bgp_dest_unlock_node(dest);
+ if (dest)
+ bgp_dest_unlock_node(dest);
/* If this is a new route or some attribute has changed, export the
* route to the global table. The route will be advertised to peers
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 1832d55ec..f76907118 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -438,7 +438,8 @@ void bgp_path_info_add_with_caller(const char *name, struct bgp_dest *dest,
/* Do the actual removal of info from RIB, for use by bgp_process
completion callback *only* */
-void bgp_path_info_reap(struct bgp_dest *dest, struct bgp_path_info *pi)
+struct bgp_dest *bgp_path_info_reap(struct bgp_dest *dest,
+ struct bgp_path_info *pi)
{
if (pi->next)
pi->next->prev = pi->prev;
@@ -450,7 +451,8 @@ void bgp_path_info_reap(struct bgp_dest *dest, struct bgp_path_info *pi)
bgp_path_info_mpath_dequeue(pi);
bgp_path_info_unlock(pi);
hook_call(bgp_snmp_update_stats, dest, pi, false);
- bgp_dest_unlock_node(dest);
+
+ return bgp_dest_unlock_node(dest);
}
void bgp_path_info_delete(struct bgp_dest *dest, struct bgp_path_info *pi)
diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h
index e001bf4f0..cc13500fa 100644
--- a/bgpd/bgp_route.h
+++ b/bgpd/bgp_route.h
@@ -727,7 +727,8 @@ extern struct bgp_path_info *
bgp_get_imported_bpi_ultimate(struct bgp_path_info *info);
extern void bgp_path_info_add(struct bgp_dest *dest, struct bgp_path_info *pi);
extern void bgp_path_info_extra_free(struct bgp_path_info_extra **extra);
-extern void bgp_path_info_reap(struct bgp_dest *dest, struct bgp_path_info *pi);
+extern struct bgp_dest *bgp_path_info_reap(struct bgp_dest *dest,
+ struct bgp_path_info *pi);
extern void bgp_path_info_delete(struct bgp_dest *dest,
struct bgp_path_info *pi);
extern struct bgp_path_info_extra *