[RFC PATCH v3] SELinux SCTP protocol support

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

 



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 ++
 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;
+}
-- 
1.9.3

_______________________________________________
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