git: e893ec49afb2 - releng/13.4 - pf: rework pf_icmp_state_lookup() failure mode

From: Kristof Provost <kp_at_FreeBSD.org>
Date: Thu, 05 Sep 2024 07:35:39 UTC
The branch releng/13.4 has been updated by kp:

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

commit e893ec49afb2caf05a2c28df4434905fa4213537
Author:     Kristof Provost <kp@FreeBSD.org>
AuthorDate: 2024-08-30 11:36:39 +0000
Commit:     Kristof Provost <kp@FreeBSD.org>
CommitDate: 2024-09-05 07:35:12 +0000

    pf: rework pf_icmp_state_lookup() failure mode
    
    If pf_icmp_state_lookup() finds a state but rejects it for not matching the
    expected direction we should unlock the state (and NULL out *state). This
    simplifies life for callers, and also ensures there's no confusion about what a
    non-NULL returned state means.
    
    Previously it could have been left in there by the caller, resulting in callers
    unlocking the same state twice.
    
    MFC after:      1 week
    Sponsored by:   Rubicon Communications, LLC ("Netgate")
    
    (cherry picked from commit 0578fe492284ded4745167060be794032e6e22f0)
    (cherry picked from commit d6e5f8643d37e925aa51fc8224cfc05aba0813f7)
    
    Approved-by:    re (cperciva)
---
 sys/net/pfvar.h     |  4 ++--
 sys/netpfil/pf/pf.c | 20 +++++++++++++-------
 2 files changed, 15 insertions(+), 9 deletions(-)

diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h
index e6c2d1f290cf..66bdbf43e212 100644
--- a/sys/net/pfvar.h
+++ b/sys/net/pfvar.h
@@ -330,8 +330,8 @@ struct pfi_dynaddr {
 		mtx_unlock(_s->lock);					\
 	} while (0)
 #else
-#define	PF_STATE_LOCK(s)	mtx_lock(s->lock)
-#define	PF_STATE_UNLOCK(s)	mtx_unlock(s->lock)
+#define	PF_STATE_LOCK(s)	mtx_lock((s)->lock)
+#define	PF_STATE_UNLOCK(s)	mtx_unlock((s)->lock)
 #endif
 
 #ifdef INVARIANTS
diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c
index 9c1aa4d0a77a..ccd6b54f7b37 100644
--- a/sys/netpfil/pf/pf.c
+++ b/sys/netpfil/pf/pf.c
@@ -6103,6 +6103,8 @@ pf_icmp_state_lookup(struct pf_state_key_cmp *key, struct pf_pdesc *pd,
 			pf_print_state(*state);
 			printf("\n");
 		}
+		PF_STATE_UNLOCK(*state);
+		*state = NULL;
 		return (PF_DROP);
 	}
 	return (-1);
@@ -6155,15 +6157,16 @@ pf_test_state_icmp(struct pf_kstate **state, int direction, struct pfi_kkif *kif
 		    kif, virtual_id, virtual_type, icmp_dir, &iidx,
 		    PF_ICMP_MULTI_NONE, 0);
 		if (ret >= 0) {
+			MPASS(*state == NULL);
 			if (ret == PF_DROP && pd->af == AF_INET6 &&
 			    icmp_dir == PF_OUT) {
-				if (*state != NULL)
-					PF_STATE_UNLOCK((*state));
 				ret = pf_icmp_state_lookup(&key, pd, state, m, off,
 				    pd->dir, kif, virtual_id, virtual_type,
 				    icmp_dir, &iidx, multi, 0);
-				if (ret >= 0)
+				if (ret >= 0) {
+					MPASS(*state == NULL);
 					return (ret);
+				}
 			} else
 				return (ret);
 		}
@@ -6570,8 +6573,10 @@ pf_test_state_icmp(struct pf_kstate **state, int direction, struct pfi_kkif *kif
 			ret = pf_icmp_state_lookup(&key, &pd2, state, m, off,
 			    pd2.dir, kif, virtual_id, virtual_type,
 			    icmp_dir, &iidx, PF_ICMP_MULTI_NONE, 1);
-			if (ret >= 0)
+			if (ret >= 0) {
+				MPASS(*state == NULL);
 				return (ret);
+			}
 
 			/* translate source/destination address, if necessary */
 			if ((*state)->key[PF_SK_WIRE] !=
@@ -6626,16 +6631,17 @@ pf_test_state_icmp(struct pf_kstate **state, int direction, struct pfi_kkif *kif
 			    pd->dir, kif, virtual_id, virtual_type,
 			    icmp_dir, &iidx, PF_ICMP_MULTI_NONE, 1);
 			if (ret >= 0) {
+				MPASS(*state == NULL);
 				if (ret == PF_DROP && pd2.af == AF_INET6 &&
 				    icmp_dir == PF_OUT) {
-					if (*state != NULL)
-						PF_STATE_UNLOCK((*state));
 					ret = pf_icmp_state_lookup(&key, &pd2,
 					    state, m, off, pd->dir, kif,
 					    virtual_id, virtual_type,
 					    icmp_dir, &iidx, multi, 1);
-					if (ret >= 0)
+					if (ret >= 0) {
+						MPASS(*state == NULL);
 						return (ret);
+					}
 				} else
 					return (ret);
 			}