lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20220521023351.GA9107@mail.hallyn.com>
Date:   Fri, 20 May 2022 21:33:51 -0500
From:   "Serge E. Hallyn" <serge@...lyn.com>
To:     Stefan Berger <stefanb@...ux.ibm.com>
Cc:     linux-integrity@...r.kernel.org, zohar@...ux.ibm.com,
        serge@...lyn.com, christian.brauner@...ntu.com,
        containers@...ts.linux.dev, dmitry.kasatkin@...il.com,
        ebiederm@...ssion.com, krzysztof.struczynski@...wei.com,
        roberto.sassu@...wei.com, mpeters@...hat.com, lhinds@...hat.com,
        lsturman@...hat.com, puiterwi@...hat.com, jejb@...ux.ibm.com,
        jamjoom@...ibm.com, linux-kernel@...r.kernel.org,
        paul@...l-moore.com, rgb@...hat.com,
        linux-security-module@...r.kernel.org, jmorris@...ei.org,
        jpenumak@...hat.com, Christian Brauner <brauner@...nel.org>
Subject: Re: [PATCH v12 03/26] ima: Define ima_namespace struct and start
 moving variables into it

On Wed, Apr 20, 2022 at 10:06:10AM -0400, Stefan Berger wrote:
> 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@...ux.ibm.com>
> Acked-by: Christian Brauner <brauner@...nel.org>
> Reviewed-by: Mimi Zohar <zohar@...ux.ibm.com>
> 
> ---
> 
> 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            |  88 +++++++-----
>  security/integrity/ima/ima_policy.c          | 142 ++++++++++---------
>  security/integrity/ima/ima_queue_keys.c      |  11 +-
>  11 files changed, 248 insertions(+), 145 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 c6805af46211..90ef246a9f43 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 63979aefc95f..7e5b4187035d 100644
> --- a/security/integrity/ima/ima_init.c
> +++ b/security/integrity/ima/ima_init.c
> @@ -101,15 +101,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
>  
> @@ -117,6 +117,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");
> @@ -142,7 +146,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@...ibm.com>
> + *   Stefan Berger <stefanb@...ux.vnet.ibm.com>
> + */
> +
> +#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 3d3f8c5c502b..400865c521dd 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;
> @@ -431,6 +434,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];
> @@ -443,13 +447,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);
>  
> @@ -485,17 +489,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);
>  }
>  
> @@ -511,22 +516,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, struct file *file, char *buf,
> -			    size_t buf_size)
> +static int __ima_inode_hash(struct ima_namespace *ns, struct inode *inode,
> +			    struct file *file, char *buf, size_t buf_size)
>  {
>  	struct integrity_iint_cache *iint = NULL, tmp_iint;
>  	int rc, hash_algo;
>  
> -	if (ima_policy_flag) {
> +	if (ns->ima_policy_flag) {
>  		iint = integrity_iint_find(inode);
>  		if (iint)
>  			mutex_lock(&iint->mutex);
> @@ -595,10 +601,12 @@ static int __ima_inode_hash(struct inode *inode, struct file *file, char *buf,
>   */
>  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), file, buf, buf_size);
> +	return __ima_inode_hash(ns, file_inode(file), file, buf, buf_size);
>  }
>  EXPORT_SYMBOL_GPL(ima_file_hash);
>  
> @@ -622,10 +630,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, NULL, buf, buf_size);
> +	return __ima_inode_hash(ns, inode, NULL, buf, buf_size);
>  }
>  EXPORT_SYMBOL_GPL(ima_inode_hash);
>  
> @@ -641,13 +651,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;
> @@ -673,14 +684,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;
> @@ -709,6 +721,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;
>  
> @@ -731,7 +744,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);
>  }
>  
> @@ -759,6 +772,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;
>  
> @@ -767,14 +781,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);
>  }
>  
> @@ -862,6 +877,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.
> @@ -880,7 +896,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,
> @@ -905,7 +922,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();
> @@ -924,7 +941,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)
> @@ -961,7 +978,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);
> @@ -995,6 +1012,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)
> @@ -1004,7 +1022,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);
> @@ -1034,10 +1053,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);
> @@ -1046,6 +1067,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();
> @@ -1070,7 +1092,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 eea6e92500b8..69b19f4d5fee 100644
> --- a/security/integrity/ima/ima_policy.c
> +++ b/security/integrity/ima/ima_policy.c
> @@ -51,7 +51,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;
>  
> @@ -232,11 +231,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)
> @@ -453,12 +447,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;
>  
> @@ -473,10 +467,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;
>  }
>  
> @@ -668,6 +664,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
> @@ -687,7 +684,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,
> @@ -701,7 +699,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))
> @@ -745,8 +743,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.
>   *
> @@ -759,14 +757,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
> @@ -796,7 +794,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)
> @@ -812,7 +810,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;
> @@ -821,7 +820,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),
> @@ -829,7 +828,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)
> @@ -842,9 +841,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;
> @@ -872,7 +872,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);
> @@ -887,26 +887,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;
> @@ -920,11 +921,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);
>  
>  	/*
> @@ -932,7 +933,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);
>  
>  	/*
> @@ -944,39 +945,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
> @@ -985,16 +988,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
> @@ -1003,10 +1007,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! */
> @@ -1076,7 +1080,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;
> @@ -1096,7 +1101,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;
> @@ -1323,7 +1329,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;
> @@ -1673,37 +1680,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;
> @@ -1804,12 +1811,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;
> @@ -1833,7 +1841,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,
> @@ -1842,23 +1850,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);
>  	}
> @@ -1884,12 +1893,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();
> @@ -1902,6 +1912,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();
> @@ -1909,8 +1920,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)
> @@ -2173,6 +2184,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;
> @@ -2184,7 +2196,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 */

Hm, yes, it seems to, but it should be unreachable with
ns != &init_ima_ns, ever, right?

So it seems better to either not have this hunk at all, (both
here and at ima_keys_handler()) or to actually have a BUG_ON.

Or am I completely misreading the situation?

> +	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.34.1

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ