git: 139fa2c12ddc - main - routing: fix rtentry use-after-free in multipath route append

From: Olivier Cochard <olivier_at_FreeBSD.org>
Date: Wed, 07 Oct 2026 04:24:43 UTC
The branch main has been updated by olivier:

URL: https://cgit.FreeBSD.org/src/commit/?id=139fa2c12ddc028048efe3946f2663dcfba9b122

commit 139fa2c12ddc028048efe3946f2663dcfba9b122
Author:     Olivier Cochard <olivier@FreeBSD.org>
AuthorDate: 2026-10-07 04:16:33 +0000
Commit:     Olivier Cochard <olivier@FreeBSD.org>
CommitDate: 2026-10-07 04:16:33 +0000

    routing: fix rtentry use-after-free in multipath route append
    
    add_route_flags() drops the RIB lock and passes the existing entry,
    rt_orig, to add_route_flags_mpath(). If a concurrent delete removes
    the prefix in that window, the retry re-inserts rt_orig, which is
    then freed while still linked, crashing later in rn_match().
    
    Pass the new rt instead, return ENOENT when the prefix is gone and
    RTM_F_CREATE is not set, and fix the rnd_orig NULL check.
    
    Approved by:    pouria
    Fixes:          c24a8f19c5d5 ("routing: fix rib_add_route_px()")
    Differential Revision:  https://reviews.freebsd.org/D60353
---
 sys/net/route/route_ctl.c | 14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)

diff --git a/sys/net/route/route_ctl.c b/sys/net/route/route_ctl.c
index fa0f41a0a559..ef58a2845424 100644
--- a/sys/net/route/route_ctl.c
+++ b/sys/net/route/route_ctl.c
@@ -818,8 +818,13 @@ add_route_flags(struct rib_head *rnh, struct rtentry *rt, struct route_nhop_data
 	    nhop_can_multipath(rnd_add->rnd_nhop) &&
 	    nhop_can_multipath(rnd_orig.rnd_nhop)) {
 
+		/*
+		 * @rt_orig may be freed once unlocked. Pass @rt if any: it
+		 * is what gets inserted if the prefix vanishes.
+		 */
 		for (int i = 0; i < RIB_MAX_RETRIES; i++) {
-			error = add_route_flags_mpath(rnh, rt_orig, rnd_add, &rnd_orig,
+			error = add_route_flags_mpath(rnh,
+			    rt != NULL ? rt : rt_orig, rnd_add, &rnd_orig,
 			    op_flags, rc);
 			if (error != EAGAIN)
 				break;
@@ -855,6 +860,10 @@ add_route_flags_mpath(struct rib_head *rnh, struct rtentry *rt,
 	struct route_nhop_data rnd_new;
 	int error = 0;
 
+	/* Prefix vanished: nothing to append to, @rt may be deleted. */
+	if (rnd_orig->rnd_nhop == NULL && !(op_flags & RTM_F_CREATE))
+		return (ENOENT);
+
 	if (!NH_IS_NHGRP(rnd_add->rnd_nhop))
 		error = nhgrp_get_addition_group(rnh, rnd_orig, rnd_add, &rnd_new);
 	else
@@ -869,7 +878,8 @@ add_route_flags_mpath(struct rib_head *rnh, struct rtentry *rt,
 			RIB_RLOCK(rnh);
 			lookup_prefix_rt(rnh, rt, rnd_orig);
 			RIB_RUNLOCK(rnh);
-			if (rnd_orig == NULL && !(op_flags & RTM_F_CREATE)) {
+			if (rnd_orig->rnd_nhop == NULL &&
+			    !(op_flags & RTM_F_CREATE)) {
 				/* In this iteration route doesn't exist */
 				error = ENOENT;
 			}