git: 12c542cd0e9e - main - dummynet: do not store struct ifnet pointers

From: Kristof Provost <kp_at_FreeBSD.org>
Date: Fri, 20 May 2022 12:51:16 UTC
The branch main has been updated by kp:

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

commit 12c542cd0e9efc1ad9f20f1035402c0acf6d403f
Author:     Kristof Provost <kp@FreeBSD.org>
AuthorDate: 2022-05-19 13:12:54 +0000
Commit:     Kristof Provost <kp@FreeBSD.org>
CommitDate: 2022-05-20 12:49:30 +0000

    dummynet: do not store struct ifnet pointers
    
    The dn_pkt_tag tag contained a struct ifnet pointer. If we persist that
    across NET_EPOCH boundaries (as we did in dummynet) we risk panics if
    the interface is removed between the packet being enqueued and it being
    dequeued.
    
    Convert the pointer into an index/generation pair and restore it when
    the packet is taken out of the queue.
    
    Sponsored by:   Rubicon Communications, LLC ("Netgate")
    Differential Revision:  https://reviews.freebsd.org/D35256
---
 sys/netpfil/ipfw/ip_dn_io.c      | 10 +++++++---
 sys/netpfil/ipfw/ip_dn_private.h |  3 ++-
 2 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/sys/netpfil/ipfw/ip_dn_io.c b/sys/netpfil/ipfw/ip_dn_io.c
index 824e7450fb8f..98f9d08495df 100644
--- a/sys/netpfil/ipfw/ip_dn_io.c
+++ b/sys/netpfil/ipfw/ip_dn_io.c
@@ -766,12 +766,12 @@ dummynet_send(struct mbuf *m)
 			/* extract the dummynet info, rename the tag
 			 * to carry reinject info.
 			 */
+			ifp = ifnet_byindexgen(pkt->if_index, pkt->if_idxgen);
 			if (pkt->dn_dir == (DIR_OUT | PROTO_LAYER2) &&
-				pkt->ifp == NULL) {
+				ifp == NULL) {
 				dst = DIR_DROP;
 			} else {
 				dst = pkt->dn_dir;
-				ifp = pkt->ifp;
 				tag->m_tag_cookie = MTAG_IPFW_RULE;
 				tag->m_tag_id = 0;
 			}
@@ -852,7 +852,11 @@ tag_mbuf(struct mbuf *m, int dir, struct ip_fw_args *fwa)
 	/* only keep this info */
 	dt->rule.info &= (IPFW_ONEPASS | IPFW_IS_DUMMYNET);
 	dt->dn_dir = dir;
-	dt->ifp = fwa->flags & IPFW_ARGS_OUT ? fwa->ifp : NULL;
+	if (fwa->flags & IPFW_ARGS_OUT && fwa->ifp != NULL) {
+		NET_EPOCH_ASSERT();
+		dt->if_index = fwa->ifp->if_index;
+		dt->if_idxgen = fwa->ifp->if_idxgen;
+	}
 	/* dt->output tame is updated as we move through */
 	dt->output_time = V_dn_cfg.curr_time;
 	dt->iphdr_off = (dir & PROTO_LAYER2) ? ETHER_HDR_LEN : 0;
diff --git a/sys/netpfil/ipfw/ip_dn_private.h b/sys/netpfil/ipfw/ip_dn_private.h
index d7df31b85345..1cd38a2c94d8 100644
--- a/sys/netpfil/ipfw/ip_dn_private.h
+++ b/sys/netpfil/ipfw/ip_dn_private.h
@@ -374,7 +374,8 @@ struct dn_pkt_tag {
 	int dn_dir;		/* action when packet comes out.*/
 				/* see ip_fw_private.h		*/
 	uint64_t output_time;	/* when the pkt is due for delivery*/
-	struct ifnet *ifp;	/* interface, for ip_output	*/
+	uint16_t if_index;
+	uint16_t if_idxgen;
 	struct _ip6dn_args ip6opt;	/* XXX ipv6 options	*/
 	uint16_t iphdr_off;	/* IP header offset for mtodo()	*/
 };