aboutsummaryrefslogtreecommitdiff
path: root/sys/netinet6
diff options
context:
space:
mode:
authorMark Johnston <markj@FreeBSD.org>2021-05-12 13:39:36 +0000
committerMark Johnston <markj@FreeBSD.org>2021-05-12 17:00:09 +0000
commitd8acd2681bcfb2ff7eb154df82f268b1cb191b4c (patch)
tree39eb45ff81d9aafb9826e2aee57a6129403803f4 /sys/netinet6
parentc1dd4d642fa0e2c8ea4f9a879f2cc4e5d6c39211 (diff)
downloadsrc-d8acd2681bcfb2ff7eb154df82f268b1cb191b4c.tar.gz
src-d8acd2681bcfb2ff7eb154df82f268b1cb191b4c.zip
Fix mbuf leaks in various pru_send implementations
The various protocol implementations are not very consistent about freeing mbufs in error paths. In general, all protocols must free both "m" and "control" upon an error, except if PRUS_NOTREADY is specified (this is only implemented by TCP and unix(4) and requires further work not handled in this diff), in which case "control" still must be freed. This diff plugs various leaks in the pru_send implementations. Reviewed by: tuexen MFC after: 2 weeks Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D30151
Diffstat (limited to 'sys/netinet6')
-rw-r--r--sys/netinet6/raw_ip6.c40
-rw-r--r--sys/netinet6/sctp6_usrreq.c25
-rw-r--r--sys/netinet6/send.c3
3 files changed, 49 insertions, 19 deletions
diff --git a/sys/netinet6/raw_ip6.c b/sys/netinet6/raw_ip6.c
index 3d2af6e5c9e6..a369abb04bfc 100644
--- a/sys/netinet6/raw_ip6.c
+++ b/sys/netinet6/raw_ip6.c
@@ -867,7 +867,7 @@ rip6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
struct inpcb *inp;
struct sockaddr_in6 tmp;
struct sockaddr_in6 *dst;
- int ret;
+ int error;
inp = sotoinpcb(so);
KASSERT(inp != NULL, ("rip6_send: inp == NULL"));
@@ -876,8 +876,8 @@ rip6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
/* Unlocked read. */
if (so->so_state & SS_ISCONNECTED) {
if (nam) {
- m_freem(m);
- return (EISCONN);
+ error = EISCONN;
+ goto release;
}
/* XXX */
bzero(&tmp, sizeof(tmp));
@@ -889,18 +889,15 @@ rip6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
INP_RUNLOCK(inp);
dst = &tmp;
} else {
- if (nam == NULL) {
- m_freem(m);
- return (ENOTCONN);
- }
- if (nam->sa_family != AF_INET6) {
- m_freem(m);
- return (EAFNOSUPPORT);
- }
- if (nam->sa_len != sizeof(struct sockaddr_in6)) {
- m_freem(m);
- return (EINVAL);
- }
+ error = 0;
+ if (nam == NULL)
+ error = ENOTCONN;
+ else if (nam->sa_family != AF_INET6)
+ error = EAFNOSUPPORT;
+ else if (nam->sa_len != sizeof(struct sockaddr_in6))
+ error = EINVAL;
+ if (error != 0)
+ goto release;
tmp = *(struct sockaddr_in6 *)nam;
dst = &tmp;
@@ -914,12 +911,17 @@ rip6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
"unspec. Assume AF_INET6\n");
dst->sin6_family = AF_INET6;
} else if (dst->sin6_family != AF_INET6) {
- m_freem(m);
- return(EAFNOSUPPORT);
+ error = EAFNOSUPPORT;
+ goto release;
}
}
- ret = rip6_output(m, so, dst, control);
- return (ret);
+ return (rip6_output(m, so, dst, control));
+
+release:
+ if (control != NULL)
+ m_freem(control);
+ m_freem(m);
+ return (error);
}
struct pr_usrreqs rip6_usrreqs = {
diff --git a/sys/netinet6/sctp6_usrreq.c b/sys/netinet6/sctp6_usrreq.c
index 1030fe1bbb68..3be7a3e25de8 100644
--- a/sys/netinet6/sctp6_usrreq.c
+++ b/sys/netinet6/sctp6_usrreq.c
@@ -713,6 +713,11 @@ sctp6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
#ifdef INET
case AF_INET:
if (addr->sa_len != sizeof(struct sockaddr_in)) {
+ if (control) {
+ SCTP_RELEASE_PKT(control);
+ control = NULL;
+ }
+ SCTP_RELEASE_PKT(m);
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
return (EINVAL);
}
@@ -721,12 +726,22 @@ sctp6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
#ifdef INET6
case AF_INET6:
if (addr->sa_len != sizeof(struct sockaddr_in6)) {
+ if (control) {
+ SCTP_RELEASE_PKT(control);
+ control = NULL;
+ }
+ SCTP_RELEASE_PKT(m);
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
return (EINVAL);
}
break;
#endif
default:
+ if (control) {
+ SCTP_RELEASE_PKT(control);
+ control = NULL;
+ }
+ SCTP_RELEASE_PKT(m);
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
return (EINVAL);
}
@@ -738,10 +753,20 @@ sctp6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
* v4 addr or v4-mapped addr
*/
if (addr->sa_family == AF_INET) {
+ if (control) {
+ SCTP_RELEASE_PKT(control);
+ control = NULL;
+ }
+ SCTP_RELEASE_PKT(m);
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
return (EINVAL);
}
if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
+ if (control) {
+ SCTP_RELEASE_PKT(control);
+ control = NULL;
+ }
+ SCTP_RELEASE_PKT(m);
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
return (EINVAL);
}
diff --git a/sys/netinet6/send.c b/sys/netinet6/send.c
index aef2ee400c0e..677a83ab94cc 100644
--- a/sys/netinet6/send.c
+++ b/sys/netinet6/send.c
@@ -250,8 +250,11 @@ send_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
m = NULL;
err:
+ if (control != NULL)
+ m_freem(control);
if (m != NULL)
m_freem(m);
+
return (error);
}