[PATCH v11 04/27] ima: Define ima_namespace struct and start moving variables into it

From: Stefan Berger
Date: Wed Mar 02 2022 - 08:52:44 EST


Define the ima_namespace structure and the ima_namespace variable
init_ima_ns for the host's IMA namespace. Implement the basic functions
ima_ns_init() and ima_init_namespace() for namespacing support.

Move variables related to the IMA policy into the ima_namespace. This way
the IMA policy of an IMA namespace can be set and displayed using a
front-end like securityfs.

In preparation for IMA namespacing, update the existing functions to
pass the ima_namespace struct. For now, use &init_ima_ns as the current
ima_namespace when a function that is related to a policy rule is called.

Signed-off-by: Stefan Berger <stefanb@xxxxxxxxxxxxx>
Acked-by: Christian Brauner <brauner@xxxxxxxxxx>
Reviewed-by: Mimi Zohar <zohar@xxxxxxxxxxxxx>

---

v11:
- Updated commit text
- Added comments to some fields in the ima_namespace struct

v9:
- squashed patched 2 and 3 of v8
- ima_post_read_file: only access ima_appraise in case of init_ima_ns
---
security/integrity/ima/Makefile | 2 +-
security/integrity/ima/ima.h | 53 ++++---
security/integrity/ima/ima_api.c | 8 +-
security/integrity/ima/ima_appraise.c | 28 ++--
security/integrity/ima/ima_asymmetric_keys.c | 4 +-
security/integrity/ima/ima_fs.c | 16 ++-
security/integrity/ima/ima_init.c | 12 +-
security/integrity/ima/ima_init_ima_ns.c | 29 ++++
security/integrity/ima/ima_main.c | 87 +++++++-----
security/integrity/ima/ima_policy.c | 142 ++++++++++---------
security/integrity/ima/ima_queue_keys.c | 11 +-
11 files changed, 248 insertions(+), 144 deletions(-)
create mode 100644 security/integrity/ima/ima_init_ima_ns.c

diff --git a/security/integrity/ima/Makefile b/security/integrity/ima/Makefile
index 2499f2485c04..f8a5e5f3975d 100644
--- a/security/integrity/ima/Makefile
+++ b/security/integrity/ima/Makefile
@@ -7,7 +7,7 @@
obj-$(CONFIG_IMA) += ima.o

ima-y := ima_fs.o ima_queue.o ima_init.o ima_main.o ima_crypto.o ima_api.o \
- ima_policy.o ima_template.o ima_template_lib.o
+ ima_policy.o ima_template.o ima_template_lib.o ima_init_ima_ns.o
ima-$(CONFIG_IMA_APPRAISE) += ima_appraise.o
ima-$(CONFIG_IMA_APPRAISE_MODSIG) += ima_modsig.o
ima-$(CONFIG_HAVE_IMA_KEXEC) += ima_kexec.o
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index be965a8715e4..9bcde1a24e74 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -20,6 +20,7 @@
#include <linux/hash.h>
#include <linux/tpm.h>
#include <linux/audit.h>
+#include <linux/user_namespace.h>
#include <crypto/hash_info.h>

#include "../integrity.h"
@@ -43,9 +44,6 @@ enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8, TPM_PCR10 = 10 };

#define NR_BANKS(chip) ((chip != NULL) ? chip->nr_allocated_banks : 0)

-/* current content of the policy */
-extern int ima_policy_flag;
-
/* bitset of digests algorithms allowed in the setxattr hook */
extern atomic_t ima_setxattr_allowed_hash_algorithms;

@@ -119,6 +117,17 @@ struct ima_kexec_hdr {
u64 count;
};

+struct ima_namespace {
+ /* policy rules */
+ struct list_head ima_default_rules; /* Kconfig, builtin & arch rules */
+ struct list_head ima_policy_rules; /* arch & custom rules */
+ struct list_head ima_temp_rules;
+
+ struct list_head __rcu *ima_rules; /* Pointer to the current policy */
+ int ima_policy_flag;
+} __randomize_layout;
+extern struct ima_namespace init_ima_ns;
+
extern const int read_idmap[];

#ifdef CONFIG_HAVE_IMA_KEXEC
@@ -136,6 +145,7 @@ extern bool ima_canonical_fmt;
/* Internal IMA function definitions */
int ima_init(void);
int ima_fs_init(void);
+int ima_ns_init(void);
int ima_add_template_entry(struct ima_template_entry *entry, int violation,
const char *op, struct inode *inode,
const unsigned char *filename);
@@ -243,18 +253,19 @@ void ima_init_key_queue(void);
bool ima_should_queue_key(void);
bool ima_queue_key(struct key *keyring, const void *payload,
size_t payload_len);
-void ima_process_queued_keys(void);
+void ima_process_queued_keys(struct ima_namespace *ns);
#else
static inline void ima_init_key_queue(void) {}
static inline bool ima_should_queue_key(void) { return false; }
static inline bool ima_queue_key(struct key *keyring,
const void *payload,
size_t payload_len) { return false; }
-static inline void ima_process_queued_keys(void) {}
+static inline void ima_process_queued_keys(struct ima_namespace *ns) {}
#endif /* CONFIG_IMA_QUEUE_EARLY_BOOT_KEYS */

/* LIM API function definitions */
-int ima_get_action(struct user_namespace *mnt_userns, struct inode *inode,
+int ima_get_action(struct ima_namespace *ns,
+ struct user_namespace *mnt_userns, struct inode *inode,
const struct cred *cred, u32 secid, int mask,
enum ima_hooks func, int *pcr,
struct ima_template_desc **template_desc,
@@ -268,7 +279,8 @@ void ima_store_measurement(struct integrity_iint_cache *iint, struct file *file,
struct evm_ima_xattr_data *xattr_value,
int xattr_len, const struct modsig *modsig, int pcr,
struct ima_template_desc *template_desc);
-int process_buffer_measurement(struct user_namespace *mnt_userns,
+int process_buffer_measurement(struct ima_namespace *ns,
+ struct user_namespace *mnt_userns,
struct inode *inode, const void *buf, int size,
const char *eventname, enum ima_hooks func,
int pcr, const char *func_data,
@@ -285,17 +297,18 @@ void ima_free_template_entry(struct ima_template_entry *entry);
const char *ima_d_path(const struct path *path, char **pathbuf, char *filename);

/* IMA policy related functions */
-int ima_match_policy(struct user_namespace *mnt_userns, struct inode *inode,
+int ima_match_policy(struct ima_namespace *ns,
+ struct user_namespace *mnt_userns, struct inode *inode,
const struct cred *cred, u32 secid, enum ima_hooks func,
int mask, int flags, int *pcr,
struct ima_template_desc **template_desc,
const char *func_data, unsigned int *allowed_algos);
-void ima_init_policy(void);
-void ima_update_policy(void);
-void ima_update_policy_flags(void);
-ssize_t ima_parse_add_rule(char *);
-void ima_delete_rules(void);
-int ima_check_policy(void);
+void ima_init_policy(struct ima_namespace *ns);
+void ima_update_policy(struct ima_namespace *ns);
+void ima_update_policy_flags(struct ima_namespace *ns);
+ssize_t ima_parse_add_rule(struct ima_namespace *ns, char *rule);
+void ima_delete_rules(struct ima_namespace *ns);
+int ima_check_policy(struct ima_namespace *ns);
void *ima_policy_start(struct seq_file *m, loff_t *pos);
void *ima_policy_next(struct seq_file *m, void *v, loff_t *pos);
void ima_policy_stop(struct seq_file *m, void *v);
@@ -311,14 +324,16 @@ int ima_policy_show(struct seq_file *m, void *v);
#define IMA_APPRAISE_KEXEC 0x40

#ifdef CONFIG_IMA_APPRAISE
-int ima_check_blacklist(struct integrity_iint_cache *iint,
+int ima_check_blacklist(struct ima_namespace *ns,
+ struct integrity_iint_cache *iint,
const struct modsig *modsig, int pcr);
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, const struct modsig *modsig);
-int ima_must_appraise(struct user_namespace *mnt_userns, struct inode *inode,
+int ima_must_appraise(struct ima_namespace *ns,
+ struct user_namespace *mnt_userns, 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,
@@ -329,7 +344,8 @@ int ima_read_xattr(struct dentry *dentry,
struct evm_ima_xattr_data **xattr_value);

#else
-static inline int ima_check_blacklist(struct integrity_iint_cache *iint,
+static inline int ima_check_blacklist(struct ima_namespace *ns,
+ struct integrity_iint_cache *iint,
const struct modsig *modsig, int pcr)
{
return 0;
@@ -346,7 +362,8 @@ static inline int ima_appraise_measurement(enum ima_hooks func,
return INTEGRITY_UNKNOWN;
}

-static inline int ima_must_appraise(struct user_namespace *mnt_userns,
+static inline int ima_must_appraise(struct ima_namespace *ns,
+ struct user_namespace *mnt_userns,
struct inode *inode, int mask,
enum ima_hooks func)
{
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c
index a64fb0130b01..2df0d8549c13 100644
--- a/security/integrity/ima/ima_api.c
+++ b/security/integrity/ima/ima_api.c
@@ -162,6 +162,7 @@ void ima_add_violation(struct file *file, const unsigned char *filename,

/**
* ima_get_action - appraise & measure decision based on policy.
+ * @ns: IMA namespace that has the policy
* @mnt_userns: user namespace of the mount the inode was found from
* @inode: pointer to the inode associated with the object being validated
* @cred: pointer to credentials structure to validate
@@ -185,7 +186,8 @@ void ima_add_violation(struct file *file, const unsigned char *filename,
* Returns IMA_MEASURE, IMA_APPRAISE mask.
*
*/
-int ima_get_action(struct user_namespace *mnt_userns, struct inode *inode,
+int ima_get_action(struct ima_namespace *ns,
+ struct user_namespace *mnt_userns, struct inode *inode,
const struct cred *cred, u32 secid, int mask,
enum ima_hooks func, int *pcr,
struct ima_template_desc **template_desc,
@@ -193,9 +195,9 @@ int ima_get_action(struct user_namespace *mnt_userns, struct inode *inode,
{
int flags = IMA_MEASURE | IMA_AUDIT | IMA_APPRAISE | IMA_HASH;

- flags &= ima_policy_flag;
+ flags &= ns->ima_policy_flag;

- return ima_match_policy(mnt_userns, inode, cred, secid, func, mask,
+ return ima_match_policy(ns, mnt_userns, inode, cred, secid, func, mask,
flags, pcr, template_desc, func_data,
allowed_algos);
}
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c
index 17232bbfb9f9..f1b99b895c68 100644
--- a/security/integrity/ima/ima_appraise.c
+++ b/security/integrity/ima/ima_appraise.c
@@ -68,7 +68,8 @@ bool is_ima_appraise_enabled(void)
*
* Return 1 to appraise or hash
*/
-int ima_must_appraise(struct user_namespace *mnt_userns, struct inode *inode,
+int ima_must_appraise(struct ima_namespace *ns,
+ struct user_namespace *mnt_userns, struct inode *inode,
int mask, enum ima_hooks func)
{
u32 secid;
@@ -77,7 +78,7 @@ int ima_must_appraise(struct user_namespace *mnt_userns, struct inode *inode,
return 0;

security_current_getsecid_subj(&secid);
- return ima_match_policy(mnt_userns, inode, current_cred(), secid,
+ return ima_match_policy(ns, mnt_userns, inode, current_cred(), secid,
func, mask, IMA_APPRAISE | IMA_HASH, NULL,
NULL, NULL, NULL);
}
@@ -341,7 +342,8 @@ static int modsig_verify(enum ima_hooks func, const struct modsig *modsig,
*
* Returns -EPERM if the hash is blacklisted.
*/
-int ima_check_blacklist(struct integrity_iint_cache *iint,
+int ima_check_blacklist(struct ima_namespace *ns,
+ struct integrity_iint_cache *iint,
const struct modsig *modsig, int pcr)
{
enum hash_algo hash_algo;
@@ -357,7 +359,8 @@ int ima_check_blacklist(struct integrity_iint_cache *iint,

rc = is_binary_blacklisted(digest, digestsize);
if ((rc == -EPERM) && (iint->flags & IMA_MEASURE))
- process_buffer_measurement(&init_user_ns, NULL, digest, digestsize,
+ process_buffer_measurement(ns, &init_user_ns, NULL,
+ digest, digestsize,
"blacklisted-hash", NONE,
pcr, NULL, false, NULL, 0);
}
@@ -527,14 +530,16 @@ void ima_inode_post_setattr(struct user_namespace *mnt_userns,
struct dentry *dentry)
{
struct inode *inode = d_backing_inode(dentry);
+ struct ima_namespace *ns = &init_ima_ns;
struct integrity_iint_cache *iint;
int action;

- if (!(ima_policy_flag & IMA_APPRAISE) || !S_ISREG(inode->i_mode)
+ if (!(ns->ima_policy_flag & IMA_APPRAISE) || !S_ISREG(inode->i_mode)
|| !(inode->i_opflags & IOP_XATTR))
return;

- action = ima_must_appraise(mnt_userns, inode, MAY_ACCESS, POST_SETATTR);
+ action = ima_must_appraise(ns, mnt_userns, inode, MAY_ACCESS,
+ POST_SETATTR);
iint = integrity_iint_find(inode);
if (iint) {
set_bit(IMA_CHANGE_ATTR, &iint->atomic_flags);
@@ -559,11 +564,12 @@ static int ima_protect_xattr(struct dentry *dentry, const char *xattr_name,
return 0;
}

-static void ima_reset_appraise_flags(struct inode *inode, int digsig)
+static void ima_reset_appraise_flags(struct ima_namespace *ns,
+ struct inode *inode, int digsig)
{
struct integrity_iint_cache *iint;

- if (!(ima_policy_flag & IMA_APPRAISE) || !S_ISREG(inode->i_mode))
+ if (!(ns->ima_policy_flag & IMA_APPRAISE) || !S_ISREG(inode->i_mode))
return;

iint = integrity_iint_find(inode);
@@ -641,6 +647,7 @@ int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name,
const void *xattr_value, size_t xattr_value_len)
{
const struct evm_ima_xattr_data *xvalue = xattr_value;
+ struct ima_namespace *ns = &init_ima_ns;
int digsig = 0;
int result;

@@ -658,18 +665,19 @@ int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name,
if (result)
return result;

- ima_reset_appraise_flags(d_backing_inode(dentry), digsig);
+ ima_reset_appraise_flags(ns, d_backing_inode(dentry), digsig);
}
return result;
}

int ima_inode_removexattr(struct dentry *dentry, const char *xattr_name)
{
+ struct ima_namespace *ns = &init_ima_ns;
int result;

result = ima_protect_xattr(dentry, xattr_name, NULL, 0);
if (result == 1 || evm_revalidate_status(xattr_name)) {
- ima_reset_appraise_flags(d_backing_inode(dentry), 0);
+ ima_reset_appraise_flags(ns, d_backing_inode(dentry), 0);
if (result == 1)
result = 0;
}
diff --git a/security/integrity/ima/ima_asymmetric_keys.c b/security/integrity/ima/ima_asymmetric_keys.c
index f6aa0b47a772..70d87df26068 100644
--- a/security/integrity/ima/ima_asymmetric_keys.c
+++ b/security/integrity/ima/ima_asymmetric_keys.c
@@ -30,6 +30,7 @@ void ima_post_key_create_or_update(struct key *keyring, struct key *key,
const void *payload, size_t payload_len,
unsigned long flags, bool create)
{
+ struct ima_namespace *ns = &init_ima_ns;
bool queued = false;

/* Only asymmetric keys are handled by this hook. */
@@ -60,7 +61,8 @@ void ima_post_key_create_or_update(struct key *keyring, struct key *key,
* if the IMA policy is configured to measure a key linked
* to the given keyring.
*/
- process_buffer_measurement(&init_user_ns, NULL, payload, payload_len,
+ process_buffer_measurement(ns, &init_user_ns, NULL,
+ payload, payload_len,
keyring->description, KEY_CHECK, 0,
keyring->description, false, NULL, 0);
}
diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c
index cd1683dad3bf..f7ad93a56982 100644
--- a/security/integrity/ima/ima_fs.c
+++ b/security/integrity/ima/ima_fs.c
@@ -271,7 +271,7 @@ static const struct file_operations ima_ascii_measurements_ops = {
.release = seq_release,
};

-static ssize_t ima_read_policy(char *path)
+static ssize_t ima_read_policy(struct ima_namespace *ns, char *path)
{
void *data = NULL;
char *datap;
@@ -296,7 +296,7 @@ static ssize_t ima_read_policy(char *path)
datap = data;
while (size > 0 && (p = strsep(&datap, "\n"))) {
pr_debug("rule: %s\n", p);
- rc = ima_parse_add_rule(p);
+ rc = ima_parse_add_rule(ns, p);
if (rc < 0)
break;
size -= rc;
@@ -314,6 +314,7 @@ static ssize_t ima_read_policy(char *path)
static ssize_t ima_write_policy(struct file *file, const char __user *buf,
size_t datalen, loff_t *ppos)
{
+ struct ima_namespace *ns = &init_ima_ns;
char *data;
ssize_t result;

@@ -336,7 +337,7 @@ static ssize_t ima_write_policy(struct file *file, const char __user *buf,
goto out_free;

if (data[0] == '/') {
- result = ima_read_policy(data);
+ result = ima_read_policy(ns, data);
} else if (ima_appraise & IMA_APPRAISE_POLICY) {
pr_err("signed policy file (specified as an absolute pathname) required\n");
integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, NULL,
@@ -344,7 +345,7 @@ static ssize_t ima_write_policy(struct file *file, const char __user *buf,
1, 0);
result = -EACCES;
} else {
- result = ima_parse_add_rule(data);
+ result = ima_parse_add_rule(ns, data);
}
mutex_unlock(&ima_write_mutex);
out_free:
@@ -410,11 +411,12 @@ static int ima_open_policy(struct inode *inode, struct file *filp)
static int ima_release_policy(struct inode *inode, struct file *file)
{
const char *cause = valid_policy ? "completed" : "failed";
+ struct ima_namespace *ns = &init_ima_ns;

if ((file->f_flags & O_ACCMODE) == O_RDONLY)
return seq_release(inode, file);

- if (valid_policy && ima_check_policy() < 0) {
+ if (valid_policy && ima_check_policy(ns) < 0) {
cause = "failed";
valid_policy = 0;
}
@@ -424,13 +426,13 @@ static int ima_release_policy(struct inode *inode, struct file *file)
"policy_update", cause, !valid_policy, 0);

if (!valid_policy) {
- ima_delete_rules();
+ ima_delete_rules(ns);
valid_policy = 1;
clear_bit(IMA_FS_BUSY, &ima_fs_flags);
return 0;
}

- ima_update_policy();
+ ima_update_policy(ns);
#if !defined(CONFIG_IMA_WRITE_POLICY) && !defined(CONFIG_IMA_READ_POLICY)
securityfs_remove(ima_policy);
ima_policy = NULL;
diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c
index b26fa67476b4..d6b829c360d7 100644
--- a/security/integrity/ima/ima_init.c
+++ b/security/integrity/ima/ima_init.c
@@ -104,15 +104,15 @@ 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 = init_ima_ns.ima_policy_flag & IMA_APPRAISE;

- ima_policy_flag &= ~unset_flags;
+ init_ima_ns.ima_policy_flag &= ~unset_flags;
integrity_load_x509(INTEGRITY_KEYRING_IMA, CONFIG_IMA_X509_PATH);

/* load also EVM key to avoid appraisal */
evm_load_x509();

- ima_policy_flag |= unset_flags;
+ init_ima_ns.ima_policy_flag |= unset_flags;
}
#endif

@@ -120,6 +120,10 @@ int __init ima_init(void)
{
int rc;

+ rc = ima_ns_init();
+ if (rc)
+ return rc;
+
ima_tpm_chip = tpm_default_chip();
if (!ima_tpm_chip)
pr_info("No TPM chip found, activating TPM-bypass!\n");
@@ -145,7 +149,7 @@ int __init ima_init(void)
if (rc != 0)
return rc;

- ima_init_policy();
+ ima_init_policy(&init_ima_ns);

rc = ima_fs_init();
if (rc != 0)
diff --git a/security/integrity/ima/ima_init_ima_ns.c b/security/integrity/ima/ima_init_ima_ns.c
new file mode 100644
index 000000000000..c919a456b525
--- /dev/null
+++ b/security/integrity/ima/ima_init_ima_ns.c
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2016-2022 IBM Corporation
+ * Author:
+ * Yuqiong Sun <suny@xxxxxxxxxx>
+ * Stefan Berger <stefanb@xxxxxxxxxxxxxxxxxx>
+ */
+
+#include "ima.h"
+
+static int ima_init_namespace(struct ima_namespace *ns)
+{
+ INIT_LIST_HEAD(&ns->ima_default_rules);
+ INIT_LIST_HEAD(&ns->ima_policy_rules);
+ INIT_LIST_HEAD(&ns->ima_temp_rules);
+ ns->ima_rules = (struct list_head __rcu *)(&ns->ima_default_rules);
+ ns->ima_policy_flag = 0;
+
+ return 0;
+}
+
+int __init ima_ns_init(void)
+{
+ return ima_init_namespace(&init_ima_ns);
+}
+
+struct ima_namespace init_ima_ns = {
+};
+EXPORT_SYMBOL(init_ima_ns);
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 8c6e4514d494..9dc48ea216a5 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -185,10 +185,11 @@ static void ima_check_last_writer(struct integrity_iint_cache *iint,
*/
void ima_file_free(struct file *file)
{
+ struct ima_namespace *ns = &init_ima_ns;
struct inode *inode = file_inode(file);
struct integrity_iint_cache *iint;

- if (!ima_policy_flag || !S_ISREG(inode->i_mode))
+ if (!ns->ima_policy_flag || !S_ISREG(inode->i_mode))
return;

iint = integrity_iint_find(inode);
@@ -198,7 +199,8 @@ void ima_file_free(struct file *file)
ima_check_last_writer(iint, inode, file);
}

-static int process_measurement(struct file *file, const struct cred *cred,
+static int process_measurement(struct ima_namespace *ns,
+ struct file *file, const struct cred *cred,
u32 secid, char *buf, loff_t size, int mask,
enum ima_hooks func)
{
@@ -217,18 +219,18 @@ static int process_measurement(struct file *file, const struct cred *cred,
enum hash_algo hash_algo;
unsigned int allowed_algos = 0;

- if (!ima_policy_flag || !S_ISREG(inode->i_mode))
+ if (!ns->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(file_mnt_user_ns(file), inode, cred, secid,
+ action = ima_get_action(ns, file_mnt_user_ns(file), inode, cred, secid,
mask, func, &pcr, &template_desc, NULL,
&allowed_algos);
violation_check = ((func == FILE_CHECK || func == MMAP_CHECK) &&
- (ima_policy_flag & IMA_MEASURE));
+ (ns->ima_policy_flag & IMA_MEASURE));
if (!action && !violation_check)
return 0;

@@ -346,7 +348,7 @@ static int process_measurement(struct file *file, const struct cred *cred,
xattr_value, xattr_len, modsig, pcr,
template_desc);
if (rc == 0 && (action & IMA_APPRAISE_SUBMASK)) {
- rc = ima_check_blacklist(iint, modsig, pcr);
+ rc = ima_check_blacklist(ns, iint, modsig, pcr);
if (rc != -EPERM) {
inode_lock(inode);
rc = ima_appraise_measurement(func, iint, file,
@@ -405,12 +407,13 @@ static int process_measurement(struct file *file, const struct cred *cred,
*/
int ima_file_mmap(struct file *file, unsigned long prot)
{
+ struct ima_namespace *ns = &init_ima_ns;
u32 secid;

if (file && (prot & PROT_EXEC)) {
security_current_getsecid_subj(&secid);
- return process_measurement(file, current_cred(), secid, NULL,
- 0, MAY_EXEC, MMAP_CHECK);
+ return process_measurement(ns, file, current_cred(), secid,
+ NULL, 0, MAY_EXEC, MMAP_CHECK);
}

return 0;
@@ -430,6 +433,7 @@ int ima_file_mmap(struct file *file, unsigned long prot)
*/
int ima_file_mprotect(struct vm_area_struct *vma, unsigned long prot)
{
+ struct ima_namespace *ns = &init_ima_ns;
struct ima_template_desc *template = NULL;
struct file *file = vma->vm_file;
char filename[NAME_MAX];
@@ -442,13 +446,13 @@ int ima_file_mprotect(struct vm_area_struct *vma, unsigned long prot)
int pcr;

/* Is mprotect making an mmap'ed file executable? */
- if (!(ima_policy_flag & IMA_APPRAISE) || !vma->vm_file ||
+ if (!(ns->ima_policy_flag & IMA_APPRAISE) || !vma->vm_file ||
!(prot & PROT_EXEC) || (vma->vm_flags & VM_EXEC))
return 0;

security_current_getsecid_subj(&secid);
inode = file_inode(vma->vm_file);
- action = ima_get_action(file_mnt_user_ns(vma->vm_file), inode,
+ action = ima_get_action(ns, file_mnt_user_ns(vma->vm_file), inode,
current_cred(), secid, MAY_EXEC, MMAP_CHECK,
&pcr, &template, NULL, NULL);

@@ -484,17 +488,18 @@ int ima_file_mprotect(struct vm_area_struct *vma, unsigned long prot)
*/
int ima_bprm_check(struct linux_binprm *bprm)
{
+ struct ima_namespace *ns = &init_ima_ns;
int ret;
u32 secid;

security_current_getsecid_subj(&secid);
- ret = process_measurement(bprm->file, current_cred(), secid, NULL, 0,
- MAY_EXEC, BPRM_CHECK);
+ ret = process_measurement(ns, bprm->file, current_cred(), secid, NULL,
+ 0, MAY_EXEC, BPRM_CHECK);
if (ret)
return ret;

security_cred_getsecid(bprm->cred, &secid);
- return process_measurement(bprm->file, bprm->cred, secid, NULL, 0,
+ return process_measurement(ns, bprm->file, bprm->cred, secid, NULL, 0,
MAY_EXEC, CREDS_CHECK);
}

@@ -510,21 +515,23 @@ int ima_bprm_check(struct linux_binprm *bprm)
*/
int ima_file_check(struct file *file, int mask)
{
+ struct ima_namespace *ns = &init_ima_ns;
u32 secid;

security_current_getsecid_subj(&secid);
- return process_measurement(file, current_cred(), secid, NULL, 0,
+ return process_measurement(ns, file, current_cred(), secid, NULL, 0,
mask & (MAY_READ | MAY_WRITE | MAY_EXEC |
MAY_APPEND), FILE_CHECK);
}
EXPORT_SYMBOL_GPL(ima_file_check);

-static int __ima_inode_hash(struct inode *inode, char *buf, size_t buf_size)
+static int __ima_inode_hash(struct ima_namespace *ns,
+ struct inode *inode, char *buf, size_t buf_size)
{
struct integrity_iint_cache *iint;
int hash_algo;

- if (!ima_policy_flag)
+ if (!ns->ima_policy_flag)
return -EOPNOTSUPP;

iint = integrity_iint_find(inode);
@@ -574,10 +581,12 @@ static int __ima_inode_hash(struct inode *inode, char *buf, size_t buf_size)
*/
int ima_file_hash(struct file *file, char *buf, size_t buf_size)
{
+ struct ima_namespace *ns = &init_ima_ns;
+
if (!file)
return -EINVAL;

- return __ima_inode_hash(file_inode(file), buf, buf_size);
+ return __ima_inode_hash(ns, file_inode(file), buf, buf_size);
}
EXPORT_SYMBOL_GPL(ima_file_hash);

@@ -601,10 +610,12 @@ EXPORT_SYMBOL_GPL(ima_file_hash);
*/
int ima_inode_hash(struct inode *inode, char *buf, size_t buf_size)
{
+ struct ima_namespace *ns = &init_ima_ns;
+
if (!inode)
return -EINVAL;

- return __ima_inode_hash(inode, buf, buf_size);
+ return __ima_inode_hash(ns, inode, buf, buf_size);
}
EXPORT_SYMBOL_GPL(ima_inode_hash);

@@ -620,13 +631,14 @@ EXPORT_SYMBOL_GPL(ima_inode_hash);
void ima_post_create_tmpfile(struct user_namespace *mnt_userns,
struct inode *inode)
{
+ struct ima_namespace *ns = &init_ima_ns;
struct integrity_iint_cache *iint;
int must_appraise;

- if (!ima_policy_flag || !S_ISREG(inode->i_mode))
+ if (!ns->ima_policy_flag || !S_ISREG(inode->i_mode))
return;

- must_appraise = ima_must_appraise(mnt_userns, inode, MAY_ACCESS,
+ must_appraise = ima_must_appraise(ns, mnt_userns, inode, MAY_ACCESS,
FILE_CHECK);
if (!must_appraise)
return;
@@ -652,14 +664,15 @@ void ima_post_create_tmpfile(struct user_namespace *mnt_userns,
void ima_post_path_mknod(struct user_namespace *mnt_userns,
struct dentry *dentry)
{
+ struct ima_namespace *ns = &init_ima_ns;
struct integrity_iint_cache *iint;
struct inode *inode = dentry->d_inode;
int must_appraise;

- if (!ima_policy_flag || !S_ISREG(inode->i_mode))
+ if (!ns->ima_policy_flag || !S_ISREG(inode->i_mode))
return;

- must_appraise = ima_must_appraise(mnt_userns, inode, MAY_ACCESS,
+ must_appraise = ima_must_appraise(ns, mnt_userns, inode, MAY_ACCESS,
FILE_CHECK);
if (!must_appraise)
return;
@@ -688,6 +701,7 @@ void ima_post_path_mknod(struct user_namespace *mnt_userns,
int ima_read_file(struct file *file, enum kernel_read_file_id read_id,
bool contents)
{
+ struct ima_namespace *ns = &init_ima_ns;
enum ima_hooks func;
u32 secid;

@@ -710,7 +724,7 @@ int ima_read_file(struct file *file, enum kernel_read_file_id read_id,
/* Read entire file for all partial reads. */
func = read_idmap[read_id] ?: FILE_CHECK;
security_current_getsecid_subj(&secid);
- return process_measurement(file, current_cred(), secid, NULL,
+ return process_measurement(ns, file, current_cred(), secid, NULL,
0, MAY_READ, func);
}

@@ -738,6 +752,7 @@ const int read_idmap[READING_MAX_ID] = {
int ima_post_read_file(struct file *file, void *buf, loff_t size,
enum kernel_read_file_id read_id)
{
+ struct ima_namespace *ns = &init_ima_ns;
enum ima_hooks func;
u32 secid;

@@ -746,14 +761,15 @@ 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 (ns == &init_ima_ns &&
+ (ima_appraise & IMA_APPRAISE_ENFORCE))
return -EACCES;
return 0;
}

func = read_idmap[read_id] ?: FILE_CHECK;
security_current_getsecid_subj(&secid);
- return process_measurement(file, current_cred(), secid, buf, size,
+ return process_measurement(ns, file, current_cred(), secid, buf, size,
MAY_READ, func);
}

@@ -841,6 +857,7 @@ int ima_post_load_data(char *buf, loff_t size,

/**
* process_buffer_measurement - Measure the buffer or the buffer data hash
+ * @ns: IMA namespace that has the policy
* @mnt_userns: user namespace of the mount the inode was found from
* @inode: inode associated with the object being measured (NULL for KEY_CHECK)
* @buf: pointer to the buffer that needs to be added to the log.
@@ -859,7 +876,8 @@ int ima_post_load_data(char *buf, loff_t size,
* has been written to the passed location but not added to a measurement entry,
* a negative value otherwise.
*/
-int process_buffer_measurement(struct user_namespace *mnt_userns,
+int process_buffer_measurement(struct ima_namespace *ns,
+ struct user_namespace *mnt_userns,
struct inode *inode, const void *buf, int size,
const char *eventname, enum ima_hooks func,
int pcr, const char *func_data,
@@ -887,7 +905,7 @@ int process_buffer_measurement(struct user_namespace *mnt_userns,
if (digest && digest_len < digest_hash_len)
return -EINVAL;

- if (!ima_policy_flag && !digest)
+ if (!ns->ima_policy_flag && !digest)
return -ENOENT;

template = ima_template_desc_buf();
@@ -906,7 +924,7 @@ int process_buffer_measurement(struct user_namespace *mnt_userns,
*/
if (func) {
security_current_getsecid_subj(&secid);
- action = ima_get_action(mnt_userns, inode, current_cred(),
+ action = ima_get_action(ns, mnt_userns, inode, current_cred(),
secid, 0, func, &pcr, &template,
func_data, NULL);
if (!(action & IMA_MEASURE) && !digest)
@@ -943,7 +961,7 @@ int process_buffer_measurement(struct user_namespace *mnt_userns,
if (digest)
memcpy(digest, iint.ima_hash->digest, digest_hash_len);

- if (!ima_policy_flag || (func && !(action & IMA_MEASURE)))
+ if (!ns->ima_policy_flag || (func && !(action & IMA_MEASURE)))
return 1;

ret = ima_alloc_init_template(&event_data, &entry, template);
@@ -977,6 +995,7 @@ int process_buffer_measurement(struct user_namespace *mnt_userns,
*/
void ima_kexec_cmdline(int kernel_fd, const void *buf, int size)
{
+ struct ima_namespace *ns = &init_ima_ns;
struct fd f;

if (!buf || !size)
@@ -986,7 +1005,8 @@ void ima_kexec_cmdline(int kernel_fd, const void *buf, int size)
if (!f.file)
return;

- process_buffer_measurement(file_mnt_user_ns(f.file), file_inode(f.file),
+ process_buffer_measurement(ns,
+ file_mnt_user_ns(f.file), file_inode(f.file),
buf, size, "kexec-cmdline", KEXEC_CMDLINE, 0,
NULL, false, NULL, 0);
fdput(f);
@@ -1016,10 +1036,12 @@ int ima_measure_critical_data(const char *event_label,
const void *buf, size_t buf_len,
bool hash, u8 *digest, size_t digest_len)
{
+ struct ima_namespace *ns = &init_ima_ns;
+
if (!event_name || !event_label || !buf || !buf_len)
return -ENOPARAM;

- return process_buffer_measurement(&init_user_ns, NULL, buf, buf_len,
+ return process_buffer_measurement(ns, &init_user_ns, NULL, buf, buf_len,
event_name, CRITICAL_DATA, 0,
event_label, hash, digest,
digest_len);
@@ -1028,6 +1050,7 @@ EXPORT_SYMBOL_GPL(ima_measure_critical_data);

static int __init init_ima(void)
{
+ struct ima_namespace *ns = &init_ima_ns;
int error;

ima_appraise_parse_cmdline();
@@ -1052,7 +1075,7 @@ static int __init init_ima(void)
pr_warn("Couldn't register LSM notifier, error %d\n", error);

if (!error)
- ima_update_policy_flags();
+ ima_update_policy_flags(ns);

return error;
}
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index 2a1f6418b10a..b0e1c16b7f37 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -52,7 +52,6 @@
#define INVALID_PCR(a) (((a) < 0) || \
(a) >= (sizeof_field(struct integrity_iint_cache, measured_pcrs) * 8))

-int ima_policy_flag;
static int temp_ima_appraise;
static int build_ima_appraise __ro_after_init;

@@ -233,11 +232,6 @@ static struct ima_rule_entry critical_data_rules[] __ro_after_init = {
/* An array of architecture specific rules */
static struct ima_rule_entry *arch_policy_entry __ro_after_init;

-static LIST_HEAD(ima_default_rules);
-static LIST_HEAD(ima_policy_rules);
-static LIST_HEAD(ima_temp_rules);
-static struct list_head __rcu *ima_rules = (struct list_head __rcu *)(&ima_default_rules);
-
static int ima_policy __initdata;

static int __init default_measure_policy_setup(char *str)
@@ -454,12 +448,12 @@ static bool ima_rule_contains_lsm_cond(struct ima_rule_entry *entry)
* to the old, stale LSM policy. Update the IMA LSM based rules to reflect
* the reloaded LSM policy.
*/
-static void ima_lsm_update_rules(void)
+static void ima_lsm_update_rules(struct ima_namespace *ns)
{
struct ima_rule_entry *entry, *e;
int result;

- list_for_each_entry_safe(entry, e, &ima_policy_rules, list) {
+ list_for_each_entry_safe(entry, e, &ns->ima_policy_rules, list) {
if (!ima_rule_contains_lsm_cond(entry))
continue;

@@ -474,10 +468,12 @@ static void ima_lsm_update_rules(void)
int ima_lsm_policy_change(struct notifier_block *nb, unsigned long event,
void *lsm_data)
{
+ struct ima_namespace *ns = &init_ima_ns;
+
if (event != LSM_POLICY_CHANGE)
return NOTIFY_DONE;

- ima_lsm_update_rules();
+ ima_lsm_update_rules(ns);
return NOTIFY_OK;
}

@@ -669,6 +665,7 @@ static int get_subaction(struct ima_rule_entry *rule, enum ima_hooks func)

/**
* ima_match_policy - decision based on LSM and other conditions
+ * @ns: IMA namespace that has the policy
* @mnt_userns: user namespace of the mount the inode was found from
* @inode: pointer to an inode for which the policy decision is being made
* @cred: pointer to a credentials structure for which the policy decision is
@@ -688,7 +685,8 @@ static int get_subaction(struct ima_rule_entry *rule, enum ima_hooks func)
* list when walking it. Reads are many orders of magnitude more numerous
* than writes so ima_match_policy() is classical RCU candidate.
*/
-int ima_match_policy(struct user_namespace *mnt_userns, struct inode *inode,
+int ima_match_policy(struct ima_namespace *ns,
+ struct user_namespace *mnt_userns, struct inode *inode,
const struct cred *cred, u32 secid, enum ima_hooks func,
int mask, int flags, int *pcr,
struct ima_template_desc **template_desc,
@@ -702,7 +700,7 @@ int ima_match_policy(struct user_namespace *mnt_userns, struct inode *inode,
*template_desc = ima_template_desc_current();

rcu_read_lock();
- ima_rules_tmp = rcu_dereference(ima_rules);
+ ima_rules_tmp = rcu_dereference(ns->ima_rules);
list_for_each_entry_rcu(entry, ima_rules_tmp, list) {

if (!(entry->action & actmask))
@@ -746,8 +744,8 @@ int ima_match_policy(struct user_namespace *mnt_userns, struct inode *inode,
}

/**
- * ima_update_policy_flags() - Update global IMA variables
- *
+ * ima_update_policy_flags() - Update namespaced IMA variables
+ * @ns: IMA namespace that has the policy
* Update ima_policy_flag and ima_setxattr_allowed_hash_algorithms
* based on the currently loaded policy.
*
@@ -760,14 +758,14 @@ int ima_match_policy(struct user_namespace *mnt_userns, struct inode *inode,
*
* Context: called after a policy update and at system initialization.
*/
-void ima_update_policy_flags(void)
+void ima_update_policy_flags(struct ima_namespace *ns)
{
struct ima_rule_entry *entry;
int new_policy_flag = 0;
struct list_head *ima_rules_tmp;

rcu_read_lock();
- ima_rules_tmp = rcu_dereference(ima_rules);
+ ima_rules_tmp = rcu_dereference(ns->ima_rules);
list_for_each_entry_rcu(entry, ima_rules_tmp, list) {
/*
* SETXATTR_CHECK rules do not implement a full policy check
@@ -797,7 +795,7 @@ void ima_update_policy_flags(void)
if (!ima_appraise)
new_policy_flag &= ~IMA_APPRAISE;

- ima_policy_flag = new_policy_flag;
+ ns->ima_policy_flag = new_policy_flag;
}

static int ima_appraise_flag(enum ima_hooks func)
@@ -813,7 +811,8 @@ static int ima_appraise_flag(enum ima_hooks func)
return 0;
}

-static void add_rules(struct ima_rule_entry *entries, int count,
+static void add_rules(struct ima_namespace *ns,
+ struct ima_rule_entry *entries, int count,
enum policy_rule_list policy_rule)
{
int i = 0;
@@ -822,7 +821,7 @@ static void add_rules(struct ima_rule_entry *entries, int count,
struct ima_rule_entry *entry;

if (policy_rule & IMA_DEFAULT_POLICY)
- list_add_tail(&entries[i].list, &ima_default_rules);
+ list_add_tail(&entries[i].list, &ns->ima_default_rules);

if (policy_rule & IMA_CUSTOM_POLICY) {
entry = kmemdup(&entries[i], sizeof(*entry),
@@ -830,7 +829,7 @@ static void add_rules(struct ima_rule_entry *entries, int count,
if (!entry)
continue;

- list_add_tail(&entry->list, &ima_policy_rules);
+ list_add_tail(&entry->list, &ns->ima_policy_rules);
}
if (entries[i].action == APPRAISE) {
if (entries != build_appraise_rules)
@@ -843,9 +842,10 @@ static void add_rules(struct ima_rule_entry *entries, int count,
}
}

-static int ima_parse_rule(char *rule, struct ima_rule_entry *entry);
+static int ima_parse_rule(struct ima_namespace *ns,
+ char *rule, struct ima_rule_entry *entry);

-static int __init ima_init_arch_policy(void)
+static int __init ima_init_arch_policy(struct ima_namespace *ns)
{
const char * const *arch_rules;
const char * const *rules;
@@ -873,7 +873,7 @@ static int __init ima_init_arch_policy(void)
result = strscpy(rule, *rules, sizeof(rule));

INIT_LIST_HEAD(&arch_policy_entry[i].list);
- result = ima_parse_rule(rule, &arch_policy_entry[i]);
+ result = ima_parse_rule(ns, rule, &arch_policy_entry[i]);
if (result) {
pr_warn("Skipping unknown architecture policy rule: %s\n",
rule);
@@ -888,26 +888,27 @@ static int __init ima_init_arch_policy(void)

/**
* ima_init_policy - initialize the default measure rules.
- *
+ * @ns: IMA namespace to which the policy belongs to
* ima_rules points to either the ima_default_rules or the new ima_policy_rules.
*/
-void __init ima_init_policy(void)
+void __init ima_init_policy(struct ima_namespace *ns)
{
int build_appraise_entries, arch_entries;

/* if !ima_policy, we load NO default rules */
if (ima_policy)
- add_rules(dont_measure_rules, ARRAY_SIZE(dont_measure_rules),
+ add_rules(ns, dont_measure_rules,
+ ARRAY_SIZE(dont_measure_rules),
IMA_DEFAULT_POLICY);

switch (ima_policy) {
case ORIGINAL_TCB:
- add_rules(original_measurement_rules,
+ add_rules(ns, original_measurement_rules,
ARRAY_SIZE(original_measurement_rules),
IMA_DEFAULT_POLICY);
break;
case DEFAULT_TCB:
- add_rules(default_measurement_rules,
+ add_rules(ns, default_measurement_rules,
ARRAY_SIZE(default_measurement_rules),
IMA_DEFAULT_POLICY);
break;
@@ -921,11 +922,11 @@ void __init ima_init_policy(void)
* and custom policies, prior to other appraise rules.
* (Highest priority)
*/
- arch_entries = ima_init_arch_policy();
+ arch_entries = ima_init_arch_policy(ns);
if (!arch_entries)
pr_info("No architecture policies found\n");
else
- add_rules(arch_policy_entry, arch_entries,
+ add_rules(ns, arch_policy_entry, arch_entries,
IMA_DEFAULT_POLICY | IMA_CUSTOM_POLICY);

/*
@@ -933,7 +934,7 @@ void __init ima_init_policy(void)
* signatures, prior to other appraise rules.
*/
if (ima_use_secure_boot)
- add_rules(secure_boot_rules, ARRAY_SIZE(secure_boot_rules),
+ add_rules(ns, secure_boot_rules, ARRAY_SIZE(secure_boot_rules),
IMA_DEFAULT_POLICY);

/*
@@ -945,39 +946,41 @@ void __init ima_init_policy(void)
build_appraise_entries = ARRAY_SIZE(build_appraise_rules);
if (build_appraise_entries) {
if (ima_use_secure_boot)
- add_rules(build_appraise_rules, build_appraise_entries,
+ add_rules(ns, build_appraise_rules,
+ build_appraise_entries,
IMA_CUSTOM_POLICY);
else
- add_rules(build_appraise_rules, build_appraise_entries,
+ add_rules(ns, build_appraise_rules,
+ build_appraise_entries,
IMA_DEFAULT_POLICY | IMA_CUSTOM_POLICY);
}

if (ima_use_appraise_tcb)
- add_rules(default_appraise_rules,
+ add_rules(ns, default_appraise_rules,
ARRAY_SIZE(default_appraise_rules),
IMA_DEFAULT_POLICY);

if (ima_use_critical_data)
- add_rules(critical_data_rules,
+ add_rules(ns, critical_data_rules,
ARRAY_SIZE(critical_data_rules),
IMA_DEFAULT_POLICY);

atomic_set(&ima_setxattr_allowed_hash_algorithms, 0);

- ima_update_policy_flags();
+ ima_update_policy_flags(ns);
}

/* Make sure we have a valid policy, at least containing some rules. */
-int ima_check_policy(void)
+int ima_check_policy(struct ima_namespace *ns)
{
- if (list_empty(&ima_temp_rules))
+ if (list_empty(&ns->ima_temp_rules))
return -EINVAL;
return 0;
}

/**
* ima_update_policy - update default_rules with new measure rules
- *
+ * @ns: IMA namespace that has the policy
* Called on file .release to update the default rules with a complete new
* policy. What we do here is to splice ima_policy_rules and ima_temp_rules so
* they make a queue. The policy may be updated multiple times and this is the
@@ -986,16 +989,17 @@ 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_namespace *ns)
{
- struct list_head *policy = &ima_policy_rules;
+ struct list_head *policy = &ns->ima_policy_rules;

- list_splice_tail_init_rcu(&ima_temp_rules, policy, synchronize_rcu);
+ list_splice_tail_init_rcu(&ns->ima_temp_rules, policy,
+ synchronize_rcu);

- if (ima_rules != (struct list_head __rcu *)policy) {
- ima_policy_flag = 0;
+ if (ns->ima_rules != (struct list_head __rcu *)policy) {
+ ns->ima_policy_flag = 0;

- rcu_assign_pointer(ima_rules, policy);
+ rcu_assign_pointer(ns->ima_rules, policy);
/*
* IMA architecture specific policy rules are specified
* as strings and converted to an array of ima_entry_rules
@@ -1004,10 +1008,10 @@ void ima_update_policy(void)
*/
kfree(arch_policy_entry);
}
- ima_update_policy_flags();
+ ima_update_policy_flags(ns);

/* Custom IMA policy has been loaded */
- ima_process_queued_keys();
+ ima_process_queued_keys(ns);
}

/* Keep the enumeration in sync with the policy_tokens! */
@@ -1077,7 +1081,8 @@ static const match_table_t policy_tokens = {
{Opt_err, NULL}
};

-static int ima_lsm_rule_init(struct ima_rule_entry *entry,
+static int ima_lsm_rule_init(struct ima_namespace *ns,
+ struct ima_rule_entry *entry,
substring_t *args, int lsm_rule, int audit_type)
{
int result;
@@ -1097,7 +1102,8 @@ static int ima_lsm_rule_init(struct ima_rule_entry *entry,
pr_warn("rule for LSM \'%s\' is undefined\n",
entry->lsm[lsm_rule].args_p);

- if (ima_rules == (struct list_head __rcu *)(&ima_default_rules)) {
+ if (ns->ima_rules ==
+ (struct list_head __rcu *)&ns->ima_default_rules) {
kfree(entry->lsm[lsm_rule].args_p);
entry->lsm[lsm_rule].args_p = NULL;
result = -EINVAL;
@@ -1324,7 +1330,8 @@ static unsigned int ima_parse_appraise_algos(char *arg)
return res;
}

-static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
+static int ima_parse_rule(struct ima_namespace *ns,
+ char *rule, struct ima_rule_entry *entry)
{
struct audit_buffer *ab;
char *from;
@@ -1674,37 +1681,37 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
break;
case Opt_obj_user:
ima_log_string(ab, "obj_user", args[0].from);
- result = ima_lsm_rule_init(entry, args,
+ result = ima_lsm_rule_init(ns, entry, args,
LSM_OBJ_USER,
AUDIT_OBJ_USER);
break;
case Opt_obj_role:
ima_log_string(ab, "obj_role", args[0].from);
- result = ima_lsm_rule_init(entry, args,
+ result = ima_lsm_rule_init(ns, entry, args,
LSM_OBJ_ROLE,
AUDIT_OBJ_ROLE);
break;
case Opt_obj_type:
ima_log_string(ab, "obj_type", args[0].from);
- result = ima_lsm_rule_init(entry, args,
+ result = ima_lsm_rule_init(ns, entry, args,
LSM_OBJ_TYPE,
AUDIT_OBJ_TYPE);
break;
case Opt_subj_user:
ima_log_string(ab, "subj_user", args[0].from);
- result = ima_lsm_rule_init(entry, args,
+ result = ima_lsm_rule_init(ns, entry, args,
LSM_SUBJ_USER,
AUDIT_SUBJ_USER);
break;
case Opt_subj_role:
ima_log_string(ab, "subj_role", args[0].from);
- result = ima_lsm_rule_init(entry, args,
+ result = ima_lsm_rule_init(ns, entry, args,
LSM_SUBJ_ROLE,
AUDIT_SUBJ_ROLE);
break;
case Opt_subj_type:
ima_log_string(ab, "subj_type", args[0].from);
- result = ima_lsm_rule_init(entry, args,
+ result = ima_lsm_rule_init(ns, entry, args,
LSM_SUBJ_TYPE,
AUDIT_SUBJ_TYPE);
break;
@@ -1805,12 +1812,13 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)

/**
* ima_parse_add_rule - add a rule to ima_policy_rules
+ * @ns: IMA namespace that has the policy
* @rule - ima measurement policy rule
*
* Avoid locking by allowing just one writer at a time in ima_write_policy()
* Returns the length of the rule parsed, an error code on failure
*/
-ssize_t ima_parse_add_rule(char *rule)
+ssize_t ima_parse_add_rule(struct ima_namespace *ns, char *rule)
{
static const char op[] = "update_policy";
char *p;
@@ -1834,7 +1842,7 @@ ssize_t ima_parse_add_rule(char *rule)

INIT_LIST_HEAD(&entry->list);

- result = ima_parse_rule(p, entry);
+ result = ima_parse_rule(ns, p, entry);
if (result) {
ima_free_rule(entry);
integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL,
@@ -1843,23 +1851,24 @@ ssize_t ima_parse_add_rule(char *rule)
return result;
}

- list_add_tail(&entry->list, &ima_temp_rules);
+ list_add_tail(&entry->list, &ns->ima_temp_rules);

return len;
}

/**
- * ima_delete_rules() called to cleanup invalid in-flight policy.
+ * ima_delete_rules - called to cleanup invalid in-flight policy.
+ * @ns: IMA namespace that has the 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_delete_rules(struct ima_namespace *ns)
{
struct ima_rule_entry *entry, *tmp;

temp_ima_appraise = 0;
- list_for_each_entry_safe(entry, tmp, &ima_temp_rules, list) {
+ list_for_each_entry_safe(entry, tmp, &ns->ima_temp_rules, list) {
list_del(&entry->list);
ima_free_rule(entry);
}
@@ -1885,12 +1894,13 @@ static const char *const mask_tokens[] = {

void *ima_policy_start(struct seq_file *m, loff_t *pos)
{
+ struct ima_namespace *ns = &init_ima_ns;
loff_t l = *pos;
struct ima_rule_entry *entry;
struct list_head *ima_rules_tmp;

rcu_read_lock();
- ima_rules_tmp = rcu_dereference(ima_rules);
+ ima_rules_tmp = rcu_dereference(ns->ima_rules);
list_for_each_entry_rcu(entry, ima_rules_tmp, list) {
if (!l--) {
rcu_read_unlock();
@@ -1903,6 +1913,7 @@ void *ima_policy_start(struct seq_file *m, loff_t *pos)

void *ima_policy_next(struct seq_file *m, void *v, loff_t *pos)
{
+ struct ima_namespace *ns = &init_ima_ns;
struct ima_rule_entry *entry = v;

rcu_read_lock();
@@ -1910,8 +1921,8 @@ void *ima_policy_next(struct seq_file *m, void *v, loff_t *pos)
rcu_read_unlock();
(*pos)++;

- return (&entry->list == &ima_default_rules ||
- &entry->list == &ima_policy_rules) ? NULL : entry;
+ return (&entry->list == &ns->ima_default_rules ||
+ &entry->list == &ns->ima_policy_rules) ? NULL : entry;
}

void ima_policy_stop(struct seq_file *m, void *v)
@@ -2174,6 +2185,7 @@ int ima_policy_show(struct seq_file *m, void *v)
*/
bool ima_appraise_signature(enum kernel_read_file_id id)
{
+ struct ima_namespace *ns = &init_ima_ns;
struct ima_rule_entry *entry;
bool found = false;
enum ima_hooks func;
@@ -2185,7 +2197,7 @@ bool ima_appraise_signature(enum kernel_read_file_id id)
func = read_idmap[id] ?: FILE_CHECK;

rcu_read_lock();
- ima_rules_tmp = rcu_dereference(ima_rules);
+ ima_rules_tmp = rcu_dereference(ns->ima_rules);
list_for_each_entry_rcu(entry, ima_rules_tmp, list) {
if (entry->action != APPRAISE)
continue;
diff --git a/security/integrity/ima/ima_queue_keys.c b/security/integrity/ima/ima_queue_keys.c
index 93056c03bf5a..e366a21dd8be 100644
--- a/security/integrity/ima/ima_queue_keys.c
+++ b/security/integrity/ima/ima_queue_keys.c
@@ -10,6 +10,7 @@

#include <linux/user_namespace.h>
#include <linux/workqueue.h>
+#include <linux/ima.h>
#include <keys/asymmetric-type.h>
#include "ima.h"

@@ -42,7 +43,7 @@ static bool timer_expired;
static void ima_keys_handler(struct work_struct *work)
{
timer_expired = true;
- ima_process_queued_keys();
+ ima_process_queued_keys(&init_ima_ns);
}

/*
@@ -130,11 +131,15 @@ bool ima_queue_key(struct key *keyring, const void *payload,
* This function sets ima_process_keys to true and processes queued keys.
* From here on keys will be processed right away (not queued).
*/
-void ima_process_queued_keys(void)
+void ima_process_queued_keys(struct ima_namespace *ns)
{
struct ima_key_entry *entry, *tmp;
bool process = false;

+ /* only applies to init_ima_ns */
+ if (ns != &init_ima_ns)
+ return;
+
if (ima_process_keys)
return;

@@ -159,7 +164,7 @@ void ima_process_queued_keys(void)

list_for_each_entry_safe(entry, tmp, &ima_keys, list) {
if (!timer_expired)
- process_buffer_measurement(&init_user_ns, NULL,
+ process_buffer_measurement(ns, &init_user_ns, NULL,
entry->payload,
entry->payload_len,
entry->keyring_name,
--
2.31.1