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
This commit is contained in:
Kristof Provost 2022-05-19 15:12:54 +02:00
parent eca368ecb6
commit 12c542cd0e
2 changed files with 9 additions and 4 deletions

View File

@ -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;

View File

@ -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() */
};