From nobody Fri Apr 3 06:53:22 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id E54A9C32771 for ; Thu, 15 Sep 2022 19:35:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230153AbiIOTfn (ORCPT ); Thu, 15 Sep 2022 15:35:43 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:36676 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229862AbiIOTdZ (ORCPT ); Thu, 15 Sep 2022 15:33:25 -0400 Received: from mx0a-001b2d01.pphosted.com (mx0a-001b2d01.pphosted.com [148.163.156.1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 93E469D8D1; Thu, 15 Sep 2022 12:33:13 -0700 (PDT) Received: from pps.filterd (m0187473.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.17.1.5/8.17.1.5) with ESMTP id 28FJFjI7029733; Thu, 15 Sep 2022 19:32:39 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding; s=pp1; bh=QUMhykhEvb1Jui8GfYH0CPTM17ACNuC3a+8SxBOG/fs=; b=PhGJp2gOZW7pI7b5Hh8D3t+91Yst3fG6jvFafzc1oFRivEghLkIqJJ5zOeE99VWGXP/E o1EkdGCBMHF1ohJLoZdZ85sluXTvtkPIo7TZ+h3alG2LBm2lzKC0ndISsoraUzwbu+xP 4bV9DnM779YxQ6UcO2heUH/kbX7TOcnEzknbFVrj5ywNtzVpWTFftg3XNfG4OO35SaKe NWxa+WQrKggwxyXDHf9Y6keVeECn+OzPrxy/vyU5kj6ybwZPTgti7SiuGBPc4xOxKjCI 6SjN7ABHce2FuIFsdJILwj8XHtzgSx5WE4K7CGc4bpH5ft+WcbYZNXcSmNIFhlhgRvfk 2w== Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 3jma27ggsr-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Thu, 15 Sep 2022 19:32:38 +0000 Received: from m0187473.ppops.net (m0187473.ppops.net [127.0.0.1]) by pps.reinject (8.17.1.5/8.17.1.5) with ESMTP id 28FJI3WK036748; Thu, 15 Sep 2022 19:32:38 GMT Received: from ppma02dal.us.ibm.com (a.bd.3ea9.ip4.static.sl-reverse.com [169.62.189.10]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 3jma27ggrr-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Thu, 15 Sep 2022 19:32:38 +0000 Received: from pps.filterd (ppma02dal.us.ibm.com [127.0.0.1]) by ppma02dal.us.ibm.com (8.16.1.2/8.16.1.2) with SMTP id 28FJKlDb023942; Thu, 15 Sep 2022 19:32:36 GMT Received: from b01cxnp23032.gho.pok.ibm.com (b01cxnp23032.gho.pok.ibm.com [9.57.198.27]) by ppma02dal.us.ibm.com with ESMTP id 3jm9170gt1-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Thu, 15 Sep 2022 19:32:36 +0000 Received: from b01ledav005.gho.pok.ibm.com (b01ledav005.gho.pok.ibm.com [9.57.199.110]) by b01cxnp23032.gho.pok.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 28FJWZDA61079922 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Thu, 15 Sep 2022 19:32:35 GMT Received: from b01ledav005.gho.pok.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 7724FAE062; Thu, 15 Sep 2022 19:32:35 +0000 (GMT) Received: from b01ledav005.gho.pok.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 4515BAE05C; Thu, 15 Sep 2022 19:32:35 +0000 (GMT) Received: from sbct-3.pok.ibm.com (unknown [9.47.158.153]) by b01ledav005.gho.pok.ibm.com (Postfix) with ESMTP; Thu, 15 Sep 2022 19:32:35 +0000 (GMT) From: Stefan Berger To: linux-integrity@vger.kernel.org Cc: zohar@linux.ibm.com, serge@hallyn.com, brauner@kernel.org, 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, Stefan Berger Subject: [PATCH v14 03/26] ima: Define ima_namespace struct and start moving variables into it Date: Thu, 15 Sep 2022 15:31:58 -0400 Message-Id: <20220915193221.1728029-4-stefanb@linux.ibm.com> X-Mailer: git-send-email 2.37.2 In-Reply-To: <20220915193221.1728029-1-stefanb@linux.ibm.com> References: <20220915193221.1728029-1-stefanb@linux.ibm.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-TM-AS-GCONF: 00 X-Proofpoint-GUID: -kgzlFPyEB-K7CzIcVAsiW6ZSNBp_hOa X-Proofpoint-ORIG-GUID: zj2Kho9Es8umoEG1_vUvI8oltsOhD4u5 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.205,Aquarius:18.0.895,Hydra:6.0.528,FMLib:17.11.122.1 definitions=2022-09-15_10,2022-09-14_04,2022-06-22_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 malwarescore=0 suspectscore=0 bulkscore=0 mlxscore=0 adultscore=0 priorityscore=1501 spamscore=0 clxscore=1015 phishscore=0 mlxlogscore=999 impostorscore=0 lowpriorityscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2209130000 definitions=main-2209150119 Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" 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/Makef= ile index 2499f2485c04..f8a5e5f3975d 100644 --- a/security/integrity/ima/Makefile +++ b/security/integrity/ima/Makefile @@ -7,7 +7,7 @@ obj-$(CONFIG_IMA) +=3D ima.o =20 ima-y :=3D 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) +=3D ima_appraise.o ima-$(CONFIG_IMA_APPRAISE_MODSIG) +=3D ima_modsig.o ima-$(CONFIG_HAVE_IMA_KEXEC) +=3D 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 =20 #include "../integrity.h" @@ -43,9 +44,6 @@ enum tpm_pcrs { TPM_PCR0 =3D 0, TPM_PCR8 =3D 8, TPM_PCR10= =3D 10 }; =20 #define NR_BANKS(chip) ((chip !=3D NULL) ? chip->nr_allocated_banks : 0) =20 -/* 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; =20 @@ -119,6 +117,17 @@ struct ima_kexec_hdr { u64 count; }; =20 +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[]; =20 #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 */ =20 /* 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_entr= y *entry); const char *ima_d_path(const struct path *path, char **pathbuf, char *file= name); =20 /* IMA policy related functions */ -int ima_match_policy(struct user_namespace *mnt_userns, struct inode *inod= e, +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 =20 #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 *ino= de, +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 *ii= nt, @@ -329,7 +344,8 @@ int ima_read_xattr(struct dentry *dentry, struct evm_ima_xattr_data **xattr_value); =20 #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_hoo= ks func, return INTEGRITY_UNKNOWN; } =20 -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 c1e76282b5ee..0b6bc357768a 100644 --- a/security/integrity/ima/ima_api.c +++ b/security/integrity/ima/ima_api.c @@ -163,6 +163,7 @@ void ima_add_violation(struct file *file, const unsigne= d char *filename, =20 /** * 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 @@ -186,7 +187,8 @@ void ima_add_violation(struct file *file, const unsigne= d 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, @@ -194,9 +196,9 @@ int ima_get_action(struct user_namespace *mnt_userns, s= truct inode *inode, { int flags =3D IMA_MEASURE | IMA_AUDIT | IMA_APPRAISE | IMA_HASH; =20 - flags &=3D ima_policy_flag; + flags &=3D ns->ima_policy_flag; =20 - 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 bde74fcecee3..618dca6e4a36 100644 --- a/security/integrity/ima/ima_appraise.c +++ b/security/integrity/ima/ima_appraise.c @@ -70,7 +70,8 @@ bool is_ima_appraise_enabled(void) * * Return 1 to appraise or hash */ -int ima_must_appraise(struct user_namespace *mnt_userns, struct inode *ino= de, +int ima_must_appraise(struct ima_namespace *ns, + struct user_namespace *mnt_userns, struct inode *inode, int mask, enum ima_hooks func) { u32 secid; @@ -79,7 +80,7 @@ int ima_must_appraise(struct user_namespace *mnt_userns, = struct inode *inode, return 0; =20 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); } @@ -440,7 +441,8 @@ static int modsig_verify(enum ima_hooks func, const str= uct 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; @@ -456,7 +458,8 @@ int ima_check_blacklist(struct integrity_iint_cache *ii= nt, =20 rc =3D is_binary_blacklisted(digest, digestsize); if ((rc =3D=3D -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); } @@ -634,14 +637,16 @@ void ima_inode_post_setattr(struct user_namespace *mn= t_userns, struct dentry *dentry) { struct inode *inode =3D d_backing_inode(dentry); + struct ima_namespace *ns =3D &init_ima_ns; struct integrity_iint_cache *iint; int action; =20 - 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; =20 - action =3D ima_must_appraise(mnt_userns, inode, MAY_ACCESS, POST_SETATTR); + action =3D ima_must_appraise(ns, mnt_userns, inode, MAY_ACCESS, + POST_SETATTR); iint =3D integrity_iint_find(inode); if (iint) { set_bit(IMA_CHANGE_ATTR, &iint->atomic_flags); @@ -666,11 +671,12 @@ static int ima_protect_xattr(struct dentry *dentry, c= onst char *xattr_name, return 0; } =20 -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; =20 - if (!(ima_policy_flag & IMA_APPRAISE) || !S_ISREG(inode->i_mode)) + if (!(ns->ima_policy_flag & IMA_APPRAISE) || !S_ISREG(inode->i_mode)) return; =20 iint =3D integrity_iint_find(inode); @@ -748,6 +754,7 @@ int ima_inode_setxattr(struct dentry *dentry, const cha= r *xattr_name, const void *xattr_value, size_t xattr_value_len) { const struct evm_ima_xattr_data *xvalue =3D xattr_value; + struct ima_namespace *ns =3D &init_ima_ns; int digsig =3D 0; int result; =20 @@ -765,18 +772,19 @@ int ima_inode_setxattr(struct dentry *dentry, const c= har *xattr_name, if (result) return result; =20 - ima_reset_appraise_flags(d_backing_inode(dentry), digsig); + ima_reset_appraise_flags(ns, d_backing_inode(dentry), digsig); } return result; } =20 int ima_inode_removexattr(struct dentry *dentry, const char *xattr_name) { + struct ima_namespace *ns =3D &init_ima_ns; int result; =20 result =3D ima_protect_xattr(dentry, xattr_name, NULL, 0); if (result =3D=3D 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 =3D=3D 1) result =3D 0; } diff --git a/security/integrity/ima/ima_asymmetric_keys.c b/security/integr= ity/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, s= truct key *key, const void *payload, size_t payload_len, unsigned long flags, bool create) { + struct ima_namespace *ns =3D &init_ima_ns; bool queued =3D false; =20 /* Only asymmetric keys are handled by this hook. */ @@ -60,7 +61,8 @@ void ima_post_key_create_or_update(struct key *keyring, s= truct 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_f= s.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_measureme= nts_ops =3D { .release =3D seq_release, }; =20 -static ssize_t ima_read_policy(char *path) +static ssize_t ima_read_policy(struct ima_namespace *ns, char *path) { void *data =3D NULL; char *datap; @@ -296,7 +296,7 @@ static ssize_t ima_read_policy(char *path) datap =3D data; while (size > 0 && (p =3D strsep(&datap, "\n"))) { pr_debug("rule: %s\n", p); - rc =3D ima_parse_add_rule(p); + rc =3D ima_parse_add_rule(ns, p); if (rc < 0) break; size -=3D 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 =3D &init_ima_ns; char *data; ssize_t result; =20 @@ -336,7 +337,7 @@ static ssize_t ima_write_policy(struct file *file, cons= t char __user *buf, goto out_free; =20 if (data[0] =3D=3D '/') { - result =3D ima_read_policy(data); + result =3D 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, cons= t char __user *buf, 1, 0); result =3D -EACCES; } else { - result =3D ima_parse_add_rule(data); + result =3D 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, struc= t file *filp) static int ima_release_policy(struct inode *inode, struct file *file) { const char *cause =3D valid_policy ? "completed" : "failed"; + struct ima_namespace *ns =3D &init_ima_ns; =20 if ((file->f_flags & O_ACCMODE) =3D=3D O_RDONLY) return seq_release(inode, file); =20 - if (valid_policy && ima_check_policy() < 0) { + if (valid_policy && ima_check_policy(ns) < 0) { cause =3D "failed"; valid_policy =3D 0; } @@ -424,13 +426,13 @@ static int ima_release_policy(struct inode *inode, st= ruct file *file) "policy_update", cause, !valid_policy, 0); =20 if (!valid_policy) { - ima_delete_rules(); + ima_delete_rules(ns); valid_policy =3D 1; clear_bit(IMA_FS_BUSY, &ima_fs_flags); return 0; } =20 - ima_update_policy(); + ima_update_policy(ns); #if !defined(CONFIG_IMA_WRITE_POLICY) && !defined(CONFIG_IMA_READ_POLICY) securityfs_remove(ima_policy); ima_policy =3D 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 =3D ima_policy_flag & IMA_APPRAISE; + int unset_flags =3D init_ima_ns.ima_policy_flag & IMA_APPRAISE; =20 - ima_policy_flag &=3D ~unset_flags; + init_ima_ns.ima_policy_flag &=3D ~unset_flags; integrity_load_x509(INTEGRITY_KEYRING_IMA, CONFIG_IMA_X509_PATH); =20 /* load also EVM key to avoid appraisal */ evm_load_x509(); =20 - ima_policy_flag |=3D unset_flags; + init_ima_ns.ima_policy_flag |=3D unset_flags; } #endif =20 @@ -117,6 +117,10 @@ int __init ima_init(void) { int rc; =20 + rc =3D ima_ns_init(); + if (rc) + return rc; + ima_tpm_chip =3D 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 !=3D 0) return rc; =20 - ima_init_policy(); + ima_init_policy(&init_ima_ns); =20 rc =3D ima_fs_init(); if (rc !=3D 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 =3D (struct list_head __rcu *)(&ns->ima_default_rules); + ns->ima_policy_flag =3D 0; + + return 0; +} + +int __init ima_ns_init(void) +{ + return ima_init_namespace(&init_ima_ns); +} + +struct ima_namespace init_ima_ns =3D { +}; +EXPORT_SYMBOL(init_ima_ns); diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima= _main.c index 040b03ddc1c7..a329db67dd00 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_ii= nt_cache *iint, */ void ima_file_free(struct file *file) { + struct ima_namespace *ns =3D &init_ima_ns; struct inode *inode =3D file_inode(file); struct integrity_iint_cache *iint; =20 - if (!ima_policy_flag || !S_ISREG(inode->i_mode)) + if (!ns->ima_policy_flag || !S_ISREG(inode->i_mode)) return; =20 iint =3D integrity_iint_find(inode); @@ -198,7 +199,8 @@ void ima_file_free(struct file *file) ima_check_last_writer(iint, inode, file); } =20 -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, con= st struct cred *cred, enum hash_algo hash_algo; unsigned int allowed_algos =3D 0; =20 - if (!ima_policy_flag || !S_ISREG(inode->i_mode)) + if (!ns->ima_policy_flag || !S_ISREG(inode->i_mode)) return 0; =20 /* Return an IMA_MEASURE, IMA_APPRAISE, IMA_AUDIT action * bitmask based on the appraise/audit/measurement policy. * Included is the appraise submask. */ - action =3D ima_get_action(file_mnt_user_ns(file), inode, cred, secid, + action =3D ima_get_action(ns, file_mnt_user_ns(file), inode, cred, secid, mask, func, &pcr, &template_desc, NULL, &allowed_algos); violation_check =3D ((func =3D=3D FILE_CHECK || func =3D=3D MMAP_CHECK) && - (ima_policy_flag & IMA_MEASURE)); + (ns->ima_policy_flag & IMA_MEASURE)); if (!action && !violation_check) return 0; =20 @@ -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 =3D=3D 0 && (action & IMA_APPRAISE_SUBMASK)) { - rc =3D ima_check_blacklist(iint, modsig, pcr); + rc =3D ima_check_blacklist(ns, iint, modsig, pcr); if (rc !=3D -EPERM) { inode_lock(inode); rc =3D ima_appraise_measurement(func, iint, file, @@ -405,12 +407,13 @@ static int process_measurement(struct file *file, con= st struct cred *cred, */ int ima_file_mmap(struct file *file, unsigned long prot) { + struct ima_namespace *ns =3D &init_ima_ns; u32 secid; =20 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); } =20 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 =3D &init_ima_ns; struct ima_template_desc *template =3D NULL; struct file *file; char filename[NAME_MAX]; @@ -443,13 +447,13 @@ int ima_file_mprotect(struct vm_area_struct *vma, uns= igned long prot) int pcr; =20 /* 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; =20 security_current_getsecid_subj(&secid); inode =3D file_inode(vma->vm_file); - action =3D ima_get_action(file_mnt_user_ns(vma->vm_file), inode, + action =3D ima_get_action(ns, file_mnt_user_ns(vma->vm_file), inode, current_cred(), secid, MAY_EXEC, MMAP_CHECK, &pcr, &template, NULL, NULL); =20 @@ -485,17 +489,18 @@ int ima_file_mprotect(struct vm_area_struct *vma, uns= igned long prot) */ int ima_bprm_check(struct linux_binprm *bprm) { + struct ima_namespace *ns =3D &init_ima_ns; int ret; u32 secid; =20 security_current_getsecid_subj(&secid); - ret =3D process_measurement(bprm->file, current_cred(), secid, NULL, 0, - MAY_EXEC, BPRM_CHECK); + ret =3D process_measurement(ns, bprm->file, current_cred(), secid, NULL, + 0, MAY_EXEC, BPRM_CHECK); if (ret) return ret; =20 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); } =20 @@ -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 =3D &init_ima_ns; u32 secid; =20 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); =20 -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 =3D NULL, tmp_iint; int rc, hash_algo; =20 - if (ima_policy_flag) { + if (ns->ima_policy_flag) { iint =3D integrity_iint_find(inode); if (iint) mutex_lock(&iint->mutex); @@ -595,10 +601,12 @@ static int __ima_inode_hash(struct inode *inode, stru= ct file *file, char *buf, */ int ima_file_hash(struct file *file, char *buf, size_t buf_size) { + struct ima_namespace *ns =3D &init_ima_ns; + if (!file) return -EINVAL; =20 - 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); =20 @@ -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 =3D &init_ima_ns; + if (!inode) return -EINVAL; =20 - 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); =20 @@ -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 =3D &init_ima_ns; struct integrity_iint_cache *iint; int must_appraise; =20 - if (!ima_policy_flag || !S_ISREG(inode->i_mode)) + if (!ns->ima_policy_flag || !S_ISREG(inode->i_mode)) return; =20 - must_appraise =3D ima_must_appraise(mnt_userns, inode, MAY_ACCESS, + must_appraise =3D 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 *m= nt_userns, void ima_post_path_mknod(struct user_namespace *mnt_userns, struct dentry *dentry) { + struct ima_namespace *ns =3D &init_ima_ns; struct integrity_iint_cache *iint; struct inode *inode =3D dentry->d_inode; int must_appraise; =20 - if (!ima_policy_flag || !S_ISREG(inode->i_mode)) + if (!ns->ima_policy_flag || !S_ISREG(inode->i_mode)) return; =20 - must_appraise =3D ima_must_appraise(mnt_userns, inode, MAY_ACCESS, + must_appraise =3D 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_use= rns, int ima_read_file(struct file *file, enum kernel_read_file_id read_id, bool contents) { + struct ima_namespace *ns =3D &init_ima_ns; enum ima_hooks func; u32 secid; =20 @@ -731,7 +744,7 @@ int ima_read_file(struct file *file, enum kernel_read_f= ile_id read_id, /* Read entire file for all partial reads. */ func =3D 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); } =20 @@ -759,6 +772,7 @@ const int read_idmap[READING_MAX_ID] =3D { int ima_post_read_file(struct file *file, void *buf, loff_t size, enum kernel_read_file_id read_id) { + struct ima_namespace *ns =3D &init_ima_ns; enum ima_hooks func; u32 secid; =20 @@ -767,14 +781,15 @@ int ima_post_read_file(struct file *file, void *buf, = loff_t size, return 0; =20 if (!file || !buf || size =3D=3D 0) { /* should never happen */ - if (ima_appraise & IMA_APPRAISE_ENFORCE) + if (ns =3D=3D &init_ima_ns && + (ima_appraise & IMA_APPRAISE_ENFORCE)) return -EACCES; return 0; } =20 func =3D 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); } =20 @@ -862,6 +877,7 @@ int ima_post_load_data(char *buf, loff_t size, =20 /** * 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_C= HECK) * @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 *m= nt_userns, if (digest && digest_len < digest_hash_len) return -EINVAL; =20 - if (!ima_policy_flag && !digest) + if (!ns->ima_policy_flag && !digest) return -ENOENT; =20 template =3D ima_template_desc_buf(); @@ -924,7 +941,7 @@ int process_buffer_measurement(struct user_namespace *m= nt_userns, */ if (func) { security_current_getsecid_subj(&secid); - action =3D ima_get_action(mnt_userns, inode, current_cred(), + action =3D 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 *m= nt_userns, if (digest) memcpy(digest, iint.ima_hash->digest, digest_hash_len); =20 - if (!ima_policy_flag || (func && !(action & IMA_MEASURE))) + if (!ns->ima_policy_flag || (func && !(action & IMA_MEASURE))) return 1; =20 ret =3D 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 =3D &init_ima_ns; struct fd f; =20 if (!buf || !size) @@ -1004,7 +1022,8 @@ void ima_kexec_cmdline(int kernel_fd, const void *buf= , int size) if (!f.file) return; =20 - 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_lab= el, const void *buf, size_t buf_len, bool hash, u8 *digest, size_t digest_len) { + struct ima_namespace *ns =3D &init_ima_ns; + if (!event_name || !event_label || !buf || !buf_len) return -ENOPARAM; =20 - 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); =20 static int __init init_ima(void) { + struct ima_namespace *ns =3D &init_ima_ns; int error; =20 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); =20 if (!error) - ima_update_policy_flags(); + ima_update_policy_flags(ns); =20 return error; } diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/i= ma_policy.c index a8802b8da946..9b6a18c580a4 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) >=3D (sizeof_field(struct integrity_iint_cache, measured_pcrs) * 8)) =20 -int ima_policy_flag; static int temp_ima_appraise; static int build_ima_appraise __ro_after_init; =20 @@ -232,11 +231,6 @@ static struct ima_rule_entry critical_data_rules[] __r= o_after_init =3D { /* An array of architecture specific rules */ static struct ima_rule_entry *arch_policy_entry __ro_after_init; =20 -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 =3D (struct list_head __rcu *)(&i= ma_default_rules); - static int ima_policy __initdata; =20 static int __init default_measure_policy_setup(char *str) @@ -453,12 +447,12 @@ static bool ima_rule_contains_lsm_cond(struct ima_rul= e_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; =20 - 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; =20 @@ -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 =3D &init_ima_ns; + if (event !=3D LSM_POLICY_CHANGE) return NOTIFY_DONE; =20 - ima_lsm_update_rules(); + ima_lsm_update_rules(ns); return NOTIFY_OK; } =20 @@ -668,6 +664,7 @@ static int get_subaction(struct ima_rule_entry *rule, e= num ima_hooks func) =20 /** * 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, e= num 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 *inod= e, +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 =3D ima_template_desc_current(); =20 rcu_read_lock(); - ima_rules_tmp =3D rcu_dereference(ima_rules); + ima_rules_tmp =3D rcu_dereference(ns->ima_rules); list_for_each_entry_rcu(entry, ima_rules_tmp, list) { =20 if (!(entry->action & actmask)) @@ -745,8 +743,8 @@ int ima_match_policy(struct user_namespace *mnt_userns,= struct inode *inode, } =20 /** - * 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_usern= s, 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 =3D 0; struct list_head *ima_rules_tmp; =20 rcu_read_lock(); - ima_rules_tmp =3D rcu_dereference(ima_rules); + ima_rules_tmp =3D 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 &=3D ~IMA_APPRAISE; =20 - ima_policy_flag =3D new_policy_flag; + ns->ima_policy_flag =3D new_policy_flag; } =20 static int ima_appraise_flag(enum ima_hooks func) @@ -812,7 +810,8 @@ static int ima_appraise_flag(enum ima_hooks func) return 0; } =20 -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 =3D 0; @@ -821,7 +820,7 @@ static void add_rules(struct ima_rule_entry *entries, i= nt count, struct ima_rule_entry *entry; =20 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); =20 if (policy_rule & IMA_CUSTOM_POLICY) { entry =3D kmemdup(&entries[i], sizeof(*entry), @@ -829,7 +828,7 @@ static void add_rules(struct ima_rule_entry *entries, i= nt count, if (!entry) continue; =20 - list_add_tail(&entry->list, &ima_policy_rules); + list_add_tail(&entry->list, &ns->ima_policy_rules); } if (entries[i].action =3D=3D APPRAISE) { if (entries !=3D build_appraise_rules) @@ -842,9 +841,10 @@ static void add_rules(struct ima_rule_entry *entries, = int count, } } =20 -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); =20 -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 =3D strscpy(rule, *rules, sizeof(rule)); =20 INIT_LIST_HEAD(&arch_policy_entry[i].list); - result =3D ima_parse_rule(rule, &arch_policy_entry[i]); + result =3D 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) =20 /** * 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; =20 /* 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); =20 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 =3D ima_init_arch_policy(); + arch_entries =3D 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); =20 /* @@ -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); =20 /* @@ -944,39 +945,41 @@ void __init ima_init_policy(void) build_appraise_entries =3D 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); } =20 if (ima_use_appraise_tcb) - add_rules(default_appraise_rules, + add_rules(ns, default_appraise_rules, ARRAY_SIZE(default_appraise_rules), IMA_DEFAULT_POLICY); =20 if (ima_use_critical_data) - add_rules(critical_data_rules, + add_rules(ns, critical_data_rules, ARRAY_SIZE(critical_data_rules), IMA_DEFAULT_POLICY); =20 atomic_set(&ima_setxattr_allowed_hash_algorithms, 0); =20 - ima_update_policy_flags(); + ima_update_policy_flags(ns); } =20 /* 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; } =20 /** * 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_rul= es so * they make a queue. The policy may be updated multiple times and this i= s 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 =3D &ima_policy_rules; + struct list_head *policy =3D &ns->ima_policy_rules; =20 - list_splice_tail_init_rcu(&ima_temp_rules, policy, synchronize_rcu); + list_splice_tail_init_rcu(&ns->ima_temp_rules, policy, + synchronize_rcu); =20 - if (ima_rules !=3D (struct list_head __rcu *)policy) { - ima_policy_flag =3D 0; + if (ns->ima_rules !=3D (struct list_head __rcu *)policy) { + ns->ima_policy_flag =3D 0; =20 - 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); =20 /* Custom IMA policy has been loaded */ - ima_process_queued_keys(); + ima_process_queued_keys(ns); } =20 /* Keep the enumeration in sync with the policy_tokens! */ @@ -1078,7 +1082,8 @@ static const match_table_t policy_tokens =3D { {Opt_err, NULL} }; =20 -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; @@ -1098,7 +1103,8 @@ static int ima_lsm_rule_init(struct ima_rule_entry *e= ntry, pr_warn("rule for LSM \'%s\' is undefined\n", entry->lsm[lsm_rule].args_p); =20 - if (ima_rules =3D=3D (struct list_head __rcu *)(&ima_default_rules)) { + if (ns->ima_rules =3D=3D + (struct list_head __rcu *)&ns->ima_default_rules) { kfree(entry->lsm[lsm_rule].args_p); entry->lsm[lsm_rule].args_p =3D NULL; result =3D -EINVAL; @@ -1353,7 +1359,8 @@ static unsigned int ima_parse_appraise_algos(char *ar= g) return res; } =20 -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; @@ -1703,37 +1710,37 @@ static int ima_parse_rule(char *rule, struct ima_ru= le_entry *entry) break; case Opt_obj_user: ima_log_string(ab, "obj_user", args[0].from); - result =3D ima_lsm_rule_init(entry, args, + result =3D 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 =3D ima_lsm_rule_init(entry, args, + result =3D 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 =3D ima_lsm_rule_init(entry, args, + result =3D 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 =3D ima_lsm_rule_init(entry, args, + result =3D 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 =3D ima_lsm_rule_init(entry, args, + result =3D 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 =3D ima_lsm_rule_init(entry, args, + result =3D ima_lsm_rule_init(ns, entry, args, LSM_SUBJ_TYPE, AUDIT_SUBJ_TYPE); break; @@ -1866,12 +1873,13 @@ static int ima_parse_rule(char *rule, struct ima_ru= le_entry *entry) =20 /** * 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[] =3D "update_policy"; char *p; @@ -1895,7 +1903,7 @@ ssize_t ima_parse_add_rule(char *rule) =20 INIT_LIST_HEAD(&entry->list); =20 - result =3D ima_parse_rule(p, entry); + result =3D ima_parse_rule(ns, p, entry); if (result) { ima_free_rule(entry); integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, @@ -1904,23 +1912,24 @@ ssize_t ima_parse_add_rule(char *rule) return result; } =20 - list_add_tail(&entry->list, &ima_temp_rules); + list_add_tail(&entry->list, &ns->ima_temp_rules); =20 return len; } =20 /** - * 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; =20 temp_ima_appraise =3D 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); } @@ -1946,12 +1955,13 @@ static const char *const mask_tokens[] =3D { =20 void *ima_policy_start(struct seq_file *m, loff_t *pos) { + struct ima_namespace *ns =3D &init_ima_ns; loff_t l =3D *pos; struct ima_rule_entry *entry; struct list_head *ima_rules_tmp; =20 rcu_read_lock(); - ima_rules_tmp =3D rcu_dereference(ima_rules); + ima_rules_tmp =3D rcu_dereference(ns->ima_rules); list_for_each_entry_rcu(entry, ima_rules_tmp, list) { if (!l--) { rcu_read_unlock(); @@ -1964,6 +1974,7 @@ void *ima_policy_start(struct seq_file *m, loff_t *po= s) =20 void *ima_policy_next(struct seq_file *m, void *v, loff_t *pos) { + struct ima_namespace *ns =3D &init_ima_ns; struct ima_rule_entry *entry =3D v; =20 rcu_read_lock(); @@ -1971,8 +1982,8 @@ void *ima_policy_next(struct seq_file *m, void *v, lo= ff_t *pos) rcu_read_unlock(); (*pos)++; =20 - return (&entry->list =3D=3D &ima_default_rules || - &entry->list =3D=3D &ima_policy_rules) ? NULL : entry; + return (&entry->list =3D=3D &ns->ima_default_rules || + &entry->list =3D=3D &ns->ima_policy_rules) ? NULL : entry; } =20 void ima_policy_stop(struct seq_file *m, void *v) @@ -2239,6 +2250,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 =3D &init_ima_ns; struct ima_rule_entry *entry; bool found =3D false; enum ima_hooks func; @@ -2254,7 +2266,7 @@ bool ima_appraise_signature(enum kernel_read_file_id = id) func =3D read_idmap[id] ?: FILE_CHECK; =20 rcu_read_lock(); - ima_rules_tmp =3D rcu_dereference(ima_rules); + ima_rules_tmp =3D rcu_dereference(ns->ima_rules); list_for_each_entry_rcu(entry, ima_rules_tmp, list) { if (entry->action !=3D APPRAISE) continue; diff --git a/security/integrity/ima/ima_queue_keys.c b/security/integrity/i= ma/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 @@ =20 #include #include +#include #include #include "ima.h" =20 @@ -42,7 +43,7 @@ static bool timer_expired; static void ima_keys_handler(struct work_struct *work) { timer_expired =3D true; - ima_process_queued_keys(); + ima_process_queued_keys(&init_ima_ns); } =20 /* @@ -130,11 +131,15 @@ bool ima_queue_key(struct key *keyring, const void *p= ayload, * 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 =3D false; =20 + /* only applies to init_ima_ns */ + if (ns !=3D &init_ima_ns) + return; + if (ima_process_keys) return; =20 @@ -159,7 +164,7 @@ void ima_process_queued_keys(void) =20 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, --=20 2.36.1