Module Name: src Committed By: martin Date: Wed Aug 15 12:07:30 UTC 2018
Modified Files: src/sys/net [netbsd-8]: if_tun.c Log Message: Pull up following revision(s) (requested by ozaki-r in ticket #974): sys/net/if_tun.c: revision 1.145 sys/net/if_tun.c: revision 1.146 tun: fix locking against myself filt_tunread is called with tun_lock held from tun_output (via tun_output => selnotify => knote), so we must not take tun_lock in filt_tunread. The bug is triggered only if a tun is used through kqueue. Found by k-goda@IIJ Fix tun(4) kevent locking filt_tunread gets called in two contexts: - by calls to selnotify in if_tun.c (or knote, as the case may be, but not here), in which case tp->tun_lock is held; and - by internal logic in kevent, in which tp->tun_lock is not held. The standard convention to discriminate between these two cases is by setting the kernel-only NOTE_SUBMIT bit in the hint to selnotify or knote; then in filt_*: if (hint & NOTE_SUBMIT) KASSERT(mutex_owned(&tp->tun_lock)); else mutex_enter(&tp->tun_lock); ... if (hint & NOTE_SUBMIT) KASSERT(mutex_owned(&tp->tun_lock)); else mutex_exit(&tp->tun_lock); Pointed out by and patch from riastradh@ Tested by ozaki-r@ (only the former path) To generate a diff of this commit: cvs rdiff -u -r1.139.2.3 -r1.139.2.4 src/sys/net/if_tun.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/net/if_tun.c diff -u src/sys/net/if_tun.c:1.139.2.3 src/sys/net/if_tun.c:1.139.2.4 --- src/sys/net/if_tun.c:1.139.2.3 Sat Mar 17 11:26:44 2018 +++ src/sys/net/if_tun.c Wed Aug 15 12:07:30 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: if_tun.c,v 1.139.2.3 2018/03/17 11:26:44 martin Exp $ */ +/* $NetBSD: if_tun.c,v 1.139.2.4 2018/08/15 12:07:30 martin Exp $ */ /* * Copyright (c) 1988, Julian Onions <j...@cs.nott.ac.uk> @@ -19,7 +19,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: if_tun.c,v 1.139.2.3 2018/03/17 11:26:44 martin Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_tun.c,v 1.139.2.4 2018/08/15 12:07:30 martin Exp $"); #ifdef _KERNEL_OPT #include "opt_inet.h" @@ -288,7 +288,7 @@ tun_clone_destroy(struct ifnet *ifp) tp->tun_flags &= ~TUN_RWAIT; cv_broadcast(&tp->tun_cv); } - selnotify(&tp->tun_rsel, 0, 0); + selnotify(&tp->tun_rsel, 0, NOTE_SUBMIT); mutex_exit(&tp->tun_lock); @@ -381,7 +381,7 @@ tunclose(dev_t dev, int flag, int mode, tp->tun_flags &= ~TUN_OPEN; tp->tun_pgid = 0; - selnotify(&tp->tun_rsel, 0, 0); + selnotify(&tp->tun_rsel, 0, NOTE_SUBMIT); TUNDEBUG ("%s: closed\n", ifp->if_xname); mutex_exit(&tp->tun_lock); @@ -625,7 +625,7 @@ tun_output(struct ifnet *ifp, struct mbu if (tp->tun_flags & TUN_ASYNC && tp->tun_pgid) softint_schedule(tp->tun_isih); - selnotify(&tp->tun_rsel, 0, 0); + selnotify(&tp->tun_rsel, 0, NOTE_SUBMIT); mutex_exit(&tp->tun_lock); out: @@ -996,7 +996,7 @@ tunstart(struct ifnet *ifp) if (tp->tun_flags & TUN_ASYNC && tp->tun_pgid) softint_schedule(tp->tun_osih); - selnotify(&tp->tun_rsel, 0, 0); + selnotify(&tp->tun_rsel, 0, NOTE_SUBMIT); } mutex_exit(&tp->tun_lock); } @@ -1057,20 +1057,24 @@ filt_tunread(struct knote *kn, long hint struct tun_softc *tp = kn->kn_hook; struct ifnet *ifp = &tp->tun_if; struct mbuf *m; + int ready; - mutex_enter(&tp->tun_lock); - IF_POLL(&ifp->if_snd, m); - if (m == NULL) { - mutex_exit(&tp->tun_lock); - return 0; - } + if (hint & NOTE_SUBMIT) + KASSERT(mutex_owned(&tp->tun_lock)); + else + mutex_enter(&tp->tun_lock); + IF_POLL(&ifp->if_snd, m); + ready = (m != NULL); for (kn->kn_data = 0; m != NULL; m = m->m_next) kn->kn_data += m->m_len; - mutex_exit(&tp->tun_lock); + if (hint & NOTE_SUBMIT) + KASSERT(mutex_owned(&tp->tun_lock)); + else + mutex_exit(&tp->tun_lock); - return 1; + return ready; } static const struct filterops tunread_filtops =