| // SPDX-License-Identifier: GPL-2.0 | |
| /* | |
| * Opening fs-verity files | |
| * | |
| * Copyright 2019 Google LLC | |
| */ | |
| #include "fsverity_private.h" | |
| #include <linux/export.h> | |
| #include <linux/mm.h> | |
| #include <linux/slab.h> | |
| static struct kmem_cache *fsverity_info_cachep; | |
| static struct rhashtable fsverity_info_hash; | |
| static const struct rhashtable_params fsverity_info_hash_params = { | |
| .key_len = sizeof_field(struct fsverity_info, inode), | |
| .key_offset = offsetof(struct fsverity_info, inode), | |
| .head_offset = offsetof(struct fsverity_info, rhash_head), | |
| .automatic_shrinking = true, | |
| }; | |
| /** | |
| * fsverity_init_merkle_tree_params() - initialize Merkle tree parameters | |
| * @params: the parameters struct to initialize | |
| * @inode: the inode for which the Merkle tree is being built | |
| * @hash_algorithm: number of hash algorithm to use | |
| * @log_blocksize: log base 2 of block size to use | |
| * @salt: pointer to salt (optional) | |
| * @salt_size: size of salt, possibly 0 | |
| * | |
| * Validate the hash algorithm and block size, then compute the tree topology | |
| * (num levels, num blocks in each level, etc.) and initialize @params. | |
| * | |
| * Return: 0 on success, -errno on failure | |
| */ | |
| int fsverity_init_merkle_tree_params(struct merkle_tree_params *params, | |
| const struct inode *inode, | |
| unsigned int hash_algorithm, | |
| unsigned int log_blocksize, | |
| const u8 *salt, size_t salt_size) | |
| { | |
| const struct fsverity_hash_alg *hash_alg; | |
| int err; | |
| u64 blocks; | |
| u64 blocks_in_level[FS_VERITY_MAX_LEVELS]; | |
| u64 offset; | |
| int level; | |
| memset(params, 0, sizeof(*params)); | |
| hash_alg = fsverity_get_hash_alg(inode, hash_algorithm); | |
| if (!hash_alg) | |
| return -EINVAL; | |
| params->hash_alg = hash_alg; | |
| params->digest_size = hash_alg->digest_size; | |
| if (salt_size) { | |
| params->hashstate = | |
| fsverity_prepare_hash_state(hash_alg, salt, salt_size); | |
| if (!params->hashstate) { | |
| err = -ENOMEM; | |
| goto out_err; | |
| } | |
| } | |
| /* | |
| * fs/verity/ directly assumes that the Merkle tree block size is a | |
| * power of 2 less than or equal to PAGE_SIZE. Another restriction | |
| * arises from the interaction between fs/verity/ and the filesystems | |
| * themselves: filesystems expect to be able to verify a single | |
| * filesystem block of data at a time. Therefore, the Merkle tree block | |
| * size must also be less than or equal to the filesystem block size. | |
| * | |
| * The above are the only hard limitations, so in theory the Merkle tree | |
| * block size could be as small as twice the digest size. However, | |
| * that's not useful, and it would result in some unusually deep and | |
| * large Merkle trees. So we currently require that the Merkle tree | |
| * block size be at least 1024 bytes. That's small enough to test the | |
| * sub-page block case on systems with 4K pages, but not too small. | |
| */ | |
| if (log_blocksize < 10 || log_blocksize > PAGE_SHIFT || | |
| log_blocksize > inode->i_blkbits) { | |
| fsverity_warn(inode, "Unsupported log_blocksize: %u", | |
| log_blocksize); | |
| err = -EINVAL; | |
| goto out_err; | |
| } | |
| params->log_blocksize = log_blocksize; | |
| params->block_size = 1 << log_blocksize; | |
| params->log_blocks_per_page = PAGE_SHIFT - log_blocksize; | |
| params->blocks_per_page = 1 << params->log_blocks_per_page; | |
| if (WARN_ON_ONCE(!is_power_of_2(params->digest_size))) { | |
| err = -EINVAL; | |
| goto out_err; | |
| } | |
| if (params->block_size < 2 * params->digest_size) { | |
| fsverity_warn(inode, | |
| "Merkle tree block size (%u) too small for hash algorithm \"%s\"", | |
| params->block_size, hash_alg->name); | |
| err = -EINVAL; | |
| goto out_err; | |
| } | |
| params->log_digestsize = ilog2(params->digest_size); | |
| params->log_arity = log_blocksize - params->log_digestsize; | |
| params->hashes_per_block = 1 << params->log_arity; | |
| /* | |
| * Compute the number of levels in the Merkle tree and create a map from | |
| * level to the starting block of that level. Level 'num_levels - 1' is | |
| * the root and is stored first. Level 0 is the level directly "above" | |
| * the data blocks and is stored last. | |
| */ | |
| /* Compute number of levels and the number of blocks in each level */ | |
| blocks = ((u64)inode->i_size + params->block_size - 1) >> log_blocksize; | |
| while (blocks > 1) { | |
| if (params->num_levels >= FS_VERITY_MAX_LEVELS) { | |
| fsverity_err(inode, "Too many levels in Merkle tree"); | |
| err = -EFBIG; | |
| goto out_err; | |
| } | |
| blocks = (blocks + params->hashes_per_block - 1) >> | |
| params->log_arity; | |
| blocks_in_level[params->num_levels++] = blocks; | |
| } | |
| /* Compute the starting block of each level */ | |
| offset = 0; | |
| for (level = (int)params->num_levels - 1; level >= 0; level--) { | |
| params->level_start[level] = offset; | |
| offset += blocks_in_level[level]; | |
| } | |
| /* | |
| * With block_size != PAGE_SIZE, an in-memory bitmap will need to be | |
| * allocated to track the "verified" status of hash blocks. Don't allow | |
| * this bitmap to get too large. For now, limit it to 1 MiB, which | |
| * limits the file size to about 4.4 TB with SHA-256 and 4K blocks. | |
| * | |
| * Together with the fact that the data, and thus also the Merkle tree, | |
| * cannot have more than ULONG_MAX pages, this implies that hash block | |
| * indices can always fit in an 'unsigned long'. But to be safe, we | |
| * explicitly check for that too. Note, this is only for hash block | |
| * indices; data block indices might not fit in an 'unsigned long'. | |
| */ | |
| if ((params->block_size != PAGE_SIZE && offset > 1 << 23) || | |
| offset > ULONG_MAX) { | |
| fsverity_err(inode, "Too many blocks in Merkle tree"); | |
| err = -EFBIG; | |
| goto out_err; | |
| } | |
| fsverity_hash_block(params, page_address(ZERO_PAGE(0)), | |
| params->zero_digest); | |
| params->tree_size = offset << log_blocksize; | |
| params->tree_pages = PAGE_ALIGN(params->tree_size) >> PAGE_SHIFT; | |
| return 0; | |
| out_err: | |
| kfree(params->hashstate); | |
| memset(params, 0, sizeof(*params)); | |
| return err; | |
| } | |
| /* | |
| * Compute the file digest by hashing the fsverity_descriptor excluding the | |
| * builtin signature and with the sig_size field set to 0. | |
| */ | |
| static void compute_file_digest(const struct fsverity_hash_alg *hash_alg, | |
| struct fsverity_descriptor *desc, | |
| u8 *file_digest) | |
| { | |
| __le32 sig_size = desc->sig_size; | |
| desc->sig_size = 0; | |
| fsverity_hash_buffer(hash_alg, desc, sizeof(*desc), file_digest); | |
| desc->sig_size = sig_size; | |
| } | |
| /* | |
| * Create a new fsverity_info from the given fsverity_descriptor (with optional | |
| * appended builtin signature), and check the signature if present. The | |
| * fsverity_descriptor must have already undergone basic validation. | |
| */ | |
| struct fsverity_info *fsverity_create_info(struct inode *inode, | |
| struct fsverity_descriptor *desc) | |
| { | |
| struct fsverity_info *vi; | |
| int err; | |
| vi = kmem_cache_zalloc(fsverity_info_cachep, GFP_KERNEL); | |
| if (!vi) | |
| return ERR_PTR(-ENOMEM); | |
| vi->inode = inode; | |
| err = fsverity_init_merkle_tree_params(&vi->tree_params, inode, | |
| desc->hash_algorithm, | |
| desc->log_blocksize, | |
| desc->salt, desc->salt_size); | |
| if (err) { | |
| fsverity_err(inode, | |
| "Error %d initializing Merkle tree parameters", | |
| err); | |
| goto fail; | |
| } | |
| memcpy(vi->root_hash, desc->root_hash, vi->tree_params.digest_size); | |
| compute_file_digest(vi->tree_params.hash_alg, desc, vi->file_digest); | |
| err = fsverity_verify_signature(vi, desc->signature, | |
| le32_to_cpu(desc->sig_size)); | |
| if (err) | |
| goto fail; | |
| if (vi->tree_params.block_size != PAGE_SIZE) { | |
| /* | |
| * When the Merkle tree block size and page size differ, we use | |
| * a bitmap to keep track of which hash blocks have been | |
| * verified. This bitmap must contain one bit per hash block, | |
| * including alignment to a page boundary at the end. | |
| * | |
| * Eventually, to support extremely large files in an efficient | |
| * way, it might be necessary to make pages of this bitmap | |
| * reclaimable. But for now, simply allocating the whole bitmap | |
| * is a simple solution that works well on the files on which | |
| * fsverity is realistically used. E.g., with SHA-256 and 4K | |
| * blocks, a 100MB file only needs a 24-byte bitmap, and the | |
| * bitmap for any file under 17GB fits in a 4K page. | |
| */ | |
| unsigned long num_bits = | |
| vi->tree_params.tree_pages << | |
| vi->tree_params.log_blocks_per_page; | |
| vi->hash_block_verified = kvcalloc(BITS_TO_LONGS(num_bits), | |
| sizeof(unsigned long), | |
| GFP_KERNEL); | |
| if (!vi->hash_block_verified) { | |
| err = -ENOMEM; | |
| goto fail; | |
| } | |
| } | |
| return vi; | |
| fail: | |
| fsverity_free_info(vi); | |
| return ERR_PTR(err); | |
| } | |
| int fsverity_set_info(struct fsverity_info *vi) | |
| { | |
| return rhashtable_lookup_insert_fast(&fsverity_info_hash, | |
| &vi->rhash_head, | |
| fsverity_info_hash_params); | |
| } | |
| struct fsverity_info *__fsverity_get_info(const struct inode *inode) | |
| { | |
| return rhashtable_lookup_fast(&fsverity_info_hash, &inode, | |
| fsverity_info_hash_params); | |
| } | |
| EXPORT_SYMBOL_GPL(__fsverity_get_info); | |
| static bool validate_fsverity_descriptor(struct inode *inode, | |
| const struct fsverity_descriptor *desc, | |
| size_t desc_size) | |
| { | |
| if (desc_size < sizeof(*desc)) { | |
| fsverity_err(inode, "Unrecognized descriptor size: %zu bytes", | |
| desc_size); | |
| return false; | |
| } | |
| if (desc->version != 1) { | |
| fsverity_err(inode, "Unrecognized descriptor version: %u", | |
| desc->version); | |
| return false; | |
| } | |
| if (memchr_inv(desc->__reserved, 0, sizeof(desc->__reserved))) { | |
| fsverity_err(inode, "Reserved bits set in descriptor"); | |
| return false; | |
| } | |
| if (desc->salt_size > sizeof(desc->salt)) { | |
| fsverity_err(inode, "Invalid salt_size: %u", desc->salt_size); | |
| return false; | |
| } | |
| if (le64_to_cpu(desc->data_size) != inode->i_size) { | |
| fsverity_err(inode, | |
| "Wrong data_size: %llu (desc) != %lld (inode)", | |
| le64_to_cpu(desc->data_size), inode->i_size); | |
| return false; | |
| } | |
| if (le32_to_cpu(desc->sig_size) > desc_size - sizeof(*desc)) { | |
| fsverity_err(inode, "Signature overflows verity descriptor"); | |
| return false; | |
| } | |
| return true; | |
| } | |
| /* | |
| * Read the inode's fsverity_descriptor (with optional appended builtin | |
| * signature) from the filesystem, and do basic validation of it. | |
| */ | |
| int fsverity_get_descriptor(struct inode *inode, | |
| struct fsverity_descriptor **desc_ret) | |
| { | |
| int res; | |
| struct fsverity_descriptor *desc; | |
| res = inode->i_sb->s_vop->get_verity_descriptor(inode, NULL, 0); | |
| if (res < 0) { | |
| fsverity_err(inode, | |
| "Error %d getting verity descriptor size", res); | |
| return res; | |
| } | |
| if (res > FS_VERITY_MAX_DESCRIPTOR_SIZE) { | |
| fsverity_err(inode, "Verity descriptor is too large (%d bytes)", | |
| res); | |
| return -EMSGSIZE; | |
| } | |
| desc = kmalloc(res, GFP_KERNEL); | |
| if (!desc) | |
| return -ENOMEM; | |
| res = inode->i_sb->s_vop->get_verity_descriptor(inode, desc, res); | |
| if (res < 0) { | |
| fsverity_err(inode, "Error %d reading verity descriptor", res); | |
| kfree(desc); | |
| return res; | |
| } | |
| if (!validate_fsverity_descriptor(inode, desc, res)) { | |
| kfree(desc); | |
| return -EINVAL; | |
| } | |
| *desc_ret = desc; | |
| return 0; | |
| } | |
| static int ensure_verity_info(struct inode *inode) | |
| { | |
| struct fsverity_info *vi = fsverity_get_info(inode), *found; | |
| struct fsverity_descriptor *desc; | |
| int err; | |
| if (vi) | |
| return 0; | |
| err = fsverity_get_descriptor(inode, &desc); | |
| if (err) | |
| return err; | |
| vi = fsverity_create_info(inode, desc); | |
| if (IS_ERR(vi)) { | |
| err = PTR_ERR(vi); | |
| goto out_free_desc; | |
| } | |
| /* | |
| * Multiple tasks may race to set the inode's verity info, in which case | |
| * we might find an existing fsverity_info in the hash table. | |
| */ | |
| found = rhashtable_lookup_get_insert_fast(&fsverity_info_hash, | |
| &vi->rhash_head, | |
| fsverity_info_hash_params); | |
| if (found) { | |
| fsverity_free_info(vi); | |
| if (IS_ERR(found)) | |
| err = PTR_ERR(found); | |
| } | |
| out_free_desc: | |
| kfree(desc); | |
| return err; | |
| } | |
| int __fsverity_file_open(struct inode *inode, struct file *filp) | |
| { | |
| if (filp->f_mode & FMODE_WRITE) | |
| return -EPERM; | |
| return ensure_verity_info(inode); | |
| } | |
| EXPORT_SYMBOL_GPL(__fsverity_file_open); | |
| void fsverity_free_info(struct fsverity_info *vi) | |
| { | |
| kfree(vi->tree_params.hashstate); | |
| kvfree(vi->hash_block_verified); | |
| kmem_cache_free(fsverity_info_cachep, vi); | |
| } | |
| void fsverity_remove_info(struct fsverity_info *vi) | |
| { | |
| rhashtable_remove_fast(&fsverity_info_hash, &vi->rhash_head, | |
| fsverity_info_hash_params); | |
| fsverity_free_info(vi); | |
| } | |
| void fsverity_cleanup_inode(struct inode *inode) | |
| { | |
| struct fsverity_info *vi = fsverity_get_info(inode); | |
| if (vi) | |
| fsverity_remove_info(vi); | |
| } | |
| void __init fsverity_init_info_cache(void) | |
| { | |
| if (rhashtable_init(&fsverity_info_hash, &fsverity_info_hash_params)) | |
| panic("failed to initialize fsverity hash\n"); | |
| fsverity_info_cachep = KMEM_CACHE_USERCOPY( | |
| fsverity_info, | |
| SLAB_RECLAIM_ACCOUNT | SLAB_PANIC, | |
| file_digest); | |
| } |