Re: [RFC PATCH v3] SELinux SCTP protocol support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 1/25/2015 7:07 AM, Richard Haines wrote:
> The Documentation/security/SELinux-sctp.txt describes how the patch has
> been implemented and tested.
>
> Patches to support the new SCTP portcon statement can be found at [1] and
> will apply to the latest release (rc7) found at [2].
>
> Also minor updates for DCCP to retrieve peer context via getpeercon(3).
>
> Built and tested on Fedora kernel-3.17.3-200.fc20.x86_64
>
> [1] http://marc.info/?l=selinux&m=141536871703018&w=2
> [2] https://github.com/SELinuxProject/selinux/wiki/Releases
>
> Signed-off-by: Richard Haines <richard_c_haines@xxxxxxxxxxxxxx>
> ---
>  Documentation/security/SELinux-sctp.txt | 247 ++++++++++++++++++++++++++++++++
>  include/linux/security.h                |  42 ++++++
>  net/sctp/sm_statefuns.c                 |  10 ++
>  net/sctp/socket.c                       |  15 ++
>  security/capability.c                   |  13 ++
>  security/security.c                     |  13 ++

Please add the LSM <linux-security-module@xxxxxxxxxxxxxxx> list to this RFC.

>  security/selinux/Makefile               |   2 +
>  security/selinux/hooks.c                | 147 ++++++++++++++++---
>  security/selinux/include/classmap.h     |   4 +
>  security/selinux/include/sctp.h         |  52 +++++++
>  security/selinux/include/sctp_private.h |  51 +++++++
>  security/selinux/netlabel.c             |   3 +
>  security/selinux/sctp.c                 | 185 ++++++++++++++++++++++++
>  13 files changed, 768 insertions(+), 16 deletions(-)
>  create mode 100644 Documentation/security/SELinux-sctp.txt
>  create mode 100644 security/selinux/include/sctp.h
>  create mode 100644 security/selinux/include/sctp_private.h
>  create mode 100644 security/selinux/sctp.c
>
> diff --git a/Documentation/security/SELinux-sctp.txt b/Documentation/security/SELinux-sctp.txt
> new file mode 100644
> index 0000000..476ba24
> --- /dev/null
> +++ b/Documentation/security/SELinux-sctp.txt
> @@ -0,0 +1,247 @@
> +                               SCTP SELinux Support
> +                              ======================
> +
> +Security Hooks
> +===============
> +security_sk_setsockopt()
> +-------------------------
> +A new security hook security_sk_setsockopt() is introduced that checks
> +permissions before setting the options associated with sock @sk.
> +This is supported in security/selinux/hooks.c and net/sctp/socket.c
> +An example usage is where sctp_getsockopt_connectx3() and
> +__sctp_setsockopt_connectx() manage the @optval data into a certain
> +state before security_sk_setsockopt is called for permission checks. This
> +means that the code to manage options does not need to be replicated in the
> +security module. See include/linux/security.h for details.
> +
> +security_sctp_assoc_request()
> +-----------------------------
> +security/selinux/hooks.c selinux_sctp_assoc_request() has been introduced to
> +support SCTP and obtains the sock peer context if first association and
> +also checks the association permission as shown in the "SCTP Peer Labeling
> +and Permission Checks" section below.
> +
> +The security_sctp_assoc_request() security hook has been added to
> +net/sctp/sm_statefuns.c where it passes the sk and chunk->skb to the security
> +module.
> +
> +security_sk_clone()
> +--------------------
> +Added to net/sctp/socket.c for cloning the security context on a new socket.
> +
> +
> +Policy Statements
> +==================
> +A new object class "sctp_socket" has been introduced with the following SCTP
> +specific permissions: "association" "bindx_add" "bindx_rem" "connectx"
> +and "peeloff". These are explained in the sections below.
> +
> +Kernel policy language
> +-----------------------
> +class sctp_socket
> +class sctp_socket inherits socket { node_bind name_connect association
> +        bindx_add bindx_rem connectx peeloff }
> +
> +CIL policy language
> +--------------------
> +(classcommon sctp_socket socket)
> +(class sctp_socket (node_bind name_connect association bindx_add bindx_rem
> +       connectx peeloff))
> +
> +Last classorder from refpolicy base:
> +   (classorder (db_language sctp_socket))
> +Last classorder from Fedora targeted base:
> +   (classorder (proxy sctp_socket))
> +
> +If userspace tools have been updated, then the portcon statement may be used
> +as shown in the following example:
> +(portcon sctp (2000 20000) (system_u object_r port_test_t ((s0) (s0))))
> +
> +NOTE: SELinux supports a maximum of 32 permissions per object class. SCTP
> +      has already allocated 29 (22 socket + 7 sctp_socket permissions).
> +      These are the permissions checked for sctp_socket in security/hooks.c:
> +          read write create getattr bind connect listen accept getopt setopt
> +          name_bind node_bind name_connect association bindx_add bindx_rem
> +          connectx peeloff
> +
> +"allow" Rule Validation Parameters (network_peer_controls = 1)
> +-------------------------------------------------------------------
> +allow domain_t socket_t : sctp_socket {bindx_add bindx_rem set_params peeloff};
> +allow socket_t port_t   : sctp_socket {name_bind name_connect};
> +allow socket_t node_t   : sctp_socket {node_bind};
> +allow socket_t peer_t   : sctp_socket {associate};
> +allow peer_t   netif_t  : netif       {ingress egress};
> +allow peer_t   node_t   : node        {recvfrom sendto};
> +allow socket_t peer_t   : peer        {recv};
> +
> +
> +SCTP Socket Option Permissions
> +===============================
> +These consist of: "bindx_add" "bindx_rem" "connectx" and "peeloff" and are
> +used as follows:
> +
> +SCTP_SOCKOPT_BINDX_ADD - Allows additional bind addresses to be
> +                         associated after (optionally) calling bind(2).
> +
> +SCTP_SOCKOPT_CONNECTX* - Allows the allocation of multiple
> +                         addresses for reaching a multi-homed peer.
> +
> +  Together they form SCTP associations and will be passed over the
> +  link to inform peer of any changes. As these two options can support
> +  multiple addresses, each address is checked via selinux_socket_bind() or
> +  selinux_socket_connect() to determine whether they have the correct
> +  permissions:
> +    bindx_add: bind, name_bind, node_bind + node SID + port SID via the
> +               (portcon sctp port ctx) policy statement.
> +    connectx:  connect, name_connect + port SID via the
> +               (portcon sctp port ctx) policy statement.
> +
> +SCTP_SOCKOPT_BINDX_REM - As the addresses would have already been
> +                         allowed, only the bindx_rem permission is checked.
> +
> +SCTP_PEER_ADDR_PARAMS - Alter heartbeats and address max retransmissions.
> +SCTP_PEER_ADDR_THLDS  - Alter the thresholds.
> + These require the set_params permission.
> +
> +SCTP_PRIMARY_ADDR          - Set local primary address.
> +SCTP_SET_PEER_PRIMARY_ADDR - Request peer sets address as association primary.
> + These require the set_addr permission.
> +
> +SCTP_SOCKOPT_PEELOFF - Branch off an association into a new socket that
> +will be a one-to-one style socket. As SELinux already handles the creation
> +of new sockets, only the peeloff permission is checked.
> +
> +
> +SCTP Peer Labeling and Permission Checks
> +=========================================
> +An SCTP socket will only have one peer label assigned to it. This will be
> +assigned during the establishment of the first association. Once the peer label
> +has been assigned, the "association" permission will be checked as follows:
> +
> +       allow socket_t peer_t : sctp_socket { associate };
> +
> +As SCTP supports multiple endpoints on a single socket it is possible that
> +each interface may be configured with a different peer label, however it is
> +recommended that the labels are consistant (see "Multi-homing Test" section
> +for examples).
> +
> +NOTES:
> +   1) If peer labeling is not enabled, then the peer context will always be
> +      SECINITSID_UNLABELED (unlabeled_t in Reference Policy).
> +
> +   2) If using NetLabel fallback labeling "netlabelctl unlbl ..." be aware
> +      that if a label is assigned to a specific interface, and that interface
> +      'goes down' (as in the "Multi-homing Test" section), then the NetLabel
> +      service will remove the entry. Therefore ensure that the network
> +      startup scripts call netlabelctl(8) to set the required label (see
> +      netlabel-config(8) helper script for details).
> +
> +   3) SCTP sockets inherit their labels from the creating process (unless
> +      there are policy rules to change this). They do NOT follow the TCP
> +      labeling method even for TCP-style sockets. For reference: TCP child
> +      sockets take the TE information from the parent server socket, but the
> +      MLS/MCS information from the connection.
> +
> +   4) getpeercon(3) may be used by userspace apps to retrieve the sockets
> +      peer context.
> +
> +   5) The peer labeling rules still apply as discussed in the following set
> +      of pages at: http://paulmoore.livejournal.com/tag/netlabel
> +
> +
> +      SCTP endpoint "A"                                SCTP endpoint "Z"
> +      =================                                =================
> +    sctp_sf_do_prm_asoc()
> + Initiate an association to
> + SCTP peer endpoint "Z".
> + Send INIT first as we need to obtain
> + a peer label before checking whether
> + this is allowed or not. This will be
> + checked once the INIT ACK has been
> + received.
> +         INIT --------------------------------------------->
> +                                                   sctp_sf_do_5_1B_init()
> +                                                 Respond to an INIT chunk.
> +                                             SCTP peer endpoint "A" is
> +                                             asking for an association. Call
> +                                             security_sctp_assoc_request()
> +                                             to set the peer label if first
> +                                             association, then check ASSOCIATE
> +                                             permission:
> +                             allow socket_t peer_t : sctp_socket { associate };
> +                                             IF valid send:
> +          <----------------------------------------------- INIT ACK
> +          |                                  ELSE audit event and silently
> +          |                                       discard the packet.
> +    sctp_sf_do_5_1C_ack
> + Respond to an INIT ACK chunk.
> + SCTP peer endpoint"A" initiated
> + this association to SCTP peer
> + endpoint "Z". The security checks
> + are done now as we have a peer
> + label to check against, so call
> + security_sctp_assoc_request()
> + to set the peer label if first
> + association, then check ASSOCIATE
> + permission:
> +    allow socket_t peer_t : sctp_socket { associate };
> + IF valid send:
> +    COOKIE ECHO ------------------------------------------------>
> + ELSE audit event and silently                                  |
> +      discard the packet.                                       |
> +                                                                |
> +          <----------------------------------------------- COOKIE ACK
> +          |                                                     |
> +   sctp_sf_do_5_1E_ca                                  sctp_sf_do_5_1D_ce
> +      ESTABLISHED                                          ESTABLISHED
> +          |                                                     |
> +    ------------------------------------------------------------------
> +    |                     Association Established                    |
> +    ------------------------------------------------------------------
> +
> +
> +Testing
> +========
> +All lksctp-tools/src/func_tests run correctly in enforcing mode except when
> +specific permissions are denied (e.g. test_peeloff_v6 will fail with
> +"test_peeloff.c  1 BROK : sctp_peeloff: Permission denied").
> +
> +Tests involving removal of the "association" permission will wait, simply
> +because the INIT or INIT ACK packets will be silently discarded, however as
> +with all AVC denials they are audited in the audit log.
> +
> +Multi-homing Test
> +------------------
> +                      ------- Wireless Router -------
> +                     /                               \
> +                    /                                 \
> +                   /                                   \
> +             192.168.1.66                          192.168.1.64
> +                 /                                       \
> +           ----------  Ethernet         193.168.1.65 ----------
> +           | CLIENT | <----------------------------> | SERVER |
> +           ---------- 193.168.1.67                   ----------
> +        sctp_darn                                 sctp_darn
> +        -H 192.168.1.66                           -H 192.168.1.64
> +        -B 193.168.1.67                           -B 193.168.1.65
> +        -P 19000                                  -P 19001
> +        -c 192.168.1.64                           -l
> +        -c 193.168.1.65
> +        -p 19001
> +        -s
> +
> +Set Netlabel fallback peer labeling on Client and Server as follows:
> +    netlabelctl unlbl add interface:wlan0 address:192.168.1.0/24 \
> +        label:system_u:object_r:sctp_netlabel_peer_t:s0
> +    netlabelctl unlbl add interface:p2p1 address:193.168.1.0/24 \
> +        label:system_u:object_r:sctp_netlabel_peer_t:s0
> +
> +Then:
> +Send data from Client to Server - ok - saddr 192.168.1.66 daddr 192.168.1.64
> +Turn Server Wifi off (192.168.1.64)
> +Send data from Client to Server - ok - saddr 192.168.1.66 daddr 193.168.1.65
> +
> +tshark(1) may be used to monitor traffic on each interface, for example:
> +    tshark -O SCTP -P -x -i wlan0
> +    tshark -O SCTP -P -x -i p2p1
> +
> diff --git a/include/linux/security.h b/include/linux/security.h
> index 623f90e..af62982 100644
> --- a/include/linux/security.h
> +++ b/include/linux/security.h
> @@ -948,6 +948,23 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
>   *	@level contains the protocol level to set options for.
>   *	@optname contains the name of the option to set.
>   *	Return 0 if permission is granted.
> + * @sk_setsockopt:
> + *	Check permissions before setting the options associated with sock @sk.
> + *	This is equivalent to @socket_setsockopt, except that it has the
> + *	option parameters, as it is intended to support permission checking
> + *	of options and their parameters within network services.
> + *	An example usage is in net/sctp/socket.c where
> + *	sctp_getsockopt_connectx3() and __sctp_setsockopt_connectx()
> + *	manage the @optval data into a certain state before @sk_setsockopt
> + *	is called for permission checks. This means that the code to
> + *	manage @optval does not need to be replicated in the security
> + *	module.
> + *	@sk contains the sock structure.
> + *	@level contains the protocol level to set options for.
> + *	@optname contains the name of the option to set.
> + *	@optval contains the value(s) to set (already copied from userspace).
> + *	@optlen contains the length of the value(s) to be set.
> + *	Return 0 if permission is granted.
>   * @socket_shutdown:
>   *	Checks permission before all or part of a connection on the socket
>   *	@sock is shut down.
> @@ -997,6 +1014,12 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
>   *	authorizations.
>   * @sock_graft:
>   *	Sets the socket's isec sid to the sock's sid.
> + * @sctp_assoc_request:
> + *	Update socket peer label if first association on @sk then check
> + *	whether association allowed.
> + *	@sk contains the sock structure.
> + *	@skb skbuff of association packet (INIT or INIT ACK) being queried.
> + *	Return 0 on success, error on failure.
>   * @inet_conn_request:
>   *	Sets the openreq's sid to socket's sid with MLS portion taken from peer sid.
>   * @inet_csk_clone:
> @@ -1666,6 +1689,8 @@ struct security_operations {
>  	int (*socket_getpeername) (struct socket *sock);
>  	int (*socket_getsockopt) (struct socket *sock, int level, int optname);
>  	int (*socket_setsockopt) (struct socket *sock, int level, int optname);
> +	int (*sk_setsockopt) (struct sock *sk, int level, int optname,
> +				    char *optval, int optlen);
>  	int (*socket_shutdown) (struct socket *sock, int how);
>  	int (*socket_sock_rcv_skb) (struct sock *sk, struct sk_buff *skb);
>  	int (*socket_getpeersec_stream) (struct socket *sock, char __user *optval, int __user *optlen, unsigned len);
> @@ -1675,6 +1700,7 @@ struct security_operations {
>  	void (*sk_clone_security) (const struct sock *sk, struct sock *newsk);
>  	void (*sk_getsecid) (struct sock *sk, u32 *secid);
>  	void (*sock_graft) (struct sock *sk, struct socket *parent);
> +	int (*sctp_assoc_request) (struct sock *sk, struct sk_buff *skb);
>  	int (*inet_conn_request) (struct sock *sk, struct sk_buff *skb,
>  				  struct request_sock *req);
>  	void (*inet_csk_clone) (struct sock *newsk, const struct request_sock *req);
> @@ -2650,6 +2676,8 @@ int security_socket_getsockname(struct socket *sock);
>  int security_socket_getpeername(struct socket *sock);
>  int security_socket_getsockopt(struct socket *sock, int level, int optname);
>  int security_socket_setsockopt(struct socket *sock, int level, int optname);
> +int security_sk_setsockopt(struct sock *sk, int level, int optname,
> +			    char *optval, int optlen);
>  int security_socket_shutdown(struct socket *sock, int how);
>  int security_sock_rcv_skb(struct sock *sk, struct sk_buff *skb);
>  int security_socket_getpeersec_stream(struct socket *sock, char __user *optval,
> @@ -2661,6 +2689,7 @@ void security_sk_clone(const struct sock *sk, struct sock *newsk);
>  void security_sk_classify_flow(struct sock *sk, struct flowi *fl);
>  void security_req_classify_flow(const struct request_sock *req, struct flowi *fl);
>  void security_sock_graft(struct sock*sk, struct socket *parent);
> +int security_sctp_assoc_request(struct sock *sk, struct sk_buff *skb);
>  int security_inet_conn_request(struct sock *sk,
>  			struct sk_buff *skb, struct request_sock *req);
>  void security_inet_csk_clone(struct sock *newsk,
> @@ -2767,6 +2796,13 @@ static inline int security_socket_setsockopt(struct socket *sock,
>  	return 0;
>  }
>  
> +static inline int security_sk_setsockopt(struct sock *sk, int level,
> +					    int optname, char *optval,
> +					    int optlen)
> +{
> +	return 0;
> +}
> +
>  static inline int security_socket_shutdown(struct socket *sock, int how)
>  {
>  	return 0;
> @@ -2813,6 +2849,12 @@ static inline void security_sock_graft(struct sock *sk, struct socket *parent)
>  {
>  }
>  
> +static inline int security_sctp_assoc_request(struct sock *sk,
> +			struct sk_buff *skb)
> +{
> +	return 0;
> +}
> +
>  static inline int security_inet_conn_request(struct sock *sk,
>  			struct sk_buff *skb, struct request_sock *req)
>  {
> diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c
> index 3ee27b7..0e7fb3d 100644
> --- a/net/sctp/sm_statefuns.c
> +++ b/net/sctp/sm_statefuns.c
> @@ -315,6 +315,11 @@ sctp_disposition_t sctp_sf_do_5_1B_init(struct net *net,
>  	sctp_unrecognized_param_t *unk_param;
>  	int len;
>  
> +	/* Update socket peer label if first association then check
> +	 * whether association allowed. */
> +	if (security_sctp_assoc_request(ep->base.sk, 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.
> @@ -508,6 +513,11 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(struct net *net,
>  	struct sctp_chunk *err_chunk;
>  	struct sctp_packet *packet;
>  
> +	/* Update socket peer label if first association then check
> +	 * whether association allowed. */
> +	if (security_sctp_assoc_request(ep->base.sk, chunk->skb))
> +		return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
> +
>  	if (!sctp_vtag_verify(chunk, asoc))
>  		return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
>  
> diff --git a/net/sctp/socket.c b/net/sctp/socket.c
> index 634a2ab..d0e0593 100644
> --- a/net/sctp/socket.c
> +++ b/net/sctp/socket.c
> @@ -1012,6 +1012,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_sk_setsockopt(sk, SOL_SCTP,
> +			    SCTP_SOCKOPT_BINDX_ADD,
> +			    (char *)kaddrs, addrs_size);
> +		if (err)
> +			goto out;
>  		err = sctp_bindx_add(sk, kaddrs, addrcnt);
>  		if (err)
>  			goto out;
> @@ -1327,9 +1333,16 @@ static int __sctp_setsockopt_connectx(struct sock *sk,
>  	if (__copy_from_user(kaddrs, addrs, addrs_size)) {
>  		err = -EFAULT;
>  	} else {
> +		/* Allow security module to validate connectx addresses. */
> +		err = security_sk_setsockopt(sk, SOL_SCTP,
> +			    SCTP_SOCKOPT_CONNECTX,
> +			   (char *)kaddrs, addrs_size);
> +		if (err)
> +			goto out_free;
>  		err = __sctp_connect(sk, kaddrs, addrs_size, assoc_id);
>  	}
>  
> +out_free:
>  	kfree(kaddrs);
>  
>  	return err;
> @@ -7335,6 +7348,8 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
>  		newsk->sk_shutdown |= RCV_SHUTDOWN;
>  
>  	newsk->sk_state = SCTP_SS_ESTABLISHED;
> +	/* Ensure newsk has the same security attributes. */
> +	security_sk_clone(oldsk, newsk);
>  	release_sock(newsk);
>  }
>  
> diff --git a/security/capability.c b/security/capability.c
> index a74fde6..0272b05 100644
> --- a/security/capability.c
> +++ b/security/capability.c
> @@ -643,6 +643,12 @@ static int cap_socket_setsockopt(struct socket *sock, int level, int optname)
>  	return 0;
>  }
>  
> +static int cap_sk_setsockopt(struct sock *sk, int level, int optname,
> +					    char *optval, int optlen)
> +{
> +	return 0;
> +}
> +
>  static int cap_socket_getsockopt(struct socket *sock, int level, int optname)
>  {
>  	return 0;
> @@ -692,6 +698,11 @@ static void cap_sock_graft(struct sock *sk, struct socket *parent)
>  {
>  }
>  
> +static int cap_sctp_assoc_request(struct sock *sk, struct sk_buff *skb)
> +{
> +	return 0;
> +}
> +
>  static int cap_inet_conn_request(struct sock *sk, struct sk_buff *skb,
>  				 struct request_sock *req)
>  {
> @@ -1084,6 +1095,7 @@ void __init security_fixup_ops(struct security_operations *ops)
>  	set_to_cap_if_null(ops, socket_getsockname);
>  	set_to_cap_if_null(ops, socket_getpeername);
>  	set_to_cap_if_null(ops, socket_setsockopt);
> +	set_to_cap_if_null(ops, sk_setsockopt);
>  	set_to_cap_if_null(ops, socket_getsockopt);
>  	set_to_cap_if_null(ops, socket_shutdown);
>  	set_to_cap_if_null(ops, socket_sock_rcv_skb);
> @@ -1094,6 +1106,7 @@ void __init security_fixup_ops(struct security_operations *ops)
>  	set_to_cap_if_null(ops, sk_clone_security);
>  	set_to_cap_if_null(ops, sk_getsecid);
>  	set_to_cap_if_null(ops, sock_graft);
> +	set_to_cap_if_null(ops, sctp_assoc_request);
>  	set_to_cap_if_null(ops, inet_conn_request);
>  	set_to_cap_if_null(ops, inet_csk_clone);
>  	set_to_cap_if_null(ops, inet_conn_established);
> diff --git a/security/security.c b/security/security.c
> index e41b1a8..a03ee03 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -1207,6 +1207,13 @@ int security_socket_setsockopt(struct socket *sock, int level, int optname)
>  	return security_ops->socket_setsockopt(sock, level, optname);
>  }
>  
> +int security_sk_setsockopt(struct sock *sk, int level, int optname,
> +				    char *optval, int optlen)
> +{
> +	return security_ops->sk_setsockopt(sk, level, optname, optval, optlen);
> +}
> +EXPORT_SYMBOL(security_sk_setsockopt);
> +
>  int security_socket_shutdown(struct socket *sock, int how)
>  {
>  	return security_ops->socket_shutdown(sock, how);
> @@ -1264,6 +1271,12 @@ void security_sock_graft(struct sock *sk, struct socket *parent)
>  }
>  EXPORT_SYMBOL(security_sock_graft);
>  
> +int security_sctp_assoc_request(struct sock *sk, struct sk_buff *skb)
> +{
> +	return security_ops->sctp_assoc_request(sk, skb);
> +}
> +EXPORT_SYMBOL(security_sctp_assoc_request);
> +
>  int security_inet_conn_request(struct sock *sk,
>  			struct sk_buff *skb, struct request_sock *req)
>  {
> diff --git a/security/selinux/Makefile b/security/selinux/Makefile
> index ad5cd76..a450c85 100644
> --- a/security/selinux/Makefile
> +++ b/security/selinux/Makefile
> @@ -13,6 +13,8 @@ selinux-$(CONFIG_SECURITY_NETWORK_XFRM) += xfrm.o
>  
>  selinux-$(CONFIG_NETLABEL) += netlabel.o
>  
> +selinux-$(subst m,y,$(CONFIG_IP_SCTP)) += sctp.o
> +
>  ccflags-y := -Isecurity/selinux -Isecurity/selinux/include
>  
>  $(addprefix $(obj)/,$(selinux-y)): $(obj)/flask.h
> diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> index e03bad5..1440d9a 100644
> --- a/security/selinux/hooks.c
> +++ b/security/selinux/hooks.c
> @@ -66,6 +66,7 @@
>  #include <linux/tcp.h>
>  #include <linux/udp.h>
>  #include <linux/dccp.h>
> +#include <linux/sctp.h>
>  #include <linux/quota.h>
>  #include <linux/un.h>		/* for Unix socket types */
>  #include <net/af_unix.h>	/* for Unix socket types */
> @@ -94,6 +95,7 @@
>  #include "netlabel.h"
>  #include "audit.h"
>  #include "avc_ss.h"
> +#include "sctp.h"
>  
>  extern struct security_operations *security_ops;
>  
> @@ -1185,8 +1187,11 @@ static inline u16 socket_type_to_security_class(int family, int type, int protoc
>  	case PF_INET6:
>  		switch (type) {
>  		case SOCK_STREAM:
> +		case SOCK_SEQPACKET:
>  			if (default_protocol_stream(protocol))
>  				return SECCLASS_TCP_SOCKET;
> +			else if (protocol == IPPROTO_SCTP)
> +				return SECCLASS_SCTP_SOCKET;
>  			else
>  				return SECCLASS_RAWIP_SOCKET;
>  		case SOCK_DGRAM:
> @@ -3726,6 +3731,23 @@ static int selinux_parse_skb_ipv4(struct sk_buff *skb,
>  		break;
>  	}
>  
> +#if defined(CONFIG_IP_SCTP) || defined(CONFIG_IP_SCTP_MODULE)
> +	case IPPROTO_SCTP: {
> +		struct sctphdr _sctph, *sh;
> +
> +		if (ntohs(ih->frag_off) & IP_OFFSET)
> +			break;
> +
> +		offset += ihlen;
> +		sh = skb_header_pointer(skb, offset, sizeof(_sctph), &_sctph);
> +		if (sh == NULL)
> +			break;
> +
> +		ad->u.net->sport = sh->source;
> +		ad->u.net->dport = sh->dest;
> +		break;
> +	}
> +#endif
>  	default:
>  		break;
>  	}
> @@ -3799,6 +3821,19 @@ static int selinux_parse_skb_ipv6(struct sk_buff *skb,
>  		break;
>  	}
>  
> +#if defined(CONFIG_IP_SCTP) || defined(CONFIG_IP_SCTP_MODULE)
> +	case IPPROTO_SCTP: {
> +		struct sctphdr _sctph, *sh;
> +
> +		sh = skb_header_pointer(skb, offset, sizeof(_sctph), &_sctph);
> +		if (sh == NULL)
> +			break;
> +
> +		ad->u.net->sport = sh->source;
> +		ad->u.net->dport = sh->dest;
> +		break;
> +	}
> +#endif
>  	/* includes fragments */
>  	default:
>  		break;
> @@ -3859,7 +3894,7 @@ okay:
>   * Description:
>   * Check the various different forms of network peer labeling and determine
>   * the peer label/SID for the packet; most of the magic actually occurs in
> - * the security server function security_net_peersid_cmp().  The function
> + * the security server function security_net_peersid_resolve().  The function
>   * returns zero if the value in @sid is valid (although it may be SECSID_NULL)
>   * or -EACCES if @sid is invalid due to inconsistencies with the different
>   * peer labels.
> @@ -3928,7 +3963,7 @@ static int socket_sockcreate_sid(const struct task_security_struct *tsec,
>  				       socksid);
>  }
>  
> -static int sock_has_perm(struct task_struct *task, struct sock *sk, u32 perms)
> +int sock_has_perm(struct task_struct *task, struct sock *sk, u32 perms)
>  {
>  	struct sk_security_struct *sksec = sk->sk_security;
>  	struct common_audit_data ad;
> @@ -3998,7 +4033,8 @@ static int selinux_socket_post_create(struct socket *sock, int family,
>     Need to determine whether we should perform a name_bind
>     permission check between the socket and the port number. */
>  
> -static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen)
> +int selinux_socket_bind(struct socket *sock, struct sockaddr *address,
> +							    int addrlen)
>  {
>  	struct sock *sk = sock->sk;
>  	u16 family;
> @@ -4010,8 +4046,8 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
>  
>  	/*
>  	 * If PF_INET or PF_INET6, check name_bind permission for the port.
> -	 * Multiple address binding for SCTP is not supported yet: we just
> -	 * check the first address now.
> +	 * Multiple address binding for SCTP is supported via
> +	 * selinux_sctp_validate_sockopt().
>  	 */
>  	family = sk->sk_family;
>  	if (family == PF_INET || family == PF_INET6) {
> @@ -4069,6 +4105,10 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
>  			node_perm = DCCP_SOCKET__NODE_BIND;
>  			break;
>  
> +		case SECCLASS_SCTP_SOCKET:
> +			node_perm = SCTP_SOCKET__NODE_BIND;
> +			break;
> +
>  		default:
>  			node_perm = RAWIP_SOCKET__NODE_BIND;
>  			break;
> @@ -4097,7 +4137,8 @@ out:
>  	return err;
>  }
>  
> -static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen)
> +int selinux_socket_connect(struct socket *sock, struct sockaddr *address,
> +							    int addrlen)
>  {
>  	struct sock *sk = sock->sk;
>  	struct sk_security_struct *sksec = sk->sk_security;
> @@ -4108,10 +4149,12 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address,
>  		return err;
>  
>  	/*
> -	 * If a TCP or DCCP socket, check name_connect permission for the port.
> +	 * If a TCP, DCCP or SCTP socket, check name_connect permission
> +	 * for the port.
>  	 */
>  	if (sksec->sclass == SECCLASS_TCP_SOCKET ||
> -	    sksec->sclass == SECCLASS_DCCP_SOCKET) {
> +	    sksec->sclass == SECCLASS_DCCP_SOCKET ||
> +	    sksec->sclass == SECCLASS_SCTP_SOCKET) {
>  		struct common_audit_data ad;
>  		struct lsm_network_audit net = {0,};
>  		struct sockaddr_in *addr4 = NULL;
> @@ -4135,8 +4178,12 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address,
>  		if (err)
>  			goto out;
>  
> -		perm = (sksec->sclass == SECCLASS_TCP_SOCKET) ?
> -		       TCP_SOCKET__NAME_CONNECT : DCCP_SOCKET__NAME_CONNECT;
> +		if (sksec->sclass == SECCLASS_TCP_SOCKET)
> +			perm = TCP_SOCKET__NAME_CONNECT;
> +		else if (sksec->sclass == SECCLASS_DCCP_SOCKET)
> +			perm = DCCP_SOCKET__NAME_CONNECT;
> +		else if (sksec->sclass == SECCLASS_SCTP_SOCKET)
> +			perm = SCTP_SOCKET__NAME_CONNECT;
>  
>  		ad.type = LSM_AUDIT_DATA_NET;
>  		ad.u.net = &net;
> @@ -4208,13 +4255,39 @@ static int selinux_socket_setsockopt(struct socket *sock, int level, int optname
>  	if (err)
>  		return err;
>  
> +	/* SCTP options that do not require handling by SCTP. */
> +	err = selinux_sctp_validate_sockopt(sock->sk, level, optname, NULL, 0);
> +	if (err)
> +		return err;
> +
>  	return selinux_netlbl_socket_setsockopt(sock, level, optname);
>  }
>  
> +static int selinux_sk_setsockopt(struct sock *sk, int level, int optname,
> +					    char *optval, int optlen)
> +{
> +	int err;
> +
> +	err = sock_has_perm(current, sk, SOCKET__SETOPT);
> +	if (err)
> +		return err;
> +
> +	/* SCTP options that require handling by SCTP first. */
> +	return selinux_sctp_validate_sockopt(sk, level, optname, optval,
> +							    optlen);
> +}
> +
>  static int selinux_socket_getsockopt(struct socket *sock, int level,
>  				     int optname)
>  {
> -	return sock_has_perm(current, sock->sk, SOCKET__GETOPT);
> +	int err;
> +
> +	err = sock_has_perm(current, sock->sk, SOCKET__GETOPT);
> +	if (err)
> +		return err;
> +
> +	return selinux_sctp_validate_sockopt(sock->sk, level, optname,
> +					    NULL, 0);
>  }
>  
>  static int selinux_socket_shutdown(struct socket *sock, int how)
> @@ -4407,7 +4480,9 @@ static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *op
>  	u32 peer_sid = SECSID_NULL;
>  
>  	if (sksec->sclass == SECCLASS_UNIX_STREAM_SOCKET ||
> -	    sksec->sclass == SECCLASS_TCP_SOCKET)
> +	    sksec->sclass == SECCLASS_TCP_SOCKET ||
> +	    sksec->sclass == SECCLASS_DCCP_SOCKET ||
> +	    sksec->sclass == SECCLASS_SCTP_SOCKET)
>  		peer_sid = sksec->peer_sid;
>  	if (peer_sid == SECSID_NULL)
>  		return -ENOPROTOOPT;
> @@ -4516,6 +4591,35 @@ static void selinux_sock_graft(struct sock *sk, struct socket *parent)
>  	sksec->sclass = isec->sclass;
>  }
>  
> +static int selinux_sctp_assoc_request(struct sock *sk, struct sk_buff *skb)
> +{
> +	struct sk_security_struct *sksec = sk->sk_security;
> +	struct common_audit_data ad;
> +	struct lsm_network_audit net = {0,};
> +	u8 peerlbl_active;
> +	int err;
> +
> +	peerlbl_active = selinux_peerlbl_enabled();
> +
> +	if (sksec->peer_sid == SECINITSID_UNLABELED && peerlbl_active) {
> +		/* Here because this is the first association on this
> +		 * socket that is always unlabeled, therefore set
> +		 * sksec->peer_sid to new peer ctx. For further info see:
> +		 *    Documentation/security/SELinux-sctp.txt */
> +		err = selinux_skb_peerlbl_sid(skb, sk->sk_family,
> +				    &sksec->peer_sid);
> +		if (err)
> +			return err;
> +	}
> +
> +	ad.type = LSM_AUDIT_DATA_NET;
> +	ad.u.net = &net;
> +	ad.u.net->sk = sk;
> +
> +	return avc_has_perm(sksec->sid, sksec->peer_sid, sksec->sclass,
> +				    SCTP_SOCKET__ASSOCIATION, &ad);
> +}
> +
>  static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
>  				     struct request_sock *req)
>  {
> @@ -4805,7 +4909,10 @@ static unsigned int selinux_ip_output(struct sk_buff *skb,
>  	if (sk) {
>  		struct sk_security_struct *sksec;
>  
> -		if (sk->sk_state == TCP_LISTEN)
> +		/* Note that TCP_LISTEN equates to SCTP_SS_LISTENING
> +		 * and DCCP_LISTEN socket states so also check protocol. */
> +		if (sk->sk_state == TCP_LISTEN &&
> +		    sk->sk_protocol == IPPROTO_TCP)
>  			/* if the socket is the listening state then this
>  			 * packet is a SYN-ACK packet which means it needs to
>  			 * be labeled based on the connection/request_sock and
> @@ -4910,9 +5017,12 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
>  	 *       TCP listening state we cannot wait until the XFRM processing
>  	 *       is done as we will miss out on the SA label if we do;
>  	 *       unfortunately, this means more work, but it is only once per
> -	 *       connection. */
> +	 *       connection.
> +	 * NOTE: that TCP_LISTEN equates to SCTP_SS_LISTENING and DCCP_LISTEN
> +	 * socket states so also check protocol. */
>  	if (skb_dst(skb) != NULL && skb_dst(skb)->xfrm != NULL &&
> -	    !(sk != NULL && sk->sk_state == TCP_LISTEN))
> +	    !(sk != NULL && sk->sk_state == TCP_LISTEN &&
> +	    sk->sk_protocol == IPPROTO_TCP))
>  		return NF_ACCEPT;
>  #endif
>  
> @@ -4929,7 +5039,10 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
>  			secmark_perm = PACKET__SEND;
>  			peer_sid = SECINITSID_KERNEL;
>  		}
> -	} else if (sk->sk_state == TCP_LISTEN) {
> +	/* Note that TCP_LISTEN equates to SCTP_SS_LISTENING and DCCP_LISTEN
> +	 * socket states so also check protocol. */
> +	} else if (sk->sk_state == TCP_LISTEN  &&
> +	    sk->sk_protocol == IPPROTO_TCP) {
>  		/* Locally generated packet but the associated socket is in the
>  		 * listening state which means this is a SYN-ACK packet.  In
>  		 * this particular case the correct security label is assigned
> @@ -5924,6 +6037,7 @@ static struct security_operations selinux_ops = {
>  	.socket_getpeername =		selinux_socket_getpeername,
>  	.socket_getsockopt =		selinux_socket_getsockopt,
>  	.socket_setsockopt =		selinux_socket_setsockopt,
> +	.sk_setsockopt =		selinux_sk_setsockopt,
>  	.socket_shutdown =		selinux_socket_shutdown,
>  	.socket_sock_rcv_skb =		selinux_socket_sock_rcv_skb,
>  	.socket_getpeersec_stream =	selinux_socket_getpeersec_stream,
> @@ -5933,6 +6047,7 @@ static struct security_operations selinux_ops = {
>  	.sk_clone_security =		selinux_sk_clone_security,
>  	.sk_getsecid =			selinux_sk_getsecid,
>  	.sock_graft =			selinux_sock_graft,
> +	.sctp_assoc_request =		selinux_sctp_assoc_request,
>  	.inet_conn_request =		selinux_inet_conn_request,
>  	.inet_csk_clone =		selinux_inet_csk_clone,
>  	.inet_conn_established =	selinux_inet_conn_established,
> diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h
> index be491a7..09797ee 100644
> --- a/security/selinux/include/classmap.h
> +++ b/security/selinux/include/classmap.h
> @@ -151,5 +151,9 @@ struct security_class_mapping secclass_map[] = {
>  	{ "kernel_service", { "use_as_override", "create_files_as", NULL } },
>  	{ "tun_socket",
>  	  { COMMON_SOCK_PERMS, "attach_queue", NULL } },
> +	{ "sctp_socket",
> +	  { COMMON_SOCK_PERMS, "node_bind", "name_connect", "association",
> +	    "bindx_add", "bindx_rem", "connectx", "peeloff", "set_addr",
> +	    "set_params", NULL } },
>  	{ NULL }
>    };
> diff --git a/security/selinux/include/sctp.h b/security/selinux/include/sctp.h
> new file mode 100644
> index 0000000..81dd469
> --- /dev/null
> +++ b/security/selinux/include/sctp.h
> @@ -0,0 +1,52 @@
> +/*
> + * SELinux SCTP Support
> + *
> + * Provides security checks for the SCTP protocol.
> + *
> + * Author: Richard Haines <richard_c_haines@xxxxxxxxxxxxxx>
> + *
> + */
> +
> +/*
> + * This program is free software;  you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY;  without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
> + * the GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program;  if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
> + *
> + */
> +
> +#ifndef _SELINUX_SCTP_H_
> +#define _SELINUX_SCTP_H_
> +
> +#include <linux/types.h>
> +#include <linux/net.h>
> +#include <net/sock.h>
> +#include "objsec.h"
> +
> +#if defined(CONFIG_IP_SCTP) || defined(CONFIG_IP_SCTP_MODULE)
> +int selinux_sctp_validate_sockopt(struct sock *sk,
> +				    int level,
> +				    int optname,
> +				    char *optval,
> +				    int optlen);
> +#else
> +static inline int selinux_sctp_validate_sockopt(struct sock *sk,
> +				    int level,
> +				    int optname,
> +				    char *optval,
> +				    int optlen)
> +{
> +	return 0;
> +}
> +#endif  /* CONFIG_IP_SCTP */
> +
> +#endif
> diff --git a/security/selinux/include/sctp_private.h b/security/selinux/include/sctp_private.h
> new file mode 100644
> index 0000000..f393f6f
> --- /dev/null
> +++ b/security/selinux/include/sctp_private.h
> @@ -0,0 +1,51 @@
> +/*
> + * SELinux SCTP Support
> + *
> + * Provides security checks for the SCTP protocol.
> + *
> + * Author: Richard Haines <richard_c_haines@xxxxxxxxxxxxxx>
> + *
> + */
> +
> +/*
> + * This program is free software;  you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY;  without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
> + * the GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program;  if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
> + *
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/sched.h>
> +#include <linux/types.h>
> +#include <linux/net.h>
> +#include <net/sock.h>
> +#include <linux/sctp.h>
> +#include <uapi/linux/sctp.h>	/* For bindx setsocket option checks */
> +#include <net/ip.h>
> +#include <linux/skbuff.h>
> +
> +#include "security.h"
> +#include "avc.h"
> +#include "objsec.h"
> +
> +extern int sock_has_perm(struct task_struct *task,
> +				    struct sock *sk, u32 perms);
> +
> +extern int selinux_socket_bind(struct socket *sock,
> +				    struct sockaddr *address,
> +					    int addrlen);
> +
> +extern int selinux_socket_connect(struct socket *sock,
> +				    struct sockaddr *address,
> +				    int addrlen);
> +
> diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c
> index 0364120..a6c6df1 100644
> --- a/security/selinux/netlabel.c
> +++ b/security/selinux/netlabel.c
> @@ -396,6 +396,9 @@ int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
>  	case SECCLASS_TCP_SOCKET:
>  		perm = TCP_SOCKET__RECVFROM;
>  		break;
> +	case SECCLASS_SCTP_SOCKET:
> +		perm = SCTP_SOCKET__RECVFROM;
> +		break;
>  	default:
>  		perm = RAWIP_SOCKET__RECVFROM;
>  	}
> diff --git a/security/selinux/sctp.c b/security/selinux/sctp.c
> new file mode 100644
> index 0000000..41c646d
> --- /dev/null
> +++ b/security/selinux/sctp.c
> @@ -0,0 +1,185 @@
> +/*
> + * SELinux SCTP Support
> + *
> + * Provides security checks for the SCTP protocol.
> + *
> + * Author: Richard Haines <richard_c_haines@xxxxxxxxxxxxxx>
> + *
> + */
> +
> +/*
> + * This program is free software;  you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY;  without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
> + * the GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program;  if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
> + *
> + */
> +
> +#include "sctp_private.h"	/* #include files + extern functions. */
> +
> +/**
> + * selinux_sctp_validate_sockopt - Check get/setsockopt values.
> + * @sk: the socket
> + * @level: contains the protocol level to validate
> + * @optname: contains the name of the option to validate
> + * @optval: contains the value(s) to set
> + * @optlen: contains the length of the value(s) to be set
> + *
> + * Description:
> + * Check whether SCTP socket options are allowed or not. Returns zero on
> + * success, negative values on failure.
> + *
> + * Supports the following socket options:
> + *
> + *    SCTP_SOCKOPT_BINDX_ADD - Allows additional bind addresses to be
> + *    associated after (optionally) calling bind(3).
> + *    sctp_bindx(3) - adds or removes a set of bind addresses on a socket.
> + *
> + *    SCTP_SOCKOPT_CONNECTX* - Allows the allocation of multiple
> + *    addresses for reaching a peer (multi-homed).
> + *    sctp_connectx(3) - initiate a connection on an SCTP socket using
> + *    multiple destination addresses. May also return an association id.
> + *
> + *   Together they form SCTP associations and will be passed over the
> + *   link to inform peer of any changes. As these two options can support
> + *   multiple addresses, each address is checked via selinux_socket_bind() or
> + *   selinux_socket_connect() to determine whether they have the correct
> + *   permissions:
> + *     bindx_add: bind, name_bind, node_bind + node SID + port SID via the
> + *                (portcon sctp port ctx) policy statement.
> + *     connectx:  connect, name_connect + port SID via the
> + *                (portcon sctp port ctx) policy statement.
> + *
> + *    SCTP_SOCKOPT_BINDX_REM - As the addresses would have already been
> + *    allowed, only the bindx_rem permission is checked.
> + *
> + *    SCTP_PEER_ADDR_PARAMS - Alter heartbeats and address max
> + *    retransmissions.
> + *    SCTP_PEER_ADDR_THLDS - Alter the thresholds.
> + *  These require the set_params permission.
> + *
> + *    SCTP_PRIMARY_ADDR - Set local primary address.
> + *    SCTP_SET_PEER_PRIMARY_ADDR - Request peer sets address as
> + *    association primary.
> + *  These require the set_addr permission.
> + *
> + *    SCTP_SOCKOPT_PEELOFF - Branch off an association into a new socket
> + *    that will be a one-to-one style socket. As SELinux already handles
> + *    the creation of new sockets, only the peeloff permission is checked.
> + *
> + */
> +int selinux_sctp_validate_sockopt(struct sock *sk, int level, int optname,
> +					    char *optval, int optlen)
> +{
> +	int err, addrlen;
> +	void *addr_buf;
> +	struct sockaddr *address;
> +	struct socket *sock;
> +	int walk_size = 0;
> +
> +	/* This handles SCTP specific options. Note that SCTP has the optval
> +	 * in kernel space already therefore no copy is required. */
> +	if (level == SOL_SCTP) {
> +		switch (optname) {
> +		/* Note that for SCTP_SOCKOPT_BINDX_ADD and
> +		 * SCTP_SOCKOPT_CONNECTX SCTP has copied the optval to kernel
> +		 * space already therefore no copy is required. See
> +		 * net/sctp/socket.c security_sk_setsockopt() calls. */
> +		case SCTP_SOCKOPT_BINDX_ADD:
> +		case SCTP_SOCKOPT_CONNECTX:
> +			err = sock_has_perm(current, sk,
> +			    (optname == SCTP_SOCKOPT_BINDX_ADD ?
> +			    SCTP_SOCKET__BINDX_ADD :
> +			    SCTP_SOCKOPT_CONNECTX));
> +			if (err)
> +				return err;
> +
> +			sock = sk->sk_socket;
> +			addr_buf = optval;
> +			/* Process list - may contain IPv4 or IPv6 addr's */
> +			while (walk_size < optlen) {
> +				address = addr_buf;
> +
> +				switch (address->sa_family) {
> +				case PF_INET:
> +					addrlen = sizeof(struct sockaddr_in);
> +					break;
> +				case PF_INET6:
> +					addrlen = sizeof(struct sockaddr_in6);
> +					break;
> +				default:
> +					return -EINVAL;
> +				}
> +
> +				err = -EINVAL;
> +				if (optname == SCTP_SOCKOPT_BINDX_ADD) {
> +					err = selinux_socket_bind(sock,
> +						    address, addrlen);
> +				} else if (optname == SCTP_SOCKOPT_CONNECTX) {
> +					err = selinux_socket_connect(sock,
> +						    address, addrlen);
> +				}
> +				if (err)
> +					return err;
> +
> +				addr_buf += addrlen;
> +				walk_size += addrlen;
> +			}
> +			break;
> +
> +		case SCTP_SOCKOPT_BINDX_REM:
> +			/* The addresses have been checked as they were
> +			 * added, so just see if allowed to be removed. */
> +			err = sock_has_perm(current, sk,
> +			    SCTP_SOCKET__BINDX_REM);
> +			if (err)
> +				return err;
> +			break;
> +
> +		case SCTP_SOCKOPT_PEELOFF:
> +			err = sock_has_perm(current, sk,
> +			    SCTP_SOCKET__PEELOFF);
> +			if (err)
> +				return err;
> +			break;
> +
> +		default:
> +			break;
> +		}
> +	} else if (level == IPPROTO_SCTP) {
> +		switch (optname) {
> +		/* Alter heartbeats and address max retransmissions. */
> +		case SCTP_PEER_ADDR_PARAMS:
> +		/* Alter the thresholds. */
> +		case SCTP_PEER_ADDR_THLDS:
> +			err = sock_has_perm(current, sk,
> +			    SCTP_SOCKET__SET_PARAMS);
> +			if (err)
> +				return err;
> +			break;
> +
> +		/* Set local primary address. */
> +		case SCTP_PRIMARY_ADDR:
> +		/* Request peer sets address as association primary. */
> +		case SCTP_SET_PEER_PRIMARY_ADDR:
> +			err = sock_has_perm(current, sk,
> +			    SCTP_SOCKET__SET_ADDR);
> +			if (err)
> +				return err;
> +			break;
> +
> +		default:
> +			break;
> +		}
> +	}
> +	return 0;
> +}

_______________________________________________
Selinux mailing list
Selinux@xxxxxxxxxxxxx
To unsubscribe, send email to Selinux-leave@xxxxxxxxxxxxx.
To get help, send an email containing "help" to Selinux-request@xxxxxxxxxxxxx.




[Index of Archives]     [Selinux Refpolicy]     [Linux SGX]     [Fedora Users]     [Fedora Desktop]     [Yosemite Photos]     [Yosemite Camping]     [Yosemite Campsites]     [KDE Users]     [Gnome Users]

  Powered by Linux