summaryrefslogtreecommitdiffstats
path: root/sys/netinet/sctp_pcb.c
diff options
context:
space:
mode:
authortuexen <tuexen@FreeBSD.org>2014-06-23 07:54:12 +0000
committertuexen <tuexen@FreeBSD.org>2014-06-23 07:54:12 +0000
commit41ae4ee23b1f12bd4544ec3a0771f62879b454c1 (patch)
treeb87905be0f947f0096a5e7e10587e62b8849d1a0 /sys/netinet/sctp_pcb.c
parente77b6c99346ca051d33f757061583fab17d94930 (diff)
downloadFreeBSD-src-41ae4ee23b1f12bd4544ec3a0771f62879b454c1.zip
FreeBSD-src-41ae4ee23b1f12bd4544ec3a0771f62879b454c1.tar.gz
MFC r267674:
Honor jails for unbound SCTP sockets when selecting source addresses, reporting IP-addresses to the peer during the handshake, adding addresses to the host, reporting the addresses via the sysctl interface (used by netstat, for example) and reporting the addresses to the application via socket options. This issue was reported by Bernd Walter.
Diffstat (limited to 'sys/netinet/sctp_pcb.c')
-rw-r--r--sys/netinet/sctp_pcb.c95
1 files changed, 82 insertions, 13 deletions
diff --git a/sys/netinet/sctp_pcb.c b/sys/netinet/sctp_pcb.c
index 861455c..3cee79e 100644
--- a/sys/netinet/sctp_pcb.c
+++ b/sys/netinet/sctp_pcb.c
@@ -898,6 +898,10 @@ sctp_does_stcb_own_this_addr(struct sctp_tcb *stcb, struct sockaddr *to)
IN4_ISPRIVATE_ADDRESS(&sin->sin_addr)) {
continue;
}
+ if (prison_check_ip4(stcb->sctp_ep->ip_inp.inp.inp_cred,
+ &sin->sin_addr) != 0) {
+ continue;
+ }
if (sin->sin_addr.s_addr == rsin->sin_addr.s_addr) {
SCTP_IPI_ADDR_RUNLOCK();
return (1);
@@ -913,6 +917,10 @@ sctp_does_stcb_own_this_addr(struct sctp_tcb *stcb, struct sockaddr *to)
sin6 = &sctp_ifa->address.sin6;
rsin6 = (struct sockaddr_in6 *)to;
+ if (prison_check_ip6(stcb->sctp_ep->ip_inp.inp.inp_cred,
+ &sin6->sin6_addr) != 0) {
+ continue;
+ }
if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
if (local_scope == 0)
continue;
@@ -1060,6 +1068,39 @@ sctp_tcb_special_locate(struct sctp_inpcb **inp_p, struct sockaddr *from,
SCTP_INP_RUNLOCK(inp);
continue;
}
+ switch (to->sa_family) {
+#ifdef INET
+ case AF_INET:
+ {
+ struct sockaddr_in *sin;
+
+ sin = (struct sockaddr_in *)to;
+ if (prison_check_ip4(inp->ip_inp.inp.inp_cred,
+ &sin->sin_addr) != 0) {
+ SCTP_INP_RUNLOCK(inp);
+ continue;
+ }
+ break;
+ }
+#endif
+#ifdef INET6
+ case AF_INET6:
+ {
+ struct sockaddr_in6 *sin6;
+
+ sin6 = (struct sockaddr_in6 *)to;
+ if (prison_check_ip6(inp->ip_inp.inp.inp_cred,
+ &sin6->sin6_addr) != 0) {
+ SCTP_INP_RUNLOCK(inp);
+ continue;
+ }
+ break;
+ }
+#endif
+ default:
+ SCTP_INP_RUNLOCK(inp);
+ continue;
+ }
if (inp->def_vrf_id != vrf_id) {
SCTP_INP_RUNLOCK(inp);
continue;
@@ -1628,23 +1669,45 @@ sctp_endpoint_probe(struct sockaddr *nam, struct sctppcbhead *head,
if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) &&
(inp->sctp_lport == lport)) {
/* got it */
+ switch (nam->sa_family) {
#ifdef INET
- if ((nam->sa_family == AF_INET) &&
- (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
- SCTP_IPV6_V6ONLY(inp)) {
- /* IPv4 on a IPv6 socket with ONLY IPv6 set */
- SCTP_INP_RUNLOCK(inp);
- continue;
- }
+ case AF_INET:
+ if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
+ SCTP_IPV6_V6ONLY(inp)) {
+ /*
+ * IPv4 on a IPv6 socket with ONLY
+ * IPv6 set
+ */
+ SCTP_INP_RUNLOCK(inp);
+ continue;
+ }
+ if (prison_check_ip4(inp->ip_inp.inp.inp_cred,
+ &sin->sin_addr) != 0) {
+ SCTP_INP_RUNLOCK(inp);
+ continue;
+ }
+ break;
#endif
#ifdef INET6
- /* A V6 address and the endpoint is NOT bound V6 */
- if (nam->sa_family == AF_INET6 &&
- (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) {
- SCTP_INP_RUNLOCK(inp);
- continue;
- }
+ case AF_INET6:
+ /*
+ * A V6 address and the endpoint is NOT
+ * bound V6
+ */
+ if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) {
+ SCTP_INP_RUNLOCK(inp);
+ continue;
+ }
+ if (prison_check_ip6(inp->ip_inp.inp.inp_cred,
+ &sin6->sin6_addr) != 0) {
+ SCTP_INP_RUNLOCK(inp);
+ continue;
+ }
+ break;
#endif
+ default:
+ break;
+ }
/* does a VRF id match? */
fnd = 0;
if (inp->def_vrf_id == vrf_id)
@@ -2403,6 +2466,7 @@ sctp_inpcb_alloc(struct socket *so, uint32_t vrf_id)
/* setup socket pointers */
inp->sctp_socket = so;
inp->ip_inp.inp.inp_socket = so;
+ inp->ip_inp.inp.inp_cred = crhold(so->so_cred);
#ifdef INET6
if (INP_SOCKAF(so) == AF_INET6) {
if (MODULE_GLOBAL(ip6_auto_flowlabel)) {
@@ -2421,6 +2485,7 @@ sctp_inpcb_alloc(struct socket *so, uint32_t vrf_id)
/* init the small hash table we use to track asocid <-> tcb */
inp->sctp_asocidhash = SCTP_HASH_INIT(SCTP_STACK_VTAG_HASH_SIZE, &inp->hashasocidmark);
if (inp->sctp_asocidhash == NULL) {
+ crfree(inp->ip_inp.inp.inp_cred);
SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_ep), inp);
SCTP_INP_INFO_WUNLOCK();
return (ENOBUFS);
@@ -2435,6 +2500,7 @@ sctp_inpcb_alloc(struct socket *so, uint32_t vrf_id)
((struct in6pcb *)(&inp->ip_inp.inp))->in6p_sp = pcb_sp;
}
if (error != 0) {
+ crfree(inp->ip_inp.inp.inp_cred);
SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_ep), inp);
SCTP_INP_INFO_WUNLOCK();
return error;
@@ -2465,6 +2531,7 @@ sctp_inpcb_alloc(struct socket *so, uint32_t vrf_id)
*/
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EOPNOTSUPP);
so->so_pcb = NULL;
+ crfree(inp->ip_inp.inp.inp_cred);
SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_ep), inp);
return (EOPNOTSUPP);
}
@@ -2484,6 +2551,7 @@ sctp_inpcb_alloc(struct socket *so, uint32_t vrf_id)
SCTP_PRINTF("Out of SCTP-INPCB->hashinit - no resources\n");
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, ENOBUFS);
so->so_pcb = NULL;
+ crfree(inp->ip_inp.inp.inp_cred);
SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_ep), inp);
return (ENOBUFS);
}
@@ -3630,6 +3698,7 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from)
inp->sctp_tcbhash = NULL;
}
/* Now we must put the ep memory back into the zone pool */
+ crfree(inp->ip_inp.inp.inp_cred);
INP_LOCK_DESTROY(&inp->ip_inp.inp);
SCTP_INP_LOCK_DESTROY(inp);
SCTP_INP_READ_DESTROY(inp);
OpenPOWER on IntegriCloud