git: d10de21f2f7d - main - pf: Access r->rpool.cur->kif under mutex protection

From: Kristof Provost <kp_at_FreeBSD.org>
Date: Thu, 24 Aug 2023 13:08:22 UTC
The branch main has been updated by kp:

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

commit d10de21f2f7df59344f8611546989b36e4fd867c
Author:     Kajetan Staszkiewicz <vegeta@tuxpowered.net>
AuthorDate: 2023-08-24 11:05:33 +0000
Commit:     Kristof Provost <kp@FreeBSD.org>
CommitDate: 2023-08-24 11:05:33 +0000

    pf: Access r->rpool.cur->kif under mutex protection
    
    pf_route() sends traffic to a specified next hop over a specific
    interface. The next hop is obtained in pf_map_addr() but the interface
    is obtained directly via r->rpool.cur->kif` outside of the lock held in
    pf_map_addr() in multiple places around pf. The chosen interface is not
    stored in source node.
    
    Move the interface selection into pf_map_addr(), have the function
    return it together with the chosen IP address and ensure its stored
    in struct pf_ksrc_node, store it in the source node and use the stored
    value when needed.
    
    Sponsored by:   InnoGames GmbH
    MFC after:      2 weeks
    Differential Revision:  https://reviews.freebsd.org/D41570
---
 sys/net/pfvar.h        |  5 +++--
 sys/netpfil/pf/pf.c    | 31 +++++++++++++++++--------------
 sys/netpfil/pf/pf_lb.c | 24 +++++++++++++++++++-----
 3 files changed, 39 insertions(+), 21 deletions(-)

diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h
index 21ebca755b3d..f9cb45f696d3 100644
--- a/sys/net/pfvar.h
+++ b/sys/net/pfvar.h
@@ -873,7 +873,7 @@ struct pf_ksrc_node {
 	struct pf_addr	 raddr;
 	struct pf_krule_slist	 match_rules;
 	union pf_krule_ptr rule;
-	struct pfi_kkif	*kif;
+	struct pfi_kkif	*rkif;
 	counter_u64_t	 bytes[2];
 	counter_u64_t	 packets[2];
 	u_int32_t	 states;
@@ -2474,7 +2474,8 @@ int			 pf_step_out_of_keth_anchor(struct pf_keth_anchor_stackframe *,
 
 u_short			 pf_map_addr(u_int8_t, struct pf_krule *,
 			    struct pf_addr *, struct pf_addr *,
-			    struct pf_addr *, struct pf_ksrc_node **);
+			    struct pfi_kkif **nkif, struct pf_addr *,
+			    struct pf_ksrc_node **);
 struct pf_krule		*pf_get_translation(struct pf_pdesc *, struct mbuf *,
 			    int, struct pfi_kkif *, struct pf_ksrc_node **,
 			    struct pf_state_key **, struct pf_state_key **,
diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c
index c80553ba017d..a5d7c1ba0155 100644
--- a/sys/netpfil/pf/pf.c
+++ b/sys/netpfil/pf/pf.c
@@ -4880,15 +4880,14 @@ pf_create_state(struct pf_krule *r, struct pf_krule *nr, struct pf_krule *a,
 
 	if (r->rt) {
 		/* pf_map_addr increases the reason counters */
-		if ((reason = pf_map_addr(pd->af, r, pd->src, &s->rt_addr, NULL,
-		    &sn)) != 0) {
+		if ((reason = pf_map_addr(pd->af, r, pd->src, &s->rt_addr,
+		    &s->rt_kif, NULL, &sn)) != 0) {
 			pf_src_tree_remove_state(s);
 			s->timeout = PFTM_UNLINKED;
 			STATE_DEC_COUNTERS(s);
 			pf_free_state(s);
 			goto csfailed;
 		}
-		s->rt_kif = r->rpool.cur->kif;
 		s->rt = r->rt;
 	}
 
@@ -6700,6 +6699,7 @@ pf_route(struct mbuf **m, struct pf_krule *r, struct ifnet *oifp,
 	struct mbuf		*m0, *m1, *md;
 	struct sockaddr_in	dst;
 	struct ip		*ip;
+	struct pfi_kkif		*nkif = NULL;
 	struct ifnet		*ifp = NULL;
 	struct pf_addr		 naddr;
 	struct pf_ksrc_node	*sn = NULL;
@@ -6784,21 +6784,22 @@ pf_route(struct mbuf **m, struct pf_krule *r, struct ifnet *oifp,
 			goto bad_locked;
 		}
 		pf_map_addr(AF_INET, r, (struct pf_addr *)&ip->ip_src,
-		    &naddr, NULL, &sn);
+		    &naddr, &nkif, NULL, &sn);
 		if (!PF_AZERO(&naddr, AF_INET))
 			dst.sin_addr.s_addr = naddr.v4.s_addr;
-		ifp = r->rpool.cur->kif ?
-		    r->rpool.cur->kif->pfik_ifp : NULL;
+		ifp = nkif ? nkif->pfik_ifp : NULL;
 	} else {
 		if (!PF_AZERO(&s->rt_addr, AF_INET))
 			dst.sin_addr.s_addr =
 			    s->rt_addr.v4.s_addr;
 		ifp = s->rt_kif ? s->rt_kif->pfik_ifp : NULL;
+		/* If pfsync'd */
+		if (ifp == NULL)
+			ifp = r->rpool.cur->kif ?
+			    r->rpool.cur->kif->pfik_ifp : NULL;
 		PF_STATE_UNLOCK(s);
 	}
-	/* If pfsync'd */
-	if (ifp == NULL)
-		ifp = r->rpool.cur->kif ? r->rpool.cur->kif->pfik_ifp : NULL;
+
 	if (ifp == NULL)
 		goto bad;
 
@@ -6913,6 +6914,7 @@ pf_route6(struct mbuf **m, struct pf_krule *r, struct ifnet *oifp,
 	struct mbuf		*m0, *md;
 	struct sockaddr_in6	dst;
 	struct ip6_hdr		*ip6;
+	struct pfi_kkif		*nkif = NULL;
 	struct ifnet		*ifp = NULL;
 	struct pf_addr		 naddr;
 	struct pf_ksrc_node	*sn = NULL;
@@ -6995,24 +6997,25 @@ pf_route6(struct mbuf **m, struct pf_krule *r, struct ifnet *oifp,
 			goto bad_locked;
 		}
 		pf_map_addr(AF_INET6, r, (struct pf_addr *)&ip6->ip6_src,
-		    &naddr, NULL, &sn);
+		    &naddr, &nkif, NULL, &sn);
 		if (!PF_AZERO(&naddr, AF_INET6))
 			PF_ACPY((struct pf_addr *)&dst.sin6_addr,
 			    &naddr, AF_INET6);
-		ifp = r->rpool.cur->kif ? r->rpool.cur->kif->pfik_ifp : NULL;
+		ifp = nkif ? nkif->pfik_ifp : NULL;
 	} else {
 		if (!PF_AZERO(&s->rt_addr, AF_INET6))
 			PF_ACPY((struct pf_addr *)&dst.sin6_addr,
 			    &s->rt_addr, AF_INET6);
 		ifp = s->rt_kif ? s->rt_kif->pfik_ifp : NULL;
+		/* If pfsync'd */
+		if (ifp == NULL)
+			ifp = r->rpool.cur->kif ?
+			    r->rpool.cur->kif->pfik_ifp : NULL;
 	}
 
 	if (s)
 		PF_STATE_UNLOCK(s);
 
-	/* If pfsync'd */
-	if (ifp == NULL)
-		ifp = r->rpool.cur->kif ? r->rpool.cur->kif->pfik_ifp : NULL;
 	if (ifp == NULL)
 		goto bad;
 
diff --git a/sys/netpfil/pf/pf_lb.c b/sys/netpfil/pf/pf_lb.c
index 09e5d6a7a97f..eb3d087e3df6 100644
--- a/sys/netpfil/pf/pf_lb.c
+++ b/sys/netpfil/pf/pf_lb.c
@@ -222,7 +222,7 @@ pf_get_sport(sa_family_t af, u_int8_t proto, struct pf_krule *r,
 	struct pf_addr		init_addr;
 
 	bzero(&init_addr, sizeof(init_addr));
-	if (pf_map_addr(af, r, saddr, naddr, &init_addr, sn))
+	if (pf_map_addr(af, r, saddr, naddr, NULL, &init_addr, sn))
 		return (1);
 
 	bzero(&key, sizeof(key));
@@ -299,7 +299,7 @@ pf_get_sport(sa_family_t af, u_int8_t proto, struct pf_krule *r,
 			 * pick a different source address since we're out
 			 * of free port choices for the current one.
 			 */
-			if (pf_map_addr(af, r, saddr, naddr, &init_addr, sn))
+			if (pf_map_addr(af, r, saddr, naddr, NULL, &init_addr, sn))
 				return (1);
 			break;
 		case PF_POOL_NONE:
@@ -350,7 +350,8 @@ pf_get_mape_sport(sa_family_t af, u_int8_t proto, struct pf_krule *r,
 
 u_short
 pf_map_addr(sa_family_t af, struct pf_krule *r, struct pf_addr *saddr,
-    struct pf_addr *naddr, struct pf_addr *init_addr, struct pf_ksrc_node **sn)
+    struct pf_addr *naddr, struct pfi_kkif **nkif, struct pf_addr *init_addr,
+    struct pf_ksrc_node **sn)
 {
 	u_short			 reason = 0;
 	struct pf_kpool		*rpool = &r->rpool;
@@ -377,11 +378,15 @@ pf_map_addr(sa_family_t af, struct pf_krule *r, struct pf_addr *saddr,
 		}
 
 		PF_ACPY(naddr, &(*sn)->raddr, af);
+		if (nkif)
+			*nkif = (*sn)->rkif;
 		if (V_pf_status.debug >= PF_DEBUG_NOISY) {
 			printf("pf_map_addr: src tracking maps ");
 			pf_print_host(saddr, 0, af);
 			printf(" to ");
 			pf_print_host(naddr, 0, af);
+			if (nkif)
+				printf("@%s", (*nkif)->pfik_name);
 			printf("\n");
 		}
 		goto done;
@@ -539,13 +544,22 @@ pf_map_addr(sa_family_t af, struct pf_krule *r, struct pf_addr *saddr,
 		break;
 	    }
 	}
-	if (*sn != NULL)
+
+	if (nkif)
+		*nkif = rpool->cur->kif;
+
+	if (*sn != NULL) {
 		PF_ACPY(&(*sn)->raddr, naddr, af);
+		if (nkif)
+			(*sn)->rkif = *nkif;
+	}
 
 	if (V_pf_status.debug >= PF_DEBUG_NOISY &&
 	    (rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_NONE) {
 		printf("pf_map_addr: selected address ");
 		pf_print_host(naddr, 0, af);
+		if (nkif)
+			printf("@%s", (*nkif)->pfik_name);
 		printf("\n");
 	}
 
@@ -711,7 +725,7 @@ pf_get_translation(struct pf_pdesc *pd, struct mbuf *m, int off,
 		}
 		break;
 	case PF_RDR: {
-		if (pf_map_addr(pd->af, r, saddr, naddr, NULL, sn))
+		if (pf_map_addr(pd->af, r, saddr, naddr, NULL, NULL, sn))
 			goto notrans;
 		if ((r->rpool.opts & PF_POOL_TYPEMASK) == PF_POOL_BITMASK)
 			PF_POOLMASK(naddr, naddr, &r->rpool.cur->addr.v.a.mask,