Fix FAST_IPSEC locking violation.
Without this change, using ESP tunnels with FAST_IPSEC on a 2-cpu i386 machine results in an mbuf leak. This change was tested in netbsd-6. When FAST_IPSEC is enabled and a tunnel is set up, after the outer packet is stripped off, FAST_IPSEC queues the inner packet on the appropriate queue (ipinstrq or ip6instrq). These queues require the KERNEL_LOCK to be held before using the queue, and the FAST_IPSEC code did not take the KERNEL_LOCK as required. KERNEL_LOCK and KERNEL_UNLOCK_ONE calls have been added. If a struct ifnet instance is passed to the if_handoff function which does this queuing, the interface's if_start function may be called. Some hardware devices require KERNEL_LOCK to be held; others do not. Looking at the body of NetBSD code, other places where an if_start function is called, KERNEL_LOCK is held. Thus, the lock is not released in if_handoff until after the if_start function is called. In practice, having the kernel lock when if_start is called makes no difference - there is not a single instance in all of the NetBSD code where if_handoff is passed an instance of struct ifnet. This commit is the work of Bev Schwartz of BBN. Approved for Public Release, Distribution Unlimited This material is based upon work supported by the Defense Advanced Research Projects Agency and Space and Naval Warfare Systems Center, Pacific, under Contract No. N66001-09-C-2073.
This commit is contained in:
parent
464306f9db
commit
0c9c715c58
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: ipsec_osdep.h,v 1.23 2011/11/29 13:15:27 drochner Exp $ */
|
||||
/* $NetBSD: ipsec_osdep.h,v 1.24 2013/05/09 19:21:50 gdt Exp $ */
|
||||
/* $FreeBSD: /repoman/r/ncvs/src/sys/netipsec/ipsec_osdep.h,v 1.1 2003/09/29 22:47:45 sam Exp $ */
|
||||
|
||||
/*
|
||||
@ -144,8 +144,10 @@ if_handoff(struct ifqueue *ifq, struct mbuf *m, struct ifnet *ifp, int adjust)
|
||||
int need_if_start = 0;
|
||||
int s = splnet();
|
||||
|
||||
KERNEL_LOCK(1, NULL);
|
||||
if (IF_QFULL(ifq)) {
|
||||
IF_DROP(ifq);
|
||||
KERNEL_UNLOCK_ONE(NULL);
|
||||
splx(s);
|
||||
m_freem(m);
|
||||
return (0);
|
||||
@ -159,6 +161,7 @@ if_handoff(struct ifqueue *ifq, struct mbuf *m, struct ifnet *ifp, int adjust)
|
||||
IF_ENQUEUE(ifq, m);
|
||||
if (need_if_start)
|
||||
(*ifp->if_start)(ifp);
|
||||
KERNEL_UNLOCK_ONE(NULL);
|
||||
splx(s);
|
||||
return (1);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user