Remove IPsec related PCB code from SCTP.

The inpcb structure has inp_sp pointer that is initialized by
ipsec_init_pcbpolicy() function. This pointer keeps strorage for IPsec
security policies associated with a specific socket.
An application can use IP_IPSEC_POLICY and IPV6_IPSEC_POLICY socket
options to configure these security policies. Then ip[6]_output()
uses inpcb pointer to specify that an outgoing packet is associated
with some socket. And IPSEC_OUTPUT() method can use a security policy
stored in the inp_sp. For inbound packet the protocol-specific input
routine uses IPSEC_CHECK_POLICY() method to check that a packet conforms
to inbound security policy configured in the inpcb.

SCTP protocol doesn't specify inpcb for ip[6]_output() when it sends
packets. Thus IPSEC_OUTPUT() method does not consider such packets as
associated with some socket and can not apply security policies
from inpcb, even if they are configured. Since IPSEC_CHECK_POLICY()
method is called from protocol-specific input routine, it can specify
inpcb pointer and associated with socket inbound policy will be
checked. But there are two problems:
1. Such check is asymmetric, becasue we can not apply security policy
from inpcb for outgoing packet.
2. IPSEC_CHECK_POLICY() expects that caller holds INPCB lock and
access to inp_sp is protected. But for SCTP this is not correct,
becasue SCTP uses own locks to protect inpcb.

To fix these problems remove IPsec related PCB code from SCTP.
This imply that IP_IPSEC_POLICY and IPV6_IPSEC_POLICY socket options
will be not applicable to SCTP sockets. To be able correctly check
inbound security policies for SCTP, mark its protocol header with
the PR_LASTHDR flag.

Reported by:	tuexen
Reviewed by:	tuexen
Differential Revision:	https://reviews.freebsd.org/D9538
This commit is contained in:
ae 2017-02-13 11:37:52 +00:00
parent 0dac2c5955
commit 5a443cfa6c
6 changed files with 4 additions and 64 deletions

View File

@ -148,7 +148,7 @@ struct protosw inetsw[] = {
.pr_type = SOCK_SEQPACKET, .pr_type = SOCK_SEQPACKET,
.pr_domain = &inetdomain, .pr_domain = &inetdomain,
.pr_protocol = IPPROTO_SCTP, .pr_protocol = IPPROTO_SCTP,
.pr_flags = PR_WANTRCVD, .pr_flags = PR_WANTRCVD|PR_LASTHDR,
.pr_input = sctp_input, .pr_input = sctp_input,
.pr_ctlinput = sctp_ctlinput, .pr_ctlinput = sctp_ctlinput,
.pr_ctloutput = sctp_ctloutput, .pr_ctloutput = sctp_ctloutput,
@ -160,7 +160,7 @@ struct protosw inetsw[] = {
.pr_type = SOCK_STREAM, .pr_type = SOCK_STREAM,
.pr_domain = &inetdomain, .pr_domain = &inetdomain,
.pr_protocol = IPPROTO_SCTP, .pr_protocol = IPPROTO_SCTP,
.pr_flags = PR_CONNREQUIRED|PR_WANTRCVD, .pr_flags = PR_CONNREQUIRED|PR_WANTRCVD|PR_LASTHDR,
.pr_input = sctp_input, .pr_input = sctp_input,
.pr_ctlinput = sctp_ctlinput, .pr_ctlinput = sctp_ctlinput,
.pr_ctloutput = sctp_ctloutput, .pr_ctloutput = sctp_ctloutput,

View File

@ -5790,40 +5790,6 @@ sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset, int lengt
} else if (stcb == NULL) { } else if (stcb == NULL) {
inp_decr = inp; inp_decr = inp;
} }
#if defined(IPSEC) || defined(IPSEC_SUPPORT)
/*-
* I very much doubt any of the IPSEC stuff will work but I have no
* idea, so I will leave it in place.
*/
if (inp != NULL) {
switch (dst->sa_family) {
#ifdef INET
case AF_INET:
if (IPSEC_ENABLED(ipv4)) {
if (IPSEC_CHECK_POLICY(ipv4, m,
&inp->ip_inp.inp) != 0) {
SCTP_STAT_INCR(sctps_hdrops);
goto out;
}
}
break;
#endif
#ifdef INET6
case AF_INET6:
if (IPSEC_ENABLED(ipv6)) {
if (IPSEC_CHECK_POLICY(ipv6, m,
&inp->ip_inp.inp) != 0) {
SCTP_STAT_INCR(sctps_hdrops);
goto out;
}
}
break;
#endif
default:
break;
}
}
#endif /* IPSEC */
SCTPDBG(SCTP_DEBUG_INPUT1, "Ok, Common input processing called, m:%p iphlen:%d offset:%d length:%d stcb:%p\n", SCTPDBG(SCTP_DEBUG_INPUT1, "Ok, Common input processing called, m:%p iphlen:%d offset:%d length:%d stcb:%p\n",
(void *)m, iphlen, offset, length, (void *)stcb); (void *)m, iphlen, offset, length, (void *)stcb);
if (stcb) { if (stcb) {

View File

@ -38,7 +38,6 @@ __FBSDID("$FreeBSD$");
/* /*
* includes * includes
*/ */
#include "opt_ipsec.h"
#include "opt_compat.h" #include "opt_compat.h"
#include "opt_inet6.h" #include "opt_inet6.h"
#include "opt_inet.h" #include "opt_inet.h"
@ -82,8 +81,6 @@ __FBSDID("$FreeBSD$");
#include <netinet/ip_icmp.h> #include <netinet/ip_icmp.h>
#include <netinet/icmp_var.h> #include <netinet/icmp_var.h>
#include <netipsec/ipsec_support.h>
#ifdef INET6 #ifdef INET6
#include <sys/domain.h> #include <sys/domain.h>
#include <netinet/ip6.h> #include <netinet/ip6.h>
@ -94,7 +91,6 @@ __FBSDID("$FreeBSD$");
#include <netinet6/scope6_var.h> #include <netinet6/scope6_var.h>
#endif /* INET6 */ #endif /* INET6 */
#include <netinet/ip_options.h> #include <netinet/ip_options.h>
#include <crypto/sha1.h> #include <crypto/sha1.h>

View File

@ -2469,15 +2469,6 @@ sctp_inpcb_alloc(struct socket *so, uint32_t vrf_id)
SCTP_INP_INFO_WUNLOCK(); SCTP_INP_INFO_WUNLOCK();
return (ENOBUFS); return (ENOBUFS);
} }
#if defined(IPSEC) || defined(IPSEC_SUPPORT)
error = ipsec_init_pcbpolicy(&inp->ip_inp.inp);
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;
}
#endif /* IPSEC */
SCTP_INCR_EP_COUNT(); SCTP_INCR_EP_COUNT();
inp->ip_inp.inp.inp_ip_ttl = MODULE_GLOBAL(ip_defttl); inp->ip_inp.inp.inp_ip_ttl = MODULE_GLOBAL(ip_defttl);
SCTP_INP_INFO_WUNLOCK(); SCTP_INP_INFO_WUNLOCK();
@ -2504,9 +2495,6 @@ sctp_inpcb_alloc(struct socket *so, uint32_t vrf_id)
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EOPNOTSUPP); SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EOPNOTSUPP);
so->so_pcb = NULL; so->so_pcb = NULL;
crfree(inp->ip_inp.inp.inp_cred); crfree(inp->ip_inp.inp.inp_cred);
#if defined(IPSEC) || defined(IPSEC_SUPPORT)
ipsec_delete_pcbpolicy(&inp->ip_inp.inp);
#endif
SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_ep), inp); SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_ep), inp);
return (EOPNOTSUPP); return (EOPNOTSUPP);
} }
@ -2527,9 +2515,6 @@ sctp_inpcb_alloc(struct socket *so, uint32_t vrf_id)
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, ENOBUFS); SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, ENOBUFS);
so->so_pcb = NULL; so->so_pcb = NULL;
crfree(inp->ip_inp.inp.inp_cred); crfree(inp->ip_inp.inp.inp_cred);
#if defined(IPSEC) || defined(IPSEC_SUPPORT)
ipsec_delete_pcbpolicy(&inp->ip_inp.inp);
#endif
SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_ep), inp); SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_ep), inp);
return (ENOBUFS); return (ENOBUFS);
} }
@ -3641,9 +3626,6 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from)
* macro here since le_next will get freed as part of the * macro here since le_next will get freed as part of the
* sctp_free_assoc() call. * sctp_free_assoc() call.
*/ */
#if defined(IPSEC) || defined(IPSEC_SUPPORT)
ipsec_delete_pcbpolicy(ip_pcb);
#endif
if (ip_pcb->inp_options) { if (ip_pcb->inp_options) {
(void)sctp_m_free(ip_pcb->inp_options); (void)sctp_m_free(ip_pcb->inp_options);
ip_pcb->inp_options = 0; ip_pcb->inp_options = 0;

View File

@ -185,7 +185,7 @@ struct protosw inet6sw[] = {
.pr_type = SOCK_SEQPACKET, .pr_type = SOCK_SEQPACKET,
.pr_domain = &inet6domain, .pr_domain = &inet6domain,
.pr_protocol = IPPROTO_SCTP, .pr_protocol = IPPROTO_SCTP,
.pr_flags = PR_WANTRCVD, .pr_flags = PR_WANTRCVD|PR_LASTHDR,
.pr_input = sctp6_input, .pr_input = sctp6_input,
.pr_ctlinput = sctp6_ctlinput, .pr_ctlinput = sctp6_ctlinput,
.pr_ctloutput = sctp_ctloutput, .pr_ctloutput = sctp_ctloutput,
@ -199,7 +199,7 @@ struct protosw inet6sw[] = {
.pr_type = SOCK_STREAM, .pr_type = SOCK_STREAM,
.pr_domain = &inet6domain, .pr_domain = &inet6domain,
.pr_protocol = IPPROTO_SCTP, .pr_protocol = IPPROTO_SCTP,
.pr_flags = PR_CONNREQUIRED|PR_WANTRCVD, .pr_flags = PR_CONNREQUIRED|PR_WANTRCVD|PR_LASTHDR,
.pr_input = sctp6_input, .pr_input = sctp6_input,
.pr_ctlinput = sctp6_ctlinput, .pr_ctlinput = sctp6_ctlinput,
.pr_ctloutput = sctp_ctloutput, .pr_ctloutput = sctp_ctloutput,

View File

@ -551,10 +551,6 @@ sctp6_attach(struct socket *so, int proto SCTP_UNUSED, struct thread *p SCTP_UNU
*/ */
inp6->inp_ip_ttl = MODULE_GLOBAL(ip_defttl); inp6->inp_ip_ttl = MODULE_GLOBAL(ip_defttl);
#endif #endif
/*
* Hmm what about the IPSEC stuff that is missing here but in
* sctp_attach()?
*/
SCTP_INP_WUNLOCK(inp); SCTP_INP_WUNLOCK(inp);
return (0); return (0);
} }