aboutsummaryrefslogtreecommitdiff
path: root/security/selinux/netlabel.c
diff options
context:
space:
mode:
authorRichard Haines <richard_c_haines@btinternet.com>2018-02-13 20:57:18 +0000
committerPaul Moore <paul@paul-moore.com>2018-02-26 17:45:25 -0500
commitd452930fd3b9031e59abfeddb2fa383f1403d61a (patch)
treebb3c24ac8fdf0065ec09f6c4b7e70488a2a5ab58 /security/selinux/netlabel.c
parent2277c7cd75e39783eeb7512a6c35f8b4abbe1039 (diff)
selinux: Add SCTP support
The SELinux SCTP implementation is explained in: Documentation/security/SELinux-sctp.rst Signed-off-by: Richard Haines <richard_c_haines@btinternet.com> Signed-off-by: Paul Moore <paul@paul-moore.com>
Diffstat (limited to 'security/selinux/netlabel.c')
-rw-r--r--security/selinux/netlabel.c133
1 files changed, 122 insertions, 11 deletions
diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c
index 2c297b995b16..8730be427390 100644
--- a/security/selinux/netlabel.c
+++ b/security/selinux/netlabel.c
@@ -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);
@@ -270,6 +271,61 @@ skbuff_setsid_return:
}
/**
+ * 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
*
@@ -319,6 +375,22 @@ void selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family)
}
/**
+ * 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
* @family: protocol family
@@ -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;
}