1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-12-18 10:35:55 +00:00

Lock down global variables in if_gif:

- Add gif_mtx, which protects globals.
- Hold gif_mtx around manipulation of gif_softc_list.
- Abstract gif destruction code into gif_destroy(), which tears down
  a softc after it's been removed from the global list by either module
  unload or clone destroy.
- Lock gif_called, even though we know gif_called is broken with reentrant
  network processing.
- Document an event ordering problem in gif_set_tunnel() that will need
  to be fixed.

gif_softc fields not locked down in this commit.
This commit is contained in:
Robert Watson 2004-03-22 15:43:14 +00:00
parent 9a1248b4cc
commit 17d5cb2d12
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=127305

View File

@ -83,6 +83,12 @@
#define GIFNAME "gif"
/*
* gif_mtx protects the global gif_softc_list, and access to gif_called.
* XXX: See comment blow on gif_called.
* XXX: Per-softc locking is still required.
*/
static struct mtx gif_mtx;
static MALLOC_DEFINE(M_GIF, "gif", "Generic Tunnel Interface");
static LIST_HEAD(, gif_softc) gif_softc_list;
@ -153,7 +159,9 @@ gif_clone_create(ifc, unit)
gifattach0(sc);
mtx_lock(&gif_mtx);
LIST_INSERT_HEAD(&gif_softc_list, sc, gif_list);
mtx_unlock(&gif_mtx);
return (0);
}
@ -181,15 +189,13 @@ gifattach0(sc)
(*ng_gif_attach_p)(&sc->gif_if);
}
void
gif_clone_destroy(ifp)
struct ifnet *ifp;
static void
gif_destroy(struct gif_softc *sc)
{
struct ifnet *ifp = &sc->gif_if;
int err;
struct gif_softc *sc = ifp->if_softc;
gif_delete_tunnel(&sc->gif_if);
LIST_REMOVE(sc, gif_list);
gif_delete_tunnel(ifp);
#ifdef INET6
if (sc->encap_cookie6 != NULL) {
err = encap_detach(sc->encap_cookie6);
@ -211,15 +217,29 @@ gif_clone_destroy(ifp)
free(sc, M_GIF);
}
void
gif_clone_destroy(ifp)
struct ifnet *ifp;
{
struct gif_softc *sc = ifp->if_softc;
mtx_lock(&gif_mtx);
LIST_REMOVE(sc, gif_list);
mtx_unlock(&gif_mtx);
gif_destroy(sc);
}
static int
gifmodevent(mod, type, data)
module_t mod;
int type;
void *data;
{
struct gif_softc *sc;
switch (type) {
case MOD_LOAD:
mtx_init(&gif_mtx, "gif_mtx", NULL, MTX_DEF);
LIST_INIT(&gif_softc_list);
if_clone_attach(&gif_cloner);
@ -231,9 +251,15 @@ gifmodevent(mod, type, data)
case MOD_UNLOAD:
if_clone_detach(&gif_cloner);
while (!LIST_EMPTY(&gif_softc_list))
gif_clone_destroy(&LIST_FIRST(&gif_softc_list)->gif_if);
mtx_lock(&gif_mtx);
while ((sc = LIST_FIRST(&gif_softc_list)) != NULL) {
LIST_REMOVE(sc, gif_list);
mtx_unlock(&gif_mtx);
gif_destroy(sc);
mtx_lock(&gif_mtx);
}
mtx_unlock(&gif_mtx);
mtx_destroy(&gif_mtx);
#ifdef INET6
ip6_gif_hlim = 0;
#endif
@ -338,7 +364,9 @@ gif_output(ifp, m, dst, rt)
* mutual exclusion of the variable CALLED, especially if we
* use kernel thread.
*/
mtx_lock(&gif_mtx);
if (++gif_called > max_gif_nesting) {
mtx_unlock(&gif_mtx);
log(LOG_NOTICE,
"gif_output: recursively called too many times(%d)\n",
gif_called);
@ -346,6 +374,7 @@ gif_output(ifp, m, dst, rt)
error = EIO; /* is there better errno? */
goto end;
}
mtx_unlock(&gif_mtx);
m->m_flags &= ~(M_BCAST|M_MCAST);
if (!(ifp->if_flags & IFF_UP) ||
@ -385,7 +414,9 @@ gif_output(ifp, m, dst, rt)
}
end:
mtx_lock(&gif_mtx);
gif_called = 0; /* reset recursion counter */
mtx_unlock(&gif_mtx);
if (error)
ifp->if_oerrors++;
return error;
@ -695,6 +726,13 @@ gif_ioctl(ifp, cmd, data)
return error;
}
/*
* XXXRW: There's a general event-ordering issue here: the code to check
* if a given tunnel is already present happens before we perform a
* potentially blocking setup of the tunnel. This code needs to be
* re-ordered so that the check and replacement can be atomic using
* a mutex.
*/
int
gif_set_tunnel(ifp, src, dst)
struct ifnet *ifp;
@ -709,6 +747,7 @@ gif_set_tunnel(ifp, src, dst)
s = splnet();
mtx_lock(&gif_mtx);
LIST_FOREACH(sc2, &gif_softc_list, gif_list) {
if (sc2 == sc)
continue;
@ -728,11 +767,13 @@ gif_set_tunnel(ifp, src, dst)
bcmp(sc2->gif_pdst, dst, dst->sa_len) == 0 &&
bcmp(sc2->gif_psrc, src, src->sa_len) == 0) {
error = EADDRNOTAVAIL;
mtx_unlock(&gif_mtx);
goto bad;
}
/* XXX both end must be valid? (I mean, not 0.0.0.0) */
}
mtx_unlock(&gif_mtx);
/* XXX we can detach from both, but be polite just in case */
if (sc->gif_psrc)