From nobody Sat Sep 13 03:56:31 2025 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 9F200C61DA4 for ; Mon, 6 Feb 2023 14:05:00 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231366AbjBFOE6 (ORCPT ); Mon, 6 Feb 2023 09:04:58 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48038 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229938AbjBFOEU (ORCPT ); Mon, 6 Feb 2023 09:04:20 -0500 Received: from mx0a-001b2d01.pphosted.com (mx0a-001b2d01.pphosted.com [148.163.156.1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 68F035B88; Mon, 6 Feb 2023 06:03:48 -0800 (PST) Received: from pps.filterd (m0098404.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.17.1.19/8.17.1.19) with ESMTP id 316E3549017985; Mon, 6 Feb 2023 14:03:12 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=NulKDC0s0zJgR5QVsuaR6Rw9baWpkEO/DBJbxbyGgIE=; b=H70RBg6fr4lwx10ONm0j6J+s9RI/PI1uufBl4pjD328PiqrmqcldoXf0zN9cHfYHW/ZH 8Eg/fy7mMyI11lgcqe8psyziRsOynGKLLj6NJhPMnVjpu8jCQSVxfFzZDgtn+B2btzDL CA65uAQz1+qbHKRmy1w/TYYaCaYJ/EUWubJogmaOFlCB06QzYqEUD9qXP/Wxy9HqSsD+ FmJIDFe7v7qVD8urdbu4N4eNJT5uhfK6l8rfe4yY9hlUkMvCsTm/bH2PPMd3k3JVH0lt RGJwSgMJrqKno+tpphkrzqtWxItpAk3GgEEy5DEjm6i4XSsC2d2R/RzXvDB41TbJyxi0 xQ== Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 3nk2ygr05u-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 06 Feb 2023 14:03:11 +0000 Received: from m0098404.ppops.net (m0098404.ppops.net [127.0.0.1]) by pps.reinject (8.17.1.5/8.17.1.5) with ESMTP id 316E35Dd017982; Mon, 6 Feb 2023 14:03:11 GMT Received: from ppma02wdc.us.ibm.com (aa.5b.37a9.ip4.static.sl-reverse.com [169.55.91.170]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 3nk2ygr04q-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 06 Feb 2023 14:03:11 +0000 Received: from pps.filterd (ppma02wdc.us.ibm.com [127.0.0.1]) by ppma02wdc.us.ibm.com (8.17.1.19/8.17.1.19) with ESMTP id 316Bjwaq027753; Mon, 6 Feb 2023 14:03:09 GMT Received: from smtprelay05.wdc07v.mail.ibm.com ([9.208.129.117]) by ppma02wdc.us.ibm.com (PPS) with ESMTPS id 3nhf07k13w-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 06 Feb 2023 14:03:09 +0000 Received: from smtpav02.wdc07v.mail.ibm.com (smtpav02.wdc07v.mail.ibm.com [10.39.53.229]) by smtprelay05.wdc07v.mail.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 316E37iT6750852 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Mon, 6 Feb 2023 14:03:07 GMT Received: from smtpav02.wdc07v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 7F0F258058; Mon, 6 Feb 2023 14:03:07 +0000 (GMT) Received: from smtpav02.wdc07v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 8EC045805B; Mon, 6 Feb 2023 14:03:05 +0000 (GMT) Received: from sbct-3.pok.ibm.com (unknown [9.47.158.153]) by smtpav02.wdc07v.mail.ibm.com (Postfix) with ESMTP; Mon, 6 Feb 2023 14:03:05 +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 v15 03/26] ima: Define ima_namespace struct and start moving variables into it Date: Mon, 6 Feb 2023 09:02:30 -0500 Message-Id: <20230206140253.3755945-4-stefanb@linux.ibm.com> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230206140253.3755945-1-stefanb@linux.ibm.com> References: <20230206140253.3755945-1-stefanb@linux.ibm.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-TM-AS-GCONF: 00 X-Proofpoint-GUID: O1sguP0u3sGH7Sq2EXjV_OEG7zysvMmi X-Proofpoint-ORIG-GUID: DGmTsZcNotgcSDFgl94Uz0RdSBsCGWL3 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.219,Aquarius:18.0.930,Hydra:6.0.562,FMLib:17.11.122.1 definitions=2023-02-06_06,2023-02-06_03,2022-06-22_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 clxscore=1015 mlxscore=0 bulkscore=0 mlxlogscore=999 adultscore=0 spamscore=0 phishscore=0 priorityscore=1501 malwarescore=0 impostorscore=0 suspectscore=0 lowpriorityscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2212070000 definitions=main-2302060121 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 --- v15: - Adjustment to new function ima_inode_set_acl() after rebase. 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 | 32 +++-- 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, 251 insertions(+), 146 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 03b440921e61..61986e271c5c 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, int xattr_len); =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 ee6f7e237f2e..89c38ce0039e 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; int err; @@ -767,7 +774,7 @@ int ima_inode_setxattr(struct dentry *dentry, const cha= r *xattr_name, digsig =3D (xvalue->type =3D=3D EVM_XATTR_PORTABLE_DIGSIG); } if (result =3D=3D 1 || evm_revalidate_status(xattr_name)) { - ima_reset_appraise_flags(d_backing_inode(dentry), digsig); + ima_reset_appraise_flags(ns, d_backing_inode(dentry), digsig); if (result =3D=3D 1) result =3D 0; } @@ -777,19 +784,22 @@ int ima_inode_setxattr(struct dentry *dentry, const c= har *xattr_name, int ima_inode_set_acl(struct user_namespace *mnt_userns, struct dentry *de= ntry, const char *acl_name, struct posix_acl *kacl) { + struct ima_namespace *ns =3D &init_ima_ns; + if (evm_revalidate_status(acl_name)) - ima_reset_appraise_flags(d_backing_inode(dentry), 0); + ima_reset_appraise_flags(ns, d_backing_inode(dentry), 0); =20 return 0; } =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 377300973e6c..00b550a64209 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 @@ -348,7 +350,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, @@ -407,12 +409,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; @@ -433,6 +436,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]; @@ -445,13 +449,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 @@ -487,17 +491,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 @@ -513,22 +518,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); @@ -602,10 +608,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 @@ -629,10 +637,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 @@ -648,13 +658,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; @@ -680,14 +691,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; @@ -716,6 +728,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 @@ -738,7 +751,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 @@ -766,6 +779,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 @@ -774,14 +788,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 @@ -869,6 +884,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. @@ -887,7 +903,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, @@ -912,7 +929,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(); @@ -931,7 +948,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) @@ -968,7 +985,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); @@ -1002,6 +1019,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) @@ -1011,7 +1029,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); @@ -1041,10 +1060,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); @@ -1053,6 +1074,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(); @@ -1077,7 +1099,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 6a68ec270822..671994bd07cb 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 @@ -256,11 +255,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) @@ -473,12 +467,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 @@ -493,10 +487,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 @@ -713,6 +709,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 @@ -732,7 +729,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, @@ -746,7 +744,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)) @@ -790,8 +788,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. * @@ -804,14 +802,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 @@ -841,7 +839,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) @@ -857,7 +855,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; @@ -866,7 +865,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), @@ -874,7 +873,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) @@ -887,9 +886,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; @@ -917,7 +917,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); @@ -932,26 +932,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; @@ -965,11 +966,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 /* @@ -977,7 +978,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 /* @@ -989,39 +990,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 @@ -1030,16 +1033,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 @@ -1048,10 +1052,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! */ @@ -1123,7 +1127,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; @@ -1143,7 +1148,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; @@ -1398,7 +1404,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; @@ -1748,37 +1755,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; @@ -1911,12 +1918,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; @@ -1940,7 +1948,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, @@ -1949,23 +1957,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); } @@ -1991,12 +2000,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(); @@ -2009,6 +2019,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(); @@ -2016,8 +2027,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) @@ -2284,6 +2295,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; @@ -2299,7 +2311,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.37.3