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
|
static int
|
||||||
wg_transmit(struct ifnet *ifp, struct mbuf *m)
|
wg_transmit(struct ifnet *ifp, struct mbuf *m)
|
||||||
{
|
{
|
||||||
struct wg_softc *sc;
|
struct wg_softc *sc = ifp->if_softc;
|
||||||
sa_family_t family;
|
sa_family_t family;
|
||||||
struct epoch_tracker et;
|
struct epoch_tracker et;
|
||||||
struct wg_peer *peer;
|
struct wg_peer *peer;
|
||||||
struct wg_tag *t;
|
struct wg_tag *t;
|
||||||
uint32_t af;
|
uint32_t af;
|
||||||
int rc;
|
int rc = 0;
|
||||||
|
|
||||||
/*
|
/* Work around lifetime issue in the ipv6 mld code. */
|
||||||
* Work around lifetime issue in the ipv6 mld code.
|
if (__predict_false((ifp->if_flags & IFF_DYING) || !sc))
|
||||||
*/
|
|
||||||
if (__predict_false(ifp->if_flags & IFF_DYING))
|
|
||||||
return (ENXIO);
|
return (ENXIO);
|
||||||
|
|
||||||
rc = 0;
|
|
||||||
sc = ifp->if_softc;
|
|
||||||
if ((t = wg_tag_get(m)) == NULL) {
|
if ((t = wg_tag_get(m)) == NULL) {
|
||||||
rc = ENOBUFS;
|
rc = ENOBUFS;
|
||||||
goto early_out;
|
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 wg_data_io *wgd = (struct wg_data_io *)data;
|
||||||
struct ifreq *ifr = (struct ifreq *)data;
|
struct ifreq *ifr = (struct ifreq *)data;
|
||||||
struct wg_softc *sc = ifp->if_softc;
|
struct wg_softc *sc;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
|
sx_slock(&wg_sx);
|
||||||
|
sc = ifp->if_softc;
|
||||||
|
if (!sc) {
|
||||||
|
ret = ENXIO;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case SIOCSWG:
|
case SIOCSWG:
|
||||||
ret = priv_check(curthread, PRIV_NET_WG);
|
ret = priv_check(curthread, PRIV_NET_WG);
|
||||||
|
@ -2908,7 +2911,7 @@ wg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
|
||||||
*/
|
*/
|
||||||
break;
|
break;
|
||||||
case SIOCSIFFLAGS:
|
case SIOCSIFFLAGS:
|
||||||
if ((ifp->if_flags & IFF_UP) != 0)
|
if (ifp->if_flags & IFF_UP)
|
||||||
ret = wg_up(sc);
|
ret = wg_up(sc);
|
||||||
else
|
else
|
||||||
wg_down(sc);
|
wg_down(sc);
|
||||||
|
@ -2940,6 +2943,8 @@ wg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
|
||||||
ret = ENOTTY;
|
ret = ENOTTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
sx_sunlock(&wg_sx);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3118,6 +3123,7 @@ wg_clone_destroy(struct ifnet *ifp)
|
||||||
struct ucred *cred;
|
struct ucred *cred;
|
||||||
|
|
||||||
sx_xlock(&wg_sx);
|
sx_xlock(&wg_sx);
|
||||||
|
ifp->if_softc = NULL;
|
||||||
sx_xlock(&sc->sc_lock);
|
sx_xlock(&sc->sc_lock);
|
||||||
sc->sc_flags |= WGF_DYING;
|
sc->sc_flags |= WGF_DYING;
|
||||||
cred = sc->sc_ucred;
|
cred = sc->sc_ucred;
|
||||||
|
|
Loading…
Reference in New Issue