diff mbox

[19/25] LSM: Infrastructure managed socket security blob

Message ID 12c680cb-e160-0fbb-ea2c-17f59414703b@schaufler-ca.com
State New
Headers show

Commit Message

Casey Schaufler Aug. 13, 2016, 8:37 p.m. UTC
Subject: [PATCH 19/25] LSM: Infrastructure managed socket security blob

Move management of the sock security blob from the security
modules to the LSM infrastructure. This requires that the modules
declare the blob size they require, so the module registration
process has to include that.

Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
---
 include/linux/lsm_hooks.h         |  1 +
 security/security.c               | 34 ++++++++++++++++++++++++++++++++++
 security/selinux/hooks.c          | 10 ++--------
 security/selinux/include/objsec.h |  4 ++++
 security/smack/smack.h            |  4 ++++
 security/smack/smack_lsm.c        | 25 +++----------------------
 6 files changed, 48 insertions(+), 30 deletions(-)
diff mbox

Patch

diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 9cc0e49..c03d339 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -1851,6 +1851,7 @@  struct lsm_blob_sizes {
 	int	lbs_cred;
 	int	lbs_file;
 	int	lbs_inode;
+	int	lbs_sock;
 };
 
 /*
diff --git a/security/security.c b/security/security.c
index 9fc5967..b728624 100644
--- a/security/security.c
+++ b/security/security.c
@@ -26,6 +26,7 @@ 
 #include <linux/personality.h>
 #include <linux/backing-dev.h>
 #include <net/flow.h>
+#include <net/sock.h>
 
 #define MAX_LSM_EVM_XATTR	2
 
@@ -87,6 +88,7 @@  int __init security_init(void)
 	pr_info("LSM: cred blob size       = %d\n", blob_sizes.lbs_cred);
 	pr_info("LSM: file blob size       = %d\n", blob_sizes.lbs_file);
 	pr_info("LSM: inode blob size      = %d\n", blob_sizes.lbs_inode);
+	pr_info("LSM: sock blob size       = %d\n", blob_sizes.lbs_sock);
 #endif
 
 	return 0;
@@ -227,6 +229,7 @@  void __init security_add_blobs(struct lsm_blob_sizes *needed)
 	lsm_set_size(&needed->lbs_cred, &blob_sizes.lbs_cred);
 	lsm_set_size(&needed->lbs_file, &blob_sizes.lbs_file);
 	lsm_set_size(&needed->lbs_inode, &blob_sizes.lbs_inode);
+	lsm_set_size(&needed->lbs_sock, &blob_sizes.lbs_sock);
 }
 
 /**
@@ -279,6 +282,31 @@  int lsm_inode_alloc(struct inode *inode)
 	return 0;
 }
 
+/**
+ * lsm_sock_alloc - allocate a composite sock blob
+ * @sock: the sock that needs a blob
+ *
+ * Allocate the sock blob for all the modules
+ *
+ * Returns 0, or -ENOMEM if memory can't be allocated.
+ */
+int lsm_sock_alloc(struct sock *sock)
+{
+#ifdef CONFIG_SECURITY_STACKING_DEBUG
+	if (sock->sk_security) {
+		pr_info("%s: Inbound sock blob is not NULL.\n", __func__);
+		return 0;
+	}
+#endif
+	if (blob_sizes.lbs_sock == 0)
+		return 0;
+
+	sock->sk_security = kzalloc(blob_sizes.lbs_sock, GFP_KERNEL);
+	if (sock->sk_security == NULL)
+		return -ENOMEM;
+	return 0;
+}
+
 /*
  * Hook list operation macros.
  *
@@ -1645,12 +1673,18 @@  EXPORT_SYMBOL(security_socket_getpeersec_dgram);
 
 int security_sk_alloc(struct sock *sk, int family, gfp_t priority)
 {
+	int rc = lsm_sock_alloc(sk);
+
+	if (rc)
+		return rc;
 	return call_int_hook(sk_alloc_security, 0, sk, family, priority);
 }
 
 void security_sk_free(struct sock *sk)
 {
 	call_void_hook(sk_free_security, sk);
+	kfree(sk->sk_security);
+	sk->sk_security = NULL;
 }
 
 void security_sk_clone(const struct sock *sk, struct sock *newsk)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 7219a6a..f930c9f 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -4639,17 +4639,12 @@  out:
 
 static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority)
 {
-	struct sk_security_struct *sksec;
-
-	sksec = kzalloc(sizeof(*sksec), priority);
-	if (!sksec)
-		return -ENOMEM;
+	struct sk_security_struct *sksec = selinux_sock(sk);
 
 	sksec->peer_sid = SECINITSID_UNLABELED;
 	sksec->sid = SECINITSID_UNLABELED;
 	sksec->sclass = SECCLASS_SOCKET;
 	selinux_netlbl_sk_security_reset(sksec);
-	sk->sk_security = sksec;
 
 	return 0;
 }
@@ -4658,9 +4653,7 @@  static void selinux_sk_free_security(struct sock *sk)
 {
 	struct sk_security_struct *sksec = selinux_sock(sk);
 
-	sk->sk_security = NULL;
 	selinux_netlbl_sk_security_free(sksec);
-	kfree(sksec);
 }
 
 static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk)
@@ -5966,6 +5959,7 @@  struct lsm_blob_sizes selinux_blob_sizes = {
 	.lbs_cred = sizeof(struct task_security_struct),
 	.lbs_file = sizeof(struct file_security_struct),
 	.lbs_inode = sizeof(struct inode_security_struct),
+	.lbs_sock = sizeof(struct sk_security_struct),
 };
 
 static struct security_hook_list selinux_hooks[] = {
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index 7f5f4b8..f2820a8 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -183,7 +183,11 @@  static inline struct key_security_struct *selinux_key(const struct key *key)
 
 static inline struct sk_security_struct *selinux_sock(const struct sock *sock)
 {
+#ifdef CONFIG_SECURITY_STACKING
+	return sock->sk_security + selinux_blob_sizes.lbs_sock;
+#else
 	return sock->sk_security;
+#endif
 }
 
 #endif /* _SELINUX_OBJSEC_H_ */
diff --git a/security/smack/smack.h b/security/smack/smack.h
index 141f3bf..d377efe 100644
--- a/security/smack/smack.h
+++ b/security/smack/smack.h
@@ -370,7 +370,11 @@  static inline struct inode_smack *smack_inode(const struct inode *inode)
 
 static inline struct socket_smack *smack_sock(const struct sock *sock)
 {
+#ifdef CONFIG_SECURITY_STACKING
+	return sock->sk_security + smack_blob_sizes.lbs_sock;
+#else
 	return sock->sk_security;
+#endif
 }
 
 static inline struct superblock_smack *smack_superblock(
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 6dea0a7..c8e4d02 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -1859,7 +1859,7 @@  static int smack_file_receive(struct file *file)
 
 	if (S_ISSOCK(inode->i_mode)) {
 		sock = SOCKET_I(inode);
-		ssp = sock->sk->sk_security;
+		ssp = smack_sock(sock->sk);
 		tsp = smack_cred(current_cred());
 		/*
 		 * If the receiving process can't write to the
@@ -2279,35 +2279,16 @@  static void smack_task_to_inode(struct task_struct *p, struct inode *inode)
 static int smack_sk_alloc_security(struct sock *sk, int family, gfp_t gfp_flags)
 {
 	struct smack_known *skp = smk_of_current();
-	struct socket_smack *ssp;
-
-	ssp = kzalloc(sizeof(struct socket_smack), gfp_flags);
-	if (ssp == NULL)
-		return -ENOMEM;
+	struct socket_smack *ssp = smack_sock(sk);
 
 	ssp->smk_in = skp;
 	ssp->smk_out = skp;
 	ssp->smk_packet = NULL;
 
-	sk->sk_security = ssp;
-
 	return 0;
 }
 
 /**
- * smack_sk_free_security - Free a socket blob
- * @sk: the socket
- *
- * Clears the blob pointer
- */
-static void smack_sk_free_security(struct sock *sk)
-{
-	struct socket_smack *ssp = smack_sock(sk);
-
-	kfree(ssp);
-}
-
-/**
 * smack_ipv4host_label - check host based restrictions
 * @sip: the object end
 *
@@ -4569,6 +4550,7 @@  struct lsm_blob_sizes smack_blob_sizes = {
 	.lbs_cred = sizeof(struct task_smack),
 	.lbs_file = sizeof(struct smack_known *),
 	.lbs_inode = sizeof(struct inode_smack),
+	.lbs_sock = sizeof(struct socket_smack),
 };
 
 static struct security_hook_list smack_hooks[] = {
@@ -4681,7 +4663,6 @@  static struct security_hook_list smack_hooks[] = {
 	LSM_HOOK_INIT(socket_getpeersec_stream, smack_socket_getpeersec_stream),
 	LSM_HOOK_INIT(socket_getpeersec_dgram, smack_socket_getpeersec_dgram),
 	LSM_HOOK_INIT(sk_alloc_security, smack_sk_alloc_security),
-	LSM_HOOK_INIT(sk_free_security, smack_sk_free_security),
 	LSM_HOOK_INIT(sock_graft, smack_sock_graft),
 	LSM_HOOK_INIT(inet_conn_request, smack_inet_conn_request),
 	LSM_HOOK_INIT(inet_csk_clone, smack_inet_csk_clone),