mirror of
https://github.com/linuxkit/linuxkit.git
synced 2025-10-03 13:42:17 +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>
690 lines
22 KiB
Diff
690 lines
22 KiB
Diff
From c424a95ccee13d974fa54e92ca50cec5b19a9e94 Mon Sep 17 00:00:00 2001
|
|
From: Guilherme Magalhaes <guilherme.magalhaes@hpe.com>
|
|
Date: Tue, 9 May 2017 18:00:55 -0300
|
|
Subject: [PATCH 10/11] ima: handling all policy flags per namespace using
|
|
ima_ns_policy structure
|
|
|
|
Global ima_appraise still saves the initial appraise mode and it is used to
|
|
initialize namespace.ima_appraise flag when a user defined policy is set.
|
|
Globals moved into ima_ns_policy structure (namespace IMA policy private data):
|
|
- ima_policy_flag
|
|
- ima_appraise
|
|
- ima_rules
|
|
- ima_policy_rules
|
|
Functions changed to take as parameter the correct ima_ns_policy structure.
|
|
ima_initial_namespace_policy is initialized in ima_init_policy and stores the
|
|
initial namespace IMA policy data.
|
|
Replacing direct uses of ima_ns_policy lock with the ima_namespace_lock() and
|
|
ima_namespace_unlock() functions.
|
|
|
|
Signed-off-by: Guilherme Magalhaes <guilherme.magalhaes@hpe.com>
|
|
---
|
|
security/integrity/ima/ima.h | 17 +++---
|
|
security/integrity/ima/ima_api.c | 6 +-
|
|
security/integrity/ima/ima_appraise.c | 21 +++++--
|
|
security/integrity/ima/ima_fs.c | 26 ++++++---
|
|
security/integrity/ima/ima_init.c | 11 +++-
|
|
security/integrity/ima/ima_main.c | 36 ++++++++----
|
|
security/integrity/ima/ima_policy.c | 100 +++++++++++++++++++++++++---------
|
|
7 files changed, 150 insertions(+), 67 deletions(-)
|
|
|
|
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
|
|
index 20b927e..fd5cfe9 100644
|
|
--- a/security/integrity/ima/ima.h
|
|
+++ b/security/integrity/ima/ima.h
|
|
@@ -61,9 +61,6 @@ enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8 };
|
|
#endif
|
|
|
|
|
|
-/* current content of the policy */
|
|
-extern int ima_policy_flag;
|
|
-
|
|
/* set during initialization */
|
|
extern int ima_initialized;
|
|
extern int ima_used_chip;
|
|
@@ -149,7 +146,6 @@ struct ima_ns_policy {
|
|
int ima_policy_flag;
|
|
int ima_appraise;
|
|
};
|
|
-
|
|
extern struct ima_ns_policy ima_initial_namespace_policy;
|
|
#ifdef CONFIG_IMA_PER_NAMESPACE
|
|
extern spinlock_t ima_ns_policy_lock;
|
|
@@ -241,7 +237,7 @@ enum ima_hooks {
|
|
|
|
/* LIM API function definitions */
|
|
int ima_get_action(struct inode *inode, int mask,
|
|
- enum ima_hooks func, int *pcr);
|
|
+ enum ima_hooks func, int *pcr, struct ima_ns_policy *ins);
|
|
int ima_must_measure(struct inode *inode, int mask, enum ima_hooks func);
|
|
int ima_collect_measurement(struct integrity_iint_cache *iint,
|
|
struct file *file, void *buf, loff_t size,
|
|
@@ -262,10 +258,10 @@ const char *ima_d_path(const struct path *path, char **pathbuf, char *filename);
|
|
|
|
/* IMA policy related functions */
|
|
int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask,
|
|
- int flags, int *pcr);
|
|
+ int flags, int *pcr, struct ima_ns_policy *ins);
|
|
void ima_init_policy(void);
|
|
-void ima_update_policy(void);
|
|
-void ima_update_policy_flag(void);
|
|
+void ima_update_policy(struct ima_ns_policy *ins);
|
|
+void ima_update_policy_flag(struct ima_ns_policy *ins);
|
|
ssize_t ima_parse_add_rule(char *);
|
|
void ima_delete_rules(void);
|
|
void ima_free_policy_rules(struct list_head *policy_rules);
|
|
@@ -283,12 +279,13 @@ int ima_policy_show(struct seq_file *m, void *v);
|
|
#define IMA_APPRAISE_FIRMWARE 0x10
|
|
#define IMA_APPRAISE_POLICY 0x20
|
|
|
|
+
|
|
#ifdef CONFIG_IMA_APPRAISE
|
|
int ima_appraise_measurement(enum ima_hooks func,
|
|
struct integrity_iint_cache *iint,
|
|
struct file *file, const unsigned char *filename,
|
|
struct evm_ima_xattr_data *xattr_value,
|
|
- int xattr_len, int opened);
|
|
+ int xattr_len, int opened, struct ima_ns_policy *ins);
|
|
int ima_must_appraise(struct inode *inode, int mask, enum ima_hooks func);
|
|
void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file);
|
|
enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint,
|
|
@@ -304,7 +301,7 @@ static inline int ima_appraise_measurement(enum ima_hooks func,
|
|
struct file *file,
|
|
const unsigned char *filename,
|
|
struct evm_ima_xattr_data *xattr_value,
|
|
- int xattr_len, int opened)
|
|
+ int xattr_len, int opened, struct ima_ns_policy *ins)
|
|
{
|
|
return INTEGRITY_UNKNOWN;
|
|
}
|
|
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c
|
|
index b05c1fd..9aba542 100644
|
|
--- a/security/integrity/ima/ima_api.c
|
|
+++ b/security/integrity/ima/ima_api.c
|
|
@@ -173,13 +173,13 @@ void ima_add_violation(struct file *file, const unsigned char *filename,
|
|
* Returns IMA_MEASURE, IMA_APPRAISE mask.
|
|
*
|
|
*/
|
|
-int ima_get_action(struct inode *inode, int mask, enum ima_hooks func, int *pcr)
|
|
+int ima_get_action(struct inode *inode, int mask, enum ima_hooks func, int *pcr, struct ima_ns_policy *ins)
|
|
{
|
|
int flags = IMA_MEASURE | IMA_AUDIT | IMA_APPRAISE;
|
|
|
|
- flags &= ima_policy_flag;
|
|
+ flags &= ins->ima_policy_flag;
|
|
|
|
- return ima_match_policy(inode, func, mask, flags, pcr);
|
|
+ return ima_match_policy(inode, func, mask, flags, pcr, ins);
|
|
}
|
|
|
|
/*
|
|
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c
|
|
index 1fd9539..510bb2f 100644
|
|
--- a/security/integrity/ima/ima_appraise.c
|
|
+++ b/security/integrity/ima/ima_appraise.c
|
|
@@ -26,6 +26,7 @@ static int __init default_appraise_setup(char *str)
|
|
ima_appraise = IMA_APPRAISE_LOG;
|
|
else if (strncmp(str, "fix", 3) == 0)
|
|
ima_appraise = IMA_APPRAISE_FIX;
|
|
+
|
|
return 1;
|
|
}
|
|
|
|
@@ -38,10 +39,12 @@ __setup("ima_appraise=", default_appraise_setup);
|
|
*/
|
|
int ima_must_appraise(struct inode *inode, int mask, enum ima_hooks func)
|
|
{
|
|
- if (!ima_appraise)
|
|
+ struct ima_ns_policy *ins = ima_get_current_namespace_policy();
|
|
+
|
|
+ if (!ins->ima_appraise)
|
|
return 0;
|
|
|
|
- return ima_match_policy(inode, func, mask, IMA_APPRAISE, NULL);
|
|
+ return ima_match_policy(inode, func, mask, IMA_APPRAISE, NULL, ins);
|
|
}
|
|
|
|
static int ima_fix_xattr(struct dentry *dentry,
|
|
@@ -189,7 +192,7 @@ int ima_appraise_measurement(enum ima_hooks func,
|
|
struct integrity_iint_cache *iint,
|
|
struct file *file, const unsigned char *filename,
|
|
struct evm_ima_xattr_data *xattr_value,
|
|
- int xattr_len, int opened)
|
|
+ int xattr_len, int opened, struct ima_ns_policy *ins)
|
|
{
|
|
static const char op[] = "appraise_data";
|
|
char *cause = "unknown";
|
|
@@ -273,7 +276,7 @@ int ima_appraise_measurement(enum ima_hooks func,
|
|
|
|
out:
|
|
if (status != INTEGRITY_PASS) {
|
|
- if ((ima_appraise & IMA_APPRAISE_FIX) &&
|
|
+ if ((ins->ima_appraise & IMA_APPRAISE_FIX) &&
|
|
(!xattr_value ||
|
|
xattr_value->type != EVM_IMA_XATTR_DIGSIG)) {
|
|
if (!ima_fix_xattr(dentry, iint))
|
|
@@ -326,8 +329,11 @@ void ima_inode_post_setattr(struct dentry *dentry)
|
|
struct inode *inode = d_backing_inode(dentry);
|
|
struct integrity_iint_cache *iint;
|
|
int must_appraise;
|
|
+ struct ima_ns_policy *ins;
|
|
|
|
- if (!(ima_policy_flag & IMA_APPRAISE) || !S_ISREG(inode->i_mode)
|
|
+ ins = ima_get_current_namespace_policy();
|
|
+
|
|
+ if (!(ins->ima_policy_flag & IMA_APPRAISE) || !S_ISREG(inode->i_mode)
|
|
|| !(inode->i_opflags & IOP_XATTR))
|
|
return;
|
|
|
|
@@ -363,8 +369,11 @@ static int ima_protect_xattr(struct dentry *dentry, const char *xattr_name,
|
|
static void ima_reset_appraise_flags(struct inode *inode, int digsig)
|
|
{
|
|
struct integrity_iint_cache *iint;
|
|
+ struct ima_ns_policy *ins;
|
|
+
|
|
+ ins = ima_get_current_namespace_policy();
|
|
|
|
- if (!(ima_policy_flag & IMA_APPRAISE) || !S_ISREG(inode->i_mode))
|
|
+ if (!(ins->ima_policy_flag & IMA_APPRAISE) || !S_ISREG(inode->i_mode))
|
|
return;
|
|
|
|
iint = integrity_iint_find(inode);
|
|
diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c
|
|
index 94e89fe..bc18722 100644
|
|
--- a/security/integrity/ima/ima_fs.c
|
|
+++ b/security/integrity/ima/ima_fs.c
|
|
@@ -308,7 +308,7 @@ static int allocate_namespace_policy(struct ima_ns_policy **ins,
|
|
|
|
p->policy_dentry = policy_dentry;
|
|
p->ns_dentry = ns_dentry;
|
|
- p->ima_appraise = 0;
|
|
+ p->ima_appraise = ima_appraise;
|
|
p->ima_policy_flag = 0;
|
|
INIT_LIST_HEAD(&p->ima_policy_rules);
|
|
/* namespace starts with empty rules and not pointing to
|
|
@@ -488,6 +488,7 @@ static ssize_t ima_write_policy(struct file *file, const char __user *buf,
|
|
{
|
|
char *data;
|
|
ssize_t result;
|
|
+ struct ima_ns_policy *ins;
|
|
|
|
if (datalen >= PAGE_SIZE)
|
|
datalen = PAGE_SIZE - 1;
|
|
@@ -512,19 +513,30 @@ static ssize_t ima_write_policy(struct file *file, const char __user *buf,
|
|
if (result < 0)
|
|
goto out_free;
|
|
|
|
+ ima_namespace_lock();
|
|
+ ins = ima_get_namespace_policy_from_inode(file->f_inode);
|
|
+ if (!ins) {
|
|
+ /* the namespace is not valid anymore, indicate the error
|
|
+ * and exit */
|
|
+ result = -EINVAL;
|
|
+ goto out_unlock;
|
|
+ }
|
|
+
|
|
if (data[0] == '/') {
|
|
result = ima_read_policy(data);
|
|
- } else if (ima_appraise & IMA_APPRAISE_POLICY) {
|
|
+ } else if (ins->ima_appraise & IMA_APPRAISE_POLICY) {
|
|
pr_err("IMA: signed policy file (specified as an absolute pathname) required\n");
|
|
integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, NULL,
|
|
"policy_update", "signed policy required",
|
|
1, 0);
|
|
|
|
- if (ima_appraise & IMA_APPRAISE_ENFORCE)
|
|
+ if (ins->ima_appraise & IMA_APPRAISE_ENFORCE)
|
|
result = -EACCES;
|
|
} else {
|
|
result = ima_parse_add_rule(data);
|
|
}
|
|
+out_unlock:
|
|
+ ima_namespace_unlock();
|
|
mutex_unlock(&ima_write_mutex);
|
|
out_free:
|
|
kfree(data);
|
|
@@ -611,7 +623,7 @@ static int ima_release_policy(struct inode *inode, struct file *file)
|
|
return 0;
|
|
}
|
|
|
|
- ima_update_policy();
|
|
+ ima_update_policy(ins);
|
|
#ifndef CONFIG_IMA_WRITE_POLICY
|
|
if (ins == &ima_initial_namespace_policy) {
|
|
securityfs_remove(ima_policy_initial_ns);
|
|
@@ -698,16 +710,16 @@ void ima_mnt_namespace_dying(unsigned int ns_id)
|
|
{
|
|
struct ima_ns_policy *p;
|
|
|
|
- spin_lock(&ima_ns_policy_lock);
|
|
+ ima_namespace_lock();
|
|
p = radix_tree_delete(&ima_ns_policy_mapping, ns_id);
|
|
|
|
if (!p) {
|
|
- spin_unlock(&ima_ns_policy_lock);
|
|
+ ima_namespace_unlock();
|
|
return;
|
|
}
|
|
|
|
free_namespace_policy(p);
|
|
- spin_unlock(&ima_ns_policy_lock);
|
|
+ ima_namespace_unlock();
|
|
}
|
|
|
|
static ssize_t handle_new_namespace_policy(const char *data, size_t datalen)
|
|
diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c
|
|
index b557ee3..f0bb196 100644
|
|
--- a/security/integrity/ima/ima_init.c
|
|
+++ b/security/integrity/ima/ima_init.c
|
|
@@ -96,11 +96,16 @@ static int __init ima_add_boot_aggregate(void)
|
|
#ifdef CONFIG_IMA_LOAD_X509
|
|
void __init ima_load_x509(void)
|
|
{
|
|
- int unset_flags = ima_policy_flag & IMA_APPRAISE;
|
|
+ int unset_flags;
|
|
+ struct ima_ns_policy *ins;
|
|
|
|
- ima_policy_flag &= ~unset_flags;
|
|
+ ins = ima_get_current_namespace_policy();
|
|
+
|
|
+ unset_flags = ins->ima_policy_flag & IMA_APPRAISE;
|
|
+
|
|
+ ins->ima_policy_flag &= ~unset_flags;
|
|
integrity_load_x509(INTEGRITY_KEYRING_IMA, CONFIG_IMA_X509_PATH);
|
|
- ima_policy_flag |= unset_flags;
|
|
+ ins->ima_policy_flag |= unset_flags;
|
|
}
|
|
#endif
|
|
|
|
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
|
|
index 2aebb79..1b995bb 100644
|
|
--- a/security/integrity/ima/ima_main.c
|
|
+++ b/security/integrity/ima/ima_main.c
|
|
@@ -30,6 +30,7 @@
|
|
int ima_initialized;
|
|
|
|
#ifdef CONFIG_IMA_APPRAISE
|
|
+/* Used during IMA initialization only */
|
|
int ima_appraise = IMA_APPRAISE_ENFORCE;
|
|
#else
|
|
int ima_appraise;
|
|
@@ -144,9 +145,13 @@ void ima_file_free(struct file *file)
|
|
{
|
|
struct inode *inode = file_inode(file);
|
|
struct integrity_iint_cache *iint;
|
|
+ struct ima_ns_policy *ins;
|
|
|
|
- if (!ima_policy_flag || !S_ISREG(inode->i_mode))
|
|
+ ins = ima_get_current_namespace_policy();
|
|
+
|
|
+ if (!ins->ima_policy_flag || !S_ISREG(inode->i_mode)) {
|
|
return;
|
|
+ }
|
|
|
|
iint = integrity_iint_find(inode);
|
|
if (!iint)
|
|
@@ -170,17 +175,20 @@ static int process_measurement(struct file *file, char *buf, loff_t size,
|
|
int xattr_len = 0;
|
|
bool violation_check;
|
|
enum hash_algo hash_algo;
|
|
+ struct ima_ns_policy *ins;
|
|
|
|
- if (!ima_policy_flag || !S_ISREG(inode->i_mode))
|
|
+ ins = ima_get_current_namespace_policy();
|
|
+
|
|
+ if (!ins->ima_policy_flag || !S_ISREG(inode->i_mode))
|
|
return 0;
|
|
|
|
/* Return an IMA_MEASURE, IMA_APPRAISE, IMA_AUDIT action
|
|
* bitmask based on the appraise/audit/measurement policy.
|
|
* Included is the appraise submask.
|
|
*/
|
|
- action = ima_get_action(inode, mask, func, &pcr);
|
|
+ action = ima_get_action(inode, mask, func, &pcr, ins);
|
|
violation_check = ((func == FILE_CHECK || func == MMAP_CHECK) &&
|
|
- (ima_policy_flag & IMA_MEASURE));
|
|
+ (ins->ima_policy_flag & IMA_MEASURE));
|
|
if (!action && !violation_check)
|
|
return 0;
|
|
|
|
@@ -249,7 +257,7 @@ static int process_measurement(struct file *file, char *buf, loff_t size,
|
|
xattr_value, xattr_len, pcr);
|
|
if (action & IMA_APPRAISE_SUBMASK)
|
|
rc = ima_appraise_measurement(func, iint, file, pathname,
|
|
- xattr_value, xattr_len, opened);
|
|
+ xattr_value, xattr_len, opened, ins);
|
|
if (action & IMA_AUDIT)
|
|
ima_audit_measurement(iint, pathname);
|
|
|
|
@@ -263,7 +271,7 @@ static int process_measurement(struct file *file, char *buf, loff_t size,
|
|
__putname(pathbuf);
|
|
out:
|
|
inode_unlock(inode);
|
|
- if ((rc && must_appraise) && (ima_appraise & IMA_APPRAISE_ENFORCE))
|
|
+ if ((rc && must_appraise) && (ins->ima_appraise & IMA_APPRAISE_ENFORCE))
|
|
return -EACCES;
|
|
return 0;
|
|
}
|
|
@@ -361,8 +369,10 @@ int ima_read_file(struct file *file, enum kernel_read_file_id read_id)
|
|
{
|
|
if (!file && read_id == READING_MODULE) {
|
|
#ifndef CONFIG_MODULE_SIG_FORCE
|
|
- if ((ima_appraise & IMA_APPRAISE_MODULES) &&
|
|
- (ima_appraise & IMA_APPRAISE_ENFORCE))
|
|
+ struct ima_ns_policy *ins;
|
|
+ ins = ima_get_current_namespace_policy();
|
|
+ if ((ins->ima_appraise & IMA_APPRAISE_MODULES) &&
|
|
+ (ins->ima_appraise & IMA_APPRAISE_ENFORCE))
|
|
return -EACCES; /* INTEGRITY_UNKNOWN */
|
|
#endif
|
|
return 0; /* We rely on module signature checking */
|
|
@@ -395,10 +405,13 @@ int ima_post_read_file(struct file *file, void *buf, loff_t size,
|
|
enum kernel_read_file_id read_id)
|
|
{
|
|
enum ima_hooks func;
|
|
+ struct ima_ns_policy *ins;
|
|
+
|
|
+ ins = ima_get_current_namespace_policy();
|
|
|
|
if (!file && read_id == READING_FIRMWARE) {
|
|
- if ((ima_appraise & IMA_APPRAISE_FIRMWARE) &&
|
|
- (ima_appraise & IMA_APPRAISE_ENFORCE))
|
|
+ if ((ins->ima_appraise & IMA_APPRAISE_FIRMWARE) &&
|
|
+ (ins->ima_appraise & IMA_APPRAISE_ENFORCE))
|
|
return -EACCES; /* INTEGRITY_UNKNOWN */
|
|
return 0;
|
|
}
|
|
@@ -407,7 +420,7 @@ int ima_post_read_file(struct file *file, void *buf, loff_t size,
|
|
return 0;
|
|
|
|
if (!file || !buf || size == 0) { /* should never happen */
|
|
- if (ima_appraise & IMA_APPRAISE_ENFORCE)
|
|
+ if (ins->ima_appraise & IMA_APPRAISE_ENFORCE)
|
|
return -EACCES;
|
|
return 0;
|
|
}
|
|
@@ -425,7 +438,6 @@ static int __init init_ima(void)
|
|
error = ima_init();
|
|
if (!error) {
|
|
ima_initialized = 1;
|
|
- ima_update_policy_flag();
|
|
}
|
|
return error;
|
|
}
|
|
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
|
|
index 8c0d4c9..4ffb4ad 100644
|
|
--- a/security/integrity/ima/ima_policy.c
|
|
+++ b/security/integrity/ima/ima_policy.c
|
|
@@ -46,7 +46,7 @@
|
|
#define INVALID_PCR(a) (((a) < 0) || \
|
|
(a) >= (FIELD_SIZEOF(struct integrity_iint_cache, measured_pcrs) * 8))
|
|
|
|
-int ima_policy_flag;
|
|
+/* used only during policy initialization and policy change */
|
|
static int temp_ima_appraise;
|
|
|
|
#ifdef CONFIG_IMA_PER_NAMESPACE
|
|
@@ -66,6 +66,7 @@ struct ima_ns_policy ima_initial_namespace_policy = {
|
|
.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
|
|
@@ -166,11 +167,12 @@ static struct ima_rule_entry default_appraise_rules[] = {
|
|
#endif
|
|
};
|
|
|
|
+/* used only during policy setup of the initial namespace */
|
|
static LIST_HEAD(ima_default_rules);
|
|
-static LIST_HEAD(ima_policy_rules);
|
|
+/* used during policy setting and cleaned up for the next policy setting */
|
|
static LIST_HEAD(ima_temp_rules);
|
|
-static struct list_head *ima_rules;
|
|
|
|
+/* only used during setup of the initial namespace policy */
|
|
static int ima_policy __initdata;
|
|
|
|
static int __init default_measure_policy_setup(char *str)
|
|
@@ -268,13 +270,14 @@ struct ima_ns_policy *ima_get_current_namespace_policy(void)
|
|
* the reloaded LSM policy. We assume the rules still exist; and BUG_ON() if
|
|
* they don't.
|
|
*/
|
|
-static void ima_lsm_update_rules(void)
|
|
+static void ima_lsm_update_rules(struct ima_ns_policy *ins)
|
|
{
|
|
struct ima_rule_entry *entry;
|
|
int result;
|
|
int i;
|
|
|
|
- list_for_each_entry(entry, &ima_policy_rules, list) {
|
|
+ rcu_read_lock();
|
|
+ list_for_each_entry_rcu(entry, &ins->ima_policy_rules, list) {
|
|
for (i = 0; i < MAX_LSM_RULES; i++) {
|
|
if (!entry->lsm[i].rule)
|
|
continue;
|
|
@@ -285,6 +288,7 @@ static void ima_lsm_update_rules(void)
|
|
BUG_ON(!entry->lsm[i].rule);
|
|
}
|
|
}
|
|
+ rcu_read_unlock();
|
|
}
|
|
|
|
/**
|
|
@@ -297,7 +301,7 @@ static void ima_lsm_update_rules(void)
|
|
* Returns true on rule match, false on failure.
|
|
*/
|
|
static bool ima_match_rules(struct ima_rule_entry *rule, struct inode *inode,
|
|
- enum ima_hooks func, int mask)
|
|
+ enum ima_hooks func, int mask, struct ima_ns_policy *ins)
|
|
{
|
|
struct task_struct *tsk = current;
|
|
const struct cred *cred = current_cred();
|
|
@@ -365,7 +369,7 @@ static bool ima_match_rules(struct ima_rule_entry *rule, struct inode *inode,
|
|
}
|
|
if ((rc < 0) && (!retried)) {
|
|
retried = 1;
|
|
- ima_lsm_update_rules();
|
|
+ ima_lsm_update_rules(ins);
|
|
goto retry;
|
|
}
|
|
if (!rc)
|
|
@@ -412,18 +416,18 @@ static int get_subaction(struct ima_rule_entry *rule, enum ima_hooks func)
|
|
* than writes so ima_match_policy() is classical RCU candidate.
|
|
*/
|
|
int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask,
|
|
- int flags, int *pcr)
|
|
+ int flags, int *pcr, struct ima_ns_policy *ins)
|
|
{
|
|
struct ima_rule_entry *entry;
|
|
int action = 0, actmask = flags | (flags << 1);
|
|
|
|
rcu_read_lock();
|
|
- list_for_each_entry_rcu(entry, ima_rules, list) {
|
|
+ list_for_each_entry_rcu(entry, ins->ima_rules, list) {
|
|
|
|
if (!(entry->action & actmask))
|
|
continue;
|
|
|
|
- if (!ima_match_rules(entry, inode, func, mask))
|
|
+ if (!ima_match_rules(entry, inode, func, mask, ins))
|
|
continue;
|
|
|
|
action |= entry->flags & IMA_ACTION_FLAGS;
|
|
@@ -454,18 +458,20 @@ int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask,
|
|
* out of a function or not call the function in the first place
|
|
* can be made earlier.
|
|
*/
|
|
-void ima_update_policy_flag(void)
|
|
+void ima_update_policy_flag(struct ima_ns_policy *ins)
|
|
{
|
|
struct ima_rule_entry *entry;
|
|
|
|
- list_for_each_entry(entry, ima_rules, list) {
|
|
+ rcu_read_lock();
|
|
+ list_for_each_entry_rcu(entry, ins->ima_rules, list) {
|
|
if (entry->action & IMA_DO_MASK)
|
|
- ima_policy_flag |= entry->action;
|
|
+ ins->ima_policy_flag |= entry->action;
|
|
}
|
|
+ rcu_read_unlock();
|
|
|
|
- ima_appraise |= temp_ima_appraise;
|
|
- if (!ima_appraise)
|
|
- ima_policy_flag &= ~IMA_APPRAISE;
|
|
+ ins->ima_appraise |= temp_ima_appraise;
|
|
+ if (!ins->ima_appraise)
|
|
+ ins->ima_policy_flag &= ~IMA_APPRAISE;
|
|
}
|
|
|
|
/**
|
|
@@ -477,6 +483,7 @@ void ima_update_policy_flag(void)
|
|
void __init ima_init_policy(void)
|
|
{
|
|
int i, measure_entries, appraise_entries;
|
|
+ struct ima_ns_policy *ins;
|
|
|
|
/* if !ima_policy set entries = 0 so we load NO default rules */
|
|
measure_entries = ima_policy ? ARRAY_SIZE(dont_measure_rules) : 0;
|
|
@@ -507,8 +514,13 @@ void __init ima_init_policy(void)
|
|
temp_ima_appraise |= IMA_APPRAISE_POLICY;
|
|
}
|
|
|
|
- ima_rules = &ima_default_rules;
|
|
- ima_update_policy_flag();
|
|
+ ins = &ima_initial_namespace_policy;
|
|
+
|
|
+ ins->ima_rules = &ima_default_rules;
|
|
+ ins->ima_appraise = ima_appraise;
|
|
+
|
|
+ ima_update_policy_flag(ins);
|
|
+ temp_ima_appraise = 0;
|
|
}
|
|
|
|
/* Make sure we have a valid policy, at least containing some rules. */
|
|
@@ -530,14 +542,14 @@ int ima_check_policy(void)
|
|
* Policy rules are never deleted so ima_policy_flag gets zeroed only once when
|
|
* we switch from the default policy to user defined.
|
|
*/
|
|
-void ima_update_policy(void)
|
|
+void ima_update_policy(struct ima_ns_policy *ins)
|
|
{
|
|
struct list_head *first, *last, *policy;
|
|
|
|
/* append current policy with the new rules */
|
|
first = (&ima_temp_rules)->next;
|
|
last = (&ima_temp_rules)->prev;
|
|
- policy = &ima_policy_rules;
|
|
+ policy = &ins->ima_policy_rules;
|
|
|
|
synchronize_rcu();
|
|
|
|
@@ -549,11 +561,14 @@ void ima_update_policy(void)
|
|
/* prepare for the next policy rules addition */
|
|
INIT_LIST_HEAD(&ima_temp_rules);
|
|
|
|
- if (ima_rules != policy) {
|
|
- ima_policy_flag = 0;
|
|
- ima_rules = policy;
|
|
+ if (ins->ima_rules != policy) {
|
|
+ ins->ima_policy_flag = 0;
|
|
+ ins->ima_rules = policy;
|
|
+ ins->ima_appraise = ima_appraise;
|
|
}
|
|
- ima_update_policy_flag();
|
|
+
|
|
+ ima_update_policy_flag(ins);
|
|
+ temp_ima_appraise = 0;
|
|
}
|
|
|
|
enum {
|
|
@@ -964,6 +979,7 @@ void ima_free_policy_rules(struct list_head *policy_rules)
|
|
void ima_delete_rules(void)
|
|
{
|
|
temp_ima_appraise = 0;
|
|
+
|
|
ima_free_policy_rules(&ima_temp_rules);
|
|
}
|
|
|
|
@@ -1002,28 +1018,49 @@ void *ima_policy_start(struct seq_file *m, loff_t *pos)
|
|
{
|
|
loff_t l = *pos;
|
|
struct ima_rule_entry *entry;
|
|
+ struct ima_ns_policy *ins;
|
|
+
|
|
+ ima_namespace_lock();
|
|
+ ins = ima_get_namespace_policy_from_inode(m->file->f_inode);
|
|
+ if (!ins) {
|
|
+ ima_namespace_unlock();
|
|
+ return NULL;
|
|
+ }
|
|
|
|
rcu_read_lock();
|
|
- list_for_each_entry_rcu(entry, ima_rules, list) {
|
|
+ list_for_each_entry_rcu(entry, ins->ima_rules, list) {
|
|
if (!l--) {
|
|
rcu_read_unlock();
|
|
+ ima_namespace_unlock();
|
|
return entry;
|
|
}
|
|
}
|
|
rcu_read_unlock();
|
|
+ ima_namespace_unlock();
|
|
return NULL;
|
|
}
|
|
|
|
void *ima_policy_next(struct seq_file *m, void *v, loff_t *pos)
|
|
{
|
|
struct ima_rule_entry *entry = v;
|
|
+ struct ima_ns_policy *ins;
|
|
+ void *p;
|
|
+
|
|
+ ima_namespace_lock();
|
|
+ ins = ima_get_namespace_policy_from_inode(m->file->f_inode);
|
|
+ if (!ins) {
|
|
+ ima_namespace_unlock();
|
|
+ return NULL;
|
|
+ }
|
|
|
|
rcu_read_lock();
|
|
entry = list_entry_rcu(entry->list.next, struct ima_rule_entry, list);
|
|
rcu_read_unlock();
|
|
(*pos)++;
|
|
|
|
- return (&entry->list == ima_rules) ? NULL : entry;
|
|
+ p = (&entry->list == ins->ima_rules) ? NULL : entry;
|
|
+ ima_namespace_unlock();
|
|
+ return p;
|
|
}
|
|
|
|
void ima_policy_stop(struct seq_file *m, void *v)
|
|
@@ -1082,6 +1119,16 @@ int ima_policy_show(struct seq_file *m, void *v)
|
|
struct ima_rule_entry *entry = v;
|
|
int i;
|
|
char tbuf[64] = {0,};
|
|
+ struct ima_ns_policy *ins;
|
|
+
|
|
+ ima_namespace_lock();
|
|
+ ins = ima_get_namespace_policy_from_inode(m->file->f_inode);
|
|
+ if (!ins) {
|
|
+ /* this namespace was release and the policy entry is not valid
|
|
+ * anymore */
|
|
+ ima_namespace_unlock();
|
|
+ return 0;
|
|
+ }
|
|
|
|
rcu_read_lock();
|
|
|
|
@@ -1184,6 +1231,7 @@ int ima_policy_show(struct seq_file *m, void *v)
|
|
seq_puts(m, "permit_directio ");
|
|
rcu_read_unlock();
|
|
seq_puts(m, "\n");
|
|
+ ima_namespace_unlock();
|
|
return 0;
|
|
}
|
|
#endif /* CONFIG_IMA_READ_POLICY */
|
|
--
|
|
2.9.3
|
|
|