All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 0/8] ima: support fs-verity digests and signatures
@ 2022-01-26  0:06 Mimi Zohar
  2022-01-26  0:06 ` [PATCH v3 1/8] ima: rename IMA_ACTION_FLAGS to IMA_NONACTION_FLAGS Mimi Zohar
                   ` (8 more replies)
  0 siblings, 9 replies; 15+ messages in thread
From: Mimi Zohar @ 2022-01-26  0:06 UTC (permalink / raw)
  To: linux-integrity
  Cc: Mimi Zohar, Eric Biggers, Stefan Berger, linux-fscrypt, linux-kernel

Support for including fs-verity file digests and signatures in the IMA
measurement list as well as verifying the fs-verity file digest based
signatures, all based on IMA policy rules, was discussed from the
beginning, prior to fs-verity being upstreamed[1,2].

Support including fs-verity file digests in the 'd-ng' template field
based on a new policy rule option named 'digest_type=hash|verity'.
Also support verifying fs-verity file digest based signatures based on
policy.

A new template field named 'd-type' as well as a new template named
'ima-ngv2' are defined to differentiate betweeen file hashes and fs-verity
file digests, when file signatures are not included in the IMA measurement
list.

To disambiguate the type of file signature, define IMA_VERITY_SIG xattr
type and a new signature format version, which is a hash of the new
ima_file_id structure.

[1] https://events19.linuxfoundation.org/wp-content/uploads/2017/11/fs-verify_Mike-Halcrow_Eric-Biggers.pdf
[2] Documentation/filesystems/fsverity.rst

Changelog v3:
- Addressed Eric Bigger's comments: included Ack, incremented the
  signature format version, the crypto issues are generic and will be
  addressed by him separately.
- Addressed Vitaly Chikunov's comments: hard coded maximum digest size
  rather than using a flexible array, removed unnecessary assignment, and
  fixed comment to match variable name.
- Defined new "ima_max_digest_size" struct to avoid wrapping the
  "ima_digest_data" struct inside a function local structure or
  having to dynamically allocate it with enough memory for the specific
  hash algo size.

Changelog v2:
- Addressed Eric Bigger's comments: sign the hash of fsverity's digest
  and the digest's metadata, use match_string, use preferred function
  name fsverity_get_digest(), support including unsigned fs-verity's
  digests in the IMA measurement list.
- Remove signatures requirement for including fs-verity's file digests in
  the 'd-ng' field of the measurement list.

Changelog v1:
- Updated both fsverity and IMA documentation.
- Addressed both Eric Bigger's and Lakshmi's comments.

Mimi Zohar (8):
  ima: rename IMA_ACTION_FLAGS to IMA_NONACTION_FLAGS
  ima: define ima_max_digest_data struct without a flexible array
    variable
  fs-verity: define a function to return the integrity protected file
    digest
  ima: define a new template field 'd-type' and a new template
    'ima-ngv2'
  ima: include fsverity's file digests in the IMA measurement list
  ima: define signature version 3
  ima: support fs-verity file digest based version 3 signatures
  fsverity: update the documentation

 Documentation/ABI/testing/ima_policy      | 17 +++++
 Documentation/filesystems/fsverity.rst    | 22 +++---
 Documentation/security/IMA-templates.rst  | 10 ++-
 fs/verity/Kconfig                         |  1 +
 fs/verity/fsverity_private.h              |  7 --
 fs/verity/measure.c                       | 39 +++++++++++
 include/linux/fsverity.h                  | 18 +++++
 security/integrity/digsig.c               |  3 +-
 security/integrity/ima/ima.h              |  2 +-
 security/integrity/ima/ima_api.c          | 29 +++++++-
 security/integrity/ima/ima_appraise.c     | 83 ++++++++++++++++++++++-
 security/integrity/ima/ima_crypto.c       |  2 +-
 security/integrity/ima/ima_init.c         |  9 +--
 security/integrity/ima/ima_main.c         |  2 +-
 security/integrity/ima/ima_policy.c       | 40 ++++++++++-
 security/integrity/ima/ima_template.c     |  3 +
 security/integrity/ima/ima_template_lib.c | 26 ++++++-
 security/integrity/ima/ima_template_lib.h |  2 +
 security/integrity/integrity.h            | 53 +++++++++++++--
 19 files changed, 329 insertions(+), 39 deletions(-)

-- 
2.27.0


^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH v3 1/8] ima: rename IMA_ACTION_FLAGS to IMA_NONACTION_FLAGS
  2022-01-26  0:06 [PATCH v3 0/8] ima: support fs-verity digests and signatures Mimi Zohar
@ 2022-01-26  0:06 ` Mimi Zohar
  2022-01-26  0:06 ` [PATCH v3 2/8] ima: define ima_max_digest_data struct without a flexible array variable Mimi Zohar
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 15+ messages in thread
From: Mimi Zohar @ 2022-01-26  0:06 UTC (permalink / raw)
  To: linux-integrity
  Cc: Mimi Zohar, Eric Biggers, Stefan Berger, linux-fscrypt, linux-kernel

Simple policy rule options, such as fowner, uid, or euid, can be checked
immediately, while other policy rule options, such as requiring a file
signature, need to be deferred.

The 'flags' field in the integrity_iint_cache struct contains the policy
action', 'subaction', and non action/subaction.

action: measure/measured, appraise/appraised, (collect)/collected,
        audit/audited
subaction: appraise status for each hook (e.g. file, mmap, bprm, read,
        creds)
non action/subaction: deferred policy rule options and state

Rename the IMA_ACTION_FLAGS to IMA_NONACTION_FLAGS.

Signed-off-by: Mimi Zohar <zohar@linux.ibm.com>
---
 security/integrity/ima/ima_main.c   | 2 +-
 security/integrity/ima/ima_policy.c | 2 +-
 security/integrity/integrity.h      | 4 ++--
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 8ed6da428328..7c80dfe2c7a5 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -263,7 +263,7 @@ static int process_measurement(struct file *file, const struct cred *cred,
 		/* reset appraisal flags if ima_inode_post_setattr was called */
 		iint->flags &= ~(IMA_APPRAISE | IMA_APPRAISED |
 				 IMA_APPRAISE_SUBMASK | IMA_APPRAISED_SUBMASK |
-				 IMA_ACTION_FLAGS);
+				 IMA_NONACTION_FLAGS);
 
 	/*
 	 * Re-evaulate the file if either the xattr has changed or the
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index ad7e19208a69..56a9f75c3d44 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -712,7 +712,7 @@ int ima_match_policy(struct user_namespace *mnt_userns, struct inode *inode,
 				     func, mask, func_data))
 			continue;
 
-		action |= entry->flags & IMA_ACTION_FLAGS;
+		action |= entry->flags & IMA_NONACTION_FLAGS;
 
 		action |= entry->action & IMA_DO_MASK;
 		if (entry->action & IMA_APPRAISE) {
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
index 547425c20e11..d045dccd415a 100644
--- a/security/integrity/integrity.h
+++ b/security/integrity/integrity.h
@@ -30,8 +30,8 @@
 #define IMA_HASH		0x00000100
 #define IMA_HASHED		0x00000200
 
-/* iint cache flags */
-#define IMA_ACTION_FLAGS	0xff000000
+/* iint policy rule cache flags */
+#define IMA_NONACTION_FLAGS	0xff000000
 #define IMA_DIGSIG_REQUIRED	0x01000000
 #define IMA_PERMIT_DIRECTIO	0x02000000
 #define IMA_NEW_FILE		0x04000000
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v3 2/8] ima: define ima_max_digest_data struct without a flexible array variable
  2022-01-26  0:06 [PATCH v3 0/8] ima: support fs-verity digests and signatures Mimi Zohar
  2022-01-26  0:06 ` [PATCH v3 1/8] ima: rename IMA_ACTION_FLAGS to IMA_NONACTION_FLAGS Mimi Zohar
@ 2022-01-26  0:06 ` Mimi Zohar
  2022-01-26  0:06 ` [PATCH v3 3/8] fs-verity: define a function to return the integrity protected file digest Mimi Zohar
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 15+ messages in thread
From: Mimi Zohar @ 2022-01-26  0:06 UTC (permalink / raw)
  To: linux-integrity
  Cc: Mimi Zohar, Eric Biggers, Stefan Berger, linux-fscrypt, linux-kernel

Replace (the ugly) wrapping of the "ima_digest_data" struct, containing
a flexible array variable, inside another local structure, by defining
"ima_max_digest_data" struct with the maximum digest size.

For example, use the "ima_max_digest_data" struct when calculating the
"boot_aggregate" value.

Signed-off-by: Mimi Zohar <zohar@linux.ibm.com>
---
 security/integrity/ima/ima.h              |  2 +-
 security/integrity/ima/ima_crypto.c       |  2 +-
 security/integrity/ima/ima_init.c         |  9 +++------
 security/integrity/ima/ima_template_lib.c |  3 ++-
 security/integrity/integrity.h            | 24 +++++++++++++++++++++++
 5 files changed, 31 insertions(+), 9 deletions(-)

diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index be965a8715e4..78395bed7fad 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -144,7 +144,7 @@ int ima_calc_buffer_hash(const void *buf, loff_t len,
 			 struct ima_digest_data *hash);
 int ima_calc_field_array_hash(struct ima_field_data *field_data,
 			      struct ima_template_entry *entry);
-int ima_calc_boot_aggregate(struct ima_digest_data *hash);
+int ima_calc_boot_aggregate(struct ima_max_digest_data *hash);
 void ima_add_violation(struct file *file, const unsigned char *filename,
 		       struct integrity_iint_cache *iint,
 		       const char *op, const char *cause);
diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c
index a7206cc1d7d1..0ff1bfcaf13f 100644
--- a/security/integrity/ima/ima_crypto.c
+++ b/security/integrity/ima/ima_crypto.c
@@ -840,7 +840,7 @@ static int ima_calc_boot_aggregate_tfm(char *digest, u16 alg_id,
 	return rc;
 }
 
-int ima_calc_boot_aggregate(struct ima_digest_data *hash)
+int ima_calc_boot_aggregate(struct ima_max_digest_data *hash)
 {
 	struct crypto_shash *tfm;
 	u16 crypto_id, alg_id;
diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c
index b26fa67476b4..dfbef713e0b6 100644
--- a/security/integrity/ima/ima_init.c
+++ b/security/integrity/ima/ima_init.c
@@ -47,16 +47,13 @@ static int __init ima_add_boot_aggregate(void)
 	struct integrity_iint_cache tmp_iint, *iint = &tmp_iint;
 	struct ima_event_data event_data = { .iint = iint,
 					     .filename = boot_aggregate_name };
+	struct ima_max_digest_data hash;
 	int result = -ENOMEM;
 	int violation = 0;
-	struct {
-		struct ima_digest_data hdr;
-		char digest[TPM_MAX_DIGEST_SIZE];
-	} hash;
 
 	memset(iint, 0, sizeof(*iint));
 	memset(&hash, 0, sizeof(hash));
-	iint->ima_hash = &hash.hdr;
+	iint->ima_hash = (struct ima_digest_data *)&hash;
 	iint->ima_hash->algo = ima_hash_algo;
 	iint->ima_hash->length = hash_digest_size[ima_hash_algo];
 
@@ -73,7 +70,7 @@ static int __init ima_add_boot_aggregate(void)
 	 * is not found.
 	 */
 	if (ima_tpm_chip) {
-		result = ima_calc_boot_aggregate(&hash.hdr);
+		result = ima_calc_boot_aggregate(&hash);
 		if (result < 0) {
 			audit_cause = "hashing_error";
 			goto err_out;
diff --git a/security/integrity/ima/ima_template_lib.c b/security/integrity/ima/ima_template_lib.c
index 5a5d462ab36d..d3aa511027cd 100644
--- a/security/integrity/ima/ima_template_lib.c
+++ b/security/integrity/ima/ima_template_lib.c
@@ -330,7 +330,8 @@ int ima_eventdigest_init(struct ima_event_data *event_data,
 	if ((const char *)event_data->filename == boot_aggregate_name) {
 		if (ima_tpm_chip) {
 			hash.hdr.algo = HASH_ALGO_SHA1;
-			result = ima_calc_boot_aggregate(&hash.hdr);
+			result = ima_calc_boot_aggregate(
+				(struct ima_max_digest_data *)&hash.hdr);
 
 			/* algo can change depending on available PCR banks */
 			if (!result && hash.hdr.algo != HASH_ALGO_SHA1)
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
index d045dccd415a..ee2e6b7c7575 100644
--- a/security/integrity/integrity.h
+++ b/security/integrity/integrity.h
@@ -15,6 +15,7 @@
 #include <linux/types.h>
 #include <linux/integrity.h>
 #include <crypto/sha1.h>
+#include <crypto/hash.h>
 #include <linux/key.h>
 #include <linux/audit.h>
 
@@ -110,6 +111,29 @@ struct ima_digest_data {
 	u8 digest[];
 } __packed;
 
+/*
+ * Instead of dynamically allocating memory for the ima_digest_data struct
+ * with space for the specific hash algo or wrapping the ima_digest_data
+ * struct inside another local structure, define ima_max_digest_data struct
+ * with the maximum digest size.
+ */
+struct ima_max_digest_data {
+	u8 algo;
+	u8 length;
+	union {
+		struct {
+			u8 unused;
+			u8 type;
+		} sha1;
+		struct {
+			u8 type;
+			u8 algo;
+		} ng;
+		u8 data[2];
+	} xattr;
+	u8 digest[HASH_MAX_DIGESTSIZE];
+} __packed;
+
 /*
  * signature format v2 - for using with asymmetric keys
  */
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v3 3/8] fs-verity: define a function to return the integrity protected file digest
  2022-01-26  0:06 [PATCH v3 0/8] ima: support fs-verity digests and signatures Mimi Zohar
  2022-01-26  0:06 ` [PATCH v3 1/8] ima: rename IMA_ACTION_FLAGS to IMA_NONACTION_FLAGS Mimi Zohar
  2022-01-26  0:06 ` [PATCH v3 2/8] ima: define ima_max_digest_data struct without a flexible array variable Mimi Zohar
@ 2022-01-26  0:06 ` Mimi Zohar
  2022-02-01  0:44   ` Eric Biggers
  2022-01-26  0:06 ` [PATCH v3 4/8] ima: define a new template field 'd-type' and a new template 'ima-ngv2' Mimi Zohar
                   ` (5 subsequent siblings)
  8 siblings, 1 reply; 15+ messages in thread
From: Mimi Zohar @ 2022-01-26  0:06 UTC (permalink / raw)
  To: linux-integrity
  Cc: Mimi Zohar, Eric Biggers, Stefan Berger, linux-fscrypt,
	linux-kernel, Eric Biggers

Define a function named fsverity_get_digest() to return the verity file
digest and the associated hash algorithm (enum hash_algo).

Acked-by: Eric Biggers <ebiggers@google.com>
Signed-off-by: Mimi Zohar <zohar@linux.ibm.com>
---
 fs/verity/Kconfig            |  1 +
 fs/verity/fsverity_private.h |  7 -------
 fs/verity/measure.c          | 39 ++++++++++++++++++++++++++++++++++++
 include/linux/fsverity.h     | 18 +++++++++++++++++
 4 files changed, 58 insertions(+), 7 deletions(-)

diff --git a/fs/verity/Kconfig b/fs/verity/Kconfig
index 24d1b54de807..54598cd80145 100644
--- a/fs/verity/Kconfig
+++ b/fs/verity/Kconfig
@@ -3,6 +3,7 @@
 config FS_VERITY
 	bool "FS Verity (read-only file-based authenticity protection)"
 	select CRYPTO
+	select CRYPTO_HASH_INFO
 	# SHA-256 is implied as it's intended to be the default hash algorithm.
 	# To avoid bloat, other wanted algorithms must be selected explicitly.
 	# Note that CRYPTO_SHA256 denotes the generic C implementation, but
diff --git a/fs/verity/fsverity_private.h b/fs/verity/fsverity_private.h
index a7920434bae5..c6fb62e0ef1a 100644
--- a/fs/verity/fsverity_private.h
+++ b/fs/verity/fsverity_private.h
@@ -14,7 +14,6 @@
 
 #define pr_fmt(fmt) "fs-verity: " fmt
 
-#include <crypto/sha2.h>
 #include <linux/fsverity.h>
 #include <linux/mempool.h>
 
@@ -26,12 +25,6 @@ struct ahash_request;
  */
 #define FS_VERITY_MAX_LEVELS		8
 
-/*
- * Largest digest size among all hash algorithms supported by fs-verity.
- * Currently assumed to be <= size of fsverity_descriptor::root_hash.
- */
-#define FS_VERITY_MAX_DIGEST_SIZE	SHA512_DIGEST_SIZE
-
 /* A hash algorithm supported by fs-verity */
 struct fsverity_hash_alg {
 	struct crypto_ahash *tfm; /* hash tfm, allocated on demand */
diff --git a/fs/verity/measure.c b/fs/verity/measure.c
index f0d7b30c62db..2152f115071a 100644
--- a/fs/verity/measure.c
+++ b/fs/verity/measure.c
@@ -57,3 +57,42 @@ int fsverity_ioctl_measure(struct file *filp, void __user *_uarg)
 	return 0;
 }
 EXPORT_SYMBOL_GPL(fsverity_ioctl_measure);
+
+/**
+ * fsverity_get_digest() - get a verity file's digest
+ * @inode: inode to get digest of
+ * @digest: (out) pointer to the digest
+ * @alg: (out) pointer to the hash algorithm enumeration
+ *
+ * Return the file hash algorithm and digest of an fsverity protected file.
+ *
+ * Return: 0 on success, -errno on failure
+ */
+int fsverity_get_digest(struct inode *inode,
+			u8 digest[FS_VERITY_MAX_DIGEST_SIZE],
+			enum hash_algo *alg)
+{
+	const struct fsverity_info *vi;
+	const struct fsverity_hash_alg *hash_alg;
+	int i;
+
+	vi = fsverity_get_info(inode);
+	if (!vi)
+		return -ENODATA; /* not a verity file */
+
+	hash_alg = vi->tree_params.hash_alg;
+	memset(digest, 0, FS_VERITY_MAX_DIGEST_SIZE);
+
+	/* convert hash algorithm to hash_algo_name */
+	i = match_string(hash_algo_name, HASH_ALGO__LAST, hash_alg->name);
+	if (i < 0)
+		return -EINVAL;
+	*alg = i;
+
+	memcpy(digest, vi->file_digest, hash_alg->digest_size);
+
+	pr_debug("file digest %s:%*phN\n", hash_algo_name[*alg],
+		 hash_digest_size[*alg], digest);
+
+	return 0;
+}
diff --git a/include/linux/fsverity.h b/include/linux/fsverity.h
index b568b3c7d095..9a1b70cc7318 100644
--- a/include/linux/fsverity.h
+++ b/include/linux/fsverity.h
@@ -12,8 +12,16 @@
 #define _LINUX_FSVERITY_H
 
 #include <linux/fs.h>
+#include <crypto/hash_info.h>
+#include <crypto/sha2.h>
 #include <uapi/linux/fsverity.h>
 
+/*
+ * Largest digest size among all hash algorithms supported by fs-verity.
+ * Currently assumed to be <= size of fsverity_descriptor::root_hash.
+ */
+#define FS_VERITY_MAX_DIGEST_SIZE	SHA512_DIGEST_SIZE
+
 /* Verity operations for filesystems */
 struct fsverity_operations {
 
@@ -131,6 +139,9 @@ int fsverity_ioctl_enable(struct file *filp, const void __user *arg);
 /* measure.c */
 
 int fsverity_ioctl_measure(struct file *filp, void __user *arg);
+int fsverity_get_digest(struct inode *inode,
+			u8 digest[FS_VERITY_MAX_DIGEST_SIZE],
+			enum hash_algo *alg);
 
 /* open.c */
 
@@ -170,6 +181,13 @@ static inline int fsverity_ioctl_measure(struct file *filp, void __user *arg)
 	return -EOPNOTSUPP;
 }
 
+static inline int fsverity_get_digest(struct inode *inode,
+				      u8 digest[FS_VERITY_MAX_DIGEST_SIZE],
+				      enum hash_algo *alg)
+{
+	return -EOPNOTSUPP;
+}
+
 /* open.c */
 
 static inline int fsverity_file_open(struct inode *inode, struct file *filp)
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v3 4/8] ima: define a new template field 'd-type' and a new template 'ima-ngv2'
  2022-01-26  0:06 [PATCH v3 0/8] ima: support fs-verity digests and signatures Mimi Zohar
                   ` (2 preceding siblings ...)
  2022-01-26  0:06 ` [PATCH v3 3/8] fs-verity: define a function to return the integrity protected file digest Mimi Zohar
@ 2022-01-26  0:06 ` Mimi Zohar
  2022-01-26  0:06 ` [PATCH v3 5/8] ima: include fsverity's file digests in the IMA measurement list Mimi Zohar
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 15+ messages in thread
From: Mimi Zohar @ 2022-01-26  0:06 UTC (permalink / raw)
  To: linux-integrity
  Cc: Mimi Zohar, Eric Biggers, Stefan Berger, linux-fscrypt, linux-kernel

In preparation to differentiate between regular file hashes and
fs-verity's file digests, define a new template field named 'd-type'.
Define and include the new 'd-type' field in the new template named
'ima-ngv2'.

Signed-off-by: Mimi Zohar <zohar@linux.ibm.com>
---
 security/integrity/ima/ima_template.c     |  3 +++
 security/integrity/ima/ima_template_lib.c | 13 +++++++++++++
 security/integrity/ima/ima_template_lib.h |  2 ++
 3 files changed, 18 insertions(+)

diff --git a/security/integrity/ima/ima_template.c b/security/integrity/ima/ima_template.c
index 694560396be0..9d8253c6c52c 100644
--- a/security/integrity/ima/ima_template.c
+++ b/security/integrity/ima/ima_template.c
@@ -19,6 +19,7 @@ enum header_fields { HDR_PCR, HDR_DIGEST, HDR_TEMPLATE_NAME,
 static struct ima_template_desc builtin_templates[] = {
 	{.name = IMA_TEMPLATE_IMA_NAME, .fmt = IMA_TEMPLATE_IMA_FMT},
 	{.name = "ima-ng", .fmt = "d-ng|n-ng"},
+	{.name = "ima-ngv2", .fmt = "d-ng|n-ng|d-type"},
 	{.name = "ima-sig", .fmt = "d-ng|n-ng|sig"},
 	{.name = "ima-buf", .fmt = "d-ng|n-ng|buf"},
 	{.name = "ima-modsig", .fmt = "d-ng|n-ng|sig|d-modsig|modsig"},
@@ -39,6 +40,8 @@ static const struct ima_template_field supported_fields[] = {
 	 .field_show = ima_show_template_digest_ng},
 	{.field_id = "n-ng", .field_init = ima_eventname_ng_init,
 	 .field_show = ima_show_template_string},
+	{.field_id = "d-type", .field_init = ima_eventdigest_type_init,
+	 .field_show = ima_show_template_string},
 	{.field_id = "sig", .field_init = ima_eventsig_init,
 	 .field_show = ima_show_template_sig},
 	{.field_id = "buf", .field_init = ima_eventbuf_init,
diff --git a/security/integrity/ima/ima_template_lib.c b/security/integrity/ima/ima_template_lib.c
index d3aa511027cd..aa5d4a490657 100644
--- a/security/integrity/ima/ima_template_lib.c
+++ b/security/integrity/ima/ima_template_lib.c
@@ -387,6 +387,19 @@ int ima_eventdigest_ng_init(struct ima_event_data *event_data,
 					   hash_algo, field_data);
 }
 
+/*
+ * This function writes the digest type of an event.
+ */
+int ima_eventdigest_type_init(struct ima_event_data *event_data,
+			      struct ima_field_data *field_data)
+{
+	static const char * const digest_type[] = {"hash"};
+
+	return ima_write_template_field_data(digest_type[0],
+					     strlen(digest_type[0]),
+					     DATA_FMT_STRING, field_data);
+}
+
 /*
  * This function writes the digest of the file which is expected to match the
  * digest contained in the file's appended signature.
diff --git a/security/integrity/ima/ima_template_lib.h b/security/integrity/ima/ima_template_lib.h
index c71f1de95753..539a5e354925 100644
--- a/security/integrity/ima/ima_template_lib.h
+++ b/security/integrity/ima/ima_template_lib.h
@@ -38,6 +38,8 @@ int ima_eventname_init(struct ima_event_data *event_data,
 		       struct ima_field_data *field_data);
 int ima_eventdigest_ng_init(struct ima_event_data *event_data,
 			    struct ima_field_data *field_data);
+int ima_eventdigest_type_init(struct ima_event_data *event_data,
+			      struct ima_field_data *field_data);
 int ima_eventdigest_modsig_init(struct ima_event_data *event_data,
 				struct ima_field_data *field_data);
 int ima_eventname_ng_init(struct ima_event_data *event_data,
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v3 5/8] ima: include fsverity's file digests in the IMA measurement list
  2022-01-26  0:06 [PATCH v3 0/8] ima: support fs-verity digests and signatures Mimi Zohar
                   ` (3 preceding siblings ...)
  2022-01-26  0:06 ` [PATCH v3 4/8] ima: define a new template field 'd-type' and a new template 'ima-ngv2' Mimi Zohar
@ 2022-01-26  0:06 ` Mimi Zohar
  2022-02-01  0:56   ` Eric Biggers
  2022-01-26  0:06 ` [PATCH v3 6/8] ima: define signature version 3 Mimi Zohar
                   ` (3 subsequent siblings)
  8 siblings, 1 reply; 15+ messages in thread
From: Mimi Zohar @ 2022-01-26  0:06 UTC (permalink / raw)
  To: linux-integrity
  Cc: Mimi Zohar, Eric Biggers, Stefan Berger, linux-fscrypt, linux-kernel

Allow fsverity's file digests to be included in the IMA measurement list
based on policy.

Define a new measurement policy rule option named 'digest_type=' to
allow fsverity file digests to be included in the measurement list
in the d-ng field.

Including the 'd-type' template field is recommended for unsigned
fs-verity digests to distinguish between d-ng digest types.  The
following policy rule, for example, specifies the new 'ima-ngv2'
template.

measure func=FILE_CHECK digest_type=hash|verity template=ima-ngv2

Signed-off-by: Mimi Zohar <zohar@linux.ibm.com>
---
 Documentation/ABI/testing/ima_policy      |  7 +++++
 Documentation/security/IMA-templates.rst  |  6 ++++
 security/integrity/ima/ima_api.c          | 29 +++++++++++++++--
 security/integrity/ima/ima_policy.c       | 38 ++++++++++++++++++++++-
 security/integrity/ima/ima_template_lib.c |  9 +++++-
 security/integrity/integrity.h            |  4 ++-
 6 files changed, 88 insertions(+), 5 deletions(-)

diff --git a/Documentation/ABI/testing/ima_policy b/Documentation/ABI/testing/ima_policy
index 839fab811b18..444bb7ccbe03 100644
--- a/Documentation/ABI/testing/ima_policy
+++ b/Documentation/ABI/testing/ima_policy
@@ -51,6 +51,7 @@ Description:
 			appraise_flag:= [check_blacklist]
 			Currently, blacklist check is only for files signed with appended
 			signature.
+			digest_type:= [hash|verity]
 			keyrings:= list of keyrings
 			(eg, .builtin_trusted_keys|.ima). Only valid
 			when action is "measure" and func is KEY_CHECK.
@@ -149,3 +150,9 @@ Description:
 		security.ima xattr of a file:
 
 			appraise func=SETXATTR_CHECK appraise_algos=sha256,sha384,sha512
+
+		Example of measure rule allowing fs-verity's digests on a
+		particular filesystem with indication of type of digest.
+
+			measure func=FILE_CHECK digest_type=hash|verity \
+				fsuuid=... template=ima-ngv2
diff --git a/Documentation/security/IMA-templates.rst b/Documentation/security/IMA-templates.rst
index 1a91d92950a7..5e31513e8ec4 100644
--- a/Documentation/security/IMA-templates.rst
+++ b/Documentation/security/IMA-templates.rst
@@ -69,6 +69,7 @@ descriptors by adding their identifier to the format string
    algorithm (field format: [<hash algo>:]digest, where the digest
    prefix is shown only if the hash algorithm is not SHA1 or MD5);
  - 'd-modsig': the digest of the event without the appended modsig;
+ - 'd-type': the type of file digest (e.g. hash, verity[1]);
  - 'n-ng': the name of the event, without size limitations;
  - 'sig': the file signature, or the EVM portable signature if the file
    signature is not found;
@@ -106,3 +107,8 @@ currently the following methods are supported:
    the ``ima_template=`` parameter;
  - register a new template descriptor with custom format through the kernel
    command line parameter ``ima_template_fmt=``.
+
+
+References
+==========
+[1] Documentation/filesystems/fsverity.rst
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c
index 5b220a2fe573..3f8fbddcabf6 100644
--- a/security/integrity/ima/ima_api.c
+++ b/security/integrity/ima/ima_api.c
@@ -14,6 +14,7 @@
 #include <linux/xattr.h>
 #include <linux/evm.h>
 #include <linux/iversion.h>
+#include <linux/fsverity.h>
 
 #include "ima.h"
 
@@ -200,6 +201,23 @@ int ima_get_action(struct user_namespace *mnt_userns, struct inode *inode,
 				allowed_algos);
 }
 
+static int ima_get_verity_digest(struct integrity_iint_cache *iint,
+				 struct ima_digest_data *hash)
+{
+	u8 verity_digest[FS_VERITY_MAX_DIGEST_SIZE];
+	enum hash_algo verity_alg;
+	int rc;
+
+	rc = fsverity_get_digest(iint->inode, verity_digest, &verity_alg);
+	if (rc)
+		return -EINVAL;
+	if (hash->algo != verity_alg)
+		return -EINVAL;
+	hash->length = hash_digest_size[verity_alg];
+	memcpy(hash->digest, verity_digest, hash->length);
+	return 0;
+}
+
 /*
  * ima_collect_measurement - collect file measurement
  *
@@ -248,10 +266,17 @@ int ima_collect_measurement(struct integrity_iint_cache *iint,
 	/* Initialize hash digest to 0's in case of failure */
 	memset(&hash.digest, 0, sizeof(hash.digest));
 
-	if (buf)
+	if (buf) {
 		result = ima_calc_buffer_hash(buf, size, &hash.hdr);
-	else
+	} else if (iint->flags & IMA_VERITY_ALLOWED) {
+		result = ima_get_verity_digest(iint, &hash.hdr);
+		if (result < 0)
+			result = ima_calc_file_hash(file, &hash.hdr);
+		else
+			iint->flags |= IMA_VERITY_DIGEST;
+	} else {
 		result = ima_calc_file_hash(file, &hash.hdr);
+	}
 
 	if (result && result != -EBADF && result != -EINVAL)
 		goto out;
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index 56a9f75c3d44..787e0eb506e6 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -1024,6 +1024,7 @@ enum policy_opt {
 	Opt_fowner_gt, Opt_fgroup_gt,
 	Opt_uid_lt, Opt_euid_lt, Opt_gid_lt, Opt_egid_lt,
 	Opt_fowner_lt, Opt_fgroup_lt,
+	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
@@ -1066,6 +1067,7 @@ static const match_table_t policy_tokens = {
 	{Opt_egid_lt, "egid<%s"},
 	{Opt_fowner_lt, "fowner<%s"},
 	{Opt_fgroup_lt, "fgroup<%s"},
+	{Opt_digest_type, "digest_type=%s"},
 	{Opt_appraise_type, "appraise_type=%s"},
 	{Opt_appraise_flag, "appraise_flag=%s"},
 	{Opt_appraise_algos, "appraise_algos=%s"},
@@ -1173,6 +1175,21 @@ static void check_template_modsig(const struct ima_template_desc *template)
 #undef MSG
 }
 
+/*
+ * Make sure the policy rule and template format are in sync.
+ */
+static void check_template_field(const struct ima_template_desc *template,
+				 const char *field, const char *msg)
+{
+	int i;
+
+	for (i = 0; i < template->num_fields; i++)
+		if (!strcmp(template->fields[i]->field_id, field))
+			return;
+
+	pr_notice_once("%s", msg);
+}
+
 static bool ima_validate_rule(struct ima_rule_entry *entry)
 {
 	/* Ensure that the action is set and is compatible with the flags */
@@ -1215,7 +1232,8 @@ static bool ima_validate_rule(struct ima_rule_entry *entry)
 				     IMA_INMASK | IMA_EUID | IMA_PCR |
 				     IMA_FSNAME | IMA_GID | IMA_EGID |
 				     IMA_FGROUP | IMA_DIGSIG_REQUIRED |
-				     IMA_PERMIT_DIRECTIO | IMA_VALIDATE_ALGOS))
+				     IMA_PERMIT_DIRECTIO | IMA_VALIDATE_ALGOS |
+				     IMA_VERITY_ALLOWED))
 			return false;
 
 		break;
@@ -1708,6 +1726,13 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
 						   LSM_SUBJ_TYPE,
 						   AUDIT_SUBJ_TYPE);
 			break;
+		case Opt_digest_type:
+			ima_log_string(ab, "digest_type", args[0].from);
+			if ((strcmp(args[0].from, "hash|verity")) == 0)
+				entry->flags |= IMA_VERITY_ALLOWED;
+			else
+				result = -EINVAL;
+			break;
 		case Opt_appraise_type:
 			ima_log_string(ab, "appraise_type", args[0].from);
 			if ((strcmp(args[0].from, "imasig")) == 0)
@@ -1798,6 +1823,15 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
 		check_template_modsig(template_desc);
 	}
 
+	/* d-type template field recommended for unsigned fs-verity digests */
+	if (!result && entry->action == MEASURE &&
+	    entry->flags & IMA_VERITY_ALLOWED) {
+		template_desc = entry->template ? entry->template :
+						  ima_template_desc_current();
+		check_template_field(template_desc, "d-type",
+				     "verity rules should include d-type");
+	}
+
 	audit_log_format(ab, "res=%d", !result);
 	audit_log_end(ab);
 	return result;
@@ -2147,6 +2181,8 @@ int ima_policy_show(struct seq_file *m, void *v)
 		else
 			seq_puts(m, "appraise_type=imasig ");
 	}
+	if (entry->flags & IMA_VERITY_ALLOWED)
+		seq_puts(m, "digest_type=hash|verity ");
 	if (entry->flags & IMA_CHECK_BLACKLIST)
 		seq_puts(m, "appraise_flag=check_blacklist ");
 	if (entry->flags & IMA_PERMIT_DIRECTIO)
diff --git a/security/integrity/ima/ima_template_lib.c b/security/integrity/ima/ima_template_lib.c
index aa5d4a490657..44e57d7e5fed 100644
--- a/security/integrity/ima/ima_template_lib.c
+++ b/security/integrity/ima/ima_template_lib.c
@@ -393,7 +393,14 @@ int ima_eventdigest_ng_init(struct ima_event_data *event_data,
 int ima_eventdigest_type_init(struct ima_event_data *event_data,
 			      struct ima_field_data *field_data)
 {
-	static const char * const digest_type[] = {"hash"};
+	static const char * const digest_type[] = {"hash", "verity"};
+
+	if (event_data->iint->flags & IMA_VERITY_DIGEST) {
+		return ima_write_template_field_data(digest_type[1],
+						     strlen(digest_type[1]),
+						     DATA_FMT_STRING,
+						     field_data);
+	}
 
 	return ima_write_template_field_data(digest_type[0],
 					     strlen(digest_type[0]),
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
index ee2e6b7c7575..a996d4fa7be3 100644
--- a/security/integrity/integrity.h
+++ b/security/integrity/integrity.h
@@ -32,7 +32,7 @@
 #define IMA_HASHED		0x00000200
 
 /* iint policy rule cache flags */
-#define IMA_NONACTION_FLAGS	0xff000000
+#define IMA_NONACTION_FLAGS	0xff800000
 #define IMA_DIGSIG_REQUIRED	0x01000000
 #define IMA_PERMIT_DIRECTIO	0x02000000
 #define IMA_NEW_FILE		0x04000000
@@ -40,6 +40,8 @@
 #define IMA_FAIL_UNVERIFIABLE_SIGS	0x10000000
 #define IMA_MODSIG_ALLOWED	0x20000000
 #define IMA_CHECK_BLACKLIST	0x40000000
+#define IMA_VERITY_ALLOWED	0x80000000
+#define IMA_VERITY_DIGEST	0x00800000
 
 #define IMA_DO_MASK		(IMA_MEASURE | IMA_APPRAISE | IMA_AUDIT | \
 				 IMA_HASH | IMA_APPRAISE_SUBMASK)
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v3 6/8] ima: define signature version 3
  2022-01-26  0:06 [PATCH v3 0/8] ima: support fs-verity digests and signatures Mimi Zohar
                   ` (4 preceding siblings ...)
  2022-01-26  0:06 ` [PATCH v3 5/8] ima: include fsverity's file digests in the IMA measurement list Mimi Zohar
@ 2022-01-26  0:06 ` Mimi Zohar
  2022-01-26  0:06 ` [PATCH v3 7/8] ima: support fs-verity file digest based version 3 signatures Mimi Zohar
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 15+ messages in thread
From: Mimi Zohar @ 2022-01-26  0:06 UTC (permalink / raw)
  To: linux-integrity
  Cc: Mimi Zohar, Eric Biggers, Stefan Berger, linux-fscrypt, linux-kernel

To disambiguate the signed data, instead of directly signing the file data
hash, signature version 3 signs the hash of the ima_file_id structure.

Signed-off-by: Mimi Zohar <zohar@linux.ibm.com>
---
 security/integrity/digsig.c           |  3 ++-
 security/integrity/ima/ima_appraise.c | 36 +++++++++++++++++++++++++++
 security/integrity/integrity.h        | 20 +++++++++++++--
 3 files changed, 56 insertions(+), 3 deletions(-)

diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c
index 3b06a01bd0fd..fd8f77d92a62 100644
--- a/security/integrity/digsig.c
+++ b/security/integrity/digsig.c
@@ -74,7 +74,8 @@ int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
 		/* v1 API expect signature without xattr type */
 		return digsig_verify(keyring, sig + 1, siglen - 1, digest,
 				     digestlen);
-	case 2:
+	case 2: /* regular file data hash based sginature */
+	case 3: /* struct ima_file_id data base signature */
 		return asymmetric_verify(keyring, sig, siglen, digest,
 					 digestlen);
 	}
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c
index 17232bbfb9f9..7bc180bd808e 100644
--- a/security/integrity/ima/ima_appraise.c
+++ b/security/integrity/ima/ima_appraise.c
@@ -225,6 +225,34 @@ int ima_read_xattr(struct dentry *dentry,
 	return ret;
 }
 
+/*
+ * calc_file_id_hash - calculate the hash of the ima_file_id struct data
+ * @type: xattr type [enum evm_ima_xattr_type]
+ * @algo: hash algorithm [enum hash_algo]
+ * @digest: pointer to the digest to be hashed
+ * @hash: (out) pointer to the hash
+ *
+ * IMA signature version 3 disambiguates the data that is signed by
+ * indirectly signing the hash of the ima_file_id structure data.
+ *
+ * Return 0 on success, error code otherwise.
+ */
+static int calc_file_id_hash(enum evm_ima_xattr_type type,
+			     enum hash_algo algo, const u8 *digest,
+			     struct ima_max_digest_data *hash)
+{
+	struct ima_file_id file_id = {.hash_algorithm = algo};
+	uint unused = HASH_MAX_DIGESTSIZE - hash_digest_size[algo];
+
+	memcpy(file_id.hash, digest, hash_digest_size[algo]);
+
+	hash->algo = algo;
+	hash->length = hash_digest_size[algo];
+
+	return ima_calc_buffer_hash(&file_id, sizeof(file_id) - unused,
+				    (struct ima_digest_data *)hash);
+}
+
 /*
  * xattr_verify - verify xattr digest or signature
  *
@@ -236,6 +264,7 @@ static int xattr_verify(enum ima_hooks func, struct integrity_iint_cache *iint,
 			struct evm_ima_xattr_data *xattr_value, int xattr_len,
 			enum integrity_status *status, const char **cause)
 {
+	struct signature_v2_hdr *sig;
 	int rc = -EINVAL, hash_start = 0;
 
 	switch (xattr_value->type) {
@@ -274,6 +303,13 @@ static int xattr_verify(enum ima_hooks func, struct integrity_iint_cache *iint,
 		break;
 	case EVM_IMA_XATTR_DIGSIG:
 		set_bit(IMA_DIGSIG, &iint->atomic_flags);
+
+		sig = (typeof(sig))xattr_value;
+		if (sig->version != 2) {
+			*cause = "invalid-signature-version";
+			*status = INTEGRITY_FAIL;
+			break;
+		}
 		rc = integrity_digsig_verify(INTEGRITY_KEYRING_IMA,
 					     (const char *)xattr_value,
 					     xattr_len,
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
index a996d4fa7be3..ed4966d943e9 100644
--- a/security/integrity/integrity.h
+++ b/security/integrity/integrity.h
@@ -94,7 +94,7 @@ struct evm_xattr {
 	u8 digest[SHA1_DIGEST_SIZE];
 } __packed;
 
-#define IMA_MAX_DIGEST_SIZE	64
+#define IMA_MAX_DIGEST_SIZE	HASH_MAX_DIGESTSIZE
 
 struct ima_digest_data {
 	u8 algo;
@@ -137,7 +137,11 @@ struct ima_max_digest_data {
 } __packed;
 
 /*
- * signature format v2 - for using with asymmetric keys
+ * signature header format v2 - for using with asymmetric keys
+ *
+ * signature format:
+ * version 2: regular file data hash based signature
+ * version 3: struct ima_file_id data based signature
  */
 struct signature_v2_hdr {
 	uint8_t type;		/* xattr type */
@@ -148,6 +152,18 @@ struct signature_v2_hdr {
 	uint8_t sig[];		/* signature payload */
 } __packed;
 
+/*
+ * IMA signature version 3 disambiguates the data that is signed, by
+ * indirectly signing the hash of the ima_file_id structure data.
+ *
+ * (The hash of the ima_file_id structure is only of the portion used.)
+ */
+struct ima_file_id {
+	__u8 hash_type;		/* xattr type [enum evm_ima_xattr_type] */
+	__u8 hash_algorithm;	/* Digest algorithm [enum hash_algo] */
+	__u8 hash[HASH_MAX_DIGESTSIZE];
+} __packed;
+
 /* integrity data associated with an inode */
 struct integrity_iint_cache {
 	struct rb_node rb_node;	/* rooted in integrity_iint_tree */
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v3 7/8] ima: support fs-verity file digest based version 3 signatures
  2022-01-26  0:06 [PATCH v3 0/8] ima: support fs-verity digests and signatures Mimi Zohar
                   ` (5 preceding siblings ...)
  2022-01-26  0:06 ` [PATCH v3 6/8] ima: define signature version 3 Mimi Zohar
@ 2022-01-26  0:06 ` Mimi Zohar
  2022-02-01  1:06   ` Eric Biggers
  2022-01-26  0:06 ` [PATCH v3 8/8] fsverity: update the documentation Mimi Zohar
  2022-02-01  0:36 ` [PATCH v3 0/8] ima: support fs-verity digests and signatures Eric Biggers
  8 siblings, 1 reply; 15+ messages in thread
From: Mimi Zohar @ 2022-01-26  0:06 UTC (permalink / raw)
  To: linux-integrity
  Cc: Mimi Zohar, Eric Biggers, Stefan Berger, linux-fscrypt, linux-kernel

Instead of calculating a file hash and verifying the signature stored
in the security.ima xattr against the calculated file hash, verify
fs-verity's signature (version 3).

To differentiate between a regular file hash and an fs-verity file digest
based signature stored as security.ima xattr, define a new signature type
named IMA_VERITY_DIGSIG.

Update the 'ima-sig' template field to display the new fs-verity signature
type as well.

For example:
  appraise func=BPRM_CHECK digest_type=hash|verity

Signed-off-by: Mimi Zohar <zohar@linux.ibm.com>
---
 Documentation/ABI/testing/ima_policy      | 10 +++++
 Documentation/security/IMA-templates.rst  |  4 +-
 security/integrity/ima/ima_appraise.c     | 49 ++++++++++++++++++++++-
 security/integrity/ima/ima_template_lib.c |  3 +-
 security/integrity/integrity.h            |  5 ++-
 5 files changed, 65 insertions(+), 6 deletions(-)

diff --git a/Documentation/ABI/testing/ima_policy b/Documentation/ABI/testing/ima_policy
index 444bb7ccbe03..fadf90dde289 100644
--- a/Documentation/ABI/testing/ima_policy
+++ b/Documentation/ABI/testing/ima_policy
@@ -151,6 +151,16 @@ Description:
 
 			appraise func=SETXATTR_CHECK appraise_algos=sha256,sha384,sha512
 
+		Example of measure and appraise rules allowing fs-verity
+		signed digests on a particular filesystem identified by
+		it's fsuuid:
+
+			measure func=BPRM_CHECK digest_type=hash|verity \
+				fsuuid=... template=ima-sig
+			appraise func=BPRM_CHECK digest_type=hash|verity \
+				fsuuid=...
+
+
 		Example of measure rule allowing fs-verity's digests on a
 		particular filesystem with indication of type of digest.
 
diff --git a/Documentation/security/IMA-templates.rst b/Documentation/security/IMA-templates.rst
index 5e31513e8ec4..390936810ebc 100644
--- a/Documentation/security/IMA-templates.rst
+++ b/Documentation/security/IMA-templates.rst
@@ -71,8 +71,8 @@ descriptors by adding their identifier to the format string
  - 'd-modsig': the digest of the event without the appended modsig;
  - 'd-type': the type of file digest (e.g. hash, verity[1]);
  - 'n-ng': the name of the event, without size limitations;
- - 'sig': the file signature, or the EVM portable signature if the file
-   signature is not found;
+ - 'sig': the file signature, based on either the file's/fsverity's digest[1],
+   or the EVM portable signature if the file signature is not found;
  - 'modsig' the appended file signature;
  - 'buf': the buffer data that was used to generate the hash without size limitations;
  - 'evmsig': the EVM portable signature;
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c
index 7bc180bd808e..68376c56feff 100644
--- a/security/integrity/ima/ima_appraise.c
+++ b/security/integrity/ima/ima_appraise.c
@@ -13,7 +13,9 @@
 #include <linux/magic.h>
 #include <linux/ima.h>
 #include <linux/evm.h>
+#include <linux/fsverity.h>
 #include <keys/system_keyring.h>
+#include <uapi/linux/fsverity.h>
 
 #include "ima.h"
 
@@ -183,13 +185,18 @@ enum hash_algo ima_get_hash_algo(const struct evm_ima_xattr_data *xattr_value,
 		return ima_hash_algo;
 
 	switch (xattr_value->type) {
+	case IMA_VERITY_DIGSIG:
+		sig = (typeof(sig))xattr_value;
+		if (sig->version != 3 || xattr_len <= sizeof(*sig) ||
+		    sig->hash_algo >= HASH_ALGO__LAST)
+			return ima_hash_algo;
+		return sig->hash_algo;
 	case EVM_IMA_XATTR_DIGSIG:
 		sig = (typeof(sig))xattr_value;
 		if (sig->version != 2 || xattr_len <= sizeof(*sig)
 		    || sig->hash_algo >= HASH_ALGO__LAST)
 			return ima_hash_algo;
 		return sig->hash_algo;
-		break;
 	case IMA_XATTR_DIGEST_NG:
 		/* first byte contains algorithm id */
 		ret = xattr_value->data[0];
@@ -235,15 +242,22 @@ int ima_read_xattr(struct dentry *dentry,
  * IMA signature version 3 disambiguates the data that is signed by
  * indirectly signing the hash of the ima_file_id structure data.
  *
+ * Signing the ima_file_id struct is currently only supported for
+ * IMA_VERITY_DIGSIG type xattrs.
+ *
  * Return 0 on success, error code otherwise.
  */
 static int calc_file_id_hash(enum evm_ima_xattr_type type,
 			     enum hash_algo algo, const u8 *digest,
 			     struct ima_max_digest_data *hash)
 {
-	struct ima_file_id file_id = {.hash_algorithm = algo};
+	struct ima_file_id file_id = {
+		.hash_type = IMA_VERITY_DIGSIG, .hash_algorithm = algo};
 	uint unused = HASH_MAX_DIGESTSIZE - hash_digest_size[algo];
 
+	if (type != IMA_VERITY_DIGSIG)
+		return -EINVAL;
+
 	memcpy(file_id.hash, digest, hash_digest_size[algo]);
 
 	hash->algo = algo;
@@ -264,6 +278,7 @@ static int xattr_verify(enum ima_hooks func, struct integrity_iint_cache *iint,
 			struct evm_ima_xattr_data *xattr_value, int xattr_len,
 			enum integrity_status *status, const char **cause)
 {
+	struct ima_max_digest_data hash;
 	struct signature_v2_hdr *sig;
 	int rc = -EINVAL, hash_start = 0;
 
@@ -332,6 +347,36 @@ static int xattr_verify(enum ima_hooks func, struct integrity_iint_cache *iint,
 		} else {
 			*status = INTEGRITY_PASS;
 		}
+		break;
+	case IMA_VERITY_DIGSIG:
+		set_bit(IMA_DIGSIG, &iint->atomic_flags);
+
+		sig = (typeof(sig))xattr_value;
+		if (sig->version != 3) {
+			*cause = "invalid-verity-version";
+			*status = INTEGRITY_FAIL;
+			break;
+		}
+
+		rc = calc_file_id_hash(IMA_VERITY_DIGSIG, iint->ima_hash->algo,
+				       iint->ima_hash->digest, &hash);
+		if (rc) {
+			*cause = "verity-hashing-error";
+			*status = INTEGRITY_FAIL;
+			break;
+		}
+
+		rc = integrity_digsig_verify(INTEGRITY_KEYRING_IMA,
+					     (const char *)xattr_value,
+					     xattr_len, hash.digest,
+					     hash.length);
+		if (rc) {
+			*cause = "invalid-verity-signature";
+			*status = INTEGRITY_FAIL;
+		} else {
+			*status = INTEGRITY_PASS;
+		}
+
 		break;
 	default:
 		*status = INTEGRITY_UNKNOWN;
diff --git a/security/integrity/ima/ima_template_lib.c b/security/integrity/ima/ima_template_lib.c
index 44e57d7e5fed..0d4bbb4da59a 100644
--- a/security/integrity/ima/ima_template_lib.c
+++ b/security/integrity/ima/ima_template_lib.c
@@ -499,7 +499,8 @@ int ima_eventsig_init(struct ima_event_data *event_data,
 {
 	struct evm_ima_xattr_data *xattr_value = event_data->xattr_value;
 
-	if ((!xattr_value) || (xattr_value->type != EVM_IMA_XATTR_DIGSIG))
+	if (!xattr_value ||
+	    !(xattr_value->type & (EVM_IMA_XATTR_DIGSIG | IMA_VERITY_DIGSIG)))
 		return ima_eventevmsig_init(event_data, field_data);
 
 	return ima_write_template_field_data(xattr_value, event_data->xattr_len,
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
index ed4966d943e9..5b1aa8b7d61c 100644
--- a/security/integrity/integrity.h
+++ b/security/integrity/integrity.h
@@ -80,6 +80,7 @@ enum evm_ima_xattr_type {
 	EVM_IMA_XATTR_DIGSIG,
 	IMA_XATTR_DIGEST_NG,
 	EVM_XATTR_PORTABLE_DIGSIG,
+	IMA_VERITY_DIGSIG,
 	IMA_XATTR_LAST
 };
 
@@ -154,7 +155,9 @@ struct signature_v2_hdr {
 
 /*
  * IMA signature version 3 disambiguates the data that is signed, by
- * indirectly signing the hash of the ima_file_id structure data.
+ * indirectly signing the hash of the ima_file_id structure data,
+ * containing either the fsverity_descriptor struct digest or, in the
+ * future, the regular IMA file hash.
  *
  * (The hash of the ima_file_id structure is only of the portion used.)
  */
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v3 8/8] fsverity: update the documentation
  2022-01-26  0:06 [PATCH v3 0/8] ima: support fs-verity digests and signatures Mimi Zohar
                   ` (6 preceding siblings ...)
  2022-01-26  0:06 ` [PATCH v3 7/8] ima: support fs-verity file digest based version 3 signatures Mimi Zohar
@ 2022-01-26  0:06 ` Mimi Zohar
  2022-02-01  0:36 ` [PATCH v3 0/8] ima: support fs-verity digests and signatures Eric Biggers
  8 siblings, 0 replies; 15+ messages in thread
From: Mimi Zohar @ 2022-01-26  0:06 UTC (permalink / raw)
  To: linux-integrity
  Cc: Mimi Zohar, Eric Biggers, Stefan Berger, linux-fscrypt, linux-kernel

Update the fsverity documentation related to IMA signature support.

Signed-off-by: Mimi Zohar <zohar@linux.ibm.com>
---
 Documentation/filesystems/fsverity.rst | 22 +++++++++++++---------
 1 file changed, 13 insertions(+), 9 deletions(-)

diff --git a/Documentation/filesystems/fsverity.rst b/Documentation/filesystems/fsverity.rst
index 1d831e3cbcb3..7d8a574a0d3b 100644
--- a/Documentation/filesystems/fsverity.rst
+++ b/Documentation/filesystems/fsverity.rst
@@ -74,8 +74,12 @@ authenticating the files is up to userspace.  However, to meet some
 users' needs, fs-verity optionally supports a simple signature
 verification mechanism where users can configure the kernel to require
 that all fs-verity files be signed by a key loaded into a keyring; see
-`Built-in signature verification`_.  Support for fs-verity file hashes
-in IMA (Integrity Measurement Architecture) policies is also planned.
+`Built-in signature verification`_.
+
+IMA supports including fs-verity file digests and signatures based
+on the fs-verity file digests in the IMA (Integrity Measurement
+Architecture) measurement list and verifying fs-verity based file
+signatures stored as security.ima xattrs, based on policy.
 
 User API
 ========
@@ -653,13 +657,13 @@ weren't already directly answered in other parts of this document.
     hashed and what to do with those hashes, such as log them,
     authenticate them, or add them to a measurement list.
 
-    IMA is planned to support the fs-verity hashing mechanism as an
-    alternative to doing full file hashes, for people who want the
-    performance and security benefits of the Merkle tree based hash.
-    But it doesn't make sense to force all uses of fs-verity to be
-    through IMA.  As a standalone filesystem feature, fs-verity
-    already meets many users' needs, and it's testable like other
-    filesystem features e.g. with xfstests.
+    IMA supports the fs-verity hashing mechanism as an alternative
+    to doing full file hashes, for people who want the performance
+    and security benefits of the Merkle tree based hash.  But it
+    doesn't make sense to force all uses of fs-verity to be through
+    IMA.  As a standalone filesystem feature, fs-verity already meets
+    many users' needs, and it's testable like other filesystem
+    features e.g. with xfstests.
 
 :Q: Isn't fs-verity useless because the attacker can just modify the
     hashes in the Merkle tree, which is stored on-disk?
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [PATCH v3 0/8] ima: support fs-verity digests and signatures
  2022-01-26  0:06 [PATCH v3 0/8] ima: support fs-verity digests and signatures Mimi Zohar
                   ` (7 preceding siblings ...)
  2022-01-26  0:06 ` [PATCH v3 8/8] fsverity: update the documentation Mimi Zohar
@ 2022-02-01  0:36 ` Eric Biggers
  2022-02-01 19:20   ` Mimi Zohar
  8 siblings, 1 reply; 15+ messages in thread
From: Eric Biggers @ 2022-02-01  0:36 UTC (permalink / raw)
  To: Mimi Zohar; +Cc: linux-integrity, Stefan Berger, linux-fscrypt, linux-kernel

On Tue, Jan 25, 2022 at 07:06:50PM -0500, Mimi Zohar wrote:
 
> Support including fs-verity file digests in the 'd-ng' template field
> based on a new policy rule option named 'digest_type=hash|verity'.

Perhaps it should be full_hash or verity?  verity is a type of hash.

- Eric

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v3 3/8] fs-verity: define a function to return the integrity protected file digest
  2022-01-26  0:06 ` [PATCH v3 3/8] fs-verity: define a function to return the integrity protected file digest Mimi Zohar
@ 2022-02-01  0:44   ` Eric Biggers
  0 siblings, 0 replies; 15+ messages in thread
From: Eric Biggers @ 2022-02-01  0:44 UTC (permalink / raw)
  To: Mimi Zohar; +Cc: linux-integrity, Stefan Berger, linux-fscrypt, linux-kernel

On Tue, Jan 25, 2022 at 07:06:53PM -0500, Mimi Zohar wrote:
> +	hash_alg = vi->tree_params.hash_alg;
> +	memset(digest, 0, FS_VERITY_MAX_DIGEST_SIZE);
> +
> +	/* convert hash algorithm to hash_algo_name */
> +	i = match_string(hash_algo_name, HASH_ALGO__LAST, hash_alg->name);
> +	if (i < 0)
> +		return -EINVAL;
> +	*alg = i;

The above comment is backwards.  This code is converting a hash algorithm name
to an ID.  The comment is unclear, but it sounds like it's saying the opposite.

> +
> +	memcpy(digest, vi->file_digest, hash_alg->digest_size);

Here there are two "sources of truth" for the digest size.  How about checking
that they are the same:

	if (WARN_ON_ONCE(hash_alg->digest_size != hash_digest_size[*alg]))
		return -EINVAL;

- Eric

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v3 5/8] ima: include fsverity's file digests in the IMA measurement list
  2022-01-26  0:06 ` [PATCH v3 5/8] ima: include fsverity's file digests in the IMA measurement list Mimi Zohar
@ 2022-02-01  0:56   ` Eric Biggers
  0 siblings, 0 replies; 15+ messages in thread
From: Eric Biggers @ 2022-02-01  0:56 UTC (permalink / raw)
  To: Mimi Zohar; +Cc: linux-integrity, Stefan Berger, linux-fscrypt, linux-kernel

On Tue, Jan 25, 2022 at 07:06:55PM -0500, Mimi Zohar wrote:
> Allow fsverity's file digests to be included in the IMA measurement list
> based on policy.
> 
> Define a new measurement policy rule option named 'digest_type=' to
> allow fsverity file digests to be included in the measurement list
> in the d-ng field.
> 
> Including the 'd-type' template field is recommended for unsigned
> fs-verity digests to distinguish between d-ng digest types.  The
> following policy rule, for example, specifies the new 'ima-ngv2'
> template.
> 
> measure func=FILE_CHECK digest_type=hash|verity template=ima-ngv2
> 
> Signed-off-by: Mimi Zohar <zohar@linux.ibm.com>
> ---
>  Documentation/ABI/testing/ima_policy      |  7 +++++
>  Documentation/security/IMA-templates.rst  |  6 ++++
>  security/integrity/ima/ima_api.c          | 29 +++++++++++++++--
>  security/integrity/ima/ima_policy.c       | 38 ++++++++++++++++++++++-
>  security/integrity/ima/ima_template_lib.c |  9 +++++-
>  security/integrity/integrity.h            |  4 ++-
>  6 files changed, 88 insertions(+), 5 deletions(-)
> 
> diff --git a/Documentation/ABI/testing/ima_policy b/Documentation/ABI/testing/ima_policy
> index 839fab811b18..444bb7ccbe03 100644
> --- a/Documentation/ABI/testing/ima_policy
> +++ b/Documentation/ABI/testing/ima_policy
> @@ -51,6 +51,7 @@ Description:
>  			appraise_flag:= [check_blacklist]
>  			Currently, blacklist check is only for files signed with appended
>  			signature.
> +			digest_type:= [hash|verity]

This doesn't explain what this option actually does.

> diff --git a/Documentation/security/IMA-templates.rst b/Documentation/security/IMA-templates.rst
> index 1a91d92950a7..5e31513e8ec4 100644
> --- a/Documentation/security/IMA-templates.rst
> +++ b/Documentation/security/IMA-templates.rst
> @@ -69,6 +69,7 @@ descriptors by adding their identifier to the format string
>     algorithm (field format: [<hash algo>:]digest, where the digest
>     prefix is shown only if the hash algorithm is not SHA1 or MD5);
>   - 'd-modsig': the digest of the event without the appended modsig;
> + - 'd-type': the type of file digest (e.g. hash, verity[1]);

This should explain how this is different from the hash algorithm.

- Eric

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v3 7/8] ima: support fs-verity file digest based version 3 signatures
  2022-01-26  0:06 ` [PATCH v3 7/8] ima: support fs-verity file digest based version 3 signatures Mimi Zohar
@ 2022-02-01  1:06   ` Eric Biggers
  2022-02-01 17:03     ` Mimi Zohar
  0 siblings, 1 reply; 15+ messages in thread
From: Eric Biggers @ 2022-02-01  1:06 UTC (permalink / raw)
  To: Mimi Zohar; +Cc: linux-integrity, Stefan Berger, linux-fscrypt, linux-kernel

On Tue, Jan 25, 2022 at 07:06:57PM -0500, Mimi Zohar wrote:
> Instead of calculating a file hash and verifying the signature stored
> in the security.ima xattr against the calculated file hash, verify
> fs-verity's signature (version 3).
> 
> To differentiate between a regular file hash and an fs-verity file digest
> based signature stored as security.ima xattr, define a new signature type
> named IMA_VERITY_DIGSIG.
> 
> Update the 'ima-sig' template field to display the new fs-verity signature
> type as well.
> 
> For example:
>   appraise func=BPRM_CHECK digest_type=hash|verity
> 
> Signed-off-by: Mimi Zohar <zohar@linux.ibm.com>
> ---
>  Documentation/ABI/testing/ima_policy      | 10 +++++
>  Documentation/security/IMA-templates.rst  |  4 +-
>  security/integrity/ima/ima_appraise.c     | 49 ++++++++++++++++++++++-
>  security/integrity/ima/ima_template_lib.c |  3 +-
>  security/integrity/integrity.h            |  5 ++-
>  5 files changed, 65 insertions(+), 6 deletions(-)

All this IMA-specific stuff is confusing to me, so let me ask a question about
what the end result actually is.  Let's say I want to use IMA to authenticate
("appraise") a file.  I've signed its fs-verity digest with a key.  I put only
that one key in the IMA keyring, and that key was only ever used to sign that
one fs-verity digest.  Can an attacker (who controls the file's contents and IMA
xattr) replace the file with one with a different contents and still pass the
IMA check?  For example, could they replace the file's contents with the
ima_file_id of the authentic file, and then downgrade the signature version to
v2?  If they can do that, then the goal of authentication wasn't met.  It might
be necessary to enforce that only one signature version is used at a time, to
avoid this kind of ambiguity.

- Eric

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v3 7/8] ima: support fs-verity file digest based version 3 signatures
  2022-02-01  1:06   ` Eric Biggers
@ 2022-02-01 17:03     ` Mimi Zohar
  0 siblings, 0 replies; 15+ messages in thread
From: Mimi Zohar @ 2022-02-01 17:03 UTC (permalink / raw)
  To: Eric Biggers; +Cc: linux-integrity, Stefan Berger, linux-fscrypt, linux-kernel

On Mon, 2022-01-31 at 17:06 -0800, Eric Biggers wrote:
> On Tue, Jan 25, 2022 at 07:06:57PM -0500, Mimi Zohar wrote:
> > Instead of calculating a file hash and verifying the signature stored
> > in the security.ima xattr against the calculated file hash, verify
> > fs-verity's signature (version 3).
> > 
> > To differentiate between a regular file hash and an fs-verity file digest
> > based signature stored as security.ima xattr, define a new signature type
> > named IMA_VERITY_DIGSIG.
> > 
> > Update the 'ima-sig' template field to display the new fs-verity signature
> > type as well.
> > 
> > For example:
> >   appraise func=BPRM_CHECK digest_type=hash|verity
> > 
> > Signed-off-by: Mimi Zohar <zohar@linux.ibm.com>
> > ---
> >  Documentation/ABI/testing/ima_policy      | 10 +++++
> >  Documentation/security/IMA-templates.rst  |  4 +-
> >  security/integrity/ima/ima_appraise.c     | 49 ++++++++++++++++++++++-
> >  security/integrity/ima/ima_template_lib.c |  3 +-
> >  security/integrity/integrity.h            |  5 ++-
> >  5 files changed, 65 insertions(+), 6 deletions(-)
> 
> All this IMA-specific stuff is confusing to me, so let me ask a question about
> what the end result actually is.  Let's say I want to use IMA to authenticate
> ("appraise") a file.  I've signed its fs-verity digest with a key.  I put only
> that one key in the IMA keyring, and that key was only ever used to sign that
> one fs-verity digest.  Can an attacker (who controls the file's contents and IMA
> xattr) replace the file with one with a different contents and still pass the
> IMA check?  For example, could they replace the file's contents with the
> ima_file_id of the authentic file, and then downgrade the signature version to
> v2?  If they can do that, then the goal of authentication wasn't met.  It might
> be necessary to enforce that only one signature version is used at a time, to
> avoid this kind of ambiguity.

Instead of only allowing a single signature version, the signature
verification could be based on policy rules.   "ima: include fsverity's
file digests in the IMA measurement list" defines the new policy rule
'digest_type=' option, which currently permits either IMA or fsverity
signatures to match.  Instead only allow IMA or fsverity signatures,
not both, on a per policy rule basis.

From an IMA perspective, this would be safe since the builtin policies
do not support fs-verity signatures.  After loading a custom policy,
additional rules can only extend the custom policy.

thanks,

Mimi


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v3 0/8] ima: support fs-verity digests and signatures
  2022-02-01  0:36 ` [PATCH v3 0/8] ima: support fs-verity digests and signatures Eric Biggers
@ 2022-02-01 19:20   ` Mimi Zohar
  0 siblings, 0 replies; 15+ messages in thread
From: Mimi Zohar @ 2022-02-01 19:20 UTC (permalink / raw)
  To: Eric Biggers; +Cc: linux-integrity, Stefan Berger, linux-fscrypt, linux-kernel

On Mon, 2022-01-31 at 16:36 -0800, Eric Biggers wrote:
> On Tue, Jan 25, 2022 at 07:06:50PM -0500, Mimi Zohar wrote:
>  
> > Support including fs-verity file digests in the 'd-ng' template field
> > based on a new policy rule option named 'digest_type=hash|verity'.
> 
> Perhaps it should be full_hash or verity?  verity is a type of hash.

Ok, but instead of "full_hash", let's rename it to "ima" or "verity".

thanks,

Mimi


^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2022-02-01 19:20 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-01-26  0:06 [PATCH v3 0/8] ima: support fs-verity digests and signatures Mimi Zohar
2022-01-26  0:06 ` [PATCH v3 1/8] ima: rename IMA_ACTION_FLAGS to IMA_NONACTION_FLAGS Mimi Zohar
2022-01-26  0:06 ` [PATCH v3 2/8] ima: define ima_max_digest_data struct without a flexible array variable Mimi Zohar
2022-01-26  0:06 ` [PATCH v3 3/8] fs-verity: define a function to return the integrity protected file digest Mimi Zohar
2022-02-01  0:44   ` Eric Biggers
2022-01-26  0:06 ` [PATCH v3 4/8] ima: define a new template field 'd-type' and a new template 'ima-ngv2' Mimi Zohar
2022-01-26  0:06 ` [PATCH v3 5/8] ima: include fsverity's file digests in the IMA measurement list Mimi Zohar
2022-02-01  0:56   ` Eric Biggers
2022-01-26  0:06 ` [PATCH v3 6/8] ima: define signature version 3 Mimi Zohar
2022-01-26  0:06 ` [PATCH v3 7/8] ima: support fs-verity file digest based version 3 signatures Mimi Zohar
2022-02-01  1:06   ` Eric Biggers
2022-02-01 17:03     ` Mimi Zohar
2022-01-26  0:06 ` [PATCH v3 8/8] fsverity: update the documentation Mimi Zohar
2022-02-01  0:36 ` [PATCH v3 0/8] ima: support fs-verity digests and signatures Eric Biggers
2022-02-01 19:20   ` Mimi Zohar

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.