Received: by 2002:a05:6602:18e:0:0:0:0 with SMTP id m14csp1667106ioo; Sun, 22 May 2022 23:39:52 -0700 (PDT) X-Google-Smtp-Source: ABdhPJxMlUw90cwZM/o4/G11E81c6MWI9pps0qeb3FG5DLiFvyemfslm3PErynAh/7F5ctpJPeIj X-Received: by 2002:a63:e315:0:b0:3fa:8780:9a1b with SMTP id f21-20020a63e315000000b003fa87809a1bmr326385pgh.306.1653287991997; Sun, 22 May 2022 23:39:51 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1653287991; cv=none; d=google.com; s=arc-20160816; b=MKkMy+YzZ3ej/rzH7FHqS1vbTKMZPZIt0JKA2H0A5tafuQ2TItk/IUronmnpTXK/t3 PlZF5U2aF3PjXb5tVrJR0ZENptnuX9uQ2CtWxPXwFeh31t6ksG1Uh/bAsnV0jWHuEXR2 DFY9h3+hCftVv5yoc25R1Xz7lE50sk4LWAuH5g/Nn2KtFBEThTK1kgYcboHO7v9wNjXT im/JiV/77uJp/EUCSTGac8tvjwJ52FKOjalQnSioifxMAJNUBgKmFp8CQq5uYiyhatda ARqLWqBs7pgoGWOUK1QeD6UhY2+zsDPeDDfKb1Q1119Pr+OTL3VGVxm4QgB1tpW4YI9H Q2ew== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:user-agent:in-reply-to:content-disposition :mime-version:references:message-id:subject:cc:to:from:date; bh=axnaJ2m2LxMGR4ODDvJcaKobCOT356fzec8ap63YvVI=; b=qm9PzLUxe/OqpCFMBcRAma44nfpZxtkGdwf9Gfl+gbPy8djZtGCE9NITxOtScgSySV ToPulWpU+xlVuVWXFkAAUlyLX7BHIM9vIqVM+rE7D9qWCnD4CVkqhOO3KvYm+nC2kzbg jPg5iF1kNa5jQE1Xs6HR1JdeQFm4Y08JF556lrRvVN3yyUynflMV4xKqiVmBE0pA0h9g nr9ST4jm2e4ygqNZ7YKlbW1uwuMi1N1EjkTJvPs6K7YocKNsTmOkwFAOEcayySQ5pg7Z NT/C67DgFXsJkMFOqHVVjR+HErrgzpkQSTklfe8f58y1g7F6lawGTh9mIRG6qhdlWhYg WmFg== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net. [2620:137:e000::1:18]) by mx.google.com with ESMTPS id q13-20020a056a00150d00b004fa8832da6dsi13283891pfu.76.2022.05.22.23.39.51 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 22 May 2022 23:39:51 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:18 as permitted sender) client-ip=2620:137:e000::1:18; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: from out1.vger.email (out1.vger.email [IPv6:2620:137:e000::1:20]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 477E219FB4; Sun, 22 May 2022 23:11:36 -0700 (PDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S239302AbiEUCeC (ORCPT + 99 others); Fri, 20 May 2022 22:34:02 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47994 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232004AbiEUCd6 (ORCPT ); Fri, 20 May 2022 22:33:58 -0400 Received: from mail.hallyn.com (mail.hallyn.com [178.63.66.53]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B84F96CAAA; Fri, 20 May 2022 19:33:53 -0700 (PDT) Received: by mail.hallyn.com (Postfix, from userid 1001) id 72BEA3F4; Fri, 20 May 2022 21:33:51 -0500 (CDT) Date: Fri, 20 May 2022 21:33:51 -0500 From: "Serge E. Hallyn" To: Stefan Berger Cc: linux-integrity@vger.kernel.org, zohar@linux.ibm.com, serge@hallyn.com, christian.brauner@ubuntu.com, containers@lists.linux.dev, dmitry.kasatkin@gmail.com, ebiederm@xmission.com, krzysztof.struczynski@huawei.com, roberto.sassu@huawei.com, mpeters@redhat.com, lhinds@redhat.com, lsturman@redhat.com, puiterwi@redhat.com, jejb@linux.ibm.com, jamjoom@us.ibm.com, linux-kernel@vger.kernel.org, paul@paul-moore.com, rgb@redhat.com, linux-security-module@vger.kernel.org, jmorris@namei.org, jpenumak@redhat.com, Christian Brauner Subject: Re: [PATCH v12 03/26] ima: Define ima_namespace struct and start moving variables into it Message-ID: <20220521023351.GA9107@mail.hallyn.com> References: <20220420140633.753772-1-stefanb@linux.ibm.com> <20220420140633.753772-4-stefanb@linux.ibm.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20220420140633.753772-4-stefanb@linux.ibm.com> User-Agent: Mutt/1.9.4 (2018-02-28) X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,MAILING_LIST_MULTI,RDNS_NONE, SPF_HELO_NONE,T_SCC_BODY_TEXT_LINE autolearn=no autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 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 > Acked-by: Christian Brauner > Reviewed-by: Mimi Zohar > > --- > > 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 > #include > #include > +#include > #include > > #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 > + * Stefan Berger > + */ > + > +#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 > #include > +#include > #include > #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