[PATCH v1 4/5] ima: support fs-verity file digest based signatures

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Instead of calculating a file hash and verifying the signature stored
in the security.ima xattr against the calculated file hash, verify the
signature based on the fs-verity's file digest and other metadata.  The
fs-verity file digest is a hash that includes the Merkle tree root hash.

Signed-off-by: Mimi Zohar <zohar@xxxxxxxxxxxxx>
---
Changelog v1:
- Based on Eric Bigger's review, instead of verifying the fsverity's file
digest directly, sign a hash of it with other file metadata.

 security/integrity/ima/ima_api.c      | 20 ++++++++++++
 security/integrity/ima/ima_appraise.c | 45 ++++++++++++++++++++++++++-
 2 files changed, 64 insertions(+), 1 deletion(-)

diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c
index 7505563315cb..4fe7bc99378a 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_collect_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_collect_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
  *
@@ -251,6 +269,8 @@ int ima_collect_measurement(struct integrity_iint_cache *iint,
 
 	if (buf)
 		result = ima_calc_buffer_hash(buf, size, &hash.hdr);
+	else if (veritysig)
+		result = ima_collect_verity_digest(iint, &hash.hdr);
 	else
 		result = ima_calc_file_hash(file, &hash.hdr);
 
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c
index 549fe051269a..53938aa0497a 100644
--- a/security/integrity/ima/ima_appraise.c
+++ b/security/integrity/ima/ima_appraise.c
@@ -240,6 +240,11 @@ 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)
 {
+	u8 verity_digest[IMA_MAX_DIGEST_SIZE + 1];
+	struct {
+		struct ima_digest_data hdr;
+		char digest[IMA_MAX_DIGEST_SIZE];
+	} hash;
 	int rc = -EINVAL, hash_start = 0;
 
 	switch (xattr_value->type) {
@@ -277,7 +282,45 @@ static int xattr_verify(enum ima_hooks func, struct integrity_iint_cache *iint,
 		*status = INTEGRITY_PASS;
 		break;
 	case IMA_VERITY_DIGSIG:
-		fallthrough;
+		set_bit(IMA_DIGSIG, &iint->atomic_flags);
+
+		/*
+		 * The IMA signature is based on a hash of IMA_VERITY_DIGSIG
+		 * and the fs-verity file digest, not directly on the
+		 * fs-verity file digest.  Both digests should probably be
+		 * included in the IMA measurement list, but for now this
+		 * digest is only used for verifying the IMA signature.
+		 */
+		verity_digest[0] = IMA_VERITY_DIGSIG;
+		memcpy(verity_digest + 1, iint->ima_hash->digest,
+		       iint->ima_hash->length);
+
+		hash.hdr.algo = iint->ima_hash->algo;
+		hash.hdr.length = iint->ima_hash->length;
+
+		rc = ima_calc_buffer_hash(verity_digest,
+					  iint->ima_hash->length + 1,
+					  &hash.hdr);
+		if (rc) {
+			*cause = "verity-hashing-error";
+			*status = INTEGRITY_FAIL;
+			break;
+		}
+
+		rc = integrity_digsig_verify(INTEGRITY_KEYRING_IMA,
+					     (const char *)xattr_value,
+					      xattr_len,
+					      hash.hdr.digest,
+					      hash.hdr.length);
+
+		if (rc) {
+			*cause = "invalid-verity-signature";
+			*status = INTEGRITY_FAIL;
+		} else {
+			*status = INTEGRITY_PASS;
+		}
+
+		break;
 	case EVM_IMA_XATTR_DIGSIG:
 		set_bit(IMA_DIGSIG, &iint->atomic_flags);
 		rc = integrity_digsig_verify(INTEGRITY_KEYRING_IMA,
-- 
2.27.0




[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux Kernel]     [Linux Kernel Hardening]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux SCSI]

  Powered by Linux