git: 84b57a4c5b84 - releng/14.1 - pf: invert direction for inner icmp state lookups

From: Mark Johnston <markj_at_FreeBSD.org>
Date: Thu, 19 Sep 2024 13:02:54 UTC
The branch releng/14.1 has been updated by markj:

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

commit 84b57a4c5b848d44ec0918c28d8c27bec948a151
Author:     Kristof Provost <kp@FreeBSD.org>
AuthorDate: 2024-08-14 09:29:30 +0000
Commit:     Mark Johnston <markj@FreeBSD.org>
CommitDate: 2024-09-19 12:55:09 +0000

    pf: invert direction for inner icmp state lookups
    
    (e.g. traceroute with icmp)
    ok henning, jsing
    
    Also extend the test case to cover this scenario.
    
    Approved by:    so
    Security:       FreeBSD-EN-24:16.pf
    PR:             280701
    Obtained from:  OpenBSD
    MFC after:      1 week
    Sponsored by:   Rubicon Communications, LLC ("Netgate")
    
    (cherry picked from commit 89f6723288b0d27d3f14f93e6e83f672fa2b8aca)
    (cherry picked from commit 46c4fc50d3012ca3c8756df243589add36b70830)
---
 sys/netpfil/pf/pf.c | 21 +++++++++++----------
 1 file changed, 11 insertions(+), 10 deletions(-)

diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c
index edfa7a450054..43f32f673842 100644
--- a/sys/netpfil/pf/pf.c
+++ b/sys/netpfil/pf/pf.c
@@ -342,7 +342,7 @@ static int		 pf_test_state_udp(struct pf_kstate **,
 int			 pf_icmp_state_lookup(struct pf_state_key_cmp *,
 			    struct pf_pdesc *, struct pf_kstate **, struct mbuf *,
 			    int, struct pfi_kkif *, u_int16_t, u_int16_t,
-			    int, int *, int);
+			    int, int *, int, int);
 static int		 pf_test_state_icmp(struct pf_kstate **,
 			    struct pfi_kkif *, struct mbuf *, int,
 			    void *, struct pf_pdesc *, u_short *);
@@ -6582,7 +6582,8 @@ pf_multihome_scan_asconf(struct mbuf *m, int start, int len,
 int
 pf_icmp_state_lookup(struct pf_state_key_cmp *key, struct pf_pdesc *pd,
     struct pf_kstate **state, struct mbuf *m, int direction, struct pfi_kkif *kif,
-    u_int16_t icmpid, u_int16_t type, int icmp_dir, int *iidx, int multi)
+    u_int16_t icmpid, u_int16_t type, int icmp_dir, int *iidx, int multi,
+    int inner)
 {
 	key->af = pd->af;
 	key->proto = pd->proto;
@@ -6619,7 +6620,8 @@ pf_icmp_state_lookup(struct pf_state_key_cmp *key, struct pf_pdesc *pd,
 
 	/* Is this ICMP message flowing in right direction? */
 	if ((*state)->rule.ptr->type &&
-	    (((*state)->direction == direction) ?
+	    (((!inner && (*state)->direction == direction) ||
+	    (inner && (*state)->direction != direction)) ?
 	    PF_IN : PF_OUT) != icmp_dir) {
 		if (V_pf_status.debug >= PF_DEBUG_MISC) {
 			printf("pf: icmp type %d in wrong direction (%d): ",
@@ -6677,7 +6679,7 @@ pf_test_state_icmp(struct pf_kstate **state, struct pfi_kkif *kif,
 		 */
 		ret = pf_icmp_state_lookup(&key, pd, state, m, pd->dir,
 		    kif, virtual_id, virtual_type, icmp_dir, &iidx,
-		    PF_ICMP_MULTI_NONE);
+		    PF_ICMP_MULTI_NONE, 0);
 		if (ret >= 0) {
 			if (ret == PF_DROP && pd->af == AF_INET6 &&
 			    icmp_dir == PF_OUT) {
@@ -6685,7 +6687,7 @@ pf_test_state_icmp(struct pf_kstate **state, struct pfi_kkif *kif,
 					PF_STATE_UNLOCK((*state));
 				ret = pf_icmp_state_lookup(&key, pd, state, m,
 				    pd->dir, kif, virtual_id, virtual_type,
-				    icmp_dir, &iidx, multi);
+				    icmp_dir, &iidx, multi, 0);
 				if (ret >= 0)
 					return (ret);
 			} else
@@ -6769,6 +6771,7 @@ pf_test_state_icmp(struct pf_kstate **state, struct pfi_kkif *kif,
 		int		off2 = 0;
 
 		pd2.af = pd->af;
+		pd2.dir = pd->dir;
 		/* Payload packet is from the opposite direction. */
 		pd2.sidx = (pd->dir == PF_IN) ? 1 : 0;
 		pd2.didx = (pd->dir == PF_IN) ? 0 : 1;
@@ -7090,10 +7093,9 @@ pf_test_state_icmp(struct pf_kstate **state, struct pfi_kkif *kif,
 			pf_icmp_mapping(&pd2, iih->icmp_type,
 			    &icmp_dir, &multi, &virtual_id, &virtual_type);
 
-			pd2.dir = icmp_dir;
 			ret = pf_icmp_state_lookup(&key, &pd2, state, m,
 			    pd2.dir, kif, virtual_id, virtual_type,
-			    icmp_dir, &iidx, PF_ICMP_MULTI_NONE);
+			    icmp_dir, &iidx, PF_ICMP_MULTI_NONE, 1);
 			if (ret >= 0)
 				return (ret);
 
@@ -7146,10 +7148,9 @@ pf_test_state_icmp(struct pf_kstate **state, struct pfi_kkif *kif,
 			pf_icmp_mapping(&pd2, iih->icmp6_type,
 			    &icmp_dir, &multi, &virtual_id, &virtual_type);
 
-			pd2.dir = icmp_dir;
 			ret = pf_icmp_state_lookup(&key, &pd2, state, m,
 			    pd->dir, kif, virtual_id, virtual_type,
-			    icmp_dir, &iidx, PF_ICMP_MULTI_NONE);
+			    icmp_dir, &iidx, PF_ICMP_MULTI_NONE, 1);
 			if (ret >= 0) {
 				if (ret == PF_DROP && pd->af == AF_INET6 &&
 				    icmp_dir == PF_OUT) {
@@ -7158,7 +7159,7 @@ pf_test_state_icmp(struct pf_kstate **state, struct pfi_kkif *kif,
 					ret = pf_icmp_state_lookup(&key, pd,
 					    state, m, pd->dir, kif,
 					    virtual_id, virtual_type,
-					    icmp_dir, &iidx, multi);
+					    icmp_dir, &iidx, multi, 1);
 					if (ret >= 0)
 						return (ret);
 				} else