aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Halcrow <mhalcrow@google.com>2018-03-07 12:39:32 -0800
committerMichael Halcrow <mhalcrow@google.com>2018-03-07 12:39:32 -0800
commitafa0ef89d58dc3a8e271df0001e3a583a092c5cc (patch)
tree78e72552e6e7f879a3e4bf1b02b8ba3f87326bf3
parent3348e940d8d8a513c18adea348859460971b0d69 (diff)
downloadlinux-fs-verity-wip-split-patches.tar.gz
fs-verity: Wire in root hash verificationfs-verity-wip-split-patches
Still needs work; an assumption regarding the lifecycle of fsverity_info doesn't work the way I think it should. Signed-off-by: Michael Halcrow <mhalcrow@google.com>
-rw-r--r--fs/f2fs/data.c3
-rw-r--r--fs/verity/fsverity_private.h3
-rw-r--r--fs/verity/verity.c69
3 files changed, 60 insertions, 15 deletions
diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index 5a4e3e8cf9a27d..4bd7d30edce81b 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -76,7 +76,8 @@ static void f2fs_read_end_io(struct bio *bio)
if (f2fs_bio_verity(bio)) {
BUG_ON(f2fs_bio_encrypted(bio)); /* TODO(mhalcrow) */
if (bio->bi_status) {
- /* TODO(mhalcrow) */
+ /* TODO(mhalcrow): Ensure we're doing
+ * everything we should be doing */
fsverity_release_bio_ctrl(bio->bi_verity_ctrl);
} else {
#ifdef CONFIG_FS_VERITY_DEBUG
diff --git a/fs/verity/fsverity_private.h b/fs/verity/fsverity_private.h
index 3b5565c01b4f6b..5550418da2b1d8 100644
--- a/fs/verity/fsverity_private.h
+++ b/fs/verity/fsverity_private.h
@@ -24,7 +24,7 @@ struct fsverity_header {
u8 log_arity; /* log2(leaves-per-node) (E.g., 7 for SHA2 ) */
__le16 meta_algorithm; /* Cryptographic digest for tree blocks */
__le16 data_algorithm; /* Cryptographic digest for data blocks */
- __le32 flags; /* Only flag is '1' if there are fsverity_extensions */
+ __le32 flags; /* No flags for now */
__le32 reserved1; /* Must be 0 */
__le64 size; /* Size of the original, unpadded data. */
/* The number of blocks from the start of this header where
@@ -86,6 +86,7 @@ struct fsverity_info {
bool root_hashed;
char root_hash[SHA256_DIGEST_SIZE]; /* Merkle tree root hash */
+ bool fail; /* File authenticity check failed */
/* starting blocks for each tree level. 0 is the lowest level. */
sector_t hash_lvl_region_idx[FS_VERITY_MAX_LEVELS];
diff --git a/fs/verity/verity.c b/fs/verity/verity.c
index f324a5382fe342..17c593b94827ab 100644
--- a/fs/verity/verity.c
+++ b/fs/verity/verity.c
@@ -156,6 +156,7 @@ static int __measure_fs_verity_root_hash(
"final returned [%d]\n", err);
goto out;
}
+ vi->root_hashed = true;
#ifdef CONFIG_FS_VERITY_DEBUG
{
char computed_hex_hash[2 * SHA256_DIGEST_SIZE + 1];
@@ -238,8 +239,6 @@ static int __full_header_size(const char *hdr_virt)
header = (struct fsverity_header *)hdr_virt;
ext_pos = sizeof(struct fsverity_header);
- if (!(le32_to_cpu(header->flags) & 1)) /* No extensions */
- goto out;
extension_count = header->extension_count;
if (extension_count == 0) {
printk(KERN_WARNING "%s: Extension flag set, but extension "
@@ -489,8 +488,20 @@ static int __read_fsverity_header(struct inode *inode,
if (err) {
pr_warn_ratelimited("Error measuring fs-verity root hash: [%d]",
err);
+#ifdef CONFIG_FS_VERITY_DEBUG
+ printk(KERN_WARNING
+ "%s: Setting &info->fail = [0x%p] to true\n",
+ __func__, &info->fail);
+#endif
+ info->fail = true;
goto put_out;
}
+#ifdef CONFIG_FS_VERITY_DEBUG
+ printk(KERN_WARNING
+ "%s: Setting &info->fail = [0x%p] to false\n",
+ __func__, &info->fail);
+#endif
+ info->fail = false;
put_out:
if (hdr_page) {
kunmap(hdr_page);
@@ -535,10 +546,24 @@ static int __get_info(struct inode *inode, struct fsverity_info *vi,
#endif
return 0;
}
- if (vi && inode->i_verity_info) {
+ if (vi && inode->i_verity_info && !root_hash) {
#ifdef CONFIG_FS_VERITY_DEBUG
- printk(KERN_WARNING "%s: vi && inode([0x%p])->i_verity_info, "
- "so skipping header read/verify\n", __func__, inode);
+ printk(KERN_WARNING
+ "%s: Checking &inode->i_verity_info->fail = [0x%p]\n",
+ __func__, &inode->i_verity_info->fail);
+#endif
+ if (inode->i_verity_info->fail) {
+#ifdef CONFIG_FS_VERITY_DEBUG
+ printk(KERN_WARNING
+ "%s: verity file in failure state\n",
+ __func__);
+#endif
+ return -EIO;
+ }
+#ifdef CONFIG_FS_VERITY_DEBUG
+ printk(KERN_WARNING "%s: vi && inode([0x%p])->i_verity_info "
+ "&& !root_hash, so skipping header read/verify\n",
+ __func__, inode);
#endif
return 0;
}
@@ -564,7 +589,12 @@ int fsverity_measure_info(struct inode *inode,
const struct fsverity_root_hash *root_hash)
{
struct fsverity_info info;
- /* TODO(mhalcrow): Not for upstream (fsverity list on the sb) */
+ /* TODO(mhalcrow): The initial root hash validation mechanism
+ * requires that userspace explicitly declare the root hash
+ * via the MEASURE ioctl. In the future, we're going to want
+ * to have a signature attached to the files that we validate
+ * whenever we load the authenticated data structure root into
+ * memory. */
struct inode *sb_inode;
struct super_block *sb;
bool found = false;
@@ -605,9 +635,9 @@ int fsverity_get_info(struct inode *inode)
err = __get_info(inode, vi, NULL);
if (err)
goto free_out;
-
if (cmpxchg(&inode->i_verity_info, NULL, vi) == NULL)
vi = NULL;
+
free_out:
__put_verity_info(vi);
return err;
@@ -1015,13 +1045,22 @@ static bool __verify_root_hash(struct page *page)
printk(KERN_WARNING "%s: page [0x%p] is the only data page in the "
"file; checking against root hash\n", __func__, page);
#endif
- /* TODO(mhalcrow): Do this right. For now we're going to rely
- * on pre-measure and superblock fs-verity inode pinning. */
+ /* TODO(mhalcrow): For now we're going to rely on pre-measure
+ * and superblock fs-verity inode pinning. */
if (!vi->root_hashed) {
- printk(KERN_WARNING "%s: TODO: Get trusted root hash\n",
+ printk(KERN_WARNING "%s: Merkle tree root hash untrusted. "
+ "Use the FS_IOC_MEASURE_FSVERITY ioctl to provide a "
+ "trusted fs-verity root hash (which covers the "
+ "header and the Merkle tree root hash).\n",
__func__);
- memcpy(vi->root_hash, page->contents_hash, SHA256_DIGEST_SIZE);
- vi->root_hashed = true;
+ page->authenticated = false;
+#ifdef CONFIG_FS_VERITY_DEBUG
+ printk(KERN_WARNING
+ "%s: Setting &vi->fail = [0x%p] to true\n",
+ __func__, &vi->fail);
+#endif
+ vi->fail = true;
+ return false;
}
page->authenticated = __are_hashes_equal(vi->root_hash,
page->contents_hash);
@@ -1090,7 +1129,11 @@ static void __complete_bio_group(struct work_struct *work)
page->authenticated = false;
if (page->is_root &&
!__verify_root_hash(page)) {
- WARN_ON_ONCE(1);
+#ifdef CONFIG_FS_VERITY_DEBUG
+ printk(KERN_WARNING
+ "%s: root hash not verified\n",
+ __func__);
+#endif
status = BLK_STS_IOERR;
goto complete;
}