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@xxxxxxxxxx> --- fs/verity/measure.c | 46 ++++++++++++++++++++++++++++++++++++++++ include/linux/fsverity.h | 12 +++++++++++ 2 files changed, 58 insertions(+) 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) -- 2.32.0