Merge tag 'selinux-pr-20180403' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux

Pull SELinux updates from Paul Moore:
 "A bigger than usual pull request for SELinux, 13 patches (lucky!)
  along with a scary looking diffstat.

  Although if you look a bit closer, excluding the usual minor
  tweaks/fixes, there are really only two significant changes in this
  pull request: the addition of proper SELinux access controls for SCTP
  and the encapsulation of a lot of internal SELinux state.

  The SCTP changes are the result of a multi-month effort (maybe even a
  year or longer?) between the SELinux folks and the SCTP folks to add
  proper SELinux controls. A special thanks go to Richard for seeing
  this through and keeping the effort moving forward.

  The state encapsulation work is a bit of janitorial work that came out
  of some early work on SELinux namespacing. The question of namespacing
  is still an open one, but I believe there is some real value in the
  encapsulation work so we've split that out and are now sending that up
  to you"

* tag 'selinux-pr-20180403' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux:
  selinux: wrap AVC state
  selinux: wrap selinuxfs state
  selinux: fix handling of uninitialized selinux state in get_bools/classes
  selinux: Update SELinux SCTP documentation
  selinux: Fix ltp test connect-syscall failure
  selinux: rename the {is,set}_enforcing() functions
  selinux: wrap global selinux state
  selinux: fix typo in selinux_netlbl_sctp_sk_clone declaration
  selinux: Add SCTP support
  sctp: Add LSM hooks
  sctp: Add ip option support
  security: Add support for SCTP security hooks
  netlabel: If PF_INET6, check sk_buff ip header version
This commit is contained in:
Linus Torvalds
2018-04-06 15:39:26 -07:00
43 changed files with 2953 additions and 1269 deletions

View File

@@ -172,6 +172,8 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
struct list_head *pos, *temp;
struct sctp_chunk *chunk;
struct sctp_datamsg *msg;
struct sctp_sock *sp;
struct sctp_af *af;
int err;
msg = sctp_datamsg_new(GFP_KERNEL);
@@ -190,9 +192,11 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
/* This is the biggest possible DATA chunk that can fit into
* the packet
*/
max_data = asoc->pathmtu -
sctp_sk(asoc->base.sk)->pf->af->net_header_len -
sizeof(struct sctphdr) - sctp_datachk_len(&asoc->stream);
sp = sctp_sk(asoc->base.sk);
af = sp->pf->af;
max_data = asoc->pathmtu - af->net_header_len -
sizeof(struct sctphdr) - sctp_datachk_len(&asoc->stream) -
af->ip_options_len(asoc->base.sk);
max_data = SCTP_TRUNC4(max_data);
/* If the the peer requested that we authenticate DATA chunks

View File

@@ -427,6 +427,41 @@ static void sctp_v6_copy_addrlist(struct list_head *addrlist,
rcu_read_unlock();
}
/* Copy over any ip options */
static void sctp_v6_copy_ip_options(struct sock *sk, struct sock *newsk)
{
struct ipv6_pinfo *newnp, *np = inet6_sk(sk);
struct ipv6_txoptions *opt;
newnp = inet6_sk(newsk);
rcu_read_lock();
opt = rcu_dereference(np->opt);
if (opt) {
opt = ipv6_dup_options(newsk, opt);
if (!opt)
pr_err("%s: Failed to copy ip options\n", __func__);
}
RCU_INIT_POINTER(newnp->opt, opt);
rcu_read_unlock();
}
/* Account for the IP options */
static int sctp_v6_ip_options_len(struct sock *sk)
{
struct ipv6_pinfo *np = inet6_sk(sk);
struct ipv6_txoptions *opt;
int len = 0;
rcu_read_lock();
opt = rcu_dereference(np->opt);
if (opt)
len = opt->opt_flen + opt->opt_nflen;
rcu_read_unlock();
return len;
}
/* Initialize a sockaddr_storage from in incoming skb. */
static void sctp_v6_from_skb(union sctp_addr *addr, struct sk_buff *skb,
int is_saddr)
@@ -666,7 +701,6 @@ static struct sock *sctp_v6_create_accept_sk(struct sock *sk,
struct sock *newsk;
struct ipv6_pinfo *newnp, *np = inet6_sk(sk);
struct sctp6_sock *newsctp6sk;
struct ipv6_txoptions *opt;
newsk = sk_alloc(sock_net(sk), PF_INET6, GFP_KERNEL, sk->sk_prot, kern);
if (!newsk)
@@ -689,12 +723,7 @@ static struct sock *sctp_v6_create_accept_sk(struct sock *sk,
newnp->ipv6_ac_list = NULL;
newnp->ipv6_fl_list = NULL;
rcu_read_lock();
opt = rcu_dereference(np->opt);
if (opt)
opt = ipv6_dup_options(newsk, opt);
RCU_INIT_POINTER(newnp->opt, opt);
rcu_read_unlock();
sctp_v6_copy_ip_options(sk, newsk);
/* Initialize sk's sport, dport, rcv_saddr and daddr for getsockname()
* and getpeername().
@@ -1041,6 +1070,7 @@ static struct sctp_af sctp_af_inet6 = {
.ecn_capable = sctp_v6_ecn_capable,
.net_header_len = sizeof(struct ipv6hdr),
.sockaddr_len = sizeof(struct sockaddr_in6),
.ip_options_len = sctp_v6_ip_options_len,
#ifdef CONFIG_COMPAT
.compat_setsockopt = compat_ipv6_setsockopt,
.compat_getsockopt = compat_ipv6_getsockopt,
@@ -1059,6 +1089,7 @@ static struct sctp_pf sctp_pf_inet6 = {
.addr_to_user = sctp_v6_addr_to_user,
.to_sk_saddr = sctp_v6_to_sk_saddr,
.to_sk_daddr = sctp_v6_to_sk_daddr,
.copy_ip_options = sctp_v6_copy_ip_options,
.af = &sctp_af_inet6,
};

View File

@@ -69,7 +69,11 @@ static enum sctp_xmit sctp_packet_will_fit(struct sctp_packet *packet,
static void sctp_packet_reset(struct sctp_packet *packet)
{
/* sctp_packet_transmit() relies on this to reset size to the
* current overhead after sending packets.
*/
packet->size = packet->overhead;
packet->has_cookie_echo = 0;
packet->has_sack = 0;
packet->has_data = 0;
@@ -87,6 +91,7 @@ void sctp_packet_config(struct sctp_packet *packet, __u32 vtag,
struct sctp_transport *tp = packet->transport;
struct sctp_association *asoc = tp->asoc;
struct sock *sk;
size_t overhead = sizeof(struct ipv6hdr) + sizeof(struct sctphdr);
pr_debug("%s: packet:%p vtag:0x%x\n", __func__, packet, vtag);
packet->vtag = vtag;
@@ -95,10 +100,22 @@ void sctp_packet_config(struct sctp_packet *packet, __u32 vtag,
if (!sctp_packet_empty(packet))
return;
/* set packet max_size with pathmtu */
/* set packet max_size with pathmtu, then calculate overhead */
packet->max_size = tp->pathmtu;
if (!asoc)
if (asoc) {
struct sctp_sock *sp = sctp_sk(asoc->base.sk);
struct sctp_af *af = sp->pf->af;
overhead = af->net_header_len +
af->ip_options_len(asoc->base.sk);
overhead += sizeof(struct sctphdr);
packet->overhead = overhead;
packet->size = overhead;
} else {
packet->overhead = overhead;
packet->size = overhead;
return;
}
/* update dst or transport pathmtu if in need */
sk = asoc->base.sk;
@@ -140,23 +157,14 @@ void sctp_packet_init(struct sctp_packet *packet,
struct sctp_transport *transport,
__u16 sport, __u16 dport)
{
struct sctp_association *asoc = transport->asoc;
size_t overhead;
pr_debug("%s: packet:%p transport:%p\n", __func__, packet, transport);
packet->transport = transport;
packet->source_port = sport;
packet->destination_port = dport;
INIT_LIST_HEAD(&packet->chunk_list);
if (asoc) {
struct sctp_sock *sp = sctp_sk(asoc->base.sk);
overhead = sp->pf->af->net_header_len;
} else {
overhead = sizeof(struct ipv6hdr);
}
overhead += sizeof(struct sctphdr);
packet->overhead = overhead;
/* The overhead will be calculated by sctp_packet_config() */
packet->overhead = 0;
sctp_packet_reset(packet);
packet->vtag = 0;
}

View File

@@ -187,6 +187,45 @@ int sctp_copy_local_addr_list(struct net *net, struct sctp_bind_addr *bp,
return error;
}
/* Copy over any ip options */
static void sctp_v4_copy_ip_options(struct sock *sk, struct sock *newsk)
{
struct inet_sock *newinet, *inet = inet_sk(sk);
struct ip_options_rcu *inet_opt, *newopt = NULL;
newinet = inet_sk(newsk);
rcu_read_lock();
inet_opt = rcu_dereference(inet->inet_opt);
if (inet_opt) {
newopt = sock_kmalloc(newsk, sizeof(*inet_opt) +
inet_opt->opt.optlen, GFP_ATOMIC);
if (newopt)
memcpy(newopt, inet_opt, sizeof(*inet_opt) +
inet_opt->opt.optlen);
else
pr_err("%s: Failed to copy ip options\n", __func__);
}
RCU_INIT_POINTER(newinet->inet_opt, newopt);
rcu_read_unlock();
}
/* Account for the IP options */
static int sctp_v4_ip_options_len(struct sock *sk)
{
struct inet_sock *inet = inet_sk(sk);
struct ip_options_rcu *inet_opt;
int len = 0;
rcu_read_lock();
inet_opt = rcu_dereference(inet->inet_opt);
if (inet_opt)
len = inet_opt->opt.optlen;
rcu_read_unlock();
return len;
}
/* Initialize a sctp_addr from in incoming skb. */
static void sctp_v4_from_skb(union sctp_addr *addr, struct sk_buff *skb,
int is_saddr)
@@ -538,6 +577,8 @@ static struct sock *sctp_v4_create_accept_sk(struct sock *sk,
sctp_copy_sock(newsk, sk, asoc);
sock_reset_flag(newsk, SOCK_ZAPPED);
sctp_v4_copy_ip_options(sk, newsk);
newinet = inet_sk(newsk);
newinet->inet_daddr = asoc->peer.primary_addr.v4.sin_addr.s_addr;
@@ -956,6 +997,7 @@ static struct sctp_pf sctp_pf_inet = {
.addr_to_user = sctp_v4_addr_to_user,
.to_sk_saddr = sctp_v4_to_sk_saddr,
.to_sk_daddr = sctp_v4_to_sk_daddr,
.copy_ip_options = sctp_v4_copy_ip_options,
.af = &sctp_af_inet
};
@@ -1040,6 +1082,7 @@ static struct sctp_af sctp_af_inet = {
.ecn_capable = sctp_v4_ecn_capable,
.net_header_len = sizeof(struct iphdr),
.sockaddr_len = sizeof(struct sockaddr_in),
.ip_options_len = sctp_v4_ip_options_len,
#ifdef CONFIG_COMPAT
.compat_setsockopt = compat_ip_setsockopt,
.compat_getsockopt = compat_ip_getsockopt,

View File

@@ -3098,6 +3098,12 @@ static __be16 sctp_process_asconf_param(struct sctp_association *asoc,
if (af->is_any(&addr))
memcpy(&addr, &asconf->source, sizeof(addr));
if (security_sctp_bind_connect(asoc->ep->base.sk,
SCTP_PARAM_ADD_IP,
(struct sockaddr *)&addr,
af->sockaddr_len))
return SCTP_ERROR_REQ_REFUSED;
/* ADDIP 4.3 D9) If an endpoint receives an ADD IP address
* request and does not have the local resources to add this
* new address to the association, it MUST return an Error
@@ -3164,6 +3170,12 @@ static __be16 sctp_process_asconf_param(struct sctp_association *asoc,
if (af->is_any(&addr))
memcpy(&addr.v4, sctp_source(asconf), sizeof(addr));
if (security_sctp_bind_connect(asoc->ep->base.sk,
SCTP_PARAM_SET_PRIMARY,
(struct sockaddr *)&addr,
af->sockaddr_len))
return SCTP_ERROR_REQ_REFUSED;
peer = sctp_assoc_lookup_paddr(asoc, &addr);
if (!peer)
return SCTP_ERROR_DNS_FAILED;

View File

@@ -321,6 +321,11 @@ enum sctp_disposition sctp_sf_do_5_1B_init(struct net *net,
struct sctp_packet *packet;
int len;
/* Update socket peer label if first association. */
if (security_sctp_assoc_request((struct sctp_endpoint *)ep,
chunk->skb))
return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
/* 6.10 Bundling
* An endpoint MUST NOT bundle INIT, INIT ACK or
* SHUTDOWN COMPLETE with any other chunks.
@@ -922,6 +927,9 @@ enum sctp_disposition sctp_sf_do_5_1E_ca(struct net *net,
*/
sctp_add_cmd_sf(commands, SCTP_CMD_INIT_COUNTER_RESET, SCTP_NULL());
/* Set peer label for connection. */
security_inet_conn_established(ep->base.sk, chunk->skb);
/* RFC 2960 5.1 Normal Establishment of an Association
*
* E) Upon reception of the COOKIE ACK, endpoint "A" will move
@@ -1459,6 +1467,11 @@ static enum sctp_disposition sctp_sf_do_unexpected_init(
struct sctp_packet *packet;
int len;
/* Update socket peer label if first association. */
if (security_sctp_assoc_request((struct sctp_endpoint *)ep,
chunk->skb))
return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
/* 6.10 Bundling
* An endpoint MUST NOT bundle INIT, INIT ACK or
* SHUTDOWN COMPLETE with any other chunks.
@@ -2145,6 +2158,11 @@ enum sctp_disposition sctp_sf_do_5_2_4_dupcook(
}
}
/* Update socket peer label if first association. */
if (security_sctp_assoc_request((struct sctp_endpoint *)ep,
chunk->skb))
return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
/* Set temp so that it won't be added into hashtable */
new_asoc->temp = 1;

View File

@@ -1046,6 +1046,12 @@ static int sctp_setsockopt_bindx(struct sock *sk,
/* Do the work. */
switch (op) {
case SCTP_BINDX_ADD_ADDR:
/* Allow security module to validate bindx addresses. */
err = security_sctp_bind_connect(sk, SCTP_SOCKOPT_BINDX_ADD,
(struct sockaddr *)kaddrs,
addrs_size);
if (err)
goto out;
err = sctp_bindx_add(sk, kaddrs, addrcnt);
if (err)
goto out;
@@ -1255,6 +1261,7 @@ static int __sctp_connect(struct sock *sk,
if (assoc_id)
*assoc_id = asoc->assoc_id;
err = sctp_wait_for_connect(asoc, &timeo);
/* Note: the asoc may be freed after the return of
* sctp_wait_for_connect.
@@ -1350,7 +1357,16 @@ static int __sctp_setsockopt_connectx(struct sock *sk,
if (unlikely(IS_ERR(kaddrs)))
return PTR_ERR(kaddrs);
/* Allow security module to validate connectx addresses. */
err = security_sctp_bind_connect(sk, SCTP_SOCKOPT_CONNECTX,
(struct sockaddr *)kaddrs,
addrs_size);
if (err)
goto out_free;
err = __sctp_connect(sk, kaddrs, addrs_size, assoc_id);
out_free:
kvfree(kaddrs);
return err;
@@ -1680,6 +1696,7 @@ static int sctp_sendmsg_new_asoc(struct sock *sk, __u16 sflags,
struct sctp_association *asoc;
enum sctp_scope scope;
struct cmsghdr *cmsg;
struct sctp_af *af;
int err;
*tp = NULL;
@@ -1705,6 +1722,21 @@ static int sctp_sendmsg_new_asoc(struct sock *sk, __u16 sflags,
scope = sctp_scope(daddr);
/* Label connection socket for first association 1-to-many
* style for client sequence socket()->sendmsg(). This
* needs to be done before sctp_assoc_add_peer() as that will
* set up the initial packet that needs to account for any
* security ip options (CIPSO/CALIPSO) added to the packet.
*/
af = sctp_get_af_specific(daddr->sa.sa_family);
if (!af)
return -EINVAL;
err = security_sctp_bind_connect(sk, SCTP_SENDMSG_CONNECT,
(struct sockaddr *)daddr,
af->sockaddr_len);
if (err < 0)
return err;
asoc = sctp_association_new(ep, sk, scope, GFP_KERNEL);
if (!asoc)
return -ENOMEM;
@@ -2932,6 +2964,8 @@ static int sctp_setsockopt_primary_addr(struct sock *sk, char __user *optval,
{
struct sctp_prim prim;
struct sctp_transport *trans;
struct sctp_af *af;
int err;
if (optlen != sizeof(struct sctp_prim))
return -EINVAL;
@@ -2939,6 +2973,17 @@ static int sctp_setsockopt_primary_addr(struct sock *sk, char __user *optval,
if (copy_from_user(&prim, optval, sizeof(struct sctp_prim)))
return -EFAULT;
/* Allow security module to validate address but need address len. */
af = sctp_get_af_specific(prim.ssp_addr.ss_family);
if (!af)
return -EINVAL;
err = security_sctp_bind_connect(sk, SCTP_PRIMARY_ADDR,
(struct sockaddr *)&prim.ssp_addr,
af->sockaddr_len);
if (err)
return err;
trans = sctp_addr_id2transport(sk, &prim.ssp_addr, prim.ssp_assoc_id);
if (!trans)
return -EINVAL;
@@ -3161,6 +3206,7 @@ static int sctp_setsockopt_mappedv4(struct sock *sk, char __user *optval, unsign
static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, unsigned int optlen)
{
struct sctp_sock *sp = sctp_sk(sk);
struct sctp_af *af = sp->pf->af;
struct sctp_assoc_value params;
struct sctp_association *asoc;
int val;
@@ -3185,7 +3231,8 @@ static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, unsigned
if (val) {
int min_len, max_len;
min_len = SCTP_DEFAULT_MINSEGMENT - sp->pf->af->net_header_len;
min_len = SCTP_DEFAULT_MINSEGMENT - af->net_header_len;
min_len -= af->ip_options_len(sk);
min_len -= sizeof(struct sctphdr) +
sizeof(struct sctp_data_chunk);
@@ -3198,7 +3245,8 @@ static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, unsigned
asoc = sctp_id2assoc(sk, params.assoc_id);
if (asoc) {
if (val == 0) {
val = asoc->pathmtu - sp->pf->af->net_header_len;
val = asoc->pathmtu - af->net_header_len;
val -= af->ip_options_len(sk);
val -= sizeof(struct sctphdr) +
sctp_datachk_len(&asoc->stream);
}
@@ -3267,6 +3315,13 @@ static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char __user *optva
if (!sctp_assoc_lookup_laddr(asoc, (union sctp_addr *)&prim.sspp_addr))
return -EADDRNOTAVAIL;
/* Allow security module to validate address. */
err = security_sctp_bind_connect(sk, SCTP_SET_PEER_PRIMARY_ADDR,
(struct sockaddr *)&prim.sspp_addr,
af->sockaddr_len);
if (err)
return err;
/* Create an ASCONF chunk with SET_PRIMARY parameter */
chunk = sctp_make_asconf_set_prim(asoc,
(union sctp_addr *)&prim.sspp_addr);
@@ -5140,9 +5195,11 @@ int sctp_do_peeloff(struct sock *sk, sctp_assoc_t id, struct socket **sockp)
sctp_copy_sock(sock->sk, sk, asoc);
/* Make peeled-off sockets more like 1-1 accepted sockets.
* Set the daddr and initialize id to something more random
* Set the daddr and initialize id to something more random and also
* copy over any ip options.
*/
sp->pf->to_sk_daddr(&asoc->peer.primary_addr, sk);
sp->pf->copy_ip_options(sk, sock->sk);
/* Populate the fields of the newsk from the oldsk and migrate the
* asoc to the newsk.
@@ -8465,6 +8522,8 @@ void sctp_copy_sock(struct sock *newsk, struct sock *sk,
{
struct inet_sock *inet = inet_sk(sk);
struct inet_sock *newinet;
struct sctp_sock *sp = sctp_sk(sk);
struct sctp_endpoint *ep = sp->ep;
newsk->sk_type = sk->sk_type;
newsk->sk_bound_dev_if = sk->sk_bound_dev_if;
@@ -8507,7 +8566,10 @@ void sctp_copy_sock(struct sock *newsk, struct sock *sk,
if (newsk->sk_flags & SK_FLAGS_TIMESTAMP)
net_enable_timestamp();
security_sk_clone(sk, newsk);
/* Set newsk security attributes from orginal sk and connection
* security attribute from ep.
*/
security_sctp_sk_clone(ep, sk, newsk);
}
static inline void sctp_copy_descendant(struct sock *sk_to,