aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJason A. Donenfeld <Jason@zx2c4.com>2021-04-14 14:42:50 -0600
committerJason A. Donenfeld <Jason@zx2c4.com>2021-04-15 18:22:10 -0600
commit65c2211c619f779bcdef50a485970ad50545fe01 (patch)
tree748240cc0c66807508e5a242ad07177dcbaf9dd4
parentif_wg: don't check return value of WAITOK (diff)
downloadwireguard-freebsd-65c2211c619f779bcdef50a485970ad50545fe01.tar.xz
wireguard-freebsd-65c2211c619f779bcdef50a485970ad50545fe01.zip
if_wg: do not allow ioctl to race with clone_destroy
This fixes the crash from: bash -c 'while true; do ifconfig wg0 create; ifconfig wg0 destroy; done& while true; do wg show wg0 > /dev/null 2>&1; done& wait' Since we're setting ifp to NULL here, we also have to account for multicast v6 packets being transmitted during destroy, which can be triggered by: ifconfig wg0 create ifconfig wg0 inet6 fe80::1234/120 ifconfig wg0 up route add -inet6 ff02::1:0/120 -iface wg0 ifconfig wg0 destroy These are unfixed upstream bug that we're working around. Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
-rw-r--r--src/if_wg.c26
1 files changed, 16 insertions, 10 deletions
diff --git a/src/if_wg.c b/src/if_wg.c
index 544884f..14b742e 100644
--- a/src/if_wg.c
+++ b/src/if_wg.c
@@ -2441,22 +2441,18 @@ free:
static int
wg_transmit(struct ifnet *ifp, struct mbuf *m)
{
- struct wg_softc *sc;
+ struct wg_softc *sc = ifp->if_softc;
sa_family_t family;
struct epoch_tracker et;
struct wg_peer *peer;
struct wg_tag *t;
uint32_t af;
- int rc;
+ int rc = 0;
- /*
- * Work around lifetime issue in the ipv6 mld code.
- */
- if (__predict_false(ifp->if_flags & IFF_DYING))
+ /* Work around lifetime issue in the ipv6 mld code. */
+ if (__predict_false((ifp->if_flags & IFF_DYING) || !sc))
return (ENXIO);
- rc = 0;
- sc = ifp->if_softc;
if ((t = wg_tag_get(m)) == NULL) {
rc = ENOBUFS;
goto early_out;
@@ -2888,9 +2884,16 @@ wg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
{
struct wg_data_io *wgd = (struct wg_data_io *)data;
struct ifreq *ifr = (struct ifreq *)data;
- struct wg_softc *sc = ifp->if_softc;
+ struct wg_softc *sc;
int ret = 0;
+ sx_slock(&wg_sx);
+ sc = ifp->if_softc;
+ if (!sc) {
+ ret = ENXIO;
+ goto out;
+ }
+
switch (cmd) {
case SIOCSWG:
ret = priv_check(curthread, PRIV_NET_WG);
@@ -2908,7 +2911,7 @@ wg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
*/
break;
case SIOCSIFFLAGS:
- if ((ifp->if_flags & IFF_UP) != 0)
+ if (ifp->if_flags & IFF_UP)
ret = wg_up(sc);
else
wg_down(sc);
@@ -2940,6 +2943,8 @@ wg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
ret = ENOTTY;
}
+out:
+ sx_sunlock(&wg_sx);
return ret;
}
@@ -3118,6 +3123,7 @@ wg_clone_destroy(struct ifnet *ifp)
struct ucred *cred;
sx_xlock(&wg_sx);
+ ifp->if_softc = NULL;
sx_xlock(&sc->sc_lock);
sc->sc_flags |= WGF_DYING;
cred = sc->sc_ucred;