selinux: Add SCTP support
[linux-2.6-microblaze.git] / security / selinux / netlabel.c
index 2c297b9..8730be4 100644 (file)
@@ -249,6 +249,7 @@ int selinux_netlbl_skbuff_setsid(struct sk_buff *skb,
        sk = skb_to_full_sk(skb);
        if (sk != NULL) {
                struct sk_security_struct *sksec = sk->sk_security;
+
                if (sksec->nlbl_state != NLBL_REQSKB)
                        return 0;
                secattr = selinux_netlbl_sock_getattr(sk, sid);
@@ -269,6 +270,61 @@ skbuff_setsid_return:
        return rc;
 }
 
+/**
+ * selinux_netlbl_sctp_assoc_request - Label an incoming sctp association.
+ * @ep: incoming association endpoint.
+ * @skb: the packet.
+ *
+ * Description:
+ * A new incoming connection is represented by @ep, ......
+ * Returns zero on success, negative values on failure.
+ *
+ */
+int selinux_netlbl_sctp_assoc_request(struct sctp_endpoint *ep,
+                                    struct sk_buff *skb)
+{
+       int rc;
+       struct netlbl_lsm_secattr secattr;
+       struct sk_security_struct *sksec = ep->base.sk->sk_security;
+       struct sockaddr *addr;
+       struct sockaddr_in addr4;
+#if IS_ENABLED(CONFIG_IPV6)
+       struct sockaddr_in6 addr6;
+#endif
+
+       if (ep->base.sk->sk_family != PF_INET &&
+                               ep->base.sk->sk_family != PF_INET6)
+               return 0;
+
+       netlbl_secattr_init(&secattr);
+       rc = security_netlbl_sid_to_secattr(ep->secid, &secattr);
+       if (rc != 0)
+               goto assoc_request_return;
+
+       /* Move skb hdr address info to a struct sockaddr and then call
+        * netlbl_conn_setattr().
+        */
+       if (ip_hdr(skb)->version == 4) {
+               addr4.sin_family = AF_INET;
+               addr4.sin_addr.s_addr = ip_hdr(skb)->saddr;
+               addr = (struct sockaddr *)&addr4;
+#if IS_ENABLED(CONFIG_IPV6)
+       } else {
+               addr6.sin6_family = AF_INET6;
+               addr6.sin6_addr = ipv6_hdr(skb)->saddr;
+               addr = (struct sockaddr *)&addr6;
+#endif
+       }
+
+       rc = netlbl_conn_setattr(ep->base.sk, addr, &secattr);
+       if (rc == 0)
+               sksec->nlbl_state = NLBL_LABELED;
+
+assoc_request_return:
+       netlbl_secattr_destroy(&secattr);
+       return rc;
+}
+
 /**
  * selinux_netlbl_inet_conn_request - Label an incoming stream connection
  * @req: incoming connection request socket
@@ -318,6 +374,22 @@ void selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family)
                sksec->nlbl_state = NLBL_UNSET;
 }
 
+/**
+ * selinux_netlbl_sctp_sk_clone - Copy state to the newly created sock
+ * @sk: current sock
+ * @newsk: the new sock
+ *
+ * Description:
+ * Called whenever a new socket is created by accept(2) or sctp_peeloff(3).
+ */
+void selinux_netlbl_sctp_sk_clone(struct sock *sk, struct sock *newsk)
+{
+       struct sk_security_struct *sksec = sk->sk_security;
+       struct sk_security_struct *newsksec = newsk->sk_security;
+
+       newsksec->nlbl_state = sksec->nlbl_state;
+}
+
 /**
  * selinux_netlbl_socket_post_create - Label a socket using NetLabel
  * @sock: the socket to label
@@ -469,7 +541,8 @@ int selinux_netlbl_socket_setsockopt(struct socket *sock,
 }
 
 /**
- * selinux_netlbl_socket_connect - Label a client-side socket on connect
+ * selinux_netlbl_socket_connect_helper - Help label a client-side socket on
+ * connect
  * @sk: the socket to label
  * @addr: the destination address
  *
@@ -478,18 +551,13 @@ int selinux_netlbl_socket_setsockopt(struct socket *sock,
  * Returns zero values on success, negative values on failure.
  *
  */
-int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr)
+static int selinux_netlbl_socket_connect_helper(struct sock *sk,
+                                               struct sockaddr *addr)
 {
        int rc;
        struct sk_security_struct *sksec = sk->sk_security;
        struct netlbl_lsm_secattr *secattr;
 
-       if (sksec->nlbl_state != NLBL_REQSKB &&
-           sksec->nlbl_state != NLBL_CONNLABELED)
-               return 0;
-
-       lock_sock(sk);
-
        /* connected sockets are allowed to disconnect when the address family
         * is set to AF_UNSPEC, if that is what is happening we want to reset
         * the socket */
@@ -497,18 +565,61 @@ int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr)
                netlbl_sock_delattr(sk);
                sksec->nlbl_state = NLBL_REQSKB;
                rc = 0;
-               goto socket_connect_return;
+               return rc;
        }
        secattr = selinux_netlbl_sock_genattr(sk);
        if (secattr == NULL) {
                rc = -ENOMEM;
-               goto socket_connect_return;
+               return rc;
        }
        rc = netlbl_conn_setattr(sk, addr, secattr);
        if (rc == 0)
                sksec->nlbl_state = NLBL_CONNLABELED;
 
-socket_connect_return:
+       return rc;
+}
+
+/**
+ * selinux_netlbl_socket_connect_locked - Label a client-side socket on
+ * connect
+ * @sk: the socket to label
+ * @addr: the destination address
+ *
+ * Description:
+ * Attempt to label a connected socket that already has the socket locked
+ * with NetLabel using the given address.
+ * Returns zero values on success, negative values on failure.
+ *
+ */
+int selinux_netlbl_socket_connect_locked(struct sock *sk,
+                                        struct sockaddr *addr)
+{
+       struct sk_security_struct *sksec = sk->sk_security;
+
+       if (sksec->nlbl_state != NLBL_REQSKB &&
+           sksec->nlbl_state != NLBL_CONNLABELED)
+               return 0;
+
+       return selinux_netlbl_socket_connect_helper(sk, addr);
+}
+
+/**
+ * selinux_netlbl_socket_connect - Label a client-side socket on connect
+ * @sk: the socket to label
+ * @addr: the destination address
+ *
+ * Description:
+ * Attempt to label a connected socket with NetLabel using the given address.
+ * Returns zero values on success, negative values on failure.
+ *
+ */
+int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr)
+{
+       int rc;
+
+       lock_sock(sk);
+       rc = selinux_netlbl_socket_connect_locked(sk, addr);
        release_sock(sk);
+
        return rc;
 }