mirror of
				https://github.com/linuxkit/linuxkit.git
				synced 2025-11-04 08:25:51 +00:00 
			
		
		
		
	This is a project with a v1 of the IMA namespacing patches. See the readme for details on use. Signed-off-by: Tycho Andersen <tycho@docker.com>
		
			
				
	
	
		
			314 lines
		
	
	
		
			9.7 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			314 lines
		
	
	
		
			9.7 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
From ffefef30c066f49ca03045aeb0f92635e998c385 Mon Sep 17 00:00:00 2001
 | 
						|
From: Guilherme Magalhaes <guilherme.magalhaes@hpe.com>
 | 
						|
Date: Tue, 9 May 2017 17:04:38 -0300
 | 
						|
Subject: [PATCH 07/11] ima: new namespace policy structure to track initial
 | 
						|
 namespace policy data
 | 
						|
 | 
						|
Adding the global ima_initial_namespace_policy which will be used when the
 | 
						|
initial namespace IMA policy data must be referred or when
 | 
						|
CONFIG_IMA_PER_NAMESPACE is not defined.
 | 
						|
New functions which will be used to retrieve the correct namespace IMA
 | 
						|
policy data from the radix tree map or from the ima_initial_namespace_policy.
 | 
						|
If the given namespace has not yet defined a private IMA policy, the IMA
 | 
						|
policy for that namespace falls back to the initial IMA policy by using
 | 
						|
ima_initial_namespace_policy.
 | 
						|
 | 
						|
Signed-off-by: Guilherme Magalhaes <guilherme.magalhaes@hpe.com>
 | 
						|
---
 | 
						|
 security/integrity/ima/ima.h        |   6 ++
 | 
						|
 security/integrity/ima/ima_fs.c     | 112 +++++++++++++++++++++++++++++-------
 | 
						|
 security/integrity/ima/ima_policy.c |  72 +++++++++++++++++++++++
 | 
						|
 3 files changed, 170 insertions(+), 20 deletions(-)
 | 
						|
 | 
						|
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
 | 
						|
index 1c5c875..20b927e 100644
 | 
						|
--- a/security/integrity/ima/ima.h
 | 
						|
+++ b/security/integrity/ima/ima.h
 | 
						|
@@ -150,6 +150,7 @@ struct ima_ns_policy {
 | 
						|
 	int ima_appraise;
 | 
						|
 };
 | 
						|
 
 | 
						|
+extern struct ima_ns_policy ima_initial_namespace_policy;
 | 
						|
 #ifdef CONFIG_IMA_PER_NAMESPACE
 | 
						|
 extern spinlock_t ima_ns_policy_lock;
 | 
						|
 extern struct radix_tree_root ima_ns_policy_mapping;
 | 
						|
@@ -203,6 +204,11 @@ static inline void ima_namespace_unlock(void) {
 | 
						|
 }
 | 
						|
 #endif
 | 
						|
 
 | 
						|
+/* IMA namespace function definitions */
 | 
						|
+struct ima_ns_policy *ima_get_current_namespace_policy(void);
 | 
						|
+struct ima_ns_policy *ima_get_namespace_policy_from_inode(struct inode *inode);
 | 
						|
+struct ima_ns_policy *ima_get_policy_from_namespace(unsigned int ns_id);
 | 
						|
+
 | 
						|
 /*
 | 
						|
  * used to protect h_table and sha_table
 | 
						|
  */
 | 
						|
diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c
 | 
						|
index 56ba0ff..61f8da1 100644
 | 
						|
--- a/security/integrity/ima/ima_fs.c
 | 
						|
+++ b/security/integrity/ima/ima_fs.c
 | 
						|
@@ -274,6 +274,22 @@ static const struct file_operations ima_ascii_measurements_ops = {
 | 
						|
 	.release = seq_release,
 | 
						|
 };
 | 
						|
 
 | 
						|
+static struct dentry *ima_dir;
 | 
						|
+static struct dentry *binary_runtime_measurements;
 | 
						|
+static struct dentry *ascii_runtime_measurements;
 | 
						|
+static struct dentry *runtime_measurements_count;
 | 
						|
+static struct dentry *violations;
 | 
						|
+static struct dentry *ima_policy_initial_ns;
 | 
						|
+#ifdef CONFIG_IMA_PER_NAMESPACE
 | 
						|
+static struct dentry *ima_namespaces;
 | 
						|
+#endif
 | 
						|
+
 | 
						|
+enum ima_fs_flags {
 | 
						|
+	IMA_FS_BUSY,
 | 
						|
+};
 | 
						|
+
 | 
						|
+static unsigned long ima_fs_flags;
 | 
						|
+
 | 
						|
 #ifdef CONFIG_IMA_PER_NAMESPACE
 | 
						|
 /* used for namespace policy rules initialization */
 | 
						|
 static LIST_HEAD(empty_policy);
 | 
						|
@@ -348,6 +364,76 @@ static int check_mntns(unsigned int ns_id)
 | 
						|
 
 | 
						|
 	return result;
 | 
						|
 }
 | 
						|
+
 | 
						|
+/*
 | 
						|
+ * ima_find_namespace_id_from_inode
 | 
						|
+ * @policy_inode: the inode of the securityfs policy file for a given
 | 
						|
+ * namespace
 | 
						|
+ *
 | 
						|
+ * Return 0 if the namespace id is not found in ima_ns_policy_mapping
 | 
						|
+ */
 | 
						|
+static unsigned int find_namespace_id_from_inode(struct inode *policy_inode)
 | 
						|
+{
 | 
						|
+	unsigned int ns_id = 0;
 | 
						|
+#ifdef CONFIG_IMA_PER_NAMESPACE
 | 
						|
+	struct ima_ns_policy *ins;
 | 
						|
+	void **slot;
 | 
						|
+	struct radix_tree_iter iter;
 | 
						|
+
 | 
						|
+	rcu_read_lock();
 | 
						|
+	radix_tree_for_each_slot(slot, &ima_ns_policy_mapping, &iter, 0) {
 | 
						|
+		ins = radix_tree_deref_slot(slot);
 | 
						|
+		if (unlikely(!ins))
 | 
						|
+			continue;
 | 
						|
+		if (radix_tree_deref_retry(ins)) {
 | 
						|
+			slot = radix_tree_iter_retry(&iter);
 | 
						|
+			continue;
 | 
						|
+		}
 | 
						|
+
 | 
						|
+		if (ins->policy_dentry && ins->policy_dentry->d_inode == policy_inode) {
 | 
						|
+			ns_id = iter.index;
 | 
						|
+			break;
 | 
						|
+		}
 | 
						|
+	}
 | 
						|
+	rcu_read_unlock();
 | 
						|
+#endif
 | 
						|
+
 | 
						|
+	return ns_id;
 | 
						|
+}
 | 
						|
+
 | 
						|
+/*
 | 
						|
+ * get_namespace_policy_from_inode - Finds namespace mapping from
 | 
						|
+ * securityfs policy file
 | 
						|
+ * It is called to get the namespace policy reference when a seurityfs
 | 
						|
+ * file such as the namespace or policy files are read or written.
 | 
						|
+ * @inode: inode of the securityfs policy file under a namespace
 | 
						|
+ * folder
 | 
						|
+ * Expects the ima_ns_policy_lock already held
 | 
						|
+ *
 | 
						|
+ * Returns NULL if the namespace policy reference is not reliable once it
 | 
						|
+ * probably was already released after a concurrent namespace release.
 | 
						|
+ * Otherwise, the namespace policy reference is returned.
 | 
						|
+ */
 | 
						|
+struct ima_ns_policy *ima_get_namespace_policy_from_inode(struct inode *inode)
 | 
						|
+{
 | 
						|
+	unsigned int ns_id;
 | 
						|
+	struct ima_ns_policy *ins;
 | 
						|
+
 | 
						|
+	ns_id = find_namespace_id_from_inode(inode);
 | 
						|
+#ifdef CONFIG_IMA_PER_NAMESPACE
 | 
						|
+	if (ns_id == 0 &&
 | 
						|
+		(!ima_policy_initial_ns || inode != ima_policy_initial_ns->d_inode)) {
 | 
						|
+		/* ns_id == 0 refers to initial namespace, but inode refers to a
 | 
						|
+		 * namespaced policy file. It might be a race condition with
 | 
						|
+		 * namespace release, return invalid reference. */
 | 
						|
+		return NULL;
 | 
						|
+	}
 | 
						|
+#endif
 | 
						|
+
 | 
						|
+	ins = ima_get_policy_from_namespace(ns_id);
 | 
						|
+
 | 
						|
+	return ins;
 | 
						|
+}
 | 
						|
 #endif
 | 
						|
 
 | 
						|
 static ssize_t ima_read_policy(char *path)
 | 
						|
@@ -439,22 +525,6 @@ static ssize_t ima_write_policy(struct file *file, const char __user *buf,
 | 
						|
 	return result;
 | 
						|
 }
 | 
						|
 
 | 
						|
-static struct dentry *ima_dir;
 | 
						|
-static struct dentry *binary_runtime_measurements;
 | 
						|
-static struct dentry *ascii_runtime_measurements;
 | 
						|
-static struct dentry *runtime_measurements_count;
 | 
						|
-static struct dentry *violations;
 | 
						|
-static struct dentry *ima_policy;
 | 
						|
-#ifdef CONFIG_IMA_PER_NAMESPACE
 | 
						|
-static struct dentry *ima_namespaces;
 | 
						|
-#endif
 | 
						|
-
 | 
						|
-enum ima_fs_flags {
 | 
						|
-	IMA_FS_BUSY,
 | 
						|
-};
 | 
						|
-
 | 
						|
-static unsigned long ima_fs_flags;
 | 
						|
-
 | 
						|
 #ifdef	CONFIG_IMA_READ_POLICY
 | 
						|
 static const struct seq_operations ima_policy_seqops = {
 | 
						|
 		.start = ima_policy_start,
 | 
						|
@@ -517,7 +587,7 @@ static int ima_release_policy(struct inode *inode, struct file *file)
 | 
						|
 
 | 
						|
 	ima_update_policy();
 | 
						|
 #ifndef	CONFIG_IMA_WRITE_POLICY
 | 
						|
-	securityfs_remove(ima_policy);
 | 
						|
+	securityfs_remove(ima_policy_initial_ns);
 | 
						|
 	ima_policy = NULL;
 | 
						|
 #endif
 | 
						|
 
 | 
						|
@@ -539,6 +609,8 @@ static const struct file_operations ima_measure_policy_ops = {
 | 
						|
 /*
 | 
						|
  * Assumes namespace id is in use by some process and this mapping
 | 
						|
  * does not exist in the map table.
 | 
						|
+ * @ns_id namespace id
 | 
						|
+ * Expects ima_ns_policy_lock already held
 | 
						|
  */
 | 
						|
 static int create_mnt_ns_directory(unsigned int ns_id)
 | 
						|
 {
 | 
						|
@@ -751,10 +823,10 @@ int __init ima_fs_init(void)
 | 
						|
 	if (IS_ERR(violations))
 | 
						|
 		goto out;
 | 
						|
 
 | 
						|
-	ima_policy = securityfs_create_file("policy", POLICY_FILE_FLAGS,
 | 
						|
+	ima_policy_initial_ns = securityfs_create_file("policy", POLICY_FILE_FLAGS,
 | 
						|
 					    ima_dir, NULL,
 | 
						|
 					    &ima_measure_policy_ops);
 | 
						|
-	if (IS_ERR(ima_policy))
 | 
						|
+	if (IS_ERR(ima_policy_initial_ns))
 | 
						|
 		goto out;
 | 
						|
 
 | 
						|
 #ifdef CONFIG_IMA_PER_NAMESPACE
 | 
						|
@@ -772,7 +844,7 @@ int __init ima_fs_init(void)
 | 
						|
 	securityfs_remove(ascii_runtime_measurements);
 | 
						|
 	securityfs_remove(binary_runtime_measurements);
 | 
						|
 	securityfs_remove(ima_dir);
 | 
						|
-	securityfs_remove(ima_policy);
 | 
						|
+	securityfs_remove(ima_policy_initial_ns);
 | 
						|
 #ifdef CONFIG_IMA_PER_NAMESPACE
 | 
						|
 	securityfs_remove(ima_namespaces);
 | 
						|
 #endif
 | 
						|
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
 | 
						|
index 2e8c3b7..8c0d4c9 100644
 | 
						|
--- a/security/integrity/ima/ima_policy.c
 | 
						|
+++ b/security/integrity/ima/ima_policy.c
 | 
						|
@@ -20,6 +20,8 @@
 | 
						|
 #include <linux/rculist.h>
 | 
						|
 #include <linux/genhd.h>
 | 
						|
 #include <linux/seq_file.h>
 | 
						|
+#include <linux/radix-tree.h>
 | 
						|
+#include <linux/proc_ns.h>
 | 
						|
 
 | 
						|
 #include "ima.h"
 | 
						|
 
 | 
						|
@@ -53,6 +55,17 @@ RADIX_TREE(ima_ns_policy_mapping, GFP_ATOMIC);
 | 
						|
 spinlock_t ima_ns_policy_lock;
 | 
						|
 #endif
 | 
						|
 
 | 
						|
+/* initial namespace map entry, not added to the ima_ns_policy_mapping
 | 
						|
+ * Used as policy fallback for namespaces without policy settings */
 | 
						|
+struct ima_ns_policy ima_initial_namespace_policy = {
 | 
						|
+			   .policy_dentry = NULL,
 | 
						|
+			   .ns_dentry = NULL,
 | 
						|
+			   .ima_rules = NULL,
 | 
						|
+			   .ima_policy_rules = LIST_HEAD_INIT(ima_initial_namespace_policy.ima_policy_rules),
 | 
						|
+			   .ima_policy_flag = 0,
 | 
						|
+			   .ima_appraise = 0
 | 
						|
+	   };
 | 
						|
+
 | 
						|
 #define MAX_LSM_RULES 6
 | 
						|
 enum lsm_rule_types { LSM_OBJ_USER, LSM_OBJ_ROLE, LSM_OBJ_TYPE,
 | 
						|
 	LSM_SUBJ_USER, LSM_SUBJ_ROLE, LSM_SUBJ_TYPE
 | 
						|
@@ -191,6 +204,65 @@ static int __init default_appraise_policy_setup(char *str)
 | 
						|
 __setup("ima_appraise_tcb", default_appraise_policy_setup);
 | 
						|
 
 | 
						|
 /*
 | 
						|
+ * ima_get_policy_from_namespace - Finds the ns_id mapping to namespace
 | 
						|
+ * policy structure
 | 
						|
+ * @ns_id: mount namespace id to look for in the policy mapping tree
 | 
						|
+ *
 | 
						|
+ * Returns either the given namespace policy data if mapped or the initial
 | 
						|
+ * namespace data instead.
 | 
						|
+ *
 | 
						|
+ * Note that if a namespace has not a specific policy defined, it will
 | 
						|
+ * fall back to the initial namespace policy.
 | 
						|
+ */
 | 
						|
+struct ima_ns_policy *ima_get_policy_from_namespace(unsigned int ns_id)
 | 
						|
+{
 | 
						|
+	struct ima_ns_policy *ins;
 | 
						|
+
 | 
						|
+#ifdef CONFIG_IMA_PER_NAMESPACE
 | 
						|
+	rcu_read_lock();
 | 
						|
+	ins = radix_tree_lookup(&ima_ns_policy_mapping, ns_id);
 | 
						|
+	rcu_read_unlock();
 | 
						|
+
 | 
						|
+	if (!ins) {
 | 
						|
+		ins = &ima_initial_namespace_policy;
 | 
						|
+	}
 | 
						|
+#else
 | 
						|
+	ins = &ima_initial_namespace_policy;
 | 
						|
+#endif
 | 
						|
+
 | 
						|
+	return ins;
 | 
						|
+}
 | 
						|
+
 | 
						|
+/*
 | 
						|
+ * ima_get_current_namespace_policy - Finds the namespace policy mapping
 | 
						|
+ * for the current task
 | 
						|
+ * This function is called on the context of a syscall and then the namespace
 | 
						|
+ * in use will not be released during this context.
 | 
						|
+ */
 | 
						|
+struct ima_ns_policy *ima_get_current_namespace_policy(void)
 | 
						|
+{
 | 
						|
+	struct ima_ns_policy *ins = NULL;
 | 
						|
+#ifdef CONFIG_IMA_PER_NAMESPACE
 | 
						|
+	struct ns_common *ns;
 | 
						|
+
 | 
						|
+	ns = mntns_operations.get(current);
 | 
						|
+	if (ns) {
 | 
						|
+		ins = ima_get_policy_from_namespace(ns->inum);
 | 
						|
+		mntns_operations.put(ns);
 | 
						|
+	}
 | 
						|
+	if (!ins || (ins->ima_rules != &ins->ima_policy_rules)) {
 | 
						|
+		/* if current namespace has no IMA policy, get the
 | 
						|
+		 * initial namespace policy */
 | 
						|
+		ins = &ima_initial_namespace_policy;
 | 
						|
+	}
 | 
						|
+#else
 | 
						|
+	ins = &ima_initial_namespace_policy;
 | 
						|
+#endif
 | 
						|
+
 | 
						|
+	return ins;
 | 
						|
+}
 | 
						|
+
 | 
						|
+/*
 | 
						|
  * The LSM policy can be reloaded, leaving the IMA LSM based rules referring
 | 
						|
  * to the old, stale LSM policy.  Update the IMA LSM based rules to reflect
 | 
						|
  * the reloaded LSM policy.  We assume the rules still exist; and BUG_ON() if
 | 
						|
-- 
 | 
						|
2.9.3
 | 
						|
 |