aboutsummaryrefslogtreecommitdiff
path: root/sys/netinet
diff options
context:
space:
mode:
authorBjoern A. Zeeb <bz@FreeBSD.org>2008-11-29 14:32:14 +0000
committerBjoern A. Zeeb <bz@FreeBSD.org>2008-11-29 14:32:14 +0000
commit413628a7e3d23a897cd959638d325395e4c9691b (patch)
tree2b8f4835032d12a0e61cc40dad151e279cf7a49f /sys/netinet
parentf0f4475a13fe3545c10e9b3e8c69679c4abfb1b3 (diff)
Notes
Diffstat (limited to 'sys/netinet')
-rw-r--r--sys/netinet/in_pcb.c162
-rw-r--r--sys/netinet/raw_ip.c46
-rw-r--r--sys/netinet/sctp_pcb.c35
-rw-r--r--sys/netinet/sctp_usrreq.c77
-rw-r--r--sys/netinet/tcp_usrreq.c12
-rw-r--r--sys/netinet/udp_usrreq.c14
6 files changed, 221 insertions, 125 deletions
diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c
index 9ca1edc8cb13..bb2eae05f1dd 100644
--- a/sys/netinet/in_pcb.c
+++ b/sys/netinet/in_pcb.c
@@ -294,7 +294,7 @@ in_pcbbind_setup(struct inpcb *inp, struct sockaddr *nam, in_addr_t *laddrp,
struct in_addr laddr;
u_short lport = 0;
int wild = 0, reuseport = (so->so_options & SO_REUSEPORT);
- int error, prison = 0;
+ int error;
int dorandom;
/*
@@ -323,9 +323,8 @@ in_pcbbind_setup(struct inpcb *inp, struct sockaddr *nam, in_addr_t *laddrp,
if (sin->sin_family != AF_INET)
return (EAFNOSUPPORT);
#endif
- if (sin->sin_addr.s_addr != INADDR_ANY)
- if (prison_ip(cred, 0, &sin->sin_addr.s_addr))
- return(EINVAL);
+ if (prison_local_ip4(cred, &sin->sin_addr))
+ return (EINVAL);
if (sin->sin_port != *lportp) {
/* Don't allow the port to change. */
if (*lportp != 0)
@@ -360,14 +359,11 @@ in_pcbbind_setup(struct inpcb *inp, struct sockaddr *nam, in_addr_t *laddrp,
priv_check_cred(cred, PRIV_NETINET_RESERVEDPORT,
0))
return (EACCES);
- if (jailed(cred))
- prison = 1;
if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr)) &&
priv_check_cred(inp->inp_cred,
PRIV_NETINET_REUSEPORT, 0) != 0) {
t = in_pcblookup_local(pcbinfo, sin->sin_addr,
- lport, prison ? 0 : INPLOOKUP_WILDCARD,
- cred);
+ lport, INPLOOKUP_WILDCARD, cred);
/*
* XXX
* This entire block sorely needs a rewrite.
@@ -384,10 +380,10 @@ in_pcbbind_setup(struct inpcb *inp, struct sockaddr *nam, in_addr_t *laddrp,
t->inp_cred->cr_uid))
return (EADDRINUSE);
}
- if (prison && prison_ip(cred, 0, &sin->sin_addr.s_addr))
+ if (prison_local_ip4(cred, &sin->sin_addr))
return (EADDRNOTAVAIL);
t = in_pcblookup_local(pcbinfo, sin->sin_addr,
- lport, prison ? 0 : wild, cred);
+ lport, wild, cred);
if (t && (t->inp_vflag & INP_TIMEWAIT)) {
/*
* XXXRW: If an incpb has had its timewait
@@ -419,9 +415,8 @@ in_pcbbind_setup(struct inpcb *inp, struct sockaddr *nam, in_addr_t *laddrp,
u_short first, last, aux;
int count;
- if (laddr.s_addr != INADDR_ANY)
- if (prison_ip(cred, 0, &laddr.s_addr))
- return (EINVAL);
+ if (prison_local_ip4(cred, &laddr))
+ return (EINVAL);
if (inp->inp_flags & INP_HIGHPORT) {
first = V_ipport_hifirstauto; /* sysctl */
@@ -487,7 +482,7 @@ in_pcbbind_setup(struct inpcb *inp, struct sockaddr *nam, in_addr_t *laddrp,
} while (in_pcblookup_local(pcbinfo, laddr,
lport, wild, cred));
}
- if (prison_ip(cred, 0, &laddr.s_addr))
+ if (prison_local_ip4(cred, &laddr))
return (EINVAL);
*laddrp = laddr.s_addr;
*lportp = lport;
@@ -556,7 +551,7 @@ in_pcbladdr(struct inpcb *inp, struct in_addr *faddr, struct in_addr *laddr,
struct route sro;
int error;
- KASSERT(laddr != NULL, ("%s: null laddr", __func__));
+ KASSERT(laddr != NULL, ("%s: laddr NULL", __func__));
error = 0;
ia = NULL;
@@ -608,7 +603,7 @@ in_pcbladdr(struct inpcb *inp, struct in_addr *faddr, struct in_addr *laddr,
if (sa->sa_family != AF_INET)
continue;
sin = (struct sockaddr_in *)sa;
- if (htonl(prison_getip(cred)) == sin->sin_addr.s_addr) {
+ if (prison_check_ip4(cred, &sin->sin_addr)) {
ia = (struct in_ifaddr *)ifa;
break;
}
@@ -619,7 +614,8 @@ in_pcbladdr(struct inpcb *inp, struct in_addr *faddr, struct in_addr *laddr,
}
/* 3. As a last resort return the 'default' jail address. */
- laddr->s_addr = htonl(prison_getip(cred));
+ if (prison_getip4(cred, laddr) != 0)
+ error = EADDRNOTAVAIL;
goto done;
}
@@ -644,7 +640,7 @@ in_pcbladdr(struct inpcb *inp, struct in_addr *faddr, struct in_addr *laddr,
/* Jailed. */
/* 1. Check if the iface address belongs to the jail. */
sin = (struct sockaddr_in *)sro.ro_rt->rt_ifa->ifa_addr;
- if (htonl(prison_getip(cred)) == sin->sin_addr.s_addr) {
+ if (prison_check_ip4(cred, &sin->sin_addr)) {
ia = (struct in_ifaddr *)sro.ro_rt->rt_ifa;
laddr->s_addr = ia->ia_addr.sin_addr.s_addr;
goto done;
@@ -660,7 +656,7 @@ in_pcbladdr(struct inpcb *inp, struct in_addr *faddr, struct in_addr *laddr,
if (sa->sa_family != AF_INET)
continue;
sin = (struct sockaddr_in *)sa;
- if (htonl(prison_getip(cred)) == sin->sin_addr.s_addr) {
+ if (prison_check_ip4(cred, &sin->sin_addr)) {
ia = (struct in_ifaddr *)ifa;
break;
}
@@ -671,7 +667,8 @@ in_pcbladdr(struct inpcb *inp, struct in_addr *faddr, struct in_addr *laddr,
}
/* 3. As a last resort return the 'default' jail address. */
- laddr->s_addr = htonl(prison_getip(cred));
+ if (prison_getip4(cred, laddr) != 0)
+ error = EADDRNOTAVAIL;
goto done;
}
@@ -717,8 +714,7 @@ in_pcbladdr(struct inpcb *inp, struct in_addr *faddr, struct in_addr *laddr,
if (sa->sa_family != AF_INET)
continue;
sin = (struct sockaddr_in *)sa;
- if (htonl(prison_getip(cred)) ==
- sin->sin_addr.s_addr) {
+ if (prison_check_ip4(cred, &sin->sin_addr)) {
ia = (struct in_ifaddr *)ifa;
break;
}
@@ -730,7 +726,8 @@ in_pcbladdr(struct inpcb *inp, struct in_addr *faddr, struct in_addr *laddr,
}
/* 3. As a last resort return the 'default' jail address. */
- laddr->s_addr = htonl(prison_getip(cred));
+ if (prison_getip4(cred, laddr) != 0)
+ error = EADDRNOTAVAIL;
goto done;
}
@@ -764,7 +761,7 @@ in_pcbconnect_setup(struct inpcb *inp, struct sockaddr *nam,
struct sockaddr_in *sin = (struct sockaddr_in *)nam;
struct in_ifaddr *ia;
struct inpcb *oinp;
- struct in_addr laddr, faddr;
+ struct in_addr laddr, faddr, jailia;
u_short lport, fport;
int error;
@@ -796,9 +793,17 @@ in_pcbconnect_setup(struct inpcb *inp, struct sockaddr *nam,
* and the primary interface supports broadcast,
* choose the broadcast address for that interface.
*/
- if (faddr.s_addr == INADDR_ANY)
- faddr = IA_SIN(TAILQ_FIRST(&V_in_ifaddrhead))->sin_addr;
- else if (faddr.s_addr == (u_long)INADDR_BROADCAST &&
+ if (faddr.s_addr == INADDR_ANY) {
+ if (cred != NULL && jailed(cred)) {
+ if (prison_getip4(cred, &jailia) != 0)
+ return (EADDRNOTAVAIL);
+ faddr.s_addr = jailia.s_addr;
+ } else {
+ faddr =
+ IA_SIN(TAILQ_FIRST(&V_in_ifaddrhead))->
+ sin_addr;
+ }
+ } else if (faddr.s_addr == (u_long)INADDR_BROADCAST &&
(TAILQ_FIRST(&V_in_ifaddrhead)->ia_ifp->if_flags &
IFF_BROADCAST))
faddr = satosin(&TAILQ_FIRST(
@@ -1115,6 +1120,7 @@ in_pcblookup_local(struct inpcbinfo *pcbinfo, struct in_addr laddr,
0, pcbinfo->ipi_hashmask)];
LIST_FOREACH(inp, head, inp_hash) {
#ifdef INET6
+ /* XXX inp locking */
if ((inp->inp_vflag & INP_IPV4) == 0)
continue;
#endif
@@ -1122,9 +1128,11 @@ in_pcblookup_local(struct inpcbinfo *pcbinfo, struct in_addr laddr,
inp->inp_laddr.s_addr == laddr.s_addr &&
inp->inp_lport == lport) {
/*
- * Found.
+ * Found?
*/
- return (inp);
+ if (cred == NULL ||
+ inp->inp_cred->cr_prison == cred->cr_prison)
+ return (inp);
}
}
/*
@@ -1154,7 +1162,11 @@ in_pcblookup_local(struct inpcbinfo *pcbinfo, struct in_addr laddr,
*/
LIST_FOREACH(inp, &phd->phd_pcblist, inp_portlist) {
wildcard = 0;
+ if (cred != NULL &&
+ inp->inp_cred->cr_prison != cred->cr_prison)
+ continue;
#ifdef INET6
+ /* XXX inp locking */
if ((inp->inp_vflag & INP_IPV4) == 0)
continue;
/*
@@ -1187,9 +1199,8 @@ in_pcblookup_local(struct inpcbinfo *pcbinfo, struct in_addr laddr,
if (wildcard < matchwild) {
match = inp;
matchwild = wildcard;
- if (matchwild == 0) {
+ if (matchwild == 0)
break;
- }
}
}
}
@@ -1207,7 +1218,7 @@ in_pcblookup_hash(struct inpcbinfo *pcbinfo, struct in_addr faddr,
struct ifnet *ifp)
{
struct inpcbhead *head;
- struct inpcb *inp;
+ struct inpcb *inp, *tmpinp;
u_short fport = fport_arg, lport = lport_arg;
INP_INFO_LOCK_ASSERT(pcbinfo);
@@ -1215,59 +1226,108 @@ in_pcblookup_hash(struct inpcbinfo *pcbinfo, struct in_addr faddr,
/*
* First look for an exact match.
*/
+ tmpinp = NULL;
head = &pcbinfo->ipi_hashbase[INP_PCBHASH(faddr.s_addr, lport, fport,
pcbinfo->ipi_hashmask)];
LIST_FOREACH(inp, head, inp_hash) {
#ifdef INET6
+ /* XXX inp locking */
if ((inp->inp_vflag & INP_IPV4) == 0)
continue;
#endif
if (inp->inp_faddr.s_addr == faddr.s_addr &&
inp->inp_laddr.s_addr == laddr.s_addr &&
inp->inp_fport == fport &&
- inp->inp_lport == lport)
- return (inp);
+ inp->inp_lport == lport) {
+ /*
+ * XXX We should be able to directly return
+ * the inp here, without any checks.
+ * Well unless both bound with SO_REUSEPORT?
+ */
+ if (jailed(inp->inp_cred))
+ return (inp);
+ if (tmpinp == NULL)
+ tmpinp = inp;
+ }
}
+ if (tmpinp != NULL)
+ return (tmpinp);
/*
* Then look for a wildcard match, if requested.
*/
- if (wildcard) {
- struct inpcb *local_wild = NULL;
+ if (wildcard == INPLOOKUP_WILDCARD) {
+ struct inpcb *local_wild = NULL, *local_exact = NULL;
#ifdef INET6
struct inpcb *local_wild_mapped = NULL;
#endif
+ struct inpcb *jail_wild = NULL;
+ int injail;
+
+ /*
+ * Order of socket selection - we always prefer jails.
+ * 1. jailed, non-wild.
+ * 2. jailed, wild.
+ * 3. non-jailed, non-wild.
+ * 4. non-jailed, wild.
+ */
head = &pcbinfo->ipi_hashbase[INP_PCBHASH(INADDR_ANY, lport,
0, pcbinfo->ipi_hashmask)];
LIST_FOREACH(inp, head, inp_hash) {
#ifdef INET6
+ /* XXX inp locking */
if ((inp->inp_vflag & INP_IPV4) == 0)
continue;
#endif
- if (inp->inp_faddr.s_addr == INADDR_ANY &&
- inp->inp_lport == lport) {
- if (ifp && ifp->if_type == IFT_FAITH &&
- (inp->inp_flags & INP_FAITH) == 0)
+ if (inp->inp_faddr.s_addr != INADDR_ANY ||
+ inp->inp_lport != lport)
+ continue;
+
+ /* XXX inp locking */
+ if (ifp && ifp->if_type == IFT_FAITH &&
+ (inp->inp_flags & INP_FAITH) == 0)
+ continue;
+
+ injail = jailed(inp->inp_cred);
+ if (injail) {
+ if (!prison_check_ip4(inp->inp_cred, &laddr))
continue;
- if (inp->inp_laddr.s_addr == laddr.s_addr)
+ } else {
+ if (local_exact != NULL)
+ continue;
+ }
+
+ if (inp->inp_laddr.s_addr == laddr.s_addr) {
+ if (injail)
return (inp);
- else if (inp->inp_laddr.s_addr == INADDR_ANY) {
+ else
+ local_exact = inp;
+ } else if (inp->inp_laddr.s_addr == INADDR_ANY) {
#ifdef INET6
- if (inp->inp_vflag & INP_IPV6PROTO)
- local_wild_mapped = inp;
+ /* XXX inp locking, NULL check */
+ if (inp->inp_vflag & INP_IPV6PROTO)
+ local_wild_mapped = inp;
+ else
+#endif /* INET6 */
+ if (injail)
+ jail_wild = inp;
else
-#endif
local_wild = inp;
- }
}
- }
+ } /* LIST_FOREACH */
+ if (jail_wild != NULL)
+ return (jail_wild);
+ if (local_exact != NULL)
+ return (local_exact);
+ if (local_wild != NULL)
+ return (local_wild);
#ifdef INET6
- if (local_wild == NULL)
+ if (local_wild_mapped != NULL)
return (local_wild_mapped);
-#endif
- return (local_wild);
- }
+#endif /* defined(INET6) */
+ } /* if (wildcard == INPLOOKUP_WILDCARD) */
+
return (NULL);
}
diff --git a/sys/netinet/raw_ip.c b/sys/netinet/raw_ip.c
index a84db95ffc45..71eaaa0b9fd1 100644
--- a/sys/netinet/raw_ip.c
+++ b/sys/netinet/raw_ip.c
@@ -273,10 +273,9 @@ rip_input(struct mbuf *m, int off)
continue;
if (inp->inp_faddr.s_addr != ip->ip_src.s_addr)
continue;
- if (jailed(inp->inp_cred) &&
- (htonl(prison_getip(inp->inp_cred)) !=
- ip->ip_dst.s_addr)) {
- continue;
+ if (jailed(inp->inp_cred)) {
+ if (!prison_check_ip4(inp->inp_cred, &ip->ip_dst))
+ continue;
}
if (last) {
struct mbuf *n;
@@ -304,10 +303,9 @@ rip_input(struct mbuf *m, int off)
if (inp->inp_faddr.s_addr &&
inp->inp_faddr.s_addr != ip->ip_src.s_addr)
continue;
- if (jailed(inp->inp_cred) &&
- (htonl(prison_getip(inp->inp_cred)) !=
- ip->ip_dst.s_addr)) {
- continue;
+ if (jailed(inp->inp_cred)) {
+ if (!prison_check_ip4(inp->inp_cred, &ip->ip_dst))
+ continue;
}
if (last) {
struct mbuf *n;
@@ -369,11 +367,15 @@ rip_output(struct mbuf *m, struct socket *so, u_long dst)
ip->ip_off = 0;
ip->ip_p = inp->inp_ip_p;
ip->ip_len = m->m_pkthdr.len;
- if (jailed(inp->inp_cred))
- ip->ip_src.s_addr =
- htonl(prison_getip(inp->inp_cred));
- else
+ if (jailed(inp->inp_cred)) {
+ if (prison_getip4(inp->inp_cred, &ip->ip_src)) {
+ INP_RUNLOCK(inp);
+ m_freem(m);
+ return (EPERM);
+ }
+ } else {
ip->ip_src = inp->inp_laddr;
+ }
ip->ip_dst.s_addr = dst;
ip->ip_ttl = inp->inp_ip_ttl;
} else {
@@ -383,13 +385,10 @@ rip_output(struct mbuf *m, struct socket *so, u_long dst)
}
INP_RLOCK(inp);
ip = mtod(m, struct ip *);
- if (jailed(inp->inp_cred)) {
- if (ip->ip_src.s_addr !=
- htonl(prison_getip(inp->inp_cred))) {
- INP_RUNLOCK(inp);
- m_freem(m);
- return (EPERM);
- }
+ if (!prison_check_ip4(inp->inp_cred, &ip->ip_src)) {
+ INP_RUNLOCK(inp);
+ m_freem(m);
+ return (EPERM);
}
/*
@@ -805,13 +804,8 @@ rip_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
if (nam->sa_len != sizeof(*addr))
return (EINVAL);
- if (jailed(td->td_ucred)) {
- if (addr->sin_addr.s_addr == INADDR_ANY)
- addr->sin_addr.s_addr =
- htonl(prison_getip(td->td_ucred));
- if (htonl(prison_getip(td->td_ucred)) != addr->sin_addr.s_addr)
- return (EADDRNOTAVAIL);
- }
+ if (!prison_check_ip4(td->td_ucred, &addr->sin_addr))
+ return (EADDRNOTAVAIL);
if (TAILQ_EMPTY(&V_ifnet) ||
(addr->sin_family != AF_INET && addr->sin_family != AF_IMPLINK) ||
diff --git a/sys/netinet/sctp_pcb.c b/sys/netinet/sctp_pcb.c
index 3fa9eb595b7a..4ce0f1268c86 100644
--- a/sys/netinet/sctp_pcb.c
+++ b/sys/netinet/sctp_pcb.c
@@ -2553,7 +2553,6 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr,
struct inpcb *ip_inp;
int port_reuse_active = 0;
int bindall;
- int prison = 0;
uint16_t lport;
int error;
uint32_t vrf_id;
@@ -2580,9 +2579,6 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr,
if (p == NULL)
panic("null proc/thread");
#endif
- if (p && jailed(p->td_ucred)) {
- prison = 1;
- }
if (addr != NULL) {
switch (addr->sa_family) {
case AF_INET:
@@ -2600,18 +2596,13 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr,
}
sin = (struct sockaddr_in *)addr;
lport = sin->sin_port;
- if (prison) {
- /*
- * For INADDR_ANY and LOOPBACK the
- * prison_ip() call will transmute
- * the ip address to the proper
- * value (i.e. the IP address owned
- * by the jail).
- */
- if (prison_ip(p->td_ucred, 0, &sin->sin_addr.s_addr)) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL);
- return (EINVAL);
- }
+ /*
+ * For LOOPBACK the prison_local_ip4() call will transmute the ip address
+ * to the proper value.
+ */
+ if (p && prison_local_ip4(p->td_ucred, &sin->sin_addr) != 0) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL);
+ return (EINVAL);
}
if (sin->sin_addr.s_addr != INADDR_ANY) {
bindall = 0;
@@ -2634,12 +2625,16 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr,
return (EINVAL);
}
lport = sin6->sin6_port;
+
/*
- * Jail checks for IPv6 should go HERE! i.e.
- * add the prison_ip() equivilant in this
- * postion to transmute the addresses to the
- * proper one jailed.
+ * For LOOPBACK the prison_local_ip6() call will transmute the ipv6 address
+ * to the proper value.
*/
+ if (p && prison_local_ip6(p->td_ucred, &sin6->sin6_addr,
+ (SCTP_IPV6_V6ONLY(inp) != 0)) != 0) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL);
+ return (EINVAL);
+ }
if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
bindall = 0;
/* KAME hack: embed scopeid */
diff --git a/sys/netinet/sctp_usrreq.c b/sys/netinet/sctp_usrreq.c
index 882aee768d5a..058415e4deef 100644
--- a/sys/netinet/sctp_usrreq.c
+++ b/sys/netinet/sctp_usrreq.c
@@ -507,11 +507,10 @@ sctp_attach(struct socket *so, int proto, struct thread *p)
struct inpcb *ip_inp;
int error;
uint32_t vrf_id = SCTP_DEFAULT_VRFID;
-
#ifdef IPSEC
uint32_t flags;
-
#endif
+
inp = (struct sctp_inpcb *)so->so_pcb;
if (inp != 0) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
@@ -3951,12 +3950,8 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
struct sctp_getaddresses *addrs;
size_t sz;
struct thread *td;
- int prison = 0;
td = (struct thread *)p;
- if (jailed(td->td_ucred)) {
- prison = 1;
- }
SCTP_CHECK_AND_CAST(addrs, optval, struct sctp_getaddresses,
optsize);
if (addrs->addr->sa_family == AF_INET) {
@@ -3966,10 +3961,12 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
error = EINVAL;
break;
}
- if (prison && prison_ip(td->td_ucred, 0, &(((struct sockaddr_in *)(addrs->addr))->sin_addr.s_addr))) {
+ if (td != NULL && prison_local_ip4(td->td_ucred, &(((struct sockaddr_in *)(addrs->addr))->sin_addr))) {
SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EADDRNOTAVAIL);
error = EADDRNOTAVAIL;
+ break;
}
+#ifdef INET6
} else if (addrs->addr->sa_family == AF_INET6) {
sz = sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in6);
if (optsize < sz) {
@@ -3977,7 +3974,16 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
error = EINVAL;
break;
}
- /* JAIL XXXX Add else here for V6 */
+ if (td != NULL && prison_local_ip6(td->td_ucred, &(((struct sockaddr_in6 *)(addrs->addr))->sin6_addr),
+ (SCTP_IPV6_V6ONLY(inp) != 0)) != 0) {
+ SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EADDRNOTAVAIL);
+ error = EADDRNOTAVAIL;
+ break;
+ }
+#endif
+ } else {
+ error = EAFNOSUPPORT;
+ break;
}
sctp_bindx_add_address(so, inp, addrs->addr,
addrs->sget_assoc_id, vrf_id,
@@ -3989,12 +3995,9 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
struct sctp_getaddresses *addrs;
size_t sz;
struct thread *td;
- int prison = 0;
td = (struct thread *)p;
- if (jailed(td->td_ucred)) {
- prison = 1;
- }
+
SCTP_CHECK_AND_CAST(addrs, optval, struct sctp_getaddresses, optsize);
if (addrs->addr->sa_family == AF_INET) {
sz = sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in);
@@ -4003,10 +4006,12 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
error = EINVAL;
break;
}
- if (prison && prison_ip(td->td_ucred, 0, &(((struct sockaddr_in *)(addrs->addr))->sin_addr.s_addr))) {
+ if (td != NULL && prison_local_ip4(td->td_ucred, &(((struct sockaddr_in *)(addrs->addr))->sin_addr))) {
SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EADDRNOTAVAIL);
error = EADDRNOTAVAIL;
+ break;
}
+#ifdef INET6
} else if (addrs->addr->sa_family == AF_INET6) {
sz = sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in6);
if (optsize < sz) {
@@ -4014,7 +4019,16 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
error = EINVAL;
break;
}
- /* JAIL XXXX Add else here for V6 */
+ if (td != NULL && prison_local_ip6(td->td_ucred, &(((struct sockaddr_in6 *)(addrs->addr))->sin6_addr),
+ (SCTP_IPV6_V6ONLY(inp) != 0)) != 0) {
+ SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EADDRNOTAVAIL);
+ error = EADDRNOTAVAIL;
+ break;
+ }
+#endif
+ } else {
+ error = EAFNOSUPPORT;
+ break;
}
sctp_bindx_delete_address(so, inp, addrs->addr,
addrs->sget_assoc_id, vrf_id,
@@ -4106,13 +4120,34 @@ sctp_connect(struct socket *so, struct sockaddr *addr, struct thread *p)
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
return EINVAL;
}
- if ((addr->sa_family == AF_INET6) && (addr->sa_len != sizeof(struct sockaddr_in6))) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- return (EINVAL);
- }
- if ((addr->sa_family == AF_INET) && (addr->sa_len != sizeof(struct sockaddr_in))) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- return (EINVAL);
+#ifdef INET6
+ if (addr->sa_family == AF_INET6) {
+ struct sockaddr_in6 *sin6p;
+ if (addr->sa_len != sizeof(struct sockaddr_in6)) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
+ return (EINVAL);
+ }
+ sin6p = (struct sockaddr_in6 *)addr;
+ if (p != NULL && prison_remote_ip6(p->td_ucred, &sin6p->sin6_addr) != 0) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
+ return (EINVAL);
+ }
+ } else
+#endif
+ if (addr->sa_family == AF_INET) {
+ struct sockaddr_in *sinp;
+ if (addr->sa_len != sizeof(struct sockaddr_in)) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
+ return (EINVAL);
+ }
+ sinp = (struct sockaddr_in *)addr;
+ if (p != NULL && prison_remote_ip4(p->td_ucred, &sinp->sin_addr) != 0) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
+ return (EINVAL);
+ }
+ } else {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EAFNOSUPPORT);
+ return (EAFNOSUPPORT);
}
SCTP_INP_INCR_REF(inp);
SCTP_ASOC_CREATE_LOCK(inp);
diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c
index 2ee8aa491e63..6428b642676e 100644
--- a/sys/netinet/tcp_usrreq.c
+++ b/sys/netinet/tcp_usrreq.c
@@ -440,8 +440,8 @@ tcp_usr_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
if (sinp->sin_family == AF_INET
&& IN_MULTICAST(ntohl(sinp->sin_addr.s_addr)))
return (EAFNOSUPPORT);
- if (jailed(td->td_ucred))
- prison_remote_ip(td->td_ucred, 0, &sinp->sin_addr.s_addr);
+ if (prison_remote_ip4(td->td_ucred, &sinp->sin_addr) != 0)
+ return (EINVAL);
TCPDEBUG0;
INP_INFO_WLOCK(&V_tcbinfo);
@@ -507,6 +507,10 @@ tcp6_usr_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
in6_sin6_2_sin(&sin, sin6p);
inp->inp_vflag |= INP_IPV4;
inp->inp_vflag &= ~INP_IPV6;
+ if (prison_remote_ip4(td->td_ucred, &sin.sin_addr) != 0) {
+ error = EINVAL;
+ goto out;
+ }
if ((error = tcp_connect(tp, (struct sockaddr *)&sin, td)) != 0)
goto out;
error = tcp_output_connect(so, nam);
@@ -515,6 +519,10 @@ tcp6_usr_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
inp->inp_vflag &= ~INP_IPV4;
inp->inp_vflag |= INP_IPV6;
inp->inp_inc.inc_isipv6 = 1;
+ if (prison_remote_ip6(td->td_ucred, &sin6p->sin6_addr) != 0) {
+ error = EINVAL;
+ goto out;
+ }
if ((error = tcp6_connect(tp, nam, td)) != 0)
goto out;
error = tcp_output_connect(so, nam);
diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c
index de341afcbe0a..2e523091c74a 100644
--- a/sys/netinet/udp_usrreq.c
+++ b/sys/netinet/udp_usrreq.c
@@ -940,9 +940,10 @@ udp_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr,
* Jail may rewrite the destination address, so let it do
* that before we use it.
*/
- if (jailed(td->td_ucred))
- prison_remote_ip(td->td_ucred, 0,
- &sin->sin_addr.s_addr);
+ if (prison_remote_ip4(td->td_ucred, &sin->sin_addr) != 0) {
+ error = EINVAL;
+ goto release;
+ }
/*
* If a local address or port hasn't yet been selected, or if
@@ -1194,8 +1195,11 @@ udp_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
return (EISCONN);
}
sin = (struct sockaddr_in *)nam;
- if (jailed(td->td_ucred))
- prison_remote_ip(td->td_ucred, 0, &sin->sin_addr.s_addr);
+ if (prison_remote_ip4(td->td_ucred, &sin->sin_addr) != 0) {
+ INP_WUNLOCK(inp);
+ INP_INFO_WUNLOCK(&udbinfo);
+ return (EAFNOSUPPORT);
+ }
error = in_pcbconnect(inp, nam, td->td_ucred);
if (error == 0)
soisconnected(so);