Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys PR kern/50522: gif(4) ioctl causes panic while someone i...
details: https://anonhg.NetBSD.org/src/rev/4bf87e5eea73
branches: trunk
changeset: 342182:4bf87e5eea73
user: knakahara <knakahara%NetBSD.org@localhost>
date: Fri Dec 11 07:59:14 2015 +0000
description:
PR kern/50522: gif(4) ioctl causes panic while someone is using the gif(4) interface.
It is required to wait other CPU's softint completion before disestablishing
the softint handler.
diffstat:
sys/net/if_gif.c | 99 ++++++++++++++++++++++++++++++++++++++++++++++---
sys/net/if_gif.h | 18 ++++++++-
sys/netinet/in_gif.c | 15 +++++--
sys/netinet6/in6_gif.c | 14 +++++-
4 files changed, 132 insertions(+), 14 deletions(-)
diffs (truncated from 317 to 300 lines):
diff -r 54d18cf44ff1 -r 4bf87e5eea73 sys/net/if_gif.c
--- a/sys/net/if_gif.c Fri Dec 11 07:21:09 2015 +0000
+++ b/sys/net/if_gif.c Fri Dec 11 07:59:14 2015 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: if_gif.c,v 1.101 2015/12/11 04:29:24 knakahara Exp $ */
+/* $NetBSD: if_gif.c,v 1.102 2015/12/11 07:59:14 knakahara Exp $ */
/* $KAME: if_gif.c,v 1.76 2001/08/20 02:01:02 kjc Exp $ */
/*
@@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_gif.c,v 1.101 2015/12/11 04:29:24 knakahara Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_gif.c,v 1.102 2015/12/11 07:59:14 knakahara Exp $");
#ifdef _KERNEL_OPT
#include "opt_inet.h"
@@ -53,6 +53,7 @@
#include <sys/cpu.h>
#include <sys/intr.h>
#include <sys/kmem.h>
+#include <sys/atomic.h>
#include <net/if.h>
#include <net/if_types.h>
@@ -146,6 +147,10 @@
gifattach0(struct gif_softc *sc)
{
+ sc->gif_si_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NONE);
+ KASSERT(sc->gif_si_lock != NULL);
+ cv_init(&sc->gif_si_cv, "if_gif_cv");
+ sc->gif_si_refs = 0;
sc->encap_cookie4 = sc->encap_cookie6 = NULL;
sc->gif_if.if_addrlen = 0;
@@ -174,6 +179,8 @@
if_detach(ifp);
rtcache_free(&sc->gif_ro);
+ cv_destroy(&sc->gif_si_cv);
+ mutex_obj_free(sc->gif_si_lock);
kmem_free(sc, sizeof(struct gif_softc));
return (0);
@@ -295,7 +302,8 @@
m->m_flags &= ~(M_BCAST|M_MCAST);
if (!(ifp->if_flags & IFF_UP) ||
- sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
+ sc->gif_psrc == NULL || sc->gif_pdst == NULL ||
+ sc->gif_si == NULL) {
m_freem(m);
error = ENETDOWN;
goto end;
@@ -321,9 +329,11 @@
splx(s);
goto end;
}
+
+ /* softint_schedule() must be called with kpreempt_disabled() */
+ softint_schedule(sc->gif_si);
splx(s);
- softint_schedule(sc->gif_si);
error = 0;
end:
@@ -346,6 +356,24 @@
sc = arg;
ifp = &sc->gif_if;
+ atomic_inc_uint(&sc->gif_si_refs);
+
+ /*
+ * pattern (a) (see also gif_set_tunnel())
+ * other CPUs does {set,delete}_tunnel after curcpu have done
+ * softint_schedule().
+ */
+ if (sc->gif_pdst == NULL || sc->gif_psrc == NULL) {
+ IFQ_PURGE(&ifp->if_snd);
+
+ if (atomic_dec_uint_nv(&sc->gif_si_refs) == 0) {
+ mutex_enter(sc->gif_si_lock);
+ cv_broadcast(&sc->gif_si_cv);
+ mutex_exit(sc->gif_si_lock);
+ }
+ return;
+ }
+
/* output processing */
while (1) {
s = splnet();
@@ -397,6 +425,16 @@
ifp->if_obytes += len;
}
}
+
+ /*
+ * pattern (b) (see also gif_set_tunnel())
+ * other CPUs begin {set,delete}_tunnel while curcpu si doing gifintr.
+ */
+ if (atomic_dec_uint_nv(&sc->gif_si_refs) == 0) {
+ mutex_enter(sc->gif_si_lock);
+ cv_broadcast(&sc->gif_si_cv);
+ mutex_exit(sc->gif_si_lock);
+ }
}
void
@@ -744,6 +782,7 @@
struct gif_softc *sc2;
struct sockaddr *osrc, *odst;
struct sockaddr *nsrc, *ndst;
+ void *osi;
int s;
int error;
@@ -777,8 +816,38 @@
/* Firstly, clear old configurations. */
if (sc->gif_si) {
- softint_disestablish(sc->gif_si);
+ osrc = sc->gif_psrc;
+ odst = sc->gif_pdst;
+ osi = sc->gif_si;
+ sc->gif_psrc = NULL;
+ sc->gif_pdst = NULL;
sc->gif_si = NULL;
+
+ /*
+ * At this point, gif_output() does not softint_schedule()
+ * any more. However, there are below 2 fears of other CPUs.
+ * (a) gif_output() has done softint_schedule(),and softint
+ * (gifintr()) is waiting for execution
+ * (b) gifintr() is already running
+ * see also gifintr()
+ */
+
+ /*
+ * To avoid the above fears, wait for gifintr() completion of
+ * all CPUs here.
+ */
+ mutex_enter(sc->gif_si_lock);
+ while (sc->gif_si_refs > 0) {
+ aprint_debug("%s: cv_wait on gif_softc\n", __func__);
+ cv_wait(&sc->gif_si_cv, sc->gif_si_lock);
+ }
+ mutex_exit(sc->gif_si_lock);
+
+ softint_disestablish(osi);
+ sc->gif_psrc = osrc;
+ sc->gif_pdst = odst;
+ osrc = NULL;
+ odst = NULL;
}
/* XXX we can detach from both, but be polite just in case */
if (sc->gif_psrc)
@@ -845,13 +914,31 @@
gif_delete_tunnel(struct ifnet *ifp)
{
struct gif_softc *sc = ifp->if_softc;
+ struct sockaddr *osrc, *odst;
+ void *osi;
int s;
s = splsoftnet();
if (sc->gif_si) {
- softint_disestablish(sc->gif_si);
+ osrc = sc->gif_psrc;
+ odst = sc->gif_pdst;
+ osi = sc->gif_si;
+
+ sc->gif_psrc = NULL;
+ sc->gif_pdst = NULL;
sc->gif_si = NULL;
+
+ mutex_enter(sc->gif_si_lock);
+ while (sc->gif_si_refs > 0) {
+ aprint_debug("%s: cv_wait on gif_softc\n", __func__);
+ cv_wait(&sc->gif_si_cv, sc->gif_si_lock);
+ }
+ mutex_exit(sc->gif_si_lock);
+
+ softint_disestablish(osi);
+ sc->gif_psrc = osrc;
+ sc->gif_pdst = odst;
}
if (sc->gif_psrc) {
sockaddr_free(sc->gif_psrc);
diff -r 54d18cf44ff1 -r 4bf87e5eea73 sys/net/if_gif.h
--- a/sys/net/if_gif.h Fri Dec 11 07:21:09 2015 +0000
+++ b/sys/net/if_gif.h Fri Dec 11 07:59:14 2015 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: if_gif.h,v 1.19 2008/11/12 12:36:28 ad Exp $ */
+/* $NetBSD: if_gif.h,v 1.20 2015/12/11 07:59:14 knakahara Exp $ */
/* $KAME: if_gif.h,v 1.23 2001/07/27 09:21:42 itojun Exp $ */
/*
@@ -38,6 +38,8 @@
#define _NET_IF_GIF_H_
#include <sys/queue.h>
+#include <sys/mutex.h>
+#include <sys/condvar.h>
#ifdef _KERNEL_OPT
#include "opt_inet.h"
@@ -60,11 +62,21 @@
const struct encaptab *encap_cookie6;
LIST_ENTRY(gif_softc) gif_list; /* list of all gifs */
void *gif_si; /* softintr handle */
+
+ struct si_sync { /* can access without gif_lock */
+ unsigned int si_refs; /* reference count for gif_si */
+ kcondvar_t si_cv; /* wait for softint completion */
+ kmutex_t *si_lock; /* lock for gif_si_sync */
+ } gif_si_sync;
};
#define GIF_ROUTE_TTL 10
#define gif_ro gifsc_gifscr.gifscr_ro
+#define gif_si_refs gif_si_sync.si_refs
+#define gif_si_cv gif_si_sync.si_cv
+#define gif_si_lock gif_si_sync.si_lock
+
#define GIF_MTU (1280) /* Default MTU */
#define GIF_MTU_MIN (1280) /* Minimum MTU */
#define GIF_MTU_MAX (8192) /* Maximum MTU */
@@ -81,4 +93,8 @@
int gif_encapcheck(struct mbuf *, int, int, void *);
#endif
+/*
+ * Locking notes:
+ * - All members of struct si_sync are protected by si_lock (an adaptive mutex)
+ */
#endif /* !_NET_IF_GIF_H_ */
diff -r 54d18cf44ff1 -r 4bf87e5eea73 sys/netinet/in_gif.c
--- a/sys/netinet/in_gif.c Fri Dec 11 07:21:09 2015 +0000
+++ b/sys/netinet/in_gif.c Fri Dec 11 07:59:14 2015 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: in_gif.c,v 1.65 2015/08/24 22:21:26 pooka Exp $ */
+/* $NetBSD: in_gif.c,v 1.66 2015/12/11 07:59:14 knakahara Exp $ */
/* $KAME: in_gif.c,v 1.66 2001/07/29 04:46:09 itojun Exp $ */
/*
@@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: in_gif.c,v 1.65 2015/08/24 22:21:26 pooka Exp $");
+__KERNEL_RCSID(0, "$NetBSD: in_gif.c,v 1.66 2015/12/11 07:59:14 knakahara Exp $");
#ifdef _KERNEL_OPT
#include "opt_inet.h"
@@ -223,13 +223,20 @@
return;
}
#ifndef GIF_ENCAPCHECK
- if (!gif_validate4(ip, gifp->if_softc, m->m_pkthdr.rcvif)) {
+ struct gif_softc *sc = (struct gif_softc *)gifp->if_softc;
+ /* other CPU do delete_tunnel */
+ if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
+ m_freem(m);
+ ip_statinc(IP_STAT_NOGIF);
+ return;
+ }
+
+ if (!gif_validate4(ip, sc, m->m_pkthdr.rcvif)) {
m_freem(m);
ip_statinc(IP_STAT_NOGIF);
return;
}
#endif
-
otos = ip->ip_tos;
m_adj(m, off);
diff -r 54d18cf44ff1 -r 4bf87e5eea73 sys/netinet6/in6_gif.c
--- a/sys/netinet6/in6_gif.c Fri Dec 11 07:21:09 2015 +0000
+++ b/sys/netinet6/in6_gif.c Fri Dec 11 07:59:14 2015 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: in6_gif.c,v 1.62 2015/08/24 22:21:27 pooka Exp $ */
+/* $NetBSD: in6_gif.c,v 1.63 2015/12/11 07:59:14 knakahara Exp $ */
/* $KAME: in6_gif.c,v 1.62 2001/07/29 04:27:25 itojun Exp $ */
/*
@@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: in6_gif.c,v 1.62 2015/08/24 22:21:27 pooka Exp $");
+__KERNEL_RCSID(0, "$NetBSD: in6_gif.c,v 1.63 2015/12/11 07:59:14 knakahara Exp $");
#ifdef _KERNEL_OPT
#include "opt_inet.h"
Home |
Main Index |
Thread Index |
Old Index