diff mbox series

[RFC,v3a,06/11] fsverity: Introduce fsverity_get_formatted_digest()

Message ID 20220127184614.2837938-2-roberto.sassu@huawei.com (mailing list archive)
State Superseded
Headers show
Series ima: support fs-verity digests and signatures (alternative) | expand

Commit Message

Roberto Sassu Jan. 27, 2022, 6:46 p.m. UTC
Introduce fsverity_get_formatted_digest() so that a caller (e.g. IMA) can
get all the information necessary to validate the fsverity signature.

Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
---
 fs/verity/measure.c      | 46 ++++++++++++++++++++++++++++++++++++++++
 include/linux/fsverity.h | 12 +++++++++++
 2 files changed, 58 insertions(+)
diff mbox series

Patch

diff --git a/fs/verity/measure.c b/fs/verity/measure.c
index 2152f115071a..7afe4274ecb0 100644
--- a/fs/verity/measure.c
+++ b/fs/verity/measure.c
@@ -8,6 +8,7 @@ 
 #include "fsverity_private.h"
 
 #include <linux/uaccess.h>
+#include <linux/slab.h>
 
 /**
  * fsverity_ioctl_measure() - get a verity file's digest
@@ -96,3 +97,48 @@  int fsverity_get_digest(struct inode *inode,
 
 	return 0;
 }
+
+/**
+ * fsverity_get_formatted_digest() - get a verity file's formatted digest
+ * @inode: inode to get the formatted digest from
+ * @formatted_digest: (out) pointer to the formatted digest
+ * @alg: (out) pointer to the hash algorithm enumeration
+ *
+ * Return the fsverity_formatted_digest structure for a given inode.
+ *
+ * Return: written bytes on success, -errno on failure
+ */
+ssize_t fsverity_get_formatted_digest(struct inode *inode,
+			u8 formatted_digest[FS_VERITY_MAX_FMT_DIGEST_SIZE],
+			enum hash_algo *alg)
+{
+	struct fsverity_formatted_digest *d =
+			(struct fsverity_formatted_digest *)formatted_digest;
+	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;
+
+	/* 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;
+
+	memset(formatted_digest, 0, FS_VERITY_MAX_FMT_DIGEST_SIZE);
+
+	memcpy(d->magic, "FSVerity", 8);
+	d->digest_algorithm = cpu_to_le16(hash_alg - fsverity_hash_algs);
+	d->digest_size = cpu_to_le16(hash_alg->digest_size);
+	memcpy(d->digest, vi->file_digest, hash_alg->digest_size);
+
+	pr_debug("file formatted digest FSVerity:%s:%d:%*phN\n", hash_alg->name,
+		 hash_alg->digest_size, hash_alg->digest_size, vi->file_digest);
+
+	return sizeof(*d) + hash_alg->digest_size;
+}
diff --git a/include/linux/fsverity.h b/include/linux/fsverity.h
index 9a1b70cc7318..17ae313ed8f4 100644
--- a/include/linux/fsverity.h
+++ b/include/linux/fsverity.h
@@ -21,6 +21,8 @@ 
  * Currently assumed to be <= size of fsverity_descriptor::root_hash.
  */
 #define FS_VERITY_MAX_DIGEST_SIZE	SHA512_DIGEST_SIZE
+#define FS_VERITY_MAX_FMT_DIGEST_SIZE	(FS_VERITY_MAX_DIGEST_SIZE + \
+				sizeof(struct fsverity_formatted_digest))
 
 /* Verity operations for filesystems */
 struct fsverity_operations {
@@ -142,6 +144,9 @@  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);
+ssize_t fsverity_get_formatted_digest(struct inode *inode,
+			u8 formatted_digest[FS_VERITY_MAX_FMT_DIGEST_SIZE],
+			enum hash_algo *alg);
 
 /* open.c */
 
@@ -188,6 +193,13 @@  static inline int fsverity_get_digest(struct inode *inode,
 	return -EOPNOTSUPP;
 }
 
+static inline ssize_t fsverity_get_formatted_digest(struct inode *inode,
+			u8 formatted_digest[FS_VERITY_MAX_FMT_DIGEST_SIZE],
+			enum hash_algo *alg)
+{
+	return -EOPNOTSUPP;
+}
+
 /* open.c */
 
 static inline int fsverity_file_open(struct inode *inode, struct file *filp)