diff mbox

[20/25] LSM: Infrastructure managed superblock security blob

Message ID 5d7f7242-1ad0-3650-0b94-8cb3d9d84039@schaufler-ca.com
State New
Headers show

Commit Message

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

Move management of the superblock 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               | 33 +++++++++++++++++++++++++++++++++
 security/selinux/hooks.c          | 21 ++-------------------
 security/selinux/include/objsec.h |  4 ++++
 security/smack/smack.h            |  4 ++++
 security/smack/smack_lsm.c        | 23 ++---------------------
 6 files changed, 46 insertions(+), 40 deletions(-)
diff mbox

Patch

diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index c03d339..70a2e7f 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -1852,6 +1852,7 @@  struct lsm_blob_sizes {
 	int	lbs_file;
 	int	lbs_inode;
 	int	lbs_sock;
+	int	lbs_superblock;
 };
 
 /*
diff --git a/security/security.c b/security/security.c
index b728624..36ce44f 100644
--- a/security/security.c
+++ b/security/security.c
@@ -89,6 +89,7 @@  int __init security_init(void)
 	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);
+	pr_info("LSM: superblock blob size = %d\n", blob_sizes.lbs_superblock);
 #endif
 
 	return 0;
@@ -230,6 +231,7 @@  void __init security_add_blobs(struct lsm_blob_sizes *needed)
 	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);
+	lsm_set_size(&needed->lbs_superblock, &blob_sizes.lbs_superblock);
 }
 
 /**
@@ -307,6 +309,31 @@  int lsm_sock_alloc(struct sock *sock)
 	return 0;
 }
 
+/**
+ * lsm_superblock_alloc - allocate a composite superblock blob
+ * @sb: the superblock that needs a blob
+ *
+ * Allocate the superblock blob for all the modules
+ *
+ * Returns 0, or -ENOMEM if memory can't be allocated.
+ */
+int lsm_superblock_alloc(struct super_block *sb)
+{
+#ifdef CONFIG_SECURITY_STACKING_DEBUG
+	if (sb->s_security) {
+		pr_info("%s: Inbound superblock blob is not NULL.\n", __func__);
+		return 0;
+	}
+#endif
+	if (blob_sizes.lbs_superblock == 0)
+		return 0;
+
+	sb->s_security = kzalloc(blob_sizes.lbs_superblock, GFP_KERNEL);
+	if (sb->s_security == NULL)
+		return -ENOMEM;
+	return 0;
+}
+
 /*
  * Hook list operation macros.
  *
@@ -479,12 +506,18 @@  int security_bprm_secureexec(struct linux_binprm *bprm)
 
 int security_sb_alloc(struct super_block *sb)
 {
+	int rc = lsm_superblock_alloc(sb);
+
+	if (rc)
+		return rc;
 	return call_int_hook(sb_alloc_security, 0, sb);
 }
 
 void security_sb_free(struct super_block *sb)
 {
 	call_void_hook(sb_free_security, sb);
+	kfree(sb->s_security);
+	sb->s_security = NULL;
 }
 
 int security_sb_copy_data(char *orig, char *copy)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index f930c9f..6effdf9 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -340,11 +340,7 @@  static int file_alloc_security(struct file *file)
 
 static int superblock_alloc_security(struct super_block *sb)
 {
-	struct superblock_security_struct *sbsec;
-
-	sbsec = kzalloc(sizeof(struct superblock_security_struct), GFP_KERNEL);
-	if (!sbsec)
-		return -ENOMEM;
+	struct superblock_security_struct *sbsec = selinux_superblock(sb);
 
 	mutex_init(&sbsec->lock);
 	INIT_LIST_HEAD(&sbsec->isec_head);
@@ -353,18 +349,10 @@  static int superblock_alloc_security(struct super_block *sb)
 	sbsec->sid = SECINITSID_UNLABELED;
 	sbsec->def_sid = SECINITSID_FILE;
 	sbsec->mntpoint_sid = SECINITSID_UNLABELED;
-	sb->s_security = sbsec;
 
 	return 0;
 }
 
-static void superblock_free_security(struct super_block *sb)
-{
-	struct superblock_security_struct *sbsec = selinux_superblock(sb);
-	sb->s_security = NULL;
-	kfree(sbsec);
-}
-
 /* The file system's label must be initialized prior to use. */
 
 static const char *labeling_behaviors[7] = {
@@ -2553,11 +2541,6 @@  static int selinux_sb_alloc_security(struct super_block *sb)
 	return superblock_alloc_security(sb);
 }
 
-static void selinux_sb_free_security(struct super_block *sb)
-{
-	superblock_free_security(sb);
-}
-
 static inline int match_prefix(char *prefix, int plen, char *option, int olen)
 {
 	if (plen > olen)
@@ -5960,6 +5943,7 @@  struct lsm_blob_sizes selinux_blob_sizes = {
 	.lbs_file = sizeof(struct file_security_struct),
 	.lbs_inode = sizeof(struct inode_security_struct),
 	.lbs_sock = sizeof(struct sk_security_struct),
+	.lbs_superblock = sizeof(struct superblock_security_struct),
 };
 
 static struct security_hook_list selinux_hooks[] = {
@@ -5986,7 +5970,6 @@  static struct security_hook_list selinux_hooks[] = {
 	LSM_HOOK_INIT(bprm_secureexec, selinux_bprm_secureexec),
 
 	LSM_HOOK_INIT(sb_alloc_security, selinux_sb_alloc_security),
-	LSM_HOOK_INIT(sb_free_security, selinux_sb_free_security),
 	LSM_HOOK_INIT(sb_copy_data, selinux_sb_copy_data),
 	LSM_HOOK_INIT(sb_remount, selinux_sb_remount),
 	LSM_HOOK_INIT(sb_kern_mount, selinux_sb_kern_mount),
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index f2820a8..336172e 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -161,7 +161,11 @@  static inline struct inode_security_struct *selinux_inode(
 static inline struct superblock_security_struct *selinux_superblock(
 					const struct super_block *superblock)
 {
+#ifdef CONFIG_SECURITY_STACKING
+	return superblock->s_security + selinux_blob_sizes.lbs_superblock;
+#else
 	return superblock->s_security;
+#endif
 }
 
 static inline struct msg_security_struct *selinux_msg_msg(
diff --git a/security/smack/smack.h b/security/smack/smack.h
index d377efe..e8de2fc 100644
--- a/security/smack/smack.h
+++ b/security/smack/smack.h
@@ -380,7 +380,11 @@  static inline struct socket_smack *smack_sock(const struct sock *sock)
 static inline struct superblock_smack *smack_superblock(
 					const struct super_block *superblock)
 {
+#ifdef CONFIG_SECURITY_STACKING
+	return superblock->s_security + smack_blob_sizes.lbs_superblock;
+#else
 	return superblock->s_security;
+#endif
 }
 
 static inline struct smack_known *smack_msg_msg(const struct msg_msg *msg)
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index c8e4d02..76df1e1 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -522,12 +522,7 @@  static int smack_syslog(int typefrom_file)
  */
 static int smack_sb_alloc_security(struct super_block *sb)
 {
-	struct superblock_smack *sbsp;
-
-	sbsp = kzalloc(sizeof(struct superblock_smack), GFP_KERNEL);
-
-	if (sbsp == NULL)
-		return -ENOMEM;
+	struct superblock_smack *sbsp = smack_superblock(sb);
 
 	sbsp->smk_root = &smack_known_floor;
 	sbsp->smk_default = &smack_known_floor;
@@ -536,25 +531,11 @@  static int smack_sb_alloc_security(struct super_block *sb)
 	/*
 	 * SMK_SB_INITIALIZED will be zero from kzalloc.
 	 */
-	sb->s_security = sbsp;
 
 	return 0;
 }
 
 /**
- * smack_sb_free_security - free a superblock blob
- * @sb: the superblock getting the blob
- *
- */
-static void smack_sb_free_security(struct super_block *sb)
-{
-	struct superblock_smack *sbsp = smack_superblock(sb);
-
-	kfree(sbsp);
-	sb->s_security = NULL;
-}
-
-/**
  * smack_sb_copy_data - copy mount options data for processing
  * @orig: where to start
  * @smackopts: mount options string
@@ -4551,6 +4532,7 @@  struct lsm_blob_sizes smack_blob_sizes = {
 	.lbs_file = sizeof(struct smack_known *),
 	.lbs_inode = sizeof(struct inode_smack),
 	.lbs_sock = sizeof(struct socket_smack),
+	.lbs_superblock = sizeof(struct superblock_smack),
 };
 
 static struct security_hook_list smack_hooks[] = {
@@ -4559,7 +4541,6 @@  static struct security_hook_list smack_hooks[] = {
 	LSM_HOOK_INIT(syslog, smack_syslog),
 
 	LSM_HOOK_INIT(sb_alloc_security, smack_sb_alloc_security),
-	LSM_HOOK_INIT(sb_free_security, smack_sb_free_security),
 	LSM_HOOK_INIT(sb_copy_data, smack_sb_copy_data),
 	LSM_HOOK_INIT(sb_kern_mount, smack_sb_kern_mount),
 	LSM_HOOK_INIT(sb_statfs, smack_sb_statfs),