svn commit: r285740 - in head/sys: netinet netinet6
Randall Stewart
rrs at FreeBSD.org
Tue Jul 21 09:54:33 UTC 2015
Author: rrs
Date: Tue Jul 21 09:54:31 2015
New Revision: 285740
URL: https://svnweb.freebsd.org/changeset/base/285740
Log:
When a tunneling protocol is being used with UDP we must release the
lock on the INP before calling the tunnel protocol, else a LOR
may occur (it does with SCTP for sure). Instead we must acquire a
ref count and release the lock, taking care to allow for the case
where the UDP socket has gone away and *not* unlocking since the
refcnt decrement on the inp will do the unlock in that case.
Reviewed by: tuexen
MFC after: 3 weeks
Modified:
head/sys/netinet/udp_usrreq.c
head/sys/netinet6/udp6_usrreq.c
Modified: head/sys/netinet/udp_usrreq.c
==============================================================================
--- head/sys/netinet/udp_usrreq.c Tue Jul 21 09:44:45 2015 (r285739)
+++ head/sys/netinet/udp_usrreq.c Tue Jul 21 09:54:31 2015 (r285740)
@@ -293,8 +293,17 @@ udplite_destroy(void)
* contains the source address. If the socket ends up being an IPv6 socket,
* udp_append() will convert to a sockaddr_in6 before passing the address
* into the socket code.
+ *
+ * In the normal case udp_append() will return 0, indicating that you
+ * must unlock the inp. However if a tunneling protocol is in place we increment
+ * the inpcb refcnt and unlock the inp, on return from the tunneling protocol we
+ * then decrement the reference count. If the inp_rele returns 1, indicating the
+ * inp is gone, we return that to the caller to tell them *not* to unlock
+ * the inp. In the case of multi-cast this will cause the distribution
+ * to stop (though most tunneling protocols known currently do *not* use
+ * multicast).
*/
-static void
+static int
udp_append(struct inpcb *inp, struct ip *ip, struct mbuf *n, int off,
struct sockaddr_in *udp_in)
{
@@ -313,9 +322,12 @@ udp_append(struct inpcb *inp, struct ip
*/
up = intoudpcb(inp);
if (up->u_tun_func != NULL) {
+ in_pcbref(inp);
+ INP_RUNLOCK(inp);
(*up->u_tun_func)(n, off, inp, (struct sockaddr *)udp_in,
up->u_tun_ctx);
- return;
+ INP_RLOCK(inp);
+ return (in_pcbrele_rlocked(inp));
}
off += sizeof(struct udphdr);
@@ -324,7 +336,7 @@ udp_append(struct inpcb *inp, struct ip
/* Check AH/ESP integrity. */
if (ipsec4_in_reject(n, inp)) {
m_freem(n);
- return;
+ return (0);
}
#ifdef IPSEC_NAT_T
up = intoudpcb(inp);
@@ -332,14 +344,14 @@ udp_append(struct inpcb *inp, struct ip
if (up->u_flags & UF_ESPINUDP_ALL) { /* IPSec UDP encaps. */
n = udp4_espdecap(inp, n, off);
if (n == NULL) /* Consumed. */
- return;
+ return (0);
}
#endif /* IPSEC_NAT_T */
#endif /* IPSEC */
#ifdef MAC
if (mac_inpcb_check_deliver(inp, n) != 0) {
m_freem(n);
- return;
+ return (0);
}
#endif /* MAC */
if (inp->inp_flags & INP_CONTROLOPTS ||
@@ -373,6 +385,7 @@ udp_append(struct inpcb *inp, struct ip
UDPSTAT_INC(udps_fullsock);
} else
sorwakeup_locked(so);
+ return (0);
}
int
@@ -579,8 +592,10 @@ udp_input(struct mbuf **mp, int *offp, i
if ((n = m_copy(m, 0, M_COPYALL)) != NULL) {
UDP_PROBE(receive, NULL, last, ip,
last, uh);
- udp_append(last, ip, n, iphlen,
- &udp_in);
+ if (udp_append(last, ip, n, iphlen,
+ &udp_in)) {
+ goto inp_lost;
+ }
}
INP_RUNLOCK(last);
}
@@ -611,8 +626,9 @@ udp_input(struct mbuf **mp, int *offp, i
goto badunlocked;
}
UDP_PROBE(receive, NULL, last, ip, last, uh);
- udp_append(last, ip, m, iphlen, &udp_in);
- INP_RUNLOCK(last);
+ if (udp_append(last, ip, m, iphlen, &udp_in) == 0)
+ INP_RUNLOCK(last);
+ inp_lost:
INP_INFO_RUNLOCK(pcbinfo);
return (IPPROTO_DONE);
}
@@ -700,8 +716,8 @@ udp_input(struct mbuf **mp, int *offp, i
}
UDP_PROBE(receive, NULL, inp, ip, inp, uh);
- udp_append(inp, ip, m, iphlen, &udp_in);
- INP_RUNLOCK(inp);
+ if (udp_append(inp, ip, m, iphlen, &udp_in) == 0)
+ INP_RUNLOCK(inp);
return (IPPROTO_DONE);
badunlocked:
Modified: head/sys/netinet6/udp6_usrreq.c
==============================================================================
--- head/sys/netinet6/udp6_usrreq.c Tue Jul 21 09:44:45 2015 (r285739)
+++ head/sys/netinet6/udp6_usrreq.c Tue Jul 21 09:54:31 2015 (r285740)
@@ -136,7 +136,7 @@ __FBSDID("$FreeBSD$");
extern struct protosw inetsw[];
static void udp6_detach(struct socket *so);
-static void
+static int
udp6_append(struct inpcb *inp, struct mbuf *n, int off,
struct sockaddr_in6 *fromsa)
{
@@ -151,21 +151,24 @@ udp6_append(struct inpcb *inp, struct mb
*/
up = intoudpcb(inp);
if (up->u_tun_func != NULL) {
+ in_pcbref(inp);
+ INP_RUNLOCK(inp);
(*up->u_tun_func)(n, off, inp, (struct sockaddr *)fromsa,
up->u_tun_ctx);
- return;
+ INP_RLOCK(inp);
+ return (in_pcbrele_rlocked(inp));
}
#ifdef IPSEC
/* Check AH/ESP integrity. */
if (ipsec6_in_reject(n, inp)) {
m_freem(n);
- return;
+ return (0);
}
#endif /* IPSEC */
#ifdef MAC
if (mac_inpcb_check_deliver(inp, n) != 0) {
m_freem(n);
- return;
+ return (0);
}
#endif
opts = NULL;
@@ -185,6 +188,7 @@ udp6_append(struct inpcb *inp, struct mb
UDPSTAT_INC(udps_fullsock);
} else
sorwakeup_locked(so);
+ return (0);
}
int
@@ -367,7 +371,8 @@ udp6_input(struct mbuf **mp, int *offp,
INP_RLOCK(last);
UDP_PROBE(receive, NULL, last, ip6,
last, uh);
- udp6_append(last, n, off, &fromsa);
+ if (udp6_append(last, n, off, &fromsa))
+ goto inp_lost;
INP_RUNLOCK(last);
}
}
@@ -398,8 +403,9 @@ udp6_input(struct mbuf **mp, int *offp,
INP_RLOCK(last);
INP_INFO_RUNLOCK(pcbinfo);
UDP_PROBE(receive, NULL, last, ip6, last, uh);
- udp6_append(last, m, off, &fromsa);
- INP_RUNLOCK(last);
+ if (udp6_append(last, m, off, &fromsa))
+ INP_RUNLOCK(last);
+ inp_lost:
return (IPPROTO_DONE);
}
/*
@@ -477,8 +483,8 @@ udp6_input(struct mbuf **mp, int *offp,
}
}
UDP_PROBE(receive, NULL, inp, ip6, inp, uh);
- udp6_append(inp, m, off, &fromsa);
- INP_RUNLOCK(inp);
+ if (udp6_append(inp, m, off, &fromsa) == 0)
+ INP_RUNLOCK(inp);
return (IPPROTO_DONE);
badheadlocked:
More information about the svn-src-head
mailing list