diff options
author | Michael Halcrow <mhalcrow@google.com> | 2018-03-07 12:39:32 -0800 |
---|---|---|
committer | Michael Halcrow <mhalcrow@google.com> | 2018-03-07 12:39:32 -0800 |
commit | afa0ef89d58dc3a8e271df0001e3a583a092c5cc (patch) | |
tree | 78e72552e6e7f879a3e4bf1b02b8ba3f87326bf3 | |
parent | 3348e940d8d8a513c18adea348859460971b0d69 (diff) | |
download | linux-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.c | 3 | ||||
-rw-r--r-- | fs/verity/fsverity_private.h | 3 | ||||
-rw-r--r-- | fs/verity/verity.c | 69 |
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; } |