From patchwork Tue Nov 19 11:00:55 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roberto Sassu X-Patchwork-Id: 13879717 Received: from frasgout13.his.huawei.com (frasgout13.his.huawei.com [14.137.139.46]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9FC4133998; Tue, 19 Nov 2024 11:01:53 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=14.137.139.46 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1732014116; cv=none; b=pK+EWjAVRNyVf8pCvrzu7X3xpJRo06i3ECVNF9OqWDL2kIUCxOyUT/Lu0LSb/bee27mF1+jV/F4RihCJPzCqJ4J/tqs341urTKzMRb+0ty34CVvn9ilRo8nArzZp47x5fYyfIHBP9sngnw8fvOoFU4PvNPyCW0k1+Dmabnqo8dQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1732014116; c=relaxed/simple; bh=3D+X1nm793EtqCiX9pT6VVUG7F1+ikmuecIe+0W6WEU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=FE/zqIWbMDFvEAKGsBoJAxEOoqWXxjWRksSbG+w0u2TNU7yz25Y4e+uN8fg2isXGCOihQPDWlqUAGtSmUXS/PMGH39zdrj5BmnwcjH6avIDiQBvs/ZMppwYIyPCWTS0WfApCxmE7r5r4kQ4Vs90f11izzxEYN6kdQmWZ413M4Hg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=huaweicloud.com; spf=none smtp.mailfrom=huaweicloud.com; arc=none smtp.client-ip=14.137.139.46 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=huaweicloud.com Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=huaweicloud.com Received: from mail.maildlp.com (unknown [172.18.186.51]) by frasgout13.his.huawei.com (SkyGuard) with ESMTP id 4Xt1Hb2q5Dz9v7JS; Tue, 19 Nov 2024 18:40:59 +0800 (CST) Received: from mail02.huawei.com (unknown [7.182.16.47]) by mail.maildlp.com (Postfix) with ESMTP id E0003140ABD; Tue, 19 Nov 2024 19:01:45 +0800 (CST) Received: from huaweicloud.com (unknown [10.204.63.22]) by APP1 (Coremail) with SMTP id LxC2BwB3NTb9bzxnNXHnAQ--.10850S3; Tue, 19 Nov 2024 12:01:45 +0100 (CET) From: Roberto Sassu To: corbet@lwn.net, zohar@linux.ibm.com, dmitry.kasatkin@gmail.com, eric.snowberg@oracle.com, paul@paul-moore.com, jmorris@namei.org, serge@hallyn.com Cc: linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, linux-integrity@vger.kernel.org, linux-security-module@vger.kernel.org, wufan@linux.microsoft.com, pbrobinson@gmail.com, zbyszek@in.waw.pl, hch@lst.de, mjg59@srcf.ucam.org, pmatilai@redhat.com, jannh@google.com, dhowells@redhat.com, jikos@kernel.org, mkoutny@suse.com, ppavlu@suse.com, petr.vorel@gmail.com, mzerqung@0pointer.de, kgold@linux.ibm.com, Roberto Sassu Subject: [RFC][PATCH v4 1/9] ima: Introduce hook DIGEST_LIST_CHECK Date: Tue, 19 Nov 2024 12:00:55 +0100 Message-ID: <20241119110103.2780453-2-roberto.sassu@huaweicloud.com> X-Mailer: git-send-email 2.47.0.118.gfd3785337b In-Reply-To: <20241119110103.2780453-1-roberto.sassu@huaweicloud.com> References: <20241119110103.2780453-1-roberto.sassu@huaweicloud.com> Precedence: bulk X-Mailing-List: linux-security-module@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-CM-TRANSID: LxC2BwB3NTb9bzxnNXHnAQ--.10850S3 X-Coremail-Antispam: 1UD129KBjvJXoWxXF45tr1DtFW5CryftrW8JFb_yoW5uw45pa 1DKay0kryYqFyIkrZ3C3W29FWkKrWSgr4UG398Z3WvkFnxZF18Xry3tr9F9FyrGryFyFn7 trn0gr43Za1jywUanT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDU0xBIdaVrnRJUUUP2b4IE77IF4wAFF20E14v26rWj6s0DM7CY07I20VC2zVCF04k2 6cxKx2IYs7xG6rWj6s0DM7CIcVAFz4kK6r1j6r18M28IrcIa0xkI8VA2jI8067AKxVWUGw A2048vs2IY020Ec7CjxVAFwI0_Xr0E3s1l8cAvFVAK0II2c7xJM28CjxkF64kEwVA0rcxS w2x7M28EF7xvwVC0I7IYx2IY67AKxVW8JVW5JwA2z4x0Y4vE2Ix0cI8IcVCY1x0267AKxV WxJr0_GcWl84ACjcxK6I8E87Iv67AKxVW8JVWxJwA2z4x0Y4vEx4A2jsIEc7CjxVAFwI0_ Cr1j6rxdM2AIxVAIcxkEcVAq07x20xvEncxIr21l5I8CrVACY4xI64kE6c02F40Ex7xfMc Ij6xIIjxv20xvE14v26r126r1DMcIj6I8E87Iv67AKxVWUJVW8JwAm72CE4IkC6x0Yz7v_ Jr0_Gr1lF7xvr2IYc2Ij64vIr41lFIxGxcIEc7CjxVA2Y2ka0xkIwI1lc7CjxVAaw2AFwI 0_GFv_Wryl42xK82IYc2Ij64vIr41l4I8I3I0E4IkC6x0Yz7v_Jr0_Gr1lx2IqxVAqx4xG 67AKxVWUJVWUGwC20s026x8GjcxK67AKxVWUGVWUWwC2zVAF1VAY17CE14v26r4a6rW5MI IYrxkI7VAKI48JMIIF0xvE2Ix0cI8IcVAFwI0_Gr0_Xr1lIxAIcVC0I7IYx2IY6xkF7I0E 14v26F4UJVW0owCI42IY6xAIw20EY4v20xvaj40_Jr0_JF4lIxAIcVC2z280aVAFwI0_Gr 0_Cr1lIxAIcVC2z280aVCY1x0267AKxVWxJr0_GcJvcSsGvfC2KfnxnUUI43ZEXa7IU07r cDUUUUU== X-CM-SenderInfo: purev21wro2thvvxqx5xdzvxpfor3voofrz/1tbiAgAMBGc79-IEowAAs0 From: Roberto Sassu Introduce DIGEST_LIST_CHECK, a new hook to check the integrity of digest lists. The new hook is invoked during a kernel read with the file type READING_DIGEST LIST, which is done by the Integrity Digest Cache when it is populating a digest cache with a digest list. The new hook makes it possible to more precisely measure/appraise the digest lists read by the kernel, as opposed to using the more generic FILE_CHECK hook, invoked for every file open. Signed-off-by: Roberto Sassu --- Documentation/ABI/testing/ima_policy | 1 + security/integrity/ima/ima.h | 1 + security/integrity/ima/ima_main.c | 3 ++- security/integrity/ima/ima_policy.c | 3 +++ 4 files changed, 7 insertions(+), 1 deletion(-) diff --git a/Documentation/ABI/testing/ima_policy b/Documentation/ABI/testing/ima_policy index c2385183826c..22237fec5532 100644 --- a/Documentation/ABI/testing/ima_policy +++ b/Documentation/ABI/testing/ima_policy @@ -36,6 +36,7 @@ Description: [KEXEC_KERNEL_CHECK] [KEXEC_INITRAMFS_CHECK] [KEXEC_CMDLINE] [KEY_CHECK] [CRITICAL_DATA] [SETXATTR_CHECK][MMAP_CHECK_REQPROT] + [DIGEST_LIST_CHECK] mask:= [[^]MAY_READ] [[^]MAY_WRITE] [[^]MAY_APPEND] [[^]MAY_EXEC] fsmagic:= hex value diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index 2eaa7f224da4..301f4ddfa487 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -317,6 +317,7 @@ static inline unsigned int ima_hash_key(u8 *digest) hook(KEY_CHECK, key) \ hook(CRITICAL_DATA, critical_data) \ hook(SETXATTR_CHECK, setxattr_check) \ + hook(DIGEST_LIST_CHECK, digest_list_check) \ hook(MAX_CHECK, none) #define __ima_hook_enumify(ENUM, str) ENUM, diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index f6cc0c7a6244..8f732d3bd024 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -798,7 +798,8 @@ const int read_idmap[READING_MAX_ID] = { [READING_MODULE] = MODULE_CHECK, [READING_KEXEC_IMAGE] = KEXEC_KERNEL_CHECK, [READING_KEXEC_INITRAMFS] = KEXEC_INITRAMFS_CHECK, - [READING_POLICY] = POLICY_CHECK + [READING_POLICY] = POLICY_CHECK, + [READING_DIGEST_LIST] = DIGEST_LIST_CHECK, }; /** diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index 09da8e639239..047d50c2eb57 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c @@ -1290,6 +1290,7 @@ static bool ima_validate_rule(struct ima_rule_entry *entry) case MODULE_CHECK: case KEXEC_KERNEL_CHECK: case KEXEC_INITRAMFS_CHECK: + case DIGEST_LIST_CHECK: if (entry->flags & ~(IMA_FUNC | IMA_MASK | IMA_FSMAGIC | IMA_UID | IMA_FOWNER | IMA_FSUUID | IMA_INMASK | IMA_EUID | IMA_PCR | @@ -1533,6 +1534,8 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) entry->func = CRITICAL_DATA; else if (strcmp(args[0].from, "SETXATTR_CHECK") == 0) entry->func = SETXATTR_CHECK; + else if (strcmp(args[0].from, "DIGEST_LIST_CHECK") == 0) + entry->func = DIGEST_LIST_CHECK; else result = -EINVAL; if (!result) From patchwork Tue Nov 19 11:00:56 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roberto Sassu X-Patchwork-Id: 13879718 Received: from frasgout13.his.huawei.com (frasgout13.his.huawei.com [14.137.139.46]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8F93C1465A1; Tue, 19 Nov 2024 11:02:10 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=14.137.139.46 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1732014133; cv=none; b=dgt43aoIsghGYAFX9sTB8laLVvjDBTvkoZF8AVQd/ZaaBBO6X6ZGfWOuzyDXkjrJG2TsIJapyiwvjwjKqQFc2SCnZNLJsd7MWjQtlqj8CFXc04SiU2AbW2ActoyUAKmzA3mN2XGHTyLEwZURmefH+To5ZSCarzOS9gar3Hcm/mE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1732014133; c=relaxed/simple; bh=Jdw+Y+AjJQtKleSeZKDc1VxrS9OvhOw1w2BNe4QWTp0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=DILNgnCHKaJydQHxrjQY2o5iLiRHOAxpaIsXy0mSZp6pAf+nxyXDsZ47LkYdKPGgoOFV9/N246siue9htxA1aeVuXNoeJID/brwrH/9f6HgmcXpKp0Gi+YlRZ6BwJ4yPe+3l3b3bR5I7QkohXrQ/vDemO9K9T+DHcUQibqOuOyk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=huaweicloud.com; spf=pass smtp.mailfrom=huaweicloud.com; arc=none smtp.client-ip=14.137.139.46 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=huaweicloud.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huaweicloud.com Received: from mail.maildlp.com (unknown [172.18.186.51]) by frasgout13.his.huawei.com (SkyGuard) with ESMTP id 4Xt1Hw2kQbz9v7NL; Tue, 19 Nov 2024 18:41:16 +0800 (CST) Received: from mail02.huawei.com (unknown [7.182.16.47]) by mail.maildlp.com (Postfix) with ESMTP id 09F3E140ABD; Tue, 19 Nov 2024 19:01:58 +0800 (CST) Received: from huaweicloud.com (unknown [10.204.63.22]) by APP1 (Coremail) with SMTP id LxC2BwB3NTb9bzxnNXHnAQ--.10850S4; Tue, 19 Nov 2024 12:01:57 +0100 (CET) From: Roberto Sassu To: corbet@lwn.net, zohar@linux.ibm.com, dmitry.kasatkin@gmail.com, eric.snowberg@oracle.com, paul@paul-moore.com, jmorris@namei.org, serge@hallyn.com Cc: linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, linux-integrity@vger.kernel.org, linux-security-module@vger.kernel.org, wufan@linux.microsoft.com, pbrobinson@gmail.com, zbyszek@in.waw.pl, hch@lst.de, mjg59@srcf.ucam.org, pmatilai@redhat.com, jannh@google.com, dhowells@redhat.com, jikos@kernel.org, mkoutny@suse.com, ppavlu@suse.com, petr.vorel@gmail.com, mzerqung@0pointer.de, kgold@linux.ibm.com, Roberto Sassu Subject: [RFC][PATCH v4 2/9] ima: Add digest_cache policy keyword Date: Tue, 19 Nov 2024 12:00:56 +0100 Message-ID: <20241119110103.2780453-3-roberto.sassu@huaweicloud.com> X-Mailer: git-send-email 2.47.0.118.gfd3785337b In-Reply-To: <20241119110103.2780453-1-roberto.sassu@huaweicloud.com> References: <20241119110103.2780453-1-roberto.sassu@huaweicloud.com> Precedence: bulk X-Mailing-List: linux-security-module@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-CM-TRANSID: LxC2BwB3NTb9bzxnNXHnAQ--.10850S4 X-Coremail-Antispam: 1UD129KBjvAXoW3Aw1xtFyxKr15XF48GFW3KFg_yoW8GryrJo ZakwsrJF48Gry3CayUCFnIyay8W3yrGw1xJFnYgr98Z3Z2qryUG3ZrWr4UZFW3XF48Xa90 k3WxX3y8tFW8Jas3n29KB7ZKAUJUUUU8529EdanIXcx71UUUUU7v73VFW2AGmfu7bjvjm3 AaLaJ3UjIYCTnIWjp_UUUO87kC6x804xWl14x267AKxVWrJVCq3wAFc2x0x2IEx4CE42xK 8VAvwI8IcIk0rVWrJVCq3wAFIxvE14AKwVWUJVWUGwA2048vs2IY020E87I2jVAFwI0_Jr yl82xGYIkIc2x26xkF7I0E14v26ryj6s0DM28lY4IEw2IIxxk0rwA2F7IY1VAKz4vEj48v e4kI8wA2z4x0Y4vE2Ix0cI8IcVAFwI0_Gr0_Xr1l84ACjcxK6xIIjxv20xvEc7CjxVAFwI 0_Cr1j6rxdM28EF7xvwVC2z280aVAFwI0_Gr0_Cr1l84ACjcxK6I8E87Iv6xkF7I0E14v2 6F4UJVW0owAS0I0E0xvYzxvE52x082IY62kv0487Mc02F40EFcxC0VAKzVAqx4xG6I80ew Av7VC0I7IYx2IY67AKxVWUAVWUtwAv7VC2z280aVAFwI0_Jr0_Gr1lOx8S6xCaFVCjc4AY 6r1j6r4UM4x0Y48IcxkI7VAKI48JM4IIrI8v6xkF7I0E8cxan2IY04v7MxkF7I0En4kS14 v26r4a6rW5MxAIw28IcxkI7VAKI48JMxC20s026xCaFVCjc4AY6r1j6r4UMI8I3I0E5I8C rVAFwI0_Jr0_Jr4lx2IqxVCjr7xvwVAFwI0_JrI_JrWlx4CE17CEb7AF67AKxVW8ZVWrXw CIc40Y0x0EwIxGrwCI42IY6xIIjxv20xvE14v26r4j6ryUMIIF0xvE2Ix0cI8IcVCY1x02 67AKxVWxJr0_GcWlIxAIcVCF04k26cxKx2IYs7xG6r1j6r1xMIIF0xvEx4A2jsIE14v26r 4j6F4UMIIF0xvEx4A2jsIEc7CjxVAFwI0_Cr1j6rxdYxBIdaVFxhVjvjDU0xZFpf9x07jx DGOUUUUU= X-CM-SenderInfo: purev21wro2thvvxqx5xdzvxpfor3voofrz/1tbiAQAMBGc797QEkwABsA From: Roberto Sassu Add the 'digest_cache=' policy keyword, to enable the usage of digest caches for specific IMA actions and purpose. At the moment, it accepts only 'data' as value, as digest caches can be used only for measurement and appraisal of file data. In the future, it might be possible to use them for file metadata too. The 'digest_cache=' keyword can be specified for the subset of IMA hooks listed in ima_digest_cache_func_allowed(). In case the function is not specified in the policy, the filtering is done when the policy is evaluated. POLICY_CHECK has been excluded for measurement, because policy changes must be visible in the IMA measurement list. For appraisal, instead, it might be useful to load custom policies in the initial ram disk (no security.ima xattr). Add the digest_cache_usage member to the ima_rule_entry structure, and set the flag IMA_DIGEST_CACHE_MEASURE_DATA if 'digest_cache=data' was specified for a measure rule, IMA_DIGEST_CACHE_APPRAISE_DATA for an appraise rule. Propagate the usage down to ima_match_policy() and ima_get_action(), so that process_measurement() can make the final decision on whether or not digest caches should be used to measure/appraise the file being evaluated. Since using digest caches changes the meaning of the IMA measurement list, which will include only digest lists and unknown files, enforce specifying 'pcr=' with a non-standard value, when 'digest_cache=data' is specified in a measure rule. This removes the ambiguity on the meaning of the IMA measurement list. Signed-off-by: Roberto Sassu --- Documentation/ABI/testing/ima_policy | 5 +- security/integrity/ima/ima.h | 10 +++- security/integrity/ima/ima_api.c | 6 +- security/integrity/ima/ima_appraise.c | 2 +- security/integrity/ima/ima_main.c | 8 +-- security/integrity/ima/ima_policy.c | 81 ++++++++++++++++++++++++++- 6 files changed, 100 insertions(+), 12 deletions(-) diff --git a/Documentation/ABI/testing/ima_policy b/Documentation/ABI/testing/ima_policy index 22237fec5532..887ac79f66eb 100644 --- a/Documentation/ABI/testing/ima_policy +++ b/Documentation/ABI/testing/ima_policy @@ -29,7 +29,7 @@ Description: [obj_user=] [obj_role=] [obj_type=]] option: [digest_type=] [template=] [permit_directio] [appraise_type=] [appraise_flag=] - [appraise_algos=] [keyrings=] + [appraise_algos=] [keyrings=] [digest_cache=] base: func:= [BPRM_CHECK][MMAP_CHECK][CREDS_CHECK][FILE_CHECK][MODULE_CHECK] [FIRMWARE_CHECK] @@ -77,6 +77,9 @@ Description: For example, "sha256,sha512" to only accept to appraise files where the security.ima xattr was hashed with one of these two algorithms. + digest_cache:= [data] + "data" means that the digest cache is used only + for file data measurement and/or appraisal. default policy: # PROC_SUPER_MAGIC diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index 301f4ddfa487..64667f16a30f 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -44,6 +44,10 @@ enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8, TPM_PCR10 = 10 }; #define NR_BANKS(chip) ((chip != NULL) ? chip->nr_allocated_banks : 0) +/* Digest cache usage flags. */ +#define IMA_DIGEST_CACHE_MEASURE_DATA 0x0000000000000001 +#define IMA_DIGEST_CACHE_APPRAISE_DATA 0x0000000000000002 + /* current content of the policy */ extern int ima_policy_flag; @@ -374,7 +378,8 @@ int ima_get_action(struct mnt_idmap *idmap, struct inode *inode, const struct cred *cred, u32 secid, int mask, enum ima_hooks func, int *pcr, struct ima_template_desc **template_desc, - const char *func_data, unsigned int *allowed_algos); + const char *func_data, unsigned int *allowed_algos, + u64 *digest_cache_usage); int ima_must_measure(struct inode *inode, int mask, enum ima_hooks func); int ima_collect_measurement(struct ima_iint_cache *iint, struct file *file, void *buf, loff_t size, enum hash_algo algo, @@ -405,7 +410,8 @@ int ima_match_policy(struct mnt_idmap *idmap, 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); + const char *func_data, unsigned int *allowed_algos, + u64 *digest_cache_usage); void ima_init_policy(void); void ima_update_policy(void); void ima_update_policy_flags(void); diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c index 984e861f6e33..b44cf7d9fbcb 100644 --- a/security/integrity/ima/ima_api.c +++ b/security/integrity/ima/ima_api.c @@ -173,6 +173,7 @@ void ima_add_violation(struct file *file, const unsigned char *filename, * @template_desc: pointer filled in if matched measure policy sets template= * @func_data: func specific data, may be NULL * @allowed_algos: allowlist of hash algorithms for the IMA xattr + * @digest_cache_usage: Actions and purpose for which digest cache is allowed * * The policy is defined in terms of keypairs: * subj=, obj=, type=, func=, mask=, fsmagic= @@ -190,7 +191,8 @@ int ima_get_action(struct mnt_idmap *idmap, struct inode *inode, const struct cred *cred, u32 secid, int mask, enum ima_hooks func, int *pcr, struct ima_template_desc **template_desc, - const char *func_data, unsigned int *allowed_algos) + const char *func_data, unsigned int *allowed_algos, + u64 *digest_cache_usage) { int flags = IMA_MEASURE | IMA_AUDIT | IMA_APPRAISE | IMA_HASH; @@ -198,7 +200,7 @@ int ima_get_action(struct mnt_idmap *idmap, struct inode *inode, return ima_match_policy(idmap, inode, cred, secid, func, mask, flags, pcr, template_desc, func_data, - allowed_algos); + allowed_algos, digest_cache_usage); } static bool ima_get_verity_digest(struct ima_iint_cache *iint, diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c index 656c709b974f..d479cf58d859 100644 --- a/security/integrity/ima/ima_appraise.c +++ b/security/integrity/ima/ima_appraise.c @@ -81,7 +81,7 @@ int ima_must_appraise(struct mnt_idmap *idmap, struct inode *inode, security_current_getsecid_subj(&secid); return ima_match_policy(idmap, inode, current_cred(), secid, func, mask, IMA_APPRAISE | IMA_HASH, NULL, - NULL, NULL, NULL); + NULL, NULL, NULL, NULL); } static int ima_fix_xattr(struct dentry *dentry, struct ima_iint_cache *iint) diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 8f732d3bd024..bcbf64bb03c2 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -234,7 +234,7 @@ static int process_measurement(struct file *file, const struct cred *cred, */ action = ima_get_action(file_mnt_idmap(file), inode, cred, secid, mask, func, &pcr, &template_desc, NULL, - &allowed_algos); + &allowed_algos, NULL); violation_check = ((func == FILE_CHECK || func == MMAP_CHECK || func == MMAP_CHECK_REQPROT) && (ima_policy_flag & IMA_MEASURE)); @@ -502,11 +502,11 @@ static int ima_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot, inode = file_inode(vma->vm_file); action = ima_get_action(file_mnt_idmap(vma->vm_file), inode, current_cred(), secid, MAY_EXEC, MMAP_CHECK, - &pcr, &template, NULL, NULL); + &pcr, &template, NULL, NULL, NULL); action |= ima_get_action(file_mnt_idmap(vma->vm_file), inode, current_cred(), secid, MAY_EXEC, MMAP_CHECK_REQPROT, &pcr, &template, NULL, - NULL); + NULL, NULL); /* Is the mmap'ed file in policy? */ if (!(action & (IMA_MEASURE | IMA_APPRAISE_SUBMASK))) @@ -994,7 +994,7 @@ int process_buffer_measurement(struct mnt_idmap *idmap, security_current_getsecid_subj(&secid); action = ima_get_action(idmap, inode, current_cred(), secid, 0, func, &pcr, &template, - func_data, NULL); + func_data, NULL, NULL); if (!(action & IMA_MEASURE) && !digest) return -ENOENT; } diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index 047d50c2eb57..eb3bfe01782d 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c @@ -122,6 +122,7 @@ struct ima_rule_entry { struct ima_rule_opt_list *keyrings; /* Measure keys added to these keyrings */ struct ima_rule_opt_list *label; /* Measure data grouped under this label */ struct ima_template_desc *template; + u64 digest_cache_usage; /* Actions and purpose for which digest cache is allowed */ }; /* @@ -714,6 +715,27 @@ static int get_subaction(struct ima_rule_entry *rule, enum ima_hooks func) } } +/* Filter IMA hooks that can use digest caches. */ +static bool ima_digest_cache_func_allowed(enum ima_hooks func) +{ + switch (func) { + case NONE: + case FILE_CHECK: + case MMAP_CHECK: + case MMAP_CHECK_REQPROT: + case BPRM_CHECK: + case CREDS_CHECK: + case FIRMWARE_CHECK: + case POLICY_CHECK: + case MODULE_CHECK: + case KEXEC_KERNEL_CHECK: + case KEXEC_INITRAMFS_CHECK: + return true; + default: + return false; + } +} + /** * ima_match_policy - decision based on LSM and other conditions * @idmap: idmap of the mount the inode was found from @@ -728,6 +750,7 @@ static int get_subaction(struct ima_rule_entry *rule, enum ima_hooks func) * @template_desc: the template that should be used for this rule * @func_data: func specific data, may be NULL * @allowed_algos: allowlist of hash algorithms for the IMA xattr + * @digest_cache_usage: Actions and purpose for which digest cache is allowed * * Measure decision based on func/mask/fsmagic and LSM(subj/obj/type) * conditions. @@ -740,7 +763,8 @@ int ima_match_policy(struct mnt_idmap *idmap, 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) + const char *func_data, unsigned int *allowed_algos, + u64 *digest_cache_usage) { struct ima_rule_entry *entry; int action = 0, actmask = flags | (flags << 1); @@ -785,6 +809,22 @@ int ima_match_policy(struct mnt_idmap *idmap, struct inode *inode, if (template_desc && entry->template) *template_desc = entry->template; + /* + * Since we allow IMA policy rules without func=, check if the + * current IMA hook is allowed and, if not, disregard the digest + * cache usage from the policy. + * + * In addition, don't allow digest caches to be used for IMA + * policy measurements, so that policies always appear in the + * measurement list. + */ + if (digest_cache_usage && ima_digest_cache_func_allowed(func)) { + *digest_cache_usage |= entry->digest_cache_usage; + + if (func == POLICY_CHECK) + *digest_cache_usage &= ~IMA_DIGEST_CACHE_MEASURE_DATA; + } + if (!actmask) break; } @@ -1075,7 +1115,7 @@ enum policy_opt { Opt_digest_type, Opt_appraise_type, Opt_appraise_flag, Opt_appraise_algos, Opt_permit_directio, Opt_pcr, Opt_template, Opt_keyrings, - Opt_label, Opt_err + Opt_label, Opt_digest_cache, Opt_err }; static const match_table_t policy_tokens = { @@ -1124,6 +1164,7 @@ static const match_table_t policy_tokens = { {Opt_template, "template=%s"}, {Opt_keyrings, "keyrings=%s"}, {Opt_label, "label=%s"}, + {Opt_digest_cache, "digest_cache=%s"}, {Opt_err, NULL} }; @@ -1248,6 +1289,19 @@ static bool ima_validate_rule(struct ima_rule_entry *entry) if (entry->action != MEASURE && entry->flags & IMA_PCR) return false; + /* New-style measurements with digest cache cannot be on default PCR. */ + if (entry->action == MEASURE && + (entry->digest_cache_usage & IMA_DIGEST_CACHE_MEASURE_DATA)) { + if (!(entry->flags & IMA_PCR) || + entry->pcr == CONFIG_IMA_MEASURE_PCR_IDX) + return false; + } + + /* Digest caches can be used only for a subset of the IMA hooks. */ + if (entry->digest_cache_usage && + !ima_digest_cache_func_allowed(entry->func)) + return false; + if (entry->action != APPRAISE && entry->flags & (IMA_DIGSIG_REQUIRED | IMA_MODSIG_ALLOWED | IMA_CHECK_BLACKLIST | IMA_VALIDATE_ALGOS)) @@ -1884,6 +1938,26 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) &(template_desc->num_fields)); entry->template = template_desc; break; + case Opt_digest_cache: + ima_log_string(ab, "digest_cache", args[0].from); + + result = -EINVAL; + + if (!strcmp(args[0].from, "data")) { + switch (entry->action) { + case MEASURE: + entry->digest_cache_usage |= IMA_DIGEST_CACHE_MEASURE_DATA; + result = 0; + break; + case APPRAISE: + entry->digest_cache_usage |= IMA_DIGEST_CACHE_APPRAISE_DATA; + result = 0; + break; + default: + break; + } + } + break; case Opt_err: ima_log_string(ab, "UNKNOWN", p); result = -EINVAL; @@ -2274,6 +2348,9 @@ int ima_policy_show(struct seq_file *m, void *v) seq_puts(m, "digest_type=verity "); if (entry->flags & IMA_PERMIT_DIRECTIO) seq_puts(m, "permit_directio "); + if ((entry->digest_cache_usage & IMA_DIGEST_CACHE_MEASURE_DATA) || + (entry->digest_cache_usage & IMA_DIGEST_CACHE_APPRAISE_DATA)) + seq_puts(m, "digest_cache=data "); rcu_read_unlock(); seq_puts(m, "\n"); return 0; From patchwork Tue Nov 19 11:00:57 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roberto Sassu X-Patchwork-Id: 13879719 Received: from frasgout12.his.huawei.com (frasgout12.his.huawei.com [14.137.139.154]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 91AB31C7B63; Tue, 19 Nov 2024 11:02:17 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=14.137.139.154 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1732014139; cv=none; b=nYDho1a56FTnifY/UFTROO0dm33KhTDSjtkJKqRvNwb/I9T0wf0/Z5Li4Q2pPv7MsM9WG3m7qt42rMgiykbdiIKnHwr2mcxUdZM2Gr1gd8dLQzVx37HbxgtsarzXa+6VsoamYJvNFlUkRpw4OHSw2DAeHUUlbfHf6RwSZF6R32s= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1732014139; c=relaxed/simple; bh=uSHAvMueJAsWgtjNECPZFK0yCRhcaZ3H+Gj790fOlNM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=YnQ2gAmxCCWT7nf+/b8wSAypaKBIAqNAya5d/dMdm5urnQa30ooHtCDMeXQIFZESgufL8iJ47Tf6BG6RsrO5zjoxC1yzB8ixeTZnWVnpcatb6zGRcFihlzx/NBr+TqO9vHbBZR2Lq0fkxbrMDozWutMRCfKm4xl3BlhyxZEk0XI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=huaweicloud.com; spf=pass smtp.mailfrom=huaweicloud.com; arc=none smtp.client-ip=14.137.139.154 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=huaweicloud.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huaweicloud.com Received: from mail.maildlp.com (unknown [172.18.186.29]) by frasgout12.his.huawei.com (SkyGuard) with ESMTP id 4Xt18l6LTrz9v7Jb; Tue, 19 Nov 2024 18:35:03 +0800 (CST) Received: from mail02.huawei.com (unknown [7.182.16.47]) by mail.maildlp.com (Postfix) with ESMTP id EE10D1407F5; Tue, 19 Nov 2024 19:02:09 +0800 (CST) Received: from huaweicloud.com (unknown [10.204.63.22]) by APP1 (Coremail) with SMTP id LxC2BwB3NTb9bzxnNXHnAQ--.10850S5; Tue, 19 Nov 2024 12:02:09 +0100 (CET) From: Roberto Sassu To: corbet@lwn.net, zohar@linux.ibm.com, dmitry.kasatkin@gmail.com, eric.snowberg@oracle.com, paul@paul-moore.com, jmorris@namei.org, serge@hallyn.com Cc: linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, linux-integrity@vger.kernel.org, linux-security-module@vger.kernel.org, wufan@linux.microsoft.com, pbrobinson@gmail.com, zbyszek@in.waw.pl, hch@lst.de, mjg59@srcf.ucam.org, pmatilai@redhat.com, jannh@google.com, dhowells@redhat.com, jikos@kernel.org, mkoutny@suse.com, ppavlu@suse.com, petr.vorel@gmail.com, mzerqung@0pointer.de, kgold@linux.ibm.com, Roberto Sassu Subject: [RFC][PATCH v4 3/9] ima: Add digest_cache_measure/appraise boot-time built-in policies Date: Tue, 19 Nov 2024 12:00:57 +0100 Message-ID: <20241119110103.2780453-4-roberto.sassu@huaweicloud.com> X-Mailer: git-send-email 2.47.0.118.gfd3785337b In-Reply-To: <20241119110103.2780453-1-roberto.sassu@huaweicloud.com> References: <20241119110103.2780453-1-roberto.sassu@huaweicloud.com> Precedence: bulk X-Mailing-List: linux-security-module@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-CM-TRANSID: LxC2BwB3NTb9bzxnNXHnAQ--.10850S5 X-Coremail-Antispam: 1UD129KBjvJXoWxtF1kKr1UWF13Zr1DWw48Zwb_yoW7CFyrpa 9FgFy5trZ8XF9xCw47Aa4xuF4Fy3s2ga13Gws8Ga4jy3Z8ur1q9w10y3WavrWDAr10q3Wx XF4Ygr4jkw1qqaDanT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDU0xBIdaVrnRJUUUP2b4IE77IF4wAFF20E14v26rWj6s0DM7CY07I20VC2zVCF04k2 6cxKx2IYs7xG6rWj6s0DM7CIcVAFz4kK6r1j6r18M28IrcIa0xkI8VA2jI8067AKxVWUWw A2048vs2IY020Ec7CjxVAFwI0_Xr0E3s1l8cAvFVAK0II2c7xJM28CjxkF64kEwVA0rcxS w2x7M28EF7xvwVC0I7IYx2IY67AKxVW8JVW5JwA2z4x0Y4vE2Ix0cI8IcVCY1x0267AKxV WxJr0_GcWl84ACjcxK6I8E87Iv67AKxVW8JVWxJwA2z4x0Y4vEx4A2jsIEc7CjxVAFwI0_ Cr1j6rxdM2AIxVAIcxkEcVAq07x20xvEncxIr21l5I8CrVACY4xI64kE6c02F40Ex7xfMc Ij6xIIjxv20xvE14v26r126r1DMcIj6I8E87Iv67AKxVWUJVW8JwAm72CE4IkC6x0Yz7v_ Jr0_Gr1lF7xvr2IYc2Ij64vIr41lFIxGxcIEc7CjxVA2Y2ka0xkIwI1lc7CjxVAaw2AFwI 0_GFv_Wryl42xK82IYc2Ij64vIr41l4I8I3I0E4IkC6x0Yz7v_Jr0_Gr1lx2IqxVAqx4xG 67AKxVWUJVWUGwC20s026x8GjcxK67AKxVWUGVWUWwC2zVAF1VAY17CE14v26r4a6rW5MI IYrxkI7VAKI48JMIIF0xvE2Ix0cI8IcVAFwI0_Gr0_Xr1lIxAIcVC0I7IYx2IY6xkF7I0E 14v26F4UJVW0owCI42IY6xAIw20EY4v20xvaj40_Jr0_JF4lIxAIcVC2z280aVAFwI0_Gr 0_Cr1lIxAIcVC2z280aVCY1x0267AKxVWxJr0_GcJvcSsGvfC2KfnxnUUI43ZEXa7IU07U UUUUUUU== X-CM-SenderInfo: purev21wro2thvvxqx5xdzvxpfor3voofrz/1tbiAQAMBGc797QEkwACsD From: Roberto Sassu Specify the 'digest_cache_measure' boot-time policy with 'ima_policy=' in the kernel command line to add the following rule at the beginning of the IMA policy, before other rules: measure func=DIGEST_LIST_CHECK pcr=12 which will measure digest lists into PCR 12 (or the value in CONFIG_IMA_DIGEST_CACHE_MEASURE_PCR_IDX). Specify 'digest_cache_appraise' to add the following rule at the beginning, before other rules: appraise func=DIGEST_LIST_CHECK appraise_type=imasig|modsig which will appraise digest lists with IMA signatures or module-style appended signatures. Adding those rules at the beginning rather than at the end is necessary to ensure that digest lists are measured and appraised in the initial ram disk, which would be otherwise prevented by the dont_ rules. Signed-off-by: Roberto Sassu --- .../admin-guide/kernel-parameters.txt | 10 +++++- security/integrity/ima/Kconfig | 10 ++++++ security/integrity/ima/ima_policy.c | 35 +++++++++++++++++++ 3 files changed, 54 insertions(+), 1 deletion(-) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 1518343bbe22..9b6f85b1376c 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -2094,7 +2094,8 @@ ima_policy= [IMA] The builtin policies to load during IMA setup. Format: "tcb | appraise_tcb | secure_boot | - fail_securely | critical_data" + fail_securely | critical_data | + digest_cache_measure | digest_cache_appraise" The "tcb" policy measures all programs exec'd, files mmap'd for exec, and all files opened with the read @@ -2116,6 +2117,13 @@ The "critical_data" policy measures kernel integrity critical data. + The "digest_cache_measure" policy measures digest lists + into PCR 12 (can be changed with kernel config). + + The "digest_cache_appraise" policy appraises digest + lists with IMA signatures or module-style appended + signatures. + ima_tcb [IMA] Deprecated. Use ima_policy= instead. Load a policy which meets the needs of the Trusted Computing Base. This means IMA will measure all diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig index 475c32615006..d2d79185f714 100644 --- a/security/integrity/ima/Kconfig +++ b/security/integrity/ima/Kconfig @@ -321,4 +321,14 @@ config IMA_DISABLE_HTABLE help This option disables htable to allow measurement of duplicate records. +config IMA_DIGEST_CACHE_MEASURE_PCR_IDX + int + range 8 14 + default 12 + help + This option determines the TPM PCR register index that IMA uses to + maintain the integrity aggregate of the measurement list, when the + Integrity Digest Cache is used (different measurement style). + If unsure, use the default 12. + endif diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index eb3bfe01782d..c2bf58010b89 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c @@ -254,6 +254,21 @@ static struct ima_rule_entry critical_data_rules[] __ro_after_init = { {.action = MEASURE, .func = CRITICAL_DATA, .flags = IMA_FUNC}, }; +static struct ima_rule_entry measure_digest_cache_rule __ro_after_init = { +#ifdef CONFIG_INTEGRITY_DIGEST_CACHE + .action = MEASURE, .func = DIGEST_LIST_CHECK, + .pcr = CONFIG_IMA_DIGEST_CACHE_MEASURE_PCR_IDX, + .flags = IMA_FUNC | IMA_PCR +#endif +}; + +static struct ima_rule_entry appraise_digest_cache_rule __ro_after_init = { +#ifdef CONFIG_INTEGRITY_DIGEST_CACHE + .action = APPRAISE, .func = DIGEST_LIST_CHECK, + .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED | IMA_MODSIG_ALLOWED, +#endif +}; + /* An array of architecture specific rules */ static struct ima_rule_entry *arch_policy_entry __ro_after_init; @@ -278,6 +293,8 @@ static bool ima_use_appraise_tcb __initdata; static bool ima_use_secure_boot __initdata; static bool ima_use_critical_data __initdata; static bool ima_fail_unverifiable_sigs __ro_after_init; +static bool ima_digest_cache_measure __ro_after_init; +static bool ima_digest_cache_appraise __ro_after_init; static int __init policy_setup(char *str) { char *p; @@ -295,6 +312,10 @@ static int __init policy_setup(char *str) ima_use_critical_data = true; else if (strcmp(p, "fail_securely") == 0) ima_fail_unverifiable_sigs = true; + else if (strcmp(p, "digest_cache_measure") == 0) + ima_digest_cache_measure = true; + else if (strcmp(p, "digest_cache_appraise") == 0) + ima_digest_cache_appraise = true; else pr_err("policy \"%s\" not found", p); } @@ -983,6 +1004,20 @@ void __init ima_init_policy(void) { int build_appraise_entries, arch_entries; + /* + * We need to load digest cache rules at the beginning, to avoid dont_ + * rules causing ours to not be reached. + */ + if (IS_ENABLED(CONFIG_INTEGRITY_DIGEST_CACHE)) { + if (ima_digest_cache_measure) + add_rules(&measure_digest_cache_rule, 1, + IMA_DEFAULT_POLICY); + + if (ima_digest_cache_appraise) + add_rules(&appraise_digest_cache_rule, 1, + IMA_DEFAULT_POLICY); + } + /* if !ima_policy, we load NO default rules */ if (ima_policy) add_rules(dont_measure_rules, ARRAY_SIZE(dont_measure_rules), From patchwork Tue Nov 19 11:00:58 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roberto Sassu X-Patchwork-Id: 13879720 Received: from frasgout11.his.huawei.com (frasgout11.his.huawei.com [14.137.139.23]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1563B1C2335; Tue, 19 Nov 2024 11:02:30 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=14.137.139.23 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1732014152; cv=none; b=fYjx7FJshzWlCEGPiMM8li+C/PGd17nhFlOgjRyabYZPVuzku92hHtgCNGWVjXLwmi65uBj+2oFB35fWM9tK4g5+WSP4ti9izImB9hVb9WE/fq7mIJZNohqmVDcMpTBB4PE4rIUh6mHwhcWyu0kaMLtV1RY4nG1Od6oNSe/PmtU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1732014152; c=relaxed/simple; bh=rls2C7PG/jZRCDjxmbSyiaDQJJ3Kvt8aX/lZdgUP+yI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=HwuCu4Ix7UweTAEZZ+bV+4g4yJUog3mlV6uhheeTivok1C7yrVbP5PjMTHv1uvUO00tdw60jI6Jk5SgWgswZ+q4Sk9HM7eqjQ+D+A9bbKoAOATzxjOVkzSnfrNKrQxMM+d4Cb0n9EnCPFr2Pnj4CRjuh43aZFnT2Ndu8tqTCyMY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=huaweicloud.com; spf=pass smtp.mailfrom=huaweicloud.com; arc=none smtp.client-ip=14.137.139.23 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=huaweicloud.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huaweicloud.com Received: from mail.maildlp.com (unknown [172.18.186.29]) by frasgout11.his.huawei.com (SkyGuard) with ESMTP id 4Xt1JG2sXhz9v7J3; Tue, 19 Nov 2024 18:41:34 +0800 (CST) Received: from mail02.huawei.com (unknown [7.182.16.47]) by mail.maildlp.com (Postfix) with ESMTP id D3989140CA3; Tue, 19 Nov 2024 19:02:21 +0800 (CST) Received: from huaweicloud.com (unknown [10.204.63.22]) by APP1 (Coremail) with SMTP id LxC2BwB3NTb9bzxnNXHnAQ--.10850S6; Tue, 19 Nov 2024 12:02:21 +0100 (CET) From: Roberto Sassu To: corbet@lwn.net, zohar@linux.ibm.com, dmitry.kasatkin@gmail.com, eric.snowberg@oracle.com, paul@paul-moore.com, jmorris@namei.org, serge@hallyn.com Cc: linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, linux-integrity@vger.kernel.org, linux-security-module@vger.kernel.org, wufan@linux.microsoft.com, pbrobinson@gmail.com, zbyszek@in.waw.pl, hch@lst.de, mjg59@srcf.ucam.org, pmatilai@redhat.com, jannh@google.com, dhowells@redhat.com, jikos@kernel.org, mkoutny@suse.com, ppavlu@suse.com, petr.vorel@gmail.com, mzerqung@0pointer.de, kgold@linux.ibm.com, Roberto Sassu Subject: [RFC][PATCH v4 4/9] ima: Modify existing boot-time built-in policies with digest cache policies Date: Tue, 19 Nov 2024 12:00:58 +0100 Message-ID: <20241119110103.2780453-5-roberto.sassu@huaweicloud.com> X-Mailer: git-send-email 2.47.0.118.gfd3785337b In-Reply-To: <20241119110103.2780453-1-roberto.sassu@huaweicloud.com> References: <20241119110103.2780453-1-roberto.sassu@huaweicloud.com> Precedence: bulk X-Mailing-List: linux-security-module@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-CM-TRANSID: LxC2BwB3NTb9bzxnNXHnAQ--.10850S6 X-Coremail-Antispam: 1UD129KBjvJXoWxXryrur4rAF45uF4fuF1kuFg_yoW5uF1rpa 9FgrySkr97Zr9rCw1fA3WIvF4rK3ykta1UWa1DK345AF45CF1qv3W8tr43uFy7Gr10qF4x JFs0gw4jk3WqyaUanT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDU0xBIdaVrnRJUUUPSb4IE77IF4wAFF20E14v26rWj6s0DM7CY07I20VC2zVCF04k2 6cxKx2IYs7xG6rWj6s0DM7CIcVAFz4kK6r1j6r18M28IrcIa0xkI8VA2jI8067AKxVWUAV Cq3wA2048vs2IY020Ec7CjxVAFwI0_Xr0E3s1l8cAvFVAK0II2c7xJM28CjxkF64kEwVA0 rcxSw2x7M28EF7xvwVC0I7IYx2IY67AKxVW5JVW7JwA2z4x0Y4vE2Ix0cI8IcVCY1x0267 AKxVWxJr0_GcWl84ACjcxK6I8E87Iv67AKxVW8JVWxJwA2z4x0Y4vEx4A2jsIEc7CjxVAF wI0_Cr1j6rxdM2AIxVAIcxkEcVAq07x20xvEncxIr21l5I8CrVACY4xI64kE6c02F40Ex7 xfMcIj6xIIjxv20xvE14v26r126r1DMcIj6I8E87Iv67AKxVWUJVW8JwAm72CE4IkC6x0Y z7v_Jr0_Gr1lF7xvr2IYc2Ij64vIr41lFIxGxcIEc7CjxVA2Y2ka0xkIwI1lc7CjxVAaw2 AFwI0_GFv_Wryl42xK82IYc2Ij64vIr41l4I8I3I0E4IkC6x0Yz7v_Jr0_Gr1lx2IqxVAq x4xG67AKxVWUJVWUGwC20s026x8GjcxK67AKxVWUGVWUWwC2zVAF1VAY17CE14v26r4a6r W5MIIYrxkI7VAKI48JMIIF0xvE2Ix0cI8IcVAFwI0_Xr0_Ar1lIxAIcVC0I7IYx2IY6xkF 7I0E14v26F4UJVW0owCI42IY6xAIw20EY4v20xvaj40_Jr0_JF4lIxAIcVC2z280aVAFwI 0_Gr0_Cr1lIxAIcVC2z280aVCY1x0267AKxVWxJr0_GcJvcSsGvfC2KfnxnUUI43ZEXa7I U04rW7UUUUU== X-CM-SenderInfo: purev21wro2thvvxqx5xdzvxpfor3voofrz/1tbiAQAMBGc797QElQABsG From: Roberto Sassu Setting the boot-time built-in policies 'digest_cache_measure' and 'digest_cache_appraise' is not sufficient to use the Integrity Digest Cache to measure and appraise files, since their effect is only to measure and appraise digest lists. Modify existing measurement rules if the 'digest_cache_measure' built-in policy is specified by adding to them: digest_cache=data pcr=12 Other than enabling the usage of the Integrity Digest Cache for measurement, the additional keywords also store measurements in the PCR 12, to not confuse new style measurements with the original ones still stored on PCR 10. Modify existing appraisal rules if the 'digest_cache_appraise' built-in policy is specified by adding to them: digest_cache=data The additional keyword enables the usage of Integrity Digest Cache for appraisal. Signed-off-by: Roberto Sassu --- Documentation/admin-guide/kernel-parameters.txt | 9 +++++++-- security/integrity/ima/ima_policy.c | 14 ++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 9b6f85b1376c..129d60f5a46b 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -2118,11 +2118,16 @@ critical data. The "digest_cache_measure" policy measures digest lists - into PCR 12 (can be changed with kernel config). + into PCR 12 (can be changed with kernel config), enables + the digest cache to be used for the other selected + measure rules (if compatible), and measures the files + with digest not found in the digest list into PCR 12 + (changeable). The "digest_cache_appraise" policy appraises digest lists with IMA signatures or module-style appended - signatures. + signatures, and enables the digest cache to be used for + the other selected appraise rules (if compatible). ima_tcb [IMA] Deprecated. Use ima_policy= instead. Load a policy which meets the needs of the Trusted diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index c2bf58010b89..c74ff36fcc1f 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c @@ -930,6 +930,20 @@ static void add_rules(struct ima_rule_entry *entries, int count, for (i = 0; i < count; i++) { struct ima_rule_entry *entry; + if (IS_ENABLED(CONFIG_INTEGRITY_DIGEST_CACHE) && + entries[i].action == MEASURE && ima_digest_cache_measure && + ima_digest_cache_func_allowed(entries[i].func)) { + entries[i].digest_cache_usage |= IMA_DIGEST_CACHE_MEASURE_DATA; + entries[i].pcr = CONFIG_IMA_DIGEST_CACHE_MEASURE_PCR_IDX; + entries[i].flags |= IMA_PCR; + } + + if (IS_ENABLED(CONFIG_INTEGRITY_DIGEST_CACHE) && + entries[i].action == APPRAISE && + ima_digest_cache_appraise && + ima_digest_cache_func_allowed(entries[i].func)) + entries[i].digest_cache_usage |= IMA_DIGEST_CACHE_APPRAISE_DATA; + if (policy_rule & IMA_DEFAULT_POLICY) list_add_tail(&entries[i].list, &ima_default_rules); From patchwork Tue Nov 19 11:00:59 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roberto Sassu X-Patchwork-Id: 13879721 Received: from frasgout11.his.huawei.com (frasgout11.his.huawei.com [14.137.139.23]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8E48E1C729B; Tue, 19 Nov 2024 11:02:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=14.137.139.23 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1732014158; cv=none; b=ASvaZxV+HQphJvTiUFM/TjVLAKnYKbDc13wavq+3G7bLZXUBKlgwnVf9JfYDGKx46+r3CBQrP/Dd0v7mIcBaOJ9xg1l8j8LwKgJl8gHY6VjN+7PSZcLljL1qYFnG+TyUlK7da+4cNs16oGSwe7Vi2yE2viMdDFgTMZn4um3tOYM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1732014158; c=relaxed/simple; bh=nUfb61F6Guo4odfuRsaEiXvEuy8IJGedd9HvWwj618E=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=NrHiG7jW1D5LyeZ7EwayhyThLPZ3BwT6Vt5YpOauFP1JoVT74PH8hR0giqbiFbCNvM5fzi5amgeKUJlnbSCE5wKvWx2yufbr8ADqIhxAMDYpM7bXMLAxSOtzR3PPrV8vOlGA6tHIDhL5su3h3HEL5wD/0Xwouuse/ecrsKqz0+Q= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=huaweicloud.com; spf=pass smtp.mailfrom=huaweicloud.com; arc=none smtp.client-ip=14.137.139.23 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=huaweicloud.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huaweicloud.com Received: from mail.maildlp.com (unknown [172.18.186.29]) by frasgout11.his.huawei.com (SkyGuard) with ESMTP id 4Xt1JN04GWz9v7J4; Tue, 19 Nov 2024 18:41:40 +0800 (CST) Received: from mail02.huawei.com (unknown [7.182.16.47]) by mail.maildlp.com (Postfix) with ESMTP id CC8FA140119; Tue, 19 Nov 2024 19:02:33 +0800 (CST) Received: from huaweicloud.com (unknown [10.204.63.22]) by APP1 (Coremail) with SMTP id LxC2BwB3NTb9bzxnNXHnAQ--.10850S7; Tue, 19 Nov 2024 12:02:33 +0100 (CET) From: Roberto Sassu To: corbet@lwn.net, zohar@linux.ibm.com, dmitry.kasatkin@gmail.com, eric.snowberg@oracle.com, paul@paul-moore.com, jmorris@namei.org, serge@hallyn.com Cc: linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, linux-integrity@vger.kernel.org, linux-security-module@vger.kernel.org, wufan@linux.microsoft.com, pbrobinson@gmail.com, zbyszek@in.waw.pl, hch@lst.de, mjg59@srcf.ucam.org, pmatilai@redhat.com, jannh@google.com, dhowells@redhat.com, jikos@kernel.org, mkoutny@suse.com, ppavlu@suse.com, petr.vorel@gmail.com, mzerqung@0pointer.de, kgold@linux.ibm.com, Roberto Sassu Subject: [RFC][PATCH v4 5/9] ima: Retrieve digest cache and check if changed Date: Tue, 19 Nov 2024 12:00:59 +0100 Message-ID: <20241119110103.2780453-6-roberto.sassu@huaweicloud.com> X-Mailer: git-send-email 2.47.0.118.gfd3785337b In-Reply-To: <20241119110103.2780453-1-roberto.sassu@huaweicloud.com> References: <20241119110103.2780453-1-roberto.sassu@huaweicloud.com> Precedence: bulk X-Mailing-List: linux-security-module@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-CM-TRANSID: LxC2BwB3NTb9bzxnNXHnAQ--.10850S7 X-Coremail-Antispam: 1UD129KBjvJXoWxKF18WFyDCrWrGr18uw4rXwb_yoW3Zr4Upa 929a4Utr48ZFW7CwsrAF12kF4rK3yFgFWxWws8XwnYyFZxXr1qvw18AryUuryrGrWUAa1x ta1Ygw15A3WUtaDanT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDU0xBIdaVrnRJUUUPSb4IE77IF4wAFF20E14v26rWj6s0DM7CY07I20VC2zVCF04k2 6cxKx2IYs7xG6rWj6s0DM7CIcVAFz4kK6r1j6r18M28IrcIa0xkI8VA2jI8067AKxVWUAV Cq3wA2048vs2IY020Ec7CjxVAFwI0_Xr0E3s1l8cAvFVAK0II2c7xJM28CjxkF64kEwVA0 rcxSw2x7M28EF7xvwVC0I7IYx2IY67AKxVW5JVW7JwA2z4x0Y4vE2Ix0cI8IcVCY1x0267 AKxVWxJr0_GcWl84ACjcxK6I8E87Iv67AKxVW8JVWxJwA2z4x0Y4vEx4A2jsIEc7CjxVAF wI0_Cr1j6rxdM2AIxVAIcxkEcVAq07x20xvEncxIr21l5I8CrVACY4xI64kE6c02F40Ex7 xfMcIj6xIIjxv20xvE14v26r126r1DMcIj6I8E87Iv67AKxVWUJVW8JwAm72CE4IkC6x0Y z7v_Jr0_Gr1lF7xvr2IYc2Ij64vIr41lFIxGxcIEc7CjxVA2Y2ka0xkIwI1lc7CjxVAaw2 AFwI0_GFv_Wryl42xK82IYc2Ij64vIr41l4I8I3I0E4IkC6x0Yz7v_Jr0_Gr1lx2IqxVAq x4xG67AKxVWUJVWUGwC20s026x8GjcxK67AKxVWUGVWUWwC2zVAF1VAY17CE14v26r4a6r W5MIIYrxkI7VAKI48JMIIF0xvE2Ix0cI8IcVAFwI0_Xr0_Ar1lIxAIcVC0I7IYx2IY6xkF 7I0E14v26F4UJVW0owCI42IY6xAIw20EY4v20xvaj40_Jr0_JF4lIxAIcVC2z280aVAFwI 0_Gr0_Cr1lIxAIcVC2z280aVCY1x0267AKxVWxJr0_GcJvcSsGvfC2KfnxnUUI43ZEXa7I U04rW7UUUUU== X-CM-SenderInfo: purev21wro2thvvxqx5xdzvxpfor3voofrz/1tbiAQAMBGc797QElgABsF From: Roberto Sassu Add a digest cache pointer to the ima_iint_cache structure and introduce ima_digest_cache_get_check() to retrieve a fresh digest cache and compare with the pointer stored in the previous calls (if digest cache was enabled in the IMA policy). If the pointers don't match, reset the integrity status since the digest cache used for the previous verification might have changed. Also, initialize and put the digest cache respectively in ima_iint_init_always() and ima_iint_free(). Call ima_digest_cache_get_check() with the iint->mutex held, to protect the assignment of the digest cache pointer in the inode integrity metadata. Change mutex_lock() to mutex_lock_nested() to avoid a lockdep warning due to a possible deadlock (recursive iint->mutex lock, during a kernel read). Nesting is safe for files opened by the Integrity Digest Cache, because the latter guarantees that it will never cause IMA to be invoked with the same inode. Call digest_cache_opened_fd() to know when nesting is safe, and pass the boolean to mutex_lock_nested(). Signed-off-by: Roberto Sassu --- security/integrity/ima/Makefile | 1 + security/integrity/ima/ima.h | 1 + security/integrity/ima/ima_digest_cache.c | 49 +++++++++++++++++++++++ security/integrity/ima/ima_digest_cache.h | 22 ++++++++++ security/integrity/ima/ima_iint.c | 4 ++ security/integrity/ima/ima_main.c | 13 +++++- 6 files changed, 88 insertions(+), 2 deletions(-) create mode 100644 security/integrity/ima/ima_digest_cache.c create mode 100644 security/integrity/ima/ima_digest_cache.h diff --git a/security/integrity/ima/Makefile b/security/integrity/ima/Makefile index b376d38b4ee6..b4a284634a07 100644 --- a/security/integrity/ima/Makefile +++ b/security/integrity/ima/Makefile @@ -14,6 +14,7 @@ ima-$(CONFIG_HAVE_IMA_KEXEC) += ima_kexec.o ima-$(CONFIG_IMA_BLACKLIST_KEYRING) += ima_mok.o ima-$(CONFIG_IMA_MEASURE_ASYMMETRIC_KEYS) += ima_asymmetric_keys.o ima-$(CONFIG_IMA_QUEUE_EARLY_BOOT_KEYS) += ima_queue_keys.o +ima-$(CONFIG_INTEGRITY_DIGEST_CACHE) += ima_digest_cache.o ifeq ($(CONFIG_EFI),y) ima-$(CONFIG_IMA_SECURE_AND_OR_TRUSTED_BOOT) += ima_efi.o diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index 64667f16a30f..f3e6dcd9defd 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -198,6 +198,7 @@ struct ima_iint_cache { enum integrity_status ima_read_status:4; enum integrity_status ima_creds_status:4; struct ima_digest_data *ima_hash; + struct digest_cache *digest_cache; }; extern struct lsm_blob_sizes ima_blob_sizes; diff --git a/security/integrity/ima/ima_digest_cache.c b/security/integrity/ima/ima_digest_cache.c new file mode 100644 index 000000000000..ad47772a05bd --- /dev/null +++ b/security/integrity/ima/ima_digest_cache.c @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2024 Huawei Technologies Duesseldorf GmbH + * + * Author: Roberto Sassu + * + * Integrate with the Integrity Digest Cache. + */ + +#include + +#include "ima_digest_cache.h" + +/** + * ima_digest_cache_get_check - Get digest cache and check if changed + * @file: File descriptor of the inode for which the digest cache will be used + * @iint: Inode integrity metadata + * + * Get a digest cache for the file descriptor parameter and compare with the + * digest cache stored in the inode integrity metadata. + * + * It must be called with the iint->mutex held. + * + * Return: True if the digest cache pointer changed, false otherwise. + */ +bool ima_digest_cache_get_check(struct file *file, + struct ima_iint_cache *iint) +{ + struct digest_cache *digest_cache; + + digest_cache = digest_cache_get(file); + + /* There was no digest cache before, not changed. */ + if (!iint->digest_cache) { + iint->digest_cache = digest_cache; + return false; + } + + /* New digest cache not available, or digest cache changed. */ + if (!digest_cache || iint->digest_cache != digest_cache) { + digest_cache_put(iint->digest_cache); + iint->digest_cache = digest_cache; + return true; + } + + /* Digest cache not changed. */ + digest_cache_put(digest_cache); + return false; +} diff --git a/security/integrity/ima/ima_digest_cache.h b/security/integrity/ima/ima_digest_cache.h new file mode 100644 index 000000000000..8126ae1e2f4f --- /dev/null +++ b/security/integrity/ima/ima_digest_cache.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2024 Huawei Technologies Duesseldorf GmbH + * + * Author: Roberto Sassu + * + * Header file of ima_digest_cache.c. + */ + +#include "ima.h" + +#ifdef CONFIG_INTEGRITY_DIGEST_CACHE +bool ima_digest_cache_get_check(struct file *file, + struct ima_iint_cache *iint); +#else +static inline bool ima_digest_cache_get_check(struct file *file, + struct ima_iint_cache *iint) +{ + return false; +} + +#endif /* CONFIG_INTEGRITY_DIGEST_CACHE */ diff --git a/security/integrity/ima/ima_iint.c b/security/integrity/ima/ima_iint.c index 00b249101f98..7ed7e857d738 100644 --- a/security/integrity/ima/ima_iint.c +++ b/security/integrity/ima/ima_iint.c @@ -68,12 +68,16 @@ static void ima_iint_init_always(struct ima_iint_cache *iint, iint->ima_read_status = INTEGRITY_UNKNOWN; iint->ima_creds_status = INTEGRITY_UNKNOWN; iint->measured_pcrs = 0; + iint->digest_cache = NULL; mutex_init(&iint->mutex); ima_iint_lockdep_annotate(iint, inode); } static void ima_iint_free(struct ima_iint_cache *iint) { + if (iint->digest_cache) + digest_cache_put(iint->digest_cache); + kfree(iint->ima_hash); mutex_destroy(&iint->mutex); kmem_cache_free(ima_iint_cache, iint); diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index bcbf64bb03c2..aaff8cd8d5c6 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -29,6 +29,7 @@ #include #include "ima.h" +#include "ima_digest_cache.h" #ifdef CONFIG_IMA_APPRAISE int ima_appraise = IMA_APPRAISE_ENFORCE; @@ -224,6 +225,7 @@ static int process_measurement(struct file *file, const struct cred *cred, bool violation_check; enum hash_algo hash_algo; unsigned int allowed_algos = 0; + u64 policy_usage = 0ULL; if (!ima_policy_flag || !S_ISREG(inode->i_mode)) return 0; @@ -234,7 +236,7 @@ static int process_measurement(struct file *file, const struct cred *cred, */ action = ima_get_action(file_mnt_idmap(file), inode, cred, secid, mask, func, &pcr, &template_desc, NULL, - &allowed_algos, NULL); + &allowed_algos, &policy_usage); violation_check = ((func == FILE_CHECK || func == MMAP_CHECK || func == MMAP_CHECK_REQPROT) && (ima_policy_flag & IMA_MEASURE)); @@ -266,7 +268,7 @@ static int process_measurement(struct file *file, const struct cred *cred, if (!action) goto out; - mutex_lock(&iint->mutex); + mutex_lock_nested(&iint->mutex, digest_cache_opened_fd(file)); if (test_and_clear_bit(IMA_CHANGE_ATTR, &iint->atomic_flags)) /* reset appraisal flags if ima_inode_post_setattr was called */ @@ -287,6 +289,13 @@ static int process_measurement(struct file *file, const struct cred *cred, iint->measured_pcrs = 0; } + /* Digest cache changed, reset integrity status. */ + if (policy_usage && + ima_digest_cache_get_check(file, iint)) { + iint->flags &= ~IMA_DONE_MASK; + iint->measured_pcrs = 0; + } + /* * On stacked filesystems, detect and re-evaluate file data and * metadata changes. From patchwork Tue Nov 19 11:01:00 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roberto Sassu X-Patchwork-Id: 13879722 Received: from frasgout11.his.huawei.com (frasgout11.his.huawei.com [14.137.139.23]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 70D9714AD1A; Tue, 19 Nov 2024 11:02:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=14.137.139.23 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1732014170; cv=none; b=BW/B1kWShayMmIQY9Ovw9rm6TltIux3Awx7CDfUs/yqTFjSaFpgXrU295mD+HeWXuWBrQ8IgPCpAqHiVASuJk87mkaPtPw/ljl1v7oK5YVUPltX+7Z6IZ1egiz5gJsXRCCxi7uwRSjMLaiWF8Gjpk5B6kVZ9W6JpQlZYELgGSMM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1732014170; c=relaxed/simple; bh=SWd2JGKyvAQyvSXgEWdVTrxzhKZepkNBg4UGmSBeP20=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=oEhwOwOeNLIxnX0ox9bqJxsaOEDx8tvWPZP7+MwntVTWJEKGC34spPC0xmRCJTR9kSJlkqX7vGw7CtJPgBwjDRBprknKeK09BbLGBDOVyzQM22SMpjKWpwKW8xo0dwtPZSWNufhkRy2WD98b5ldJcefKUsiZH1EaanhPAvj4JTo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=huaweicloud.com; spf=pass smtp.mailfrom=huaweicloud.com; arc=none smtp.client-ip=14.137.139.23 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=huaweicloud.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huaweicloud.com Received: from mail.maildlp.com (unknown [172.18.186.51]) by frasgout11.his.huawei.com (SkyGuard) with ESMTP id 4Xt1Jb6fMtz9v7N1; Tue, 19 Nov 2024 18:41:51 +0800 (CST) Received: from mail02.huawei.com (unknown [7.182.16.47]) by mail.maildlp.com (Postfix) with ESMTP id BA93F1407F5; Tue, 19 Nov 2024 19:02:45 +0800 (CST) Received: from huaweicloud.com (unknown [10.204.63.22]) by APP1 (Coremail) with SMTP id LxC2BwB3NTb9bzxnNXHnAQ--.10850S8; Tue, 19 Nov 2024 12:02:45 +0100 (CET) From: Roberto Sassu To: corbet@lwn.net, zohar@linux.ibm.com, dmitry.kasatkin@gmail.com, eric.snowberg@oracle.com, paul@paul-moore.com, jmorris@namei.org, serge@hallyn.com Cc: linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, linux-integrity@vger.kernel.org, linux-security-module@vger.kernel.org, wufan@linux.microsoft.com, pbrobinson@gmail.com, zbyszek@in.waw.pl, hch@lst.de, mjg59@srcf.ucam.org, pmatilai@redhat.com, jannh@google.com, dhowells@redhat.com, jikos@kernel.org, mkoutny@suse.com, ppavlu@suse.com, petr.vorel@gmail.com, mzerqung@0pointer.de, kgold@linux.ibm.com, Roberto Sassu Subject: [RFC][PATCH v4 6/9] ima: Store verified usage in digest cache based on integrity metadata flags Date: Tue, 19 Nov 2024 12:01:00 +0100 Message-ID: <20241119110103.2780453-7-roberto.sassu@huaweicloud.com> X-Mailer: git-send-email 2.47.0.118.gfd3785337b In-Reply-To: <20241119110103.2780453-1-roberto.sassu@huaweicloud.com> References: <20241119110103.2780453-1-roberto.sassu@huaweicloud.com> Precedence: bulk X-Mailing-List: linux-security-module@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-CM-TRANSID: LxC2BwB3NTb9bzxnNXHnAQ--.10850S8 X-Coremail-Antispam: 1UD129KBjvJXoWxKrWUZFW8Zr47Kr1DZF47Jwb_yoW7Xr17pa 9IgF9rtr1kZry7CrsxAF17uayFkrZ5ta1UXw45Zrn0ya15Zr1qy393Cr1UuFy5JFWvq3Wx tw42gw13Cw1DtaDanT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDU0xBIdaVrnRJUUUPSb4IE77IF4wAFF20E14v26rWj6s0DM7CY07I20VC2zVCF04k2 6cxKx2IYs7xG6rWj6s0DM7CIcVAFz4kK6r1j6r18M28IrcIa0xkI8VA2jI8067AKxVWUAV Cq3wA2048vs2IY020Ec7CjxVAFwI0_Xr0E3s1l8cAvFVAK0II2c7xJM28CjxkF64kEwVA0 rcxSw2x7M28EF7xvwVC0I7IYx2IY67AKxVW5JVW7JwA2z4x0Y4vE2Ix0cI8IcVCY1x0267 AKxVWxJr0_GcWl84ACjcxK6I8E87Iv67AKxVW8JVWxJwA2z4x0Y4vEx4A2jsIEc7CjxVAF wI0_Cr1j6rxdM2AIxVAIcxkEcVAq07x20xvEncxIr21l5I8CrVACY4xI64kE6c02F40Ex7 xfMcIj6xIIjxv20xvE14v26r126r1DMcIj6I8E87Iv67AKxVWUJVW8JwAm72CE4IkC6x0Y z7v_Jr0_Gr1lF7xvr2IYc2Ij64vIr41lFIxGxcIEc7CjxVA2Y2ka0xkIwI1lc7CjxVAaw2 AFwI0_GFv_Wryl42xK82IYc2Ij64vIr41l4I8I3I0E4IkC6x0Yz7v_Jr0_Gr1lx2IqxVAq x4xG67AKxVWUJVWUGwC20s026x8GjcxK67AKxVWUGVWUWwC2zVAF1VAY17CE14v26r4a6r W5MIIYrxkI7VAKI48JMIIF0xvE2Ix0cI8IcVAFwI0_Xr0_Ar1lIxAIcVC0I7IYx2IY6xkF 7I0E14v26F4UJVW0owCI42IY6xAIw20EY4v20xvaj40_Jr0_JF4lIxAIcVC2z280aVAFwI 0_Gr0_Cr1lIxAIcVC2z280aVCY1x0267AKxVWxJr0_GcJvcSsGvfC2KfnxnUUI43ZEXa7I U04rW7UUUUU== X-CM-SenderInfo: purev21wro2thvvxqx5xdzvxpfor3voofrz/1tbiAgAMBGc79-IEpgAAsx From: Roberto Sassu The Integrity Digest Cache allows integrity providers to record how the digest list being used to populate the digest cache was verified. Integrity providers can register a kernel_post_read_file LSM hook implementation, and call digest_cache_verif_set() providing the result of the digest list verification, together with the digest list file descriptor. IMA implements ima_digest_cache_store_verified_usage(), storing the verified usage of the digest cache based on whether or not the digest list the digest cache is being populated from was measured/appraised. If the digest list was measured (IMA_MEASURED set in iint->flags), ima_digest_cache_store_verified_usage() sets the IMA_DIGEST_CACHE_MEASURE_DATA in the verified usage. If the digest list was appraised (IMA_APPRAISED_SUBMASK), ima_digest_cache_store_verified_usage() sets the IMA_DIGEST_CACHE_APPRAISE_DATA in the verified usage. Verified usage based on integrity metadata will be ANDed with the policy usage from the IMA policy. Then, the final decision will ultimately depend on whether or not the calculated digest of the accessed file was found in the digest cache. ANDing the verified usage with the policy usage prevents remote verifiers from receiving an incomplete IMA measurement list, where measurements of files are skipped, but there isn't the measurement of the digest lists the calculated file digests were searched into. It also prevents successful appraisal without appraising the digest list itself. Signed-off-by: Roberto Sassu --- security/integrity/ima/ima_digest_cache.c | 35 +++++++++++++++++++++++ security/integrity/ima/ima_digest_cache.h | 7 +++++ security/integrity/ima/ima_main.c | 2 ++ 3 files changed, 44 insertions(+) diff --git a/security/integrity/ima/ima_digest_cache.c b/security/integrity/ima/ima_digest_cache.c index ad47772a05bd..2c7824ce05cd 100644 --- a/security/integrity/ima/ima_digest_cache.c +++ b/security/integrity/ima/ima_digest_cache.c @@ -47,3 +47,38 @@ bool ima_digest_cache_get_check(struct file *file, digest_cache_put(digest_cache); return false; } + +/** + * ima_digest_cache_store_verified_usage - Store verified usage in digest cache + * @file: Digest list file descriptor + * @iint: Inode integrity metadata + * + * Set digest cache verified usage in the digest cache associated to the + * digest list file descriptor. Verified usage is based on whether or not the + * digest list was measured/appraised, and is ANDed with the policy usage to + * make the final decision on whether a digest cache can be used for a specific + * IMA action. + */ +void ima_digest_cache_store_verified_usage(struct file *file, + struct ima_iint_cache *iint) +{ + u64 verified_usage = 0; + int rc; + + if (iint->flags & IMA_MEASURED) + verified_usage |= IMA_DIGEST_CACHE_MEASURE_DATA; + if (iint->flags & IMA_APPRAISED_SUBMASK) + verified_usage |= IMA_DIGEST_CACHE_APPRAISE_DATA; + + /* + * Set digest cache verified usage from integrity metadata flags for + * later use. + */ + rc = digest_cache_verif_set(file, "ima", &verified_usage, + sizeof(verified_usage)); + + /* Ignore if fd doesn't have digest cache set (prefetching). */ + if (rc && rc != -ENOENT) + pr_debug("Cannot set verified usage for %s, ret: %d, ignoring\n", + file_dentry(file)->d_name.name, rc); +} diff --git a/security/integrity/ima/ima_digest_cache.h b/security/integrity/ima/ima_digest_cache.h index 8126ae1e2f4f..167690930078 100644 --- a/security/integrity/ima/ima_digest_cache.h +++ b/security/integrity/ima/ima_digest_cache.h @@ -12,6 +12,8 @@ #ifdef CONFIG_INTEGRITY_DIGEST_CACHE bool ima_digest_cache_get_check(struct file *file, struct ima_iint_cache *iint); +void ima_digest_cache_store_verified_usage(struct file *file, + struct ima_iint_cache *iint); #else static inline bool ima_digest_cache_get_check(struct file *file, struct ima_iint_cache *iint) @@ -19,4 +21,9 @@ static inline bool ima_digest_cache_get_check(struct file *file, return false; } +static inline void +ima_digest_cache_store_verified_usage(struct file *file, + struct ima_iint_cache *iint) +{ } + #endif /* CONFIG_INTEGRITY_DIGEST_CACHE */ diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index aaff8cd8d5c6..607749d520b0 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -421,6 +421,8 @@ static int process_measurement(struct file *file, const struct cred *cred, if ((mask & MAY_WRITE) && test_bit(IMA_DIGSIG, &iint->atomic_flags) && !(iint->flags & IMA_NEW_FILE)) rc = -EACCES; + if (!rc && func == DIGEST_LIST_CHECK) + ima_digest_cache_store_verified_usage(file, iint); mutex_unlock(&iint->mutex); kfree(xattr_value); ima_free_modsig(modsig); From patchwork Tue Nov 19 11:01:01 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roberto Sassu X-Patchwork-Id: 13879723 Received: from frasgout13.his.huawei.com (frasgout13.his.huawei.com [14.137.139.46]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E28C41C68A3; Tue, 19 Nov 2024 11:03:05 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=14.137.139.46 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1732014187; cv=none; b=d3oQ0Rug10XWfRp1FG4wysTs5n4QShdw9sftLNSUUBSryrNWBGWgCx8s1WELjCkyp+8WxHl/+5Jq2Swa+3rqLEhNDfV5G2viAZPBwm9mECEM4WIE+x25Y0aXO8dm6anfQN1n556tRpkXbT8Sq6IuJqAGKvZYrVbKGV9tNEJlTKE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1732014187; c=relaxed/simple; bh=ju/IAw6dPeGn+d1vHJhFySBDcHhb9QLqKEczPv4HD9g=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=AVvL93HdwKBmL9Zs844yI5M6o9bg7GW/vYk5xF2MA+ZChz2XMtKKLj3Ypp7p6w+sSp+A12Wz64JunO62+90MXz3iIQY1Fs15KPfnIyo5qUO1xSEKn2izUsQr5hNIjle8VDXFNu7wI5R0MJ+tm3ODEnRFOHQd6aWEv35Sg4hc69c= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=huaweicloud.com; spf=none smtp.mailfrom=huaweicloud.com; arc=none smtp.client-ip=14.137.139.46 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=huaweicloud.com Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=huaweicloud.com Received: from mail.maildlp.com (unknown [172.18.186.51]) by frasgout13.his.huawei.com (SkyGuard) with ESMTP id 4Xt1Jz5krRz9v7NH; Tue, 19 Nov 2024 18:42:11 +0800 (CST) Received: from mail02.huawei.com (unknown [7.182.16.47]) by mail.maildlp.com (Postfix) with ESMTP id AAE0D140E9A; Tue, 19 Nov 2024 19:02:57 +0800 (CST) Received: from huaweicloud.com (unknown [10.204.63.22]) by APP1 (Coremail) with SMTP id LxC2BwB3NTb9bzxnNXHnAQ--.10850S9; Tue, 19 Nov 2024 12:02:57 +0100 (CET) From: Roberto Sassu To: corbet@lwn.net, zohar@linux.ibm.com, dmitry.kasatkin@gmail.com, eric.snowberg@oracle.com, paul@paul-moore.com, jmorris@namei.org, serge@hallyn.com Cc: linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, linux-integrity@vger.kernel.org, linux-security-module@vger.kernel.org, wufan@linux.microsoft.com, pbrobinson@gmail.com, zbyszek@in.waw.pl, hch@lst.de, mjg59@srcf.ucam.org, pmatilai@redhat.com, jannh@google.com, dhowells@redhat.com, jikos@kernel.org, mkoutny@suse.com, ppavlu@suse.com, petr.vorel@gmail.com, mzerqung@0pointer.de, kgold@linux.ibm.com, Roberto Sassu Subject: [RFC][PATCH v4 7/9] ima: Load verified usage from digest cache found from query Date: Tue, 19 Nov 2024 12:01:01 +0100 Message-ID: <20241119110103.2780453-8-roberto.sassu@huaweicloud.com> X-Mailer: git-send-email 2.47.0.118.gfd3785337b In-Reply-To: <20241119110103.2780453-1-roberto.sassu@huaweicloud.com> References: <20241119110103.2780453-1-roberto.sassu@huaweicloud.com> Precedence: bulk X-Mailing-List: linux-security-module@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-CM-TRANSID: LxC2BwB3NTb9bzxnNXHnAQ--.10850S9 X-Coremail-Antispam: 1UD129KBjvJXoWxWr15KFyrJr13AFyrur4rXwb_yoWrWw4rpa 9agFnrtr4rZry7Cw43AFy29rWrKrykta17J398ZwnIya15Zr1jyws5Cw1UuryfJr4jqa1x tw4jgw15Cw1qkaDanT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDU0xBIdaVrnRJUUUPSb4IE77IF4wAFF20E14v26rWj6s0DM7CY07I20VC2zVCF04k2 6cxKx2IYs7xG6rWj6s0DM7CIcVAFz4kK6r1j6r18M28IrcIa0xkI8VA2jI8067AKxVWUAV Cq3wA2048vs2IY020Ec7CjxVAFwI0_Xr0E3s1l8cAvFVAK0II2c7xJM28CjxkF64kEwVA0 rcxSw2x7M28EF7xvwVC0I7IYx2IY67AKxVW5JVW7JwA2z4x0Y4vE2Ix0cI8IcVCY1x0267 AKxVWxJr0_GcWl84ACjcxK6I8E87Iv67AKxVW8JVWxJwA2z4x0Y4vEx4A2jsIEc7CjxVAF wI0_Cr1j6rxdM2AIxVAIcxkEcVAq07x20xvEncxIr21l5I8CrVACY4xI64kE6c02F40Ex7 xfMcIj6xIIjxv20xvE14v26r126r1DMcIj6I8E87Iv67AKxVWUJVW8JwAm72CE4IkC6x0Y z7v_Jr0_Gr1lF7xvr2IYc2Ij64vIr41lFIxGxcIEc7CjxVA2Y2ka0xkIwI1lc7CjxVAaw2 AFwI0_GFv_Wryl42xK82IYc2Ij64vIr41l4I8I3I0E4IkC6x0Yz7v_Jr0_Gr1lx2IqxVAq x4xG67AKxVWUJVWUGwC20s026x8GjcxK67AKxVWUGVWUWwC2zVAF1VAY17CE14v26r4a6r W5MIIYrxkI7VAKI48JMIIF0xvE2Ix0cI8IcVAFwI0_Xr0_Ar1lIxAIcVC0I7IYx2IY6xkF 7I0E14v26F4UJVW0owCI42IY6xAIw20EY4v20xvaj40_Jr0_JF4lIxAIcVC2z280aVAFwI 0_Gr0_Cr1lIxAIcVC2z280aVCY1x0267AKxVWxJr0_GcJvcSsGvfC2KfnxnUUI43ZEXa7I U04rW7UUUUU== X-CM-SenderInfo: purev21wro2thvvxqx5xdzvxpfor3voofrz/1tbiAQAMBGc797QElwABsE From: Roberto Sassu Introduce ima_digest_cache_load_verified_usage() to retrieve the verified usage from the digest cache pointer returned by digest_cache_lookup(). Verified usage cannot be loaded from the digest cache returned by digest_cache_get() since the latter might return a directory digest cache, which does not contain any verification data (only set to digest caches populated from a file). If digest_cache_lookup() returns the ERR_PTR(-EAGAIN) error pointer, replace the digest cache pointer in the inode integrity metadata, by calling digest_cache_get() again, and perform the lookup. ERR_PTR(-EAGAIN) is returned if the digest cache currently stored in the inode integrity metadata changed between digest_cache_get() and digest_cache_lookup(). In this case, getting a fresh digest cache is necessary to see which changes have been made on the digest cache. Signed-off-by: Roberto Sassu --- security/integrity/ima/ima_digest_cache.c | 42 +++++++++++++++++++++++ security/integrity/ima/ima_digest_cache.h | 9 +++++ 2 files changed, 51 insertions(+) diff --git a/security/integrity/ima/ima_digest_cache.c b/security/integrity/ima/ima_digest_cache.c index 2c7824ce05cd..b6bd6f9d5442 100644 --- a/security/integrity/ima/ima_digest_cache.c +++ b/security/integrity/ima/ima_digest_cache.c @@ -82,3 +82,45 @@ void ima_digest_cache_store_verified_usage(struct file *file, pr_debug("Cannot set verified usage for %s, ret: %d, ignoring\n", file_dentry(file)->d_name.name, rc); } + +/** + * ima_digest_cache_load_verified_usage - Load verified usage from digest cache + * @file: File descriptor of the inode for which the digest cache will be used + * @iint: Inode integrity metadata + * + * Load digest cache verified usage from the digest cache returned by + * digest_cache_lookup(), containing the file digest calculated by IMA (if the + * digest is found). + * + * Return: Verified usage if digest is found in digest cache, zero otherwise. + */ +u64 ima_digest_cache_load_verified_usage(struct file *file, + struct ima_iint_cache *iint) +{ + u64 verified_usage = 0ULL; + void *verified_usage_ptr; + struct digest_cache *found_cache; +again: + if (!iint->digest_cache) + return 0ULL; + + /* Do lookup to get digest cache containing calculated file digest. */ + found_cache = digest_cache_lookup(file_dentry(file), iint->digest_cache, + iint->ima_hash->digest, + iint->ima_hash->algo); + if (!found_cache) { + return 0ULL; + } else if (found_cache == ERR_PTR(-EAGAIN)) { + digest_cache_put(iint->digest_cache); + iint->digest_cache = digest_cache_get(file); + goto again; + } + + /* Get verification data from digest cache with calculated digest. */ + verified_usage_ptr = digest_cache_verif_get(found_cache, "ima"); + if (verified_usage_ptr) + verified_usage = *(u64 *)verified_usage_ptr; + + digest_cache_put(found_cache); + return verified_usage; +} diff --git a/security/integrity/ima/ima_digest_cache.h b/security/integrity/ima/ima_digest_cache.h index 167690930078..23cb53ed02e5 100644 --- a/security/integrity/ima/ima_digest_cache.h +++ b/security/integrity/ima/ima_digest_cache.h @@ -14,6 +14,8 @@ bool ima_digest_cache_get_check(struct file *file, struct ima_iint_cache *iint); void ima_digest_cache_store_verified_usage(struct file *file, struct ima_iint_cache *iint); +u64 ima_digest_cache_load_verified_usage(struct file *file, + struct ima_iint_cache *iint); #else static inline bool ima_digest_cache_get_check(struct file *file, struct ima_iint_cache *iint) @@ -26,4 +28,11 @@ ima_digest_cache_store_verified_usage(struct file *file, struct ima_iint_cache *iint) { } +static inline u64 +ima_digest_cache_load_verified_usage(struct file *file, + struct ima_iint_cache *iint) +{ + return 0ULL; +} + #endif /* CONFIG_INTEGRITY_DIGEST_CACHE */ From patchwork Tue Nov 19 11:01:02 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roberto Sassu X-Patchwork-Id: 13879724 Received: from frasgout11.his.huawei.com (frasgout11.his.huawei.com [14.137.139.23]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3FA691C4A36; Tue, 19 Nov 2024 11:03:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=14.137.139.23 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1732014199; cv=none; b=gSnZCAJ37jk4+NDTat+pYENEo/4JtgcObBum86MMuuRZ5Y/zvdX4GHXgYJnlbkQ8tAt7F/vcNTUTUqOvRnyVOuv83EDUSZswJn2syYe2jB+t612Bz1vSNNPoam5NXpc5s3mZdCETROvF2QpXRfyWxdwU6FJT6q8KCWxLfobjEwQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1732014199; c=relaxed/simple; bh=Dtn3dFiwEnuNFVgKfjmK1osRUp4jcnUCWtkeo22Tyfo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=a2Pn8wsy3nRbHefxu8YdE/EYJTMvMXw3lwsUZGjY1U5G0j7X5ap9uqwVWUBZ/AG6OMBK7XqYTqlO0Yr5s1LMXD0Yk1RrttuRCd1gY5x48+HyHQ7b1CPc0Lt/sOuoJtYe3os3GfXTeUpe5DAqacAI6GHbn7eT8PmGenYKlzfMaiI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=huaweicloud.com; spf=pass smtp.mailfrom=huaweicloud.com; arc=none smtp.client-ip=14.137.139.23 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=huaweicloud.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huaweicloud.com Received: from mail.maildlp.com (unknown [172.18.186.51]) by frasgout11.his.huawei.com (SkyGuard) with ESMTP id 4Xt1K95dtvz9v7J6; Tue, 19 Nov 2024 18:42:21 +0800 (CST) Received: from mail02.huawei.com (unknown [7.182.16.47]) by mail.maildlp.com (Postfix) with ESMTP id A4FC9140DF8; Tue, 19 Nov 2024 19:03:09 +0800 (CST) Received: from huaweicloud.com (unknown [10.204.63.22]) by APP1 (Coremail) with SMTP id LxC2BwB3NTb9bzxnNXHnAQ--.10850S10; Tue, 19 Nov 2024 12:03:09 +0100 (CET) From: Roberto Sassu To: corbet@lwn.net, zohar@linux.ibm.com, dmitry.kasatkin@gmail.com, eric.snowberg@oracle.com, paul@paul-moore.com, jmorris@namei.org, serge@hallyn.com Cc: linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, linux-integrity@vger.kernel.org, linux-security-module@vger.kernel.org, wufan@linux.microsoft.com, pbrobinson@gmail.com, zbyszek@in.waw.pl, hch@lst.de, mjg59@srcf.ucam.org, pmatilai@redhat.com, jannh@google.com, dhowells@redhat.com, jikos@kernel.org, mkoutny@suse.com, ppavlu@suse.com, petr.vorel@gmail.com, mzerqung@0pointer.de, kgold@linux.ibm.com, Roberto Sassu Subject: [RFC][PATCH v4 8/9] ima: Use digest caches for measurement Date: Tue, 19 Nov 2024 12:01:02 +0100 Message-ID: <20241119110103.2780453-9-roberto.sassu@huaweicloud.com> X-Mailer: git-send-email 2.47.0.118.gfd3785337b In-Reply-To: <20241119110103.2780453-1-roberto.sassu@huaweicloud.com> References: <20241119110103.2780453-1-roberto.sassu@huaweicloud.com> Precedence: bulk X-Mailing-List: linux-security-module@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-CM-TRANSID: LxC2BwB3NTb9bzxnNXHnAQ--.10850S10 X-Coremail-Antispam: 1UD129KBjvJXoW3JFy7KrWkXF1UJw4UZFW5ZFb_yoWxGw1xpa 9IgF1UKr1kXFySkrn3A3W7Za1F93y8ta1UX398Ww1ay3ZxZr1q9w4Fkr1j9Fs8GrWvya4I yanFqw4UAw1qyaDanT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDU0xBIdaVrnRJUUUPSb4IE77IF4wAFF20E14v26rWj6s0DM7CY07I20VC2zVCF04k2 6cxKx2IYs7xG6rWj6s0DM7CIcVAFz4kK6r1j6r18M28IrcIa0xkI8VA2jI8067AKxVWUAV Cq3wA2048vs2IY020Ec7CjxVAFwI0_Xr0E3s1l8cAvFVAK0II2c7xJM28CjxkF64kEwVA0 rcxSw2x7M28EF7xvwVC0I7IYx2IY67AKxVW5JVW7JwA2z4x0Y4vE2Ix0cI8IcVCY1x0267 AKxVWxJr0_GcWl84ACjcxK6I8E87Iv67AKxVW8JVWxJwA2z4x0Y4vEx4A2jsIEc7CjxVAF wI0_Cr1j6rxdM2AIxVAIcxkEcVAq07x20xvEncxIr21l5I8CrVACY4xI64kE6c02F40Ex7 xfMcIj6xIIjxv20xvE14v26r126r1DMcIj6I8E87Iv67AKxVWUJVW8JwAm72CE4IkC6x0Y z7v_Jr0_Gr1lF7xvr2IYc2Ij64vIr41lFIxGxcIEc7CjxVA2Y2ka0xkIwI1lc7CjxVAaw2 AFwI0_GFv_Wryl42xK82IYc2Ij64vIr41l4I8I3I0E4IkC6x0Yz7v_Jr0_Gr1lx2IqxVAq x4xG67AKxVWUJVWUGwC20s026x8GjcxK67AKxVWUGVWUWwC2zVAF1VAY17CE14v26r4a6r W5MIIYrxkI7VAKI48JMIIF0xvE2Ix0cI8IcVAFwI0_Xr0_Ar1lIxAIcVC0I7IYx2IY6xkF 7I0E14v26F4UJVW0owCI42IY6xAIw20EY4v20xvaj40_Jr0_JF4lIxAIcVC2z280aVAFwI 0_Gr0_Cr1lIxAIcVC2z280aVCY1x0267AKxVWxJr0_GcJvcSsGvfC2KfnxnUUI43ZEXa7I U04rW7UUUUU== X-CM-SenderInfo: purev21wro2thvvxqx5xdzvxpfor3voofrz/1tbiAQAMBGc797QEmAAAsK From: Roberto Sassu Introduce a new measurement style using digest caches, which can be performed exclusively on non-standard PCRs, to avoid ambiguity. While a measurement on the standard PCR means that a file was accessed and had the measured data, a measurement with the digest cache means only that the calculated file digest was not found in any of the measured digest lists (any digest list used for the search must be measured, otherwise IMA wouldn't use it). The new measurement style does not tell: whether or not the file was actually accessed (since its measurement is skipped even if it was); in which sequence files were accessed. So, one has to guess that the system might have possibly accessed any of the files whose digest is in the measured digest lists, in any order. However, it has the following benefits: the IMA measurement list can be much shorter, system performance can be much better due to less PCR extend operations (see the performance evaluation in the Integrity Digest Cache documentation); the PCR can be predictable as long as the set of measured digest lists does not change (which obviously happens during software updates). The PCR can be predictable because the Integrity Digest Cache has a prefetching mechanism that reads digest lists in a deterministic order, until it finds the digest list containing the digest calculated by IMA from an accessed file. If IMA measures digest lists, the PCR is extended in a deterministic order too. Predictable PCR means that a TPM key can be made dependent on specific PCR values (or a OR of them, depending on the key policy). Accessing a file with an unknown digest immediately makes that TPM key unusable, requiring a reboot to use it again. This mechanism can be used for the so called implicit remote attestation, where the ability of a system to respond to challenges based on the private part of the TPM key means that the system has the expected PCR values (which would mean that the integrity of the system is ok). This is opposed to the explicit remote attestation, where a system has to send all its measurements, to prove to a remote party about its integrity. Call the newly introduced function ima_digest_cache_load_verified_usage() to retrieve the verified usage from the digest cache containing the calculated digest of the file being accessed (if it is found), and AND it with the policy usage. If the AND result has the IMA_DIGEST_CACHE_MEASURE_DATA flag set, behave as if the file was successfully added to the IMA measurement list (i.e. set the IMA_MEASURED flag and the PCR flag from the value specified in the matching policy rule), but actually don't do it. Signed-off-by: Roberto Sassu --- security/integrity/ima/ima.h | 3 ++- security/integrity/ima/ima_api.c | 15 ++++++++++++++- security/integrity/ima/ima_main.c | 7 +++++-- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index f3e6dcd9defd..61b019e7bace 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -389,7 +389,8 @@ void ima_store_measurement(struct ima_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 pcr, - struct ima_template_desc *template_desc); + struct ima_template_desc *template_desc, + u64 allowed_usage); int process_buffer_measurement(struct mnt_idmap *idmap, struct inode *inode, const void *buf, int size, const char *eventname, enum ima_hooks func, diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c index b44cf7d9fbcb..530c5bcc115e 100644 --- a/security/integrity/ima/ima_api.c +++ b/security/integrity/ima/ima_api.c @@ -351,7 +351,8 @@ void ima_store_measurement(struct ima_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 pcr, - struct ima_template_desc *template_desc) + struct ima_template_desc *template_desc, + u64 allowed_usage) { static const char op[] = "add_template_measure"; static const char audit_cause[] = "ENOMEM"; @@ -375,6 +376,18 @@ void ima_store_measurement(struct ima_iint_cache *iint, struct file *file, if (iint->measured_pcrs & (0x1 << pcr) && !modsig) return; + /* + * If digest cache usage was authorized with the IMA policy, the digest + * list the digest cache was populated from was measured, and the file + * digest was found in the digest cache, mark the file as successfully + * measured. + */ + if (allowed_usage & IMA_DIGEST_CACHE_MEASURE_DATA) { + iint->flags |= IMA_MEASURED; + iint->measured_pcrs |= (0x1 << pcr); + return; + } + result = ima_alloc_init_template(&event_data, &entry, template_desc); if (result < 0) { integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, filename, diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 607749d520b0..0d37cdc01622 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -225,7 +225,7 @@ static int process_measurement(struct file *file, const struct cred *cred, bool violation_check; enum hash_algo hash_algo; unsigned int allowed_algos = 0; - u64 policy_usage = 0ULL; + u64 policy_usage = 0ULL, verified_usage = 0ULL; if (!ima_policy_flag || !S_ISREG(inode->i_mode)) return 0; @@ -385,10 +385,13 @@ static int process_measurement(struct file *file, const struct cred *cred, if (!pathbuf) /* ima_rdwr_violation possibly pre-fetched */ pathname = ima_d_path(&file->f_path, &pathbuf, filename); + verified_usage = ima_digest_cache_load_verified_usage(file, iint); + if (action & IMA_MEASURE) ima_store_measurement(iint, file, pathname, xattr_value, xattr_len, modsig, pcr, - template_desc); + template_desc, + (policy_usage & verified_usage)); if (rc == 0 && (action & IMA_APPRAISE_SUBMASK)) { rc = ima_check_blacklist(iint, modsig, pcr); if (rc != -EPERM) { From patchwork Tue Nov 19 11:01:03 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roberto Sassu X-Patchwork-Id: 13879725 Received: from frasgout13.his.huawei.com (frasgout13.his.huawei.com [14.137.139.46]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4C16E1C9EB5; Tue, 19 Nov 2024 11:03:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=14.137.139.46 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1732014216; cv=none; b=TVdeyWL2zs9WQ4wHks+5CzD5iJ7qFlqmsz4rIsL325glOnd7vy+KgJBtH7KVQecSsKsStBDjMuzy6/aXLx+n0MA8GtexNyzKyJCZbqslzcOegxGT1taaaimFI1I0Xl9bNRWbucf/t+gW95Z3QMazk9ZsH6fWDLHtCsyx8tJPPs4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1732014216; c=relaxed/simple; bh=pvLhc8RjAUhHE0Ypcfb/nA2SMc5FHFY1VQfKtwXor2g=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=lY2bnqGBKl9QOVUH+Ct1JIgr7+fbMIitQT7ahVUkpm2PH9D9VIpcnU7GOlvMk0B1Y7cRVk91WJpe37XMbZ4EWn8a5XBXXss7VhQjx03kuq5LDwOZxcfxfU0P7OoF56C1paYNMpUikOMaVZq+ctlbSxwD+a6HPVp8bG4zumiqBHs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=huaweicloud.com; spf=pass smtp.mailfrom=huaweicloud.com; arc=none smtp.client-ip=14.137.139.46 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=huaweicloud.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huaweicloud.com Received: from mail.maildlp.com (unknown [172.18.186.51]) by frasgout13.his.huawei.com (SkyGuard) with ESMTP id 4Xt1KX0C3nz9v7NH; Tue, 19 Nov 2024 18:42:40 +0800 (CST) Received: from mail02.huawei.com (unknown [7.182.16.47]) by mail.maildlp.com (Postfix) with ESMTP id A194014086A; Tue, 19 Nov 2024 19:03:21 +0800 (CST) Received: from huaweicloud.com (unknown [10.204.63.22]) by APP1 (Coremail) with SMTP id LxC2BwB3NTb9bzxnNXHnAQ--.10850S11; Tue, 19 Nov 2024 12:03:20 +0100 (CET) From: Roberto Sassu To: corbet@lwn.net, zohar@linux.ibm.com, dmitry.kasatkin@gmail.com, eric.snowberg@oracle.com, paul@paul-moore.com, jmorris@namei.org, serge@hallyn.com Cc: linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, linux-integrity@vger.kernel.org, linux-security-module@vger.kernel.org, wufan@linux.microsoft.com, pbrobinson@gmail.com, zbyszek@in.waw.pl, hch@lst.de, mjg59@srcf.ucam.org, pmatilai@redhat.com, jannh@google.com, dhowells@redhat.com, jikos@kernel.org, mkoutny@suse.com, ppavlu@suse.com, petr.vorel@gmail.com, mzerqung@0pointer.de, kgold@linux.ibm.com, Roberto Sassu Subject: [RFC][PATCH v4 9/9] ima: Use digest caches for appraisal Date: Tue, 19 Nov 2024 12:01:03 +0100 Message-ID: <20241119110103.2780453-10-roberto.sassu@huaweicloud.com> X-Mailer: git-send-email 2.47.0.118.gfd3785337b In-Reply-To: <20241119110103.2780453-1-roberto.sassu@huaweicloud.com> References: <20241119110103.2780453-1-roberto.sassu@huaweicloud.com> Precedence: bulk X-Mailing-List: linux-security-module@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-CM-TRANSID: LxC2BwB3NTb9bzxnNXHnAQ--.10850S11 X-Coremail-Antispam: 1UD129KBjvJXoW3XFWkZrW5Ar47Zr45tr1UJrb_yoW7WFW8pa 9xKF1UKry8WFWI9rZxAa9rCa1Sk3y0gFWUWws8W3429FnxXr109ryrtw12vF15Wr1UJrs7 twsFgr1UAa1rt3DanT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDU0xBIdaVrnRJUUUPSb4IE77IF4wAFF20E14v26rWj6s0DM7CY07I20VC2zVCF04k2 6cxKx2IYs7xG6rWj6s0DM7CIcVAFz4kK6r1j6r18M28IrcIa0xkI8VA2jI8067AKxVWUAV Cq3wA2048vs2IY020Ec7CjxVAFwI0_Xr0E3s1l8cAvFVAK0II2c7xJM28CjxkF64kEwVA0 rcxSw2x7M28EF7xvwVC0I7IYx2IY67AKxVW5JVW7JwA2z4x0Y4vE2Ix0cI8IcVCY1x0267 AKxVWxJr0_GcWl84ACjcxK6I8E87Iv67AKxVW8JVWxJwA2z4x0Y4vEx4A2jsIEc7CjxVAF wI0_Cr1j6rxdM2AIxVAIcxkEcVAq07x20xvEncxIr21l5I8CrVACY4xI64kE6c02F40Ex7 xfMcIj6xIIjxv20xvE14v26r126r1DMcIj6I8E87Iv67AKxVWUJVW8JwAm72CE4IkC6x0Y z7v_Jr0_Gr1lF7xvr2IYc2Ij64vIr41lFIxGxcIEc7CjxVA2Y2ka0xkIwI1lc7CjxVAaw2 AFwI0_GFv_Wryl42xK82IYc2Ij64vIr41l4I8I3I0E4IkC6x0Yz7v_Jr0_Gr1lx2IqxVAq x4xG67AKxVWUJVWUGwC20s026x8GjcxK67AKxVWUGVWUWwC2zVAF1VAY17CE14v26r4a6r W5MIIYrxkI7VAKI48JMIIF0xvE2Ix0cI8IcVAFwI0_Xr0_Ar1lIxAIcVC0I7IYx2IY6xkF 7I0E14v26F4UJVW0owCI42IY6xAIw20EY4v20xvaj40_Jr0_JF4lIxAIcVC2z280aVAFwI 0_Gr0_Cr1lIxAIcVC2z280aVCY1x0267AKxVWxJr0_GcJvcSsGvfC2KfnxnUUI43ZEXa7I U04rW7UUUUU== X-CM-SenderInfo: purev21wro2thvvxqx5xdzvxpfor3voofrz/1tbiAgAMBGc79-IEqgAAs9 From: Roberto Sassu Similarly to measurement, enable the new appraisal style too using digest caches. It allows files to be verified by only checking the signature of the package they belong to (as opposed to checking individual file signatures), and by doing a digest lookup in the digest cache. The first benefit is that packages are already signed (e.g. RPM package headers) and also contain file digests, so it is not necessary to further add signatures for each file. The second benefit is performance, which improves due to verifying less signatures (computationally expensive). Appraisal with a digest cache is successful only if the allowed usage (AND of policy usage and verified usage) has the IMA_DIGEST_CACHE_APPRAISE_DATA bit set, and if EVM is disabled or the file does not have any protected xattr The digest cache appraisal method is tried first, for performance reasons. Signed-off-by: Roberto Sassu --- security/integrity/ima/ima.h | 6 ++++-- security/integrity/ima/ima_appraise.c | 31 +++++++++++++++++++++------ security/integrity/ima/ima_main.c | 4 +++- 3 files changed, 31 insertions(+), 10 deletions(-) diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index 61b019e7bace..aec61984b12c 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -440,7 +440,8 @@ int ima_check_blacklist(struct ima_iint_cache *iint, int ima_appraise_measurement(enum ima_hooks func, struct ima_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 xattr_len, const struct modsig *modsig, + u64 allowed_usage); int ima_must_appraise(struct mnt_idmap *idmap, struct inode *inode, int mask, enum ima_hooks func); void ima_update_xattr(struct ima_iint_cache *iint, struct file *file); @@ -465,7 +466,8 @@ static inline int ima_appraise_measurement(enum ima_hooks func, const unsigned char *filename, struct evm_ima_xattr_data *xattr_value, int xattr_len, - const struct modsig *modsig) + const struct modsig *modsig, + u64 allowed_usage) { return INTEGRITY_UNKNOWN; } diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c index d479cf58d859..d4745d90ae23 100644 --- a/security/integrity/ima/ima_appraise.c +++ b/security/integrity/ima/ima_appraise.c @@ -480,7 +480,8 @@ int ima_check_blacklist(struct ima_iint_cache *iint, int ima_appraise_measurement(enum ima_hooks func, struct ima_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 xattr_len, const struct modsig *modsig, + u64 allowed_usage) { static const char op[] = "appraise_data"; const char *cause = "unknown"; @@ -489,13 +490,20 @@ int ima_appraise_measurement(enum ima_hooks func, struct ima_iint_cache *iint, enum integrity_status status = INTEGRITY_UNKNOWN; int rc = xattr_len; bool try_modsig = iint->flags & IMA_MODSIG_ALLOWED && modsig; + bool cache_pass = (allowed_usage & IMA_DIGEST_CACHE_APPRAISE_DATA); - /* If not appraising a modsig, we need an xattr. */ - if (!(inode->i_opflags & IOP_XATTR) && !try_modsig) + /* + * If not appraising a modsig/there is no digest cache match, we need + * an xattr. + */ + if (!(inode->i_opflags & IOP_XATTR) && !try_modsig && !cache_pass) return INTEGRITY_UNKNOWN; - /* If reading the xattr failed and there's no modsig, error out. */ - if (rc <= 0 && !try_modsig) { + /* + * If reading the xattr failed and there's no modsig/digest cache match, + * error out. + */ + if (rc <= 0 && !try_modsig && !cache_pass) { if (rc && rc != -ENODATA) goto out; @@ -526,8 +534,11 @@ int ima_appraise_measurement(enum ima_hooks func, struct ima_iint_cache *iint, case INTEGRITY_UNKNOWN: break; case INTEGRITY_NOXATTRS: /* No EVM protected xattrs. */ - /* It's fine not to have xattrs when using a modsig. */ - if (try_modsig) + /* + * It's fine not to have xattrs when using a modsig or there + * is a digest cache match. + */ + if (try_modsig || cache_pass) break; fallthrough; case INTEGRITY_NOLABEL: /* No security.evm xattr. */ @@ -544,6 +555,12 @@ int ima_appraise_measurement(enum ima_hooks func, struct ima_iint_cache *iint, WARN_ONCE(true, "Unexpected integrity status %d\n", status); } + if (cache_pass) { + status = INTEGRITY_PASS; + rc = 0; + goto out; + } + if (xattr_value) rc = xattr_verify(func, iint, xattr_value, xattr_len, &status, &cause); diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 0d37cdc01622..049e379fed7f 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -398,7 +398,9 @@ static int process_measurement(struct file *file, const struct cred *cred, inode_lock(inode); rc = ima_appraise_measurement(func, iint, file, pathname, xattr_value, - xattr_len, modsig); + xattr_len, modsig, + (policy_usage & + verified_usage)); inode_unlock(inode); } if (!rc)