mirror of
https://github.com/linuxkit/linuxkit.git
synced 2025-11-01 05:08:02 +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>
302 lines
8.3 KiB
Diff
302 lines
8.3 KiB
Diff
From 9f1840db5abfabeaeb7835bc277a75ac23c4b188 Mon Sep 17 00:00:00 2001
|
|
From: Guilherme Magalhaes <guilherme.magalhaes@hpe.com>
|
|
Date: Tue, 9 May 2017 16:24:05 -0300
|
|
Subject: [PATCH 05/11] ima: store new namespace policy structure in a radix
|
|
tree
|
|
|
|
New ima_ns_policy structure to describe IMA policy data per namespace.
|
|
Using a radix tree to map namespace ids to a respective ima_ns_policy
|
|
structure.
|
|
When it is needed to retrieve IMA policy rules/flags, the target
|
|
ima_ns_policy structure is retrieved from the radix tree by getting the
|
|
namespace id from the current context.
|
|
|
|
Signed-off-by: Guilherme Magalhaes <guilherme.magalhaes@hpe.com>
|
|
---
|
|
security/integrity/ima/ima.h | 37 +++++++++++++++++
|
|
security/integrity/ima/ima_fs.c | 79 ++++++++++++++++++++++++++++++++++---
|
|
security/integrity/ima/ima_init.c | 2 +
|
|
security/integrity/ima/ima_policy.c | 29 +++++++++-----
|
|
4 files changed, 133 insertions(+), 14 deletions(-)
|
|
|
|
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
|
|
index 6e8ca8e..1c5c875 100644
|
|
--- a/security/integrity/ima/ima.h
|
|
+++ b/security/integrity/ima/ima.h
|
|
@@ -140,6 +140,21 @@ static inline void ima_load_kexec_buffer(void) {}
|
|
*/
|
|
extern bool ima_canonical_fmt;
|
|
|
|
+/* Namespace policy globals */
|
|
+struct ima_ns_policy {
|
|
+ struct dentry *policy_dentry;
|
|
+ struct dentry *ns_dentry;
|
|
+ struct list_head *ima_rules;
|
|
+ struct list_head ima_policy_rules;
|
|
+ int ima_policy_flag;
|
|
+ int ima_appraise;
|
|
+};
|
|
+
|
|
+#ifdef CONFIG_IMA_PER_NAMESPACE
|
|
+extern spinlock_t ima_ns_policy_lock;
|
|
+extern struct radix_tree_root ima_ns_policy_mapping;
|
|
+#endif
|
|
+
|
|
/* Internal IMA function definitions */
|
|
int ima_init(void);
|
|
int ima_fs_init(void);
|
|
@@ -166,6 +181,27 @@ int ima_measurements_show(struct seq_file *m, void *v);
|
|
unsigned long ima_get_binary_runtime_size(void);
|
|
int ima_init_template(void);
|
|
void ima_init_template_list(void);
|
|
+#ifdef CONFIG_IMA_PER_NAMESPACE
|
|
+static inline void ima_namespace_lock_init(void) {
|
|
+ spin_lock_init(&ima_ns_policy_lock);
|
|
+}
|
|
+static inline void ima_namespace_lock(void) {
|
|
+ spin_lock(&ima_ns_policy_lock);
|
|
+}
|
|
+static inline void ima_namespace_unlock(void) {
|
|
+ spin_unlock(&ima_ns_policy_lock);
|
|
+}
|
|
+#else
|
|
+static inline void ima_namespace_lock_init(void) {
|
|
+ return;
|
|
+}
|
|
+static inline void ima_namespace_lock(void) {
|
|
+ return;
|
|
+}
|
|
+static inline void ima_namespace_unlock(void) {
|
|
+ return;
|
|
+}
|
|
+#endif
|
|
|
|
/*
|
|
* used to protect h_table and sha_table
|
|
@@ -226,6 +262,7 @@ void ima_update_policy(void);
|
|
void ima_update_policy_flag(void);
|
|
ssize_t ima_parse_add_rule(char *);
|
|
void ima_delete_rules(void);
|
|
+void ima_free_policy_rules(struct list_head *policy_rules);
|
|
int ima_check_policy(void);
|
|
void *ima_policy_start(struct seq_file *m, loff_t *pos);
|
|
void *ima_policy_next(struct seq_file *m, void *v, loff_t *pos);
|
|
diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c
|
|
index 6456407..ce6dcdf 100644
|
|
--- a/security/integrity/ima/ima_fs.c
|
|
+++ b/security/integrity/ima/ima_fs.c
|
|
@@ -275,6 +275,48 @@ static const struct file_operations ima_ascii_measurements_ops = {
|
|
};
|
|
|
|
#ifdef CONFIG_IMA_PER_NAMESPACE
|
|
+/* used for namespace policy rules initialization */
|
|
+static LIST_HEAD(empty_policy);
|
|
+
|
|
+static int allocate_namespace_policy(struct ima_ns_policy **ins,
|
|
+ struct dentry *policy_dentry, struct dentry *ns_dentry)
|
|
+{
|
|
+ int result;
|
|
+ struct ima_ns_policy *p;
|
|
+
|
|
+ p = kmalloc(sizeof(struct ima_ns_policy), GFP_KERNEL);
|
|
+ if (!p) {
|
|
+ result = -ENOMEM;
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ p->policy_dentry = policy_dentry;
|
|
+ p->ns_dentry = ns_dentry;
|
|
+ p->ima_appraise = 0;
|
|
+ p->ima_policy_flag = 0;
|
|
+ INIT_LIST_HEAD(&p->ima_policy_rules);
|
|
+ /* namespace starts with empty rules and not pointing to
|
|
+ * ima_policy_rules */
|
|
+ p->ima_rules = &empty_policy;
|
|
+
|
|
+ result = 0;
|
|
+ *ins = p;
|
|
+
|
|
+out:
|
|
+ return result;
|
|
+}
|
|
+
|
|
+static void free_namespace_policy(struct ima_ns_policy *ins)
|
|
+{
|
|
+ if (ins->policy_dentry)
|
|
+ securityfs_remove(ins->policy_dentry);
|
|
+ securityfs_remove(ins->ns_dentry);
|
|
+
|
|
+ ima_free_policy_rules(&ins->ima_policy_rules);
|
|
+
|
|
+ kfree(ins);
|
|
+}
|
|
+
|
|
/*
|
|
* check_mntns: check a mount namespace is valid
|
|
*
|
|
@@ -476,9 +518,11 @@ static int ima_release_policy(struct inode *inode, struct file *file)
|
|
#ifndef CONFIG_IMA_WRITE_POLICY
|
|
securityfs_remove(ima_policy);
|
|
ima_policy = NULL;
|
|
-#else
|
|
- clear_bit(IMA_FS_BUSY, &ima_fs_flags);
|
|
#endif
|
|
+
|
|
+ /* always clear the busy flag so other namespaces can use it */
|
|
+ clear_bit(IMA_FS_BUSY, &ima_fs_flags);
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
@@ -500,11 +544,14 @@ static int create_mnt_ns_directory(unsigned int ns_id)
|
|
int result;
|
|
struct dentry *ns_dir, *ns_policy;
|
|
char dir_name[64];
|
|
+ struct ima_ns_policy *ins;
|
|
|
|
snprintf(dir_name, sizeof(dir_name), "%u", ns_id);
|
|
|
|
ns_dir = securityfs_create_dir(dir_name, ima_dir);
|
|
if (IS_ERR(ns_dir)) {
|
|
+ /* TODO: handle EEXIST error, remove the folder and
|
|
+ continue the procedure */
|
|
result = PTR_ERR(ns_dir);
|
|
goto out;
|
|
}
|
|
@@ -518,7 +565,15 @@ static int create_mnt_ns_directory(unsigned int ns_id)
|
|
goto out;
|
|
}
|
|
|
|
- result = 0;
|
|
+ result = allocate_namespace_policy(&ins, ns_policy, ns_dir);
|
|
+ if (!result) {
|
|
+ result = radix_tree_insert(&ima_ns_policy_mapping, ns_id, ins);
|
|
+ if (result)
|
|
+ free_namespace_policy(ins);
|
|
+ } else {
|
|
+ securityfs_remove(ns_policy);
|
|
+ securityfs_remove(ns_dir);
|
|
+ }
|
|
|
|
out:
|
|
return result;
|
|
@@ -528,6 +583,7 @@ static ssize_t handle_new_namespace_policy(const char *data, size_t datalen)
|
|
{
|
|
unsigned int ns_id;
|
|
ssize_t result;
|
|
+ struct ima_ns_policy *ins;
|
|
|
|
result = -EINVAL;
|
|
|
|
@@ -536,21 +592,34 @@ static ssize_t handle_new_namespace_policy(const char *data, size_t datalen)
|
|
goto out;
|
|
}
|
|
|
|
+ rcu_read_lock();
|
|
+ ins = radix_tree_lookup(&ima_ns_policy_mapping, ns_id);
|
|
+ rcu_read_unlock();
|
|
+ if (ins) {
|
|
+ pr_info("IMA: directory for namespace id %u already created\n", ns_id);
|
|
+ result = datalen;
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ ima_namespace_lock();
|
|
if (check_mntns(ns_id)) {
|
|
result = -ENOENT;
|
|
pr_err("IMA: unused namespace id %u\n", ns_id);
|
|
- goto out;
|
|
+ goto out_unlock;
|
|
}
|
|
|
|
result = create_mnt_ns_directory(ns_id);
|
|
if (result != 0) {
|
|
pr_err("IMA: namespace id %u directory creation failed\n", ns_id);
|
|
- goto out;
|
|
+ goto out_unlock;
|
|
}
|
|
|
|
result = datalen;
|
|
pr_info("IMA: directory created for namespace id %u\n", ns_id);
|
|
|
|
+out_unlock:
|
|
+ ima_namespace_unlock();
|
|
+
|
|
out:
|
|
return result;
|
|
}
|
|
diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c
|
|
index 2967d49..b557ee3 100644
|
|
--- a/security/integrity/ima/ima_init.c
|
|
+++ b/security/integrity/ima/ima_init.c
|
|
@@ -135,6 +135,8 @@ int __init ima_init(void)
|
|
if (rc != 0)
|
|
return rc;
|
|
|
|
+ ima_namespace_lock_init();
|
|
+
|
|
ima_init_policy();
|
|
|
|
return ima_fs_init();
|
|
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
|
|
index aed47b7..2e8c3b7 100644
|
|
--- a/security/integrity/ima/ima_policy.c
|
|
+++ b/security/integrity/ima/ima_policy.c
|
|
@@ -47,6 +47,12 @@
|
|
int ima_policy_flag;
|
|
static int temp_ima_appraise;
|
|
|
|
+#ifdef CONFIG_IMA_PER_NAMESPACE
|
|
+/* policy namespace map entries except the initial namespace policy */
|
|
+RADIX_TREE(ima_ns_policy_mapping, GFP_ATOMIC);
|
|
+spinlock_t ima_ns_policy_lock;
|
|
+#endif
|
|
+
|
|
#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
|
|
@@ -863,19 +869,12 @@ ssize_t ima_parse_add_rule(char *rule)
|
|
return len;
|
|
}
|
|
|
|
-/**
|
|
- * ima_delete_rules() called to cleanup invalid in-flight policy.
|
|
- * We don't need locking as we operate on the temp list, which is
|
|
- * different from the active one. There is also only one user of
|
|
- * ima_delete_rules() at a time.
|
|
- */
|
|
-void ima_delete_rules(void)
|
|
+void ima_free_policy_rules(struct list_head *policy_rules)
|
|
{
|
|
struct ima_rule_entry *entry, *tmp;
|
|
int i;
|
|
|
|
- temp_ima_appraise = 0;
|
|
- list_for_each_entry_safe(entry, tmp, &ima_temp_rules, list) {
|
|
+ list_for_each_entry_safe(entry, tmp, policy_rules, list) {
|
|
for (i = 0; i < MAX_LSM_RULES; i++)
|
|
kfree(entry->lsm[i].args_p);
|
|
|
|
@@ -884,6 +883,18 @@ void ima_delete_rules(void)
|
|
}
|
|
}
|
|
|
|
+/**
|
|
+ * ima_delete_rules() called to cleanup invalid in-flight policy.
|
|
+ * We don't need locking as we operate on the temp list, which is
|
|
+ * different from the active one. There is also only one user of
|
|
+ * ima_delete_rules() at a time.
|
|
+ */
|
|
+void ima_delete_rules(void)
|
|
+{
|
|
+ temp_ima_appraise = 0;
|
|
+ ima_free_policy_rules(&ima_temp_rules);
|
|
+}
|
|
+
|
|
#ifdef CONFIG_IMA_READ_POLICY
|
|
enum {
|
|
mask_exec = 0, mask_write, mask_read, mask_append
|
|
--
|
|
2.9.3
|
|
|