diff options
author | Joel Sing <jsing@cvs.openbsd.org> | 2009-02-20 12:47:58 +0000 |
---|---|---|
committer | Joel Sing <jsing@cvs.openbsd.org> | 2009-02-20 12:47:58 +0000 |
commit | 8a40f245500d864a8aa008f8bb4e2fc61d6994d2 (patch) | |
tree | b9efb39205ad6aae69ee416f58bbddd14a7d7b01 /sys/net/if_tun.c | |
parent | e55e994ccda27e04666ed3d8cce062880d2d1475 (diff) |
Ensure that bpf_mtap() is always called at the same interrupt priority
level within the tun(4) driver. Otherwise we can be interrupted whilst
copying a packet into the BPF buffer, leading to a race between bpf_mtap()
calls. This can result in corruption within the BPF buffers.
Also ensure that we are at IPL_NET when calling ether_input_mbuf().
Fixes PR6073.
ok claudio@, canacar@ (for an earlier version of this diff)
Diffstat (limited to 'sys/net/if_tun.c')
-rw-r--r-- | sys/net/if_tun.c | 16 |
1 files changed, 13 insertions, 3 deletions
diff --git a/sys/net/if_tun.c b/sys/net/if_tun.c index 9b37e7ab460..5123e9c2ed0 100644 --- a/sys/net/if_tun.c +++ b/sys/net/if_tun.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_tun.c,v 1.95 2008/10/02 20:21:14 brad Exp $ */ +/* $OpenBSD: if_tun.c,v 1.96 2009/02/20 12:47:57 jsing Exp $ */ /* $NetBSD: if_tun.c,v 1.24 1996/05/07 02:40:48 thorpej Exp $ */ /* @@ -556,13 +556,14 @@ tun_output(struct ifnet *ifp, struct mbuf *m0, struct sockaddr *dst, af = mtod(m0, u_int32_t *); *af = htonl(dst->sa_family); + s = splnet(); + #if NBPFILTER > 0 if (ifp->if_bpf) bpf_mtap(ifp->if_bpf, m0, BPF_DIRECTION_OUT); #endif len = m0->m_pkthdr.len; - s = splnet(); IFQ_ENQUEUE(&ifp->if_snd, m0, NULL, error); if (error) { splx(s); @@ -852,16 +853,23 @@ tunwrite(dev_t dev, struct uio *uio, int ioflag) top->m_pkthdr.rcvif = ifp; #if NBPFILTER > 0 - if (ifp->if_bpf) + if (ifp->if_bpf) { + s = splnet(); bpf_mtap(ifp->if_bpf, top, BPF_DIRECTION_IN); + splx(s); + } #endif if (tp->tun_flags & TUN_LAYER2) { /* quirk to not add randomness from a virtual device */ atomic_setbits_int(&netisr, (1 << NETISR_RND_DONE)); + s = splnet(); ether_input_mbuf(ifp, top); + splx(s); + ifp->if_ipackets++; /* ibytes are counted in ether_input */ + return (0); } @@ -1088,6 +1096,8 @@ tunstart(struct ifnet *ifp) struct tun_softc *tp = ifp->if_softc; struct mbuf *m; + splassert(IPL_NET); + if (!(tp->tun_flags & TUN_LAYER2) && !ALTQ_IS_ENABLED(&ifp->if_snd) && !TBR_IS_ENABLED(&ifp->if_snd)) |