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>
This commit is contained in:
parent
15df6797da
commit
65c2211c61
26
src/if_wg.c
26
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;
|
||||
|
|
Loading…
Reference in New Issue