162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Ioctl to enable verity on a file 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright 2019 Google LLC 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include "fsverity_private.h" 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <crypto/hash.h> 1162306a36Sopenharmony_ci#include <linux/mount.h> 1262306a36Sopenharmony_ci#include <linux/sched/signal.h> 1362306a36Sopenharmony_ci#include <linux/uaccess.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_cistruct block_buffer { 1662306a36Sopenharmony_ci u32 filled; 1762306a36Sopenharmony_ci bool is_root_hash; 1862306a36Sopenharmony_ci u8 *data; 1962306a36Sopenharmony_ci}; 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci/* Hash a block, writing the result to the next level's pending block buffer. */ 2262306a36Sopenharmony_cistatic int hash_one_block(struct inode *inode, 2362306a36Sopenharmony_ci const struct merkle_tree_params *params, 2462306a36Sopenharmony_ci struct block_buffer *cur) 2562306a36Sopenharmony_ci{ 2662306a36Sopenharmony_ci struct block_buffer *next = cur + 1; 2762306a36Sopenharmony_ci int err; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci /* 3062306a36Sopenharmony_ci * Safety check to prevent a buffer overflow in case of a filesystem bug 3162306a36Sopenharmony_ci * that allows the file size to change despite deny_write_access(), or a 3262306a36Sopenharmony_ci * bug in the Merkle tree logic itself 3362306a36Sopenharmony_ci */ 3462306a36Sopenharmony_ci if (WARN_ON_ONCE(next->is_root_hash && next->filled != 0)) 3562306a36Sopenharmony_ci return -EINVAL; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci /* Zero-pad the block if it's shorter than the block size. */ 3862306a36Sopenharmony_ci memset(&cur->data[cur->filled], 0, params->block_size - cur->filled); 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci err = fsverity_hash_block(params, inode, cur->data, 4162306a36Sopenharmony_ci &next->data[next->filled]); 4262306a36Sopenharmony_ci if (err) 4362306a36Sopenharmony_ci return err; 4462306a36Sopenharmony_ci next->filled += params->digest_size; 4562306a36Sopenharmony_ci cur->filled = 0; 4662306a36Sopenharmony_ci return 0; 4762306a36Sopenharmony_ci} 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_cistatic int write_merkle_tree_block(struct inode *inode, const u8 *buf, 5062306a36Sopenharmony_ci unsigned long index, 5162306a36Sopenharmony_ci const struct merkle_tree_params *params) 5262306a36Sopenharmony_ci{ 5362306a36Sopenharmony_ci u64 pos = (u64)index << params->log_blocksize; 5462306a36Sopenharmony_ci int err; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci err = inode->i_sb->s_vop->write_merkle_tree_block(inode, buf, pos, 5762306a36Sopenharmony_ci params->block_size); 5862306a36Sopenharmony_ci if (err) 5962306a36Sopenharmony_ci fsverity_err(inode, "Error %d writing Merkle tree block %lu", 6062306a36Sopenharmony_ci err, index); 6162306a36Sopenharmony_ci return err; 6262306a36Sopenharmony_ci} 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistatic int check_file_and_enable_verity(struct file *filp, 6562306a36Sopenharmony_ci const struct fsverity_enable_arg *arg); 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci#ifdef CONFIG_SECURITY_CODE_SIGN 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_cistatic int code_sign_init_descriptor(struct inode *inode, 7062306a36Sopenharmony_ci const struct fsverity_enable_arg *_arg, struct fsverity_descriptor *_desc); 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistatic int code_sign_copy_merkle_tree(struct file *filp, const void *_desc, 7362306a36Sopenharmony_ci const struct merkle_tree_params *params); 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci#else /* !CONFIG_SECURITY_CODE_SIGN */ 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistatic inline int code_sign_init_descriptor(struct inode *inode, 7862306a36Sopenharmony_ci const struct fsverity_enable_arg *_arg, struct fsverity_descriptor *_desc) 7962306a36Sopenharmony_ci{ 8062306a36Sopenharmony_ci return 0; 8162306a36Sopenharmony_ci} 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_cistatic int code_sign_copy_merkle_tree(struct file *filp, 8462306a36Sopenharmony_ci const void *_desc, 8562306a36Sopenharmony_ci const struct merkle_tree_params *params) 8662306a36Sopenharmony_ci{ 8762306a36Sopenharmony_ci return 0; 8862306a36Sopenharmony_ci} 8962306a36Sopenharmony_ci#endif /* !CONFIG_SECURITY_CODE_SIGN */ 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci/* 9262306a36Sopenharmony_ci * Build the Merkle tree for the given file using the given parameters, and 9362306a36Sopenharmony_ci * return the root hash in @root_hash. 9462306a36Sopenharmony_ci * 9562306a36Sopenharmony_ci * The tree is written to a filesystem-specific location as determined by the 9662306a36Sopenharmony_ci * ->write_merkle_tree_block() method. However, the blocks that comprise the 9762306a36Sopenharmony_ci * tree are the same for all filesystems. 9862306a36Sopenharmony_ci */ 9962306a36Sopenharmony_cistatic int build_merkle_tree(struct file *filp, 10062306a36Sopenharmony_ci const struct merkle_tree_params *params, 10162306a36Sopenharmony_ci u8 *root_hash, 10262306a36Sopenharmony_ci size_t data_size) 10362306a36Sopenharmony_ci{ 10462306a36Sopenharmony_ci struct inode *inode = file_inode(filp); 10562306a36Sopenharmony_ci const int num_levels = params->num_levels; 10662306a36Sopenharmony_ci struct block_buffer _buffers[1 + FS_VERITY_MAX_LEVELS + 1] = {}; 10762306a36Sopenharmony_ci struct block_buffer *buffers = &_buffers[1]; 10862306a36Sopenharmony_ci unsigned long level_offset[FS_VERITY_MAX_LEVELS]; 10962306a36Sopenharmony_ci int level; 11062306a36Sopenharmony_ci u64 offset; 11162306a36Sopenharmony_ci int err; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci if (data_size == 0) { 11462306a36Sopenharmony_ci /* Empty file is a special case; root hash is all 0's */ 11562306a36Sopenharmony_ci memset(root_hash, 0, params->digest_size); 11662306a36Sopenharmony_ci return 0; 11762306a36Sopenharmony_ci } 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci /* 12062306a36Sopenharmony_ci * Allocate the block buffers. Buffer "-1" is for data blocks. 12162306a36Sopenharmony_ci * Buffers 0 <= level < num_levels are for the actual tree levels. 12262306a36Sopenharmony_ci * Buffer 'num_levels' is for the root hash. 12362306a36Sopenharmony_ci */ 12462306a36Sopenharmony_ci for (level = -1; level < num_levels; level++) { 12562306a36Sopenharmony_ci buffers[level].data = kzalloc(params->block_size, GFP_KERNEL); 12662306a36Sopenharmony_ci if (!buffers[level].data) { 12762306a36Sopenharmony_ci err = -ENOMEM; 12862306a36Sopenharmony_ci goto out; 12962306a36Sopenharmony_ci } 13062306a36Sopenharmony_ci } 13162306a36Sopenharmony_ci buffers[num_levels].data = root_hash; 13262306a36Sopenharmony_ci buffers[num_levels].is_root_hash = true; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(level_offset) != sizeof(params->level_start)); 13562306a36Sopenharmony_ci memcpy(level_offset, params->level_start, sizeof(level_offset)); 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci /* Hash each data block, also hashing the tree blocks as they fill up */ 13862306a36Sopenharmony_ci for (offset = 0; offset < data_size; offset += params->block_size) { 13962306a36Sopenharmony_ci ssize_t bytes_read; 14062306a36Sopenharmony_ci loff_t pos = offset; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci buffers[-1].filled = min_t(u64, params->block_size, 14362306a36Sopenharmony_ci data_size - offset); 14462306a36Sopenharmony_ci bytes_read = __kernel_read(filp, buffers[-1].data, 14562306a36Sopenharmony_ci buffers[-1].filled, &pos); 14662306a36Sopenharmony_ci if (bytes_read < 0) { 14762306a36Sopenharmony_ci err = bytes_read; 14862306a36Sopenharmony_ci fsverity_err(inode, "Error %d reading file data", err); 14962306a36Sopenharmony_ci goto out; 15062306a36Sopenharmony_ci } 15162306a36Sopenharmony_ci if (bytes_read != buffers[-1].filled) { 15262306a36Sopenharmony_ci err = -EINVAL; 15362306a36Sopenharmony_ci fsverity_err(inode, "Short read of file data"); 15462306a36Sopenharmony_ci goto out; 15562306a36Sopenharmony_ci } 15662306a36Sopenharmony_ci err = hash_one_block(inode, params, &buffers[-1]); 15762306a36Sopenharmony_ci if (err) 15862306a36Sopenharmony_ci goto out; 15962306a36Sopenharmony_ci for (level = 0; level < num_levels; level++) { 16062306a36Sopenharmony_ci if (buffers[level].filled + params->digest_size <= 16162306a36Sopenharmony_ci params->block_size) { 16262306a36Sopenharmony_ci /* Next block at @level isn't full yet */ 16362306a36Sopenharmony_ci break; 16462306a36Sopenharmony_ci } 16562306a36Sopenharmony_ci /* Next block at @level is full */ 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci err = hash_one_block(inode, params, &buffers[level]); 16862306a36Sopenharmony_ci if (err) 16962306a36Sopenharmony_ci goto out; 17062306a36Sopenharmony_ci err = write_merkle_tree_block(inode, 17162306a36Sopenharmony_ci buffers[level].data, 17262306a36Sopenharmony_ci level_offset[level], 17362306a36Sopenharmony_ci params); 17462306a36Sopenharmony_ci if (err) 17562306a36Sopenharmony_ci goto out; 17662306a36Sopenharmony_ci level_offset[level]++; 17762306a36Sopenharmony_ci } 17862306a36Sopenharmony_ci if (fatal_signal_pending(current)) { 17962306a36Sopenharmony_ci err = -EINTR; 18062306a36Sopenharmony_ci goto out; 18162306a36Sopenharmony_ci } 18262306a36Sopenharmony_ci cond_resched(); 18362306a36Sopenharmony_ci } 18462306a36Sopenharmony_ci /* Finish all nonempty pending tree blocks. */ 18562306a36Sopenharmony_ci for (level = 0; level < num_levels; level++) { 18662306a36Sopenharmony_ci if (buffers[level].filled != 0) { 18762306a36Sopenharmony_ci err = hash_one_block(inode, params, &buffers[level]); 18862306a36Sopenharmony_ci if (err) 18962306a36Sopenharmony_ci goto out; 19062306a36Sopenharmony_ci err = write_merkle_tree_block(inode, 19162306a36Sopenharmony_ci buffers[level].data, 19262306a36Sopenharmony_ci level_offset[level], 19362306a36Sopenharmony_ci params); 19462306a36Sopenharmony_ci if (err) 19562306a36Sopenharmony_ci goto out; 19662306a36Sopenharmony_ci } 19762306a36Sopenharmony_ci } 19862306a36Sopenharmony_ci /* The root hash was filled by the last call to hash_one_block(). */ 19962306a36Sopenharmony_ci if (WARN_ON_ONCE(buffers[num_levels].filled != params->digest_size)) { 20062306a36Sopenharmony_ci err = -EINVAL; 20162306a36Sopenharmony_ci goto out; 20262306a36Sopenharmony_ci } 20362306a36Sopenharmony_ci err = 0; 20462306a36Sopenharmony_ciout: 20562306a36Sopenharmony_ci for (level = -1; level < num_levels; level++) 20662306a36Sopenharmony_ci kfree(buffers[level].data); 20762306a36Sopenharmony_ci return err; 20862306a36Sopenharmony_ci} 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_cistatic int enable_verity(struct file *filp, 21162306a36Sopenharmony_ci const struct fsverity_enable_arg *arg) 21262306a36Sopenharmony_ci{ 21362306a36Sopenharmony_ci struct inode *inode = file_inode(filp); 21462306a36Sopenharmony_ci struct fsverity_descriptor *desc; 21562306a36Sopenharmony_ci size_t desc_size = struct_size(desc, signature, arg->sig_size); 21662306a36Sopenharmony_ci int err; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci /* Start initializing the fsverity_descriptor */ 21962306a36Sopenharmony_ci desc = kzalloc(desc_size, GFP_KERNEL); 22062306a36Sopenharmony_ci if (!desc) 22162306a36Sopenharmony_ci return -ENOMEM; 22262306a36Sopenharmony_ci desc->version = 1; 22362306a36Sopenharmony_ci desc->hash_algorithm = arg->hash_algorithm; 22462306a36Sopenharmony_ci desc->log_blocksize = ilog2(arg->block_size); 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci /* Get the salt if the user provided one */ 22762306a36Sopenharmony_ci if (arg->salt_size && 22862306a36Sopenharmony_ci copy_from_user(desc->salt, u64_to_user_ptr(arg->salt_ptr), 22962306a36Sopenharmony_ci arg->salt_size)) { 23062306a36Sopenharmony_ci err = -EFAULT; 23162306a36Sopenharmony_ci goto out; 23262306a36Sopenharmony_ci } 23362306a36Sopenharmony_ci desc->salt_size = arg->salt_size; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci /* Get the builtin signature if the user provided one */ 23662306a36Sopenharmony_ci if (arg->sig_size && 23762306a36Sopenharmony_ci copy_from_user(desc->signature, u64_to_user_ptr(arg->sig_ptr), 23862306a36Sopenharmony_ci arg->sig_size)) { 23962306a36Sopenharmony_ci err = -EFAULT; 24062306a36Sopenharmony_ci goto out; 24162306a36Sopenharmony_ci } 24262306a36Sopenharmony_ci desc->sig_size = cpu_to_le32(arg->sig_size); 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci desc->data_size = cpu_to_le64(inode->i_size); 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci err = code_sign_init_descriptor(inode, arg, desc); 24762306a36Sopenharmony_ci if (err) { 24862306a36Sopenharmony_ci fsverity_err(inode, "Init code sign descriptor err: %u", err); 24962306a36Sopenharmony_ci goto out; 25062306a36Sopenharmony_ci } 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci err = fsverity_enable_with_descriptor(filp, (void *)desc, desc_size); 25362306a36Sopenharmony_ciout: 25462306a36Sopenharmony_ci kfree(desc); 25562306a36Sopenharmony_ci return err; 25662306a36Sopenharmony_ci} 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ciint fsverity_enable_with_descriptor(struct file *filp, 25962306a36Sopenharmony_ci void *_desc, size_t desc_size) 26062306a36Sopenharmony_ci{ 26162306a36Sopenharmony_ci struct inode *inode = file_inode(filp); 26262306a36Sopenharmony_ci const struct fsverity_operations *vops = inode->i_sb->s_vop; 26362306a36Sopenharmony_ci struct merkle_tree_params params = { }; 26462306a36Sopenharmony_ci struct fsverity_descriptor *desc = (struct fsverity_descriptor *)_desc; 26562306a36Sopenharmony_ci struct fsverity_info *vi; 26662306a36Sopenharmony_ci int err; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci if (vops == NULL) { 26962306a36Sopenharmony_ci fsverity_err(inode, "current filesystem doesn't support fs-verity."); 27062306a36Sopenharmony_ci return -ENOTTY; 27162306a36Sopenharmony_ci } 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci /* Prepare the Merkle tree parameters */ 27462306a36Sopenharmony_ci err = fsverity_init_merkle_tree_params(¶ms, inode, 27562306a36Sopenharmony_ci desc->hash_algorithm, 27662306a36Sopenharmony_ci desc->log_blocksize, 27762306a36Sopenharmony_ci desc->salt, desc->salt_size, 27862306a36Sopenharmony_ci desc->data_size); 27962306a36Sopenharmony_ci if (err) 28062306a36Sopenharmony_ci goto out; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci /* 28362306a36Sopenharmony_ci * Start enabling verity on this file, serialized by the inode lock. 28462306a36Sopenharmony_ci * Fail if verity is already enabled or is already being enabled. 28562306a36Sopenharmony_ci */ 28662306a36Sopenharmony_ci inode_lock(inode); 28762306a36Sopenharmony_ci if (IS_VERITY(inode)) 28862306a36Sopenharmony_ci err = -EEXIST; 28962306a36Sopenharmony_ci else 29062306a36Sopenharmony_ci err = vops->begin_enable_verity(filp); 29162306a36Sopenharmony_ci inode_unlock(inode); 29262306a36Sopenharmony_ci if (err) 29362306a36Sopenharmony_ci goto out; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci err = code_sign_copy_merkle_tree(filp, _desc, ¶ms); 29662306a36Sopenharmony_ci if (err < 0) { 29762306a36Sopenharmony_ci fsverity_err(inode, "Error %d copying Merkle tree", err); 29862306a36Sopenharmony_ci goto rollback; 29962306a36Sopenharmony_ci } else if (err == 1) /* already copy merkle tree */ 30062306a36Sopenharmony_ci goto skip_build; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci /* 30362306a36Sopenharmony_ci * Build the Merkle tree. Don't hold the inode lock during this, since 30462306a36Sopenharmony_ci * on huge files this may take a very long time and we don't want to 30562306a36Sopenharmony_ci * force unrelated syscalls like chown() to block forever. We don't 30662306a36Sopenharmony_ci * need the inode lock here because deny_write_access() already prevents 30762306a36Sopenharmony_ci * the file from being written to or truncated, and we still serialize 30862306a36Sopenharmony_ci * ->begin_enable_verity() and ->end_enable_verity() using the inode 30962306a36Sopenharmony_ci * lock and only allow one process to be here at a time on a given file. 31062306a36Sopenharmony_ci */ 31162306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(desc->root_hash) < FS_VERITY_MAX_DIGEST_SIZE); 31262306a36Sopenharmony_ci err = build_merkle_tree(filp, ¶ms, desc->root_hash, desc->data_size); 31362306a36Sopenharmony_ci if (err) { 31462306a36Sopenharmony_ci fsverity_err(inode, "Error %d building Merkle tree", err); 31562306a36Sopenharmony_ci goto rollback; 31662306a36Sopenharmony_ci } 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ciskip_build: 31962306a36Sopenharmony_ci pr_debug("Done building Merkle tree. Root hash is %s:%*phN\n", 32062306a36Sopenharmony_ci params.hash_alg->name, params.digest_size, desc->root_hash); 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci /* 32362306a36Sopenharmony_ci * Create the fsverity_info. Don't bother trying to save work by 32462306a36Sopenharmony_ci * reusing the merkle_tree_params from above. Instead, just create the 32562306a36Sopenharmony_ci * fsverity_info from the fsverity_descriptor as if it were just loaded 32662306a36Sopenharmony_ci * from disk. This is simpler, and it serves as an extra check that the 32762306a36Sopenharmony_ci * metadata we're writing is valid before actually enabling verity. 32862306a36Sopenharmony_ci */ 32962306a36Sopenharmony_ci vi = fsverity_create_info(inode, desc); 33062306a36Sopenharmony_ci if (IS_ERR(vi)) { 33162306a36Sopenharmony_ci err = PTR_ERR(vi); 33262306a36Sopenharmony_ci goto rollback; 33362306a36Sopenharmony_ci } 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci /* 33662306a36Sopenharmony_ci * Tell the filesystem to finish enabling verity on the file. 33762306a36Sopenharmony_ci * Serialized with ->begin_enable_verity() by the inode lock. 33862306a36Sopenharmony_ci */ 33962306a36Sopenharmony_ci inode_lock(inode); 34062306a36Sopenharmony_ci err = vops->end_enable_verity(filp, desc, desc_size, params.tree_size); 34162306a36Sopenharmony_ci inode_unlock(inode); 34262306a36Sopenharmony_ci if (err) { 34362306a36Sopenharmony_ci fsverity_err(inode, "%ps() failed with err %d", 34462306a36Sopenharmony_ci vops->end_enable_verity, err); 34562306a36Sopenharmony_ci fsverity_free_info(vi); 34662306a36Sopenharmony_ci } else if (WARN_ON_ONCE(!IS_VERITY(inode))) { 34762306a36Sopenharmony_ci err = -EINVAL; 34862306a36Sopenharmony_ci fsverity_free_info(vi); 34962306a36Sopenharmony_ci } else { 35062306a36Sopenharmony_ci /* Successfully enabled verity */ 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci /* 35362306a36Sopenharmony_ci * Readers can start using ->i_verity_info immediately, so it 35462306a36Sopenharmony_ci * can't be rolled back once set. So don't set it until just 35562306a36Sopenharmony_ci * after the filesystem has successfully enabled verity. 35662306a36Sopenharmony_ci */ 35762306a36Sopenharmony_ci fsverity_set_info(inode, vi); 35862306a36Sopenharmony_ci } 35962306a36Sopenharmony_ciout: 36062306a36Sopenharmony_ci kfree(params.hashstate); 36162306a36Sopenharmony_ci return err; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_cirollback: 36462306a36Sopenharmony_ci inode_lock(inode); 36562306a36Sopenharmony_ci (void)vops->end_enable_verity(filp, NULL, 0, params.tree_size); 36662306a36Sopenharmony_ci inode_unlock(inode); 36762306a36Sopenharmony_ci goto out; 36862306a36Sopenharmony_ci} 36962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(fsverity_enable_with_descriptor); 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci/** 37262306a36Sopenharmony_ci * fsverity_ioctl_enable() - enable verity on a file 37362306a36Sopenharmony_ci * @filp: file to enable verity on 37462306a36Sopenharmony_ci * @uarg: user pointer to fsverity_enable_arg 37562306a36Sopenharmony_ci * 37662306a36Sopenharmony_ci * Enable fs-verity on a file. See the "FS_IOC_ENABLE_VERITY" section of 37762306a36Sopenharmony_ci * Documentation/filesystems/fsverity.rst for the documentation. 37862306a36Sopenharmony_ci * 37962306a36Sopenharmony_ci * Return: 0 on success, -errno on failure 38062306a36Sopenharmony_ci */ 38162306a36Sopenharmony_ciint fsverity_ioctl_enable(struct file *filp, const void __user *uarg) 38262306a36Sopenharmony_ci{ 38362306a36Sopenharmony_ci struct inode *inode = file_inode(filp); 38462306a36Sopenharmony_ci struct fsverity_enable_arg arg; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci if (copy_from_user(&arg, uarg, sizeof(arg))) 38762306a36Sopenharmony_ci return -EFAULT; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci if (arg.version != 1) 39062306a36Sopenharmony_ci return -EINVAL; 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci if (arg.__reserved1 || 39362306a36Sopenharmony_ci memchr_inv(arg.__reserved2, 0, sizeof(arg.__reserved2))) 39462306a36Sopenharmony_ci return -EINVAL; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci if (!is_power_of_2(arg.block_size)) 39762306a36Sopenharmony_ci return -EINVAL; 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci if (arg.salt_size > sizeof_field(struct fsverity_descriptor, salt)) 40062306a36Sopenharmony_ci return -EMSGSIZE; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci if (arg.sig_size > FS_VERITY_MAX_SIGNATURE_SIZE) 40362306a36Sopenharmony_ci return -EMSGSIZE; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci return check_file_and_enable_verity(filp, &arg); 40662306a36Sopenharmony_ci} 40762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(fsverity_ioctl_enable); 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_cistatic int check_file_and_enable_verity(struct file *filp, 41062306a36Sopenharmony_ci const struct fsverity_enable_arg *arg) 41162306a36Sopenharmony_ci{ 41262306a36Sopenharmony_ci struct inode *inode = file_inode(filp); 41362306a36Sopenharmony_ci int err; 41462306a36Sopenharmony_ci /* 41562306a36Sopenharmony_ci * Require a regular file with write access. But the actual fd must 41662306a36Sopenharmony_ci * still be readonly so that we can lock out all writers. This is 41762306a36Sopenharmony_ci * needed to guarantee that no writable fds exist to the file once it 41862306a36Sopenharmony_ci * has verity enabled, and to stabilize the data being hashed. 41962306a36Sopenharmony_ci */ 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci err = file_permission(filp, MAY_WRITE); 42262306a36Sopenharmony_ci if (err) 42362306a36Sopenharmony_ci return err; 42462306a36Sopenharmony_ci /* 42562306a36Sopenharmony_ci * __kernel_read() is used while building the Merkle tree. So, we can't 42662306a36Sopenharmony_ci * allow file descriptors that were opened for ioctl access only, using 42762306a36Sopenharmony_ci * the special nonstandard access mode 3. O_RDONLY only, please! 42862306a36Sopenharmony_ci */ 42962306a36Sopenharmony_ci if (!(filp->f_mode & FMODE_READ)) 43062306a36Sopenharmony_ci return -EBADF; 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci if (IS_APPEND(inode)) 43362306a36Sopenharmony_ci return -EPERM; 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci if (S_ISDIR(inode->i_mode)) 43662306a36Sopenharmony_ci return -EISDIR; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci if (!S_ISREG(inode->i_mode)) 43962306a36Sopenharmony_ci return -EINVAL; 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci err = mnt_want_write_file(filp); 44262306a36Sopenharmony_ci if (err) /* -EROFS */ 44362306a36Sopenharmony_ci return err; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci err = deny_write_access(filp); 44662306a36Sopenharmony_ci if (err) /* -ETXTBSY */ 44762306a36Sopenharmony_ci goto out_drop_write; 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci err = enable_verity(filp, arg); 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci /* 45262306a36Sopenharmony_ci * We no longer drop the inode's pagecache after enabling verity. This 45362306a36Sopenharmony_ci * used to be done to try to avoid a race condition where pages could be 45462306a36Sopenharmony_ci * evicted after being used in the Merkle tree construction, then 45562306a36Sopenharmony_ci * re-instantiated by a concurrent read. Such pages are unverified, and 45662306a36Sopenharmony_ci * the backing storage could have filled them with different content, so 45762306a36Sopenharmony_ci * they shouldn't be used to fulfill reads once verity is enabled. 45862306a36Sopenharmony_ci * 45962306a36Sopenharmony_ci * But, dropping the pagecache has a big performance impact, and it 46062306a36Sopenharmony_ci * doesn't fully solve the race condition anyway. So for those reasons, 46162306a36Sopenharmony_ci * and also because this race condition isn't very important relatively 46262306a36Sopenharmony_ci * speaking (especially for small-ish files, where the chance of a page 46362306a36Sopenharmony_ci * being used, evicted, *and* re-instantiated all while enabling verity 46462306a36Sopenharmony_ci * is quite small), we no longer drop the inode's pagecache. 46562306a36Sopenharmony_ci */ 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci /* 46862306a36Sopenharmony_ci * allow_write_access() is needed to pair with deny_write_access(). 46962306a36Sopenharmony_ci * Regardless, the filesystem won't allow writing to verity files. 47062306a36Sopenharmony_ci */ 47162306a36Sopenharmony_ci allow_write_access(filp); 47262306a36Sopenharmony_ciout_drop_write: 47362306a36Sopenharmony_ci mnt_drop_write_file(filp); 47462306a36Sopenharmony_ci return err; 47562306a36Sopenharmony_ci} 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci#ifdef CONFIG_SECURITY_CODE_SIGN 47862306a36Sopenharmony_cistatic int code_sign_copy_merkle_tree(struct file *filp, 47962306a36Sopenharmony_ci const void *_desc, 48062306a36Sopenharmony_ci const struct merkle_tree_params *params) 48162306a36Sopenharmony_ci{ 48262306a36Sopenharmony_ci struct inode *inode = file_inode(filp); 48362306a36Sopenharmony_ci struct block_buffer buffer = {}; 48462306a36Sopenharmony_ci int err = -ENOMEM; 48562306a36Sopenharmony_ci u64 offset; 48662306a36Sopenharmony_ci u64 tree_offset; 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci if (!is_inside_tree_compact(_desc)) 48962306a36Sopenharmony_ci return 0; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci tree_offset = get_tree_offset_compact(_desc); 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci if (inode->i_size < tree_offset + params->tree_size) { 49462306a36Sopenharmony_ci fsverity_err(inode, "File is too small to contain Merkle tree."); 49562306a36Sopenharmony_ci return -EFAULT; 49662306a36Sopenharmony_ci } 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci buffer.data = kzalloc(params->block_size, GFP_KERNEL); 49962306a36Sopenharmony_ci if (!buffer.data) 50062306a36Sopenharmony_ci goto out; 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci for (offset = tree_offset; offset < tree_offset + params->tree_size; offset += params->block_size) { 50362306a36Sopenharmony_ci ssize_t bytes_read; 50462306a36Sopenharmony_ci loff_t pos = offset; 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci bytes_read = __kernel_read(filp, buffer.data, 50762306a36Sopenharmony_ci params->block_size, &pos); 50862306a36Sopenharmony_ci if (bytes_read < 0) { 50962306a36Sopenharmony_ci err = bytes_read; 51062306a36Sopenharmony_ci fsverity_err(inode, "Error %d reading Merkle tree block %llu", 51162306a36Sopenharmony_ci err, offset / params->block_size); 51262306a36Sopenharmony_ci goto out; 51362306a36Sopenharmony_ci } 51462306a36Sopenharmony_ci if (bytes_read != params->block_size) { 51562306a36Sopenharmony_ci err = -EINVAL; 51662306a36Sopenharmony_ci fsverity_err(inode, "Short read of Merkle tree block %llu", 51762306a36Sopenharmony_ci offset / params->block_size); 51862306a36Sopenharmony_ci goto out; 51962306a36Sopenharmony_ci } 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci err = write_merkle_tree_block(inode, buffer.data, 52262306a36Sopenharmony_ci (offset - tree_offset) / params->block_size, 52362306a36Sopenharmony_ci params); 52462306a36Sopenharmony_ci if (err) 52562306a36Sopenharmony_ci goto out; 52662306a36Sopenharmony_ci } 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci /* already copy merkle tree */ 52962306a36Sopenharmony_ci err = 1; 53062306a36Sopenharmony_ciout: 53162306a36Sopenharmony_ci kfree(buffer.data); 53262306a36Sopenharmony_ci return err; 53362306a36Sopenharmony_ci} 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_cistatic int code_sign_init_descriptor(struct inode *inode, 53662306a36Sopenharmony_ci const struct fsverity_enable_arg *_arg, 53762306a36Sopenharmony_ci struct fsverity_descriptor *_desc) 53862306a36Sopenharmony_ci{ 53962306a36Sopenharmony_ci struct code_sign_descriptor *desc = CAST_CODE_SIGN_DESC(_desc); 54062306a36Sopenharmony_ci const struct code_sign_enable_arg *arg = (const struct code_sign_enable_arg *)_arg; 54162306a36Sopenharmony_ci int algo_index; 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci if (!arg->cs_version) 54462306a36Sopenharmony_ci return 0; 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci /* init extended fields */ 54762306a36Sopenharmony_ci desc->flags = cpu_to_le32(arg->flags); 54862306a36Sopenharmony_ci desc->data_size = cpu_to_le64(arg->data_size); 54962306a36Sopenharmony_ci desc->tree_offset = cpu_to_le64(arg->tree_offset); 55062306a36Sopenharmony_ci desc->cs_version = arg->cs_version; 55162306a36Sopenharmony_ci desc->pgtypeinfo_size = cpu_to_le32(arg->pgtypeinfo_size); 55262306a36Sopenharmony_ci desc->pgtypeinfo_off = cpu_to_le64(arg->pgtypeinfo_off); 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci /* Get root hash if a Merkle tree carried in file */ 55562306a36Sopenharmony_ci if (!IS_INSIDE_TREE(desc)) 55662306a36Sopenharmony_ci return 0; 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci /* Get size of root hash */ 55962306a36Sopenharmony_ci algo_index = desc->hash_algorithm; 56062306a36Sopenharmony_ci if (algo_index >= g_fsverity_hash_algs_num || 56162306a36Sopenharmony_ci !fsverity_hash_algs[algo_index].name) { 56262306a36Sopenharmony_ci fsverity_err(inode, "Unknown hash algorithm: %u", algo_index); 56362306a36Sopenharmony_ci return -EINVAL; 56462306a36Sopenharmony_ci } 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci if (copy_from_user(desc->root_hash, u64_to_user_ptr(arg->root_hash_ptr), 56762306a36Sopenharmony_ci fsverity_hash_algs[algo_index].digest_size)) { 56862306a36Sopenharmony_ci return -EFAULT; 56962306a36Sopenharmony_ci } 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci return 0; 57262306a36Sopenharmony_ci} 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci/** 57562306a36Sopenharmony_ci * fsverity_ioctl_enable_code_sign() - enable code signing on a file 57662306a36Sopenharmony_ci * @filp: file to enable code signing on 57762306a36Sopenharmony_ci * @uarg: user pointer to code_sign_enable_arg 57862306a36Sopenharmony_ci * 57962306a36Sopenharmony_ci * Enable fs-verity on a file with code signing features. 58062306a36Sopenharmony_ci * 58162306a36Sopenharmony_ci * Return: 0 on success, -errno on failure 58262306a36Sopenharmony_ci */ 58362306a36Sopenharmony_ciint fsverity_ioctl_enable_code_sign(struct file *filp, const void __user *uarg) 58462306a36Sopenharmony_ci{ 58562306a36Sopenharmony_ci struct inode *inode = file_inode(filp); 58662306a36Sopenharmony_ci struct code_sign_enable_arg arg; 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci if (copy_from_user(&arg, uarg, sizeof(arg))) 58962306a36Sopenharmony_ci return -EFAULT; 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci if (arg.version != 1) 59262306a36Sopenharmony_ci return -EINVAL; 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci if (arg.__reserved1 || 59562306a36Sopenharmony_ci memchr_inv(arg.__reserved2, 0, sizeof(arg.__reserved2))) 59662306a36Sopenharmony_ci return -EINVAL; 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci if (arg.data_size > inode->i_size) 59962306a36Sopenharmony_ci return -EINVAL; 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci if (arg.tree_offset % arg.block_size != 0) 60262306a36Sopenharmony_ci return -EINVAL; 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci if (!is_power_of_2(arg.block_size)) 60562306a36Sopenharmony_ci return -EINVAL; 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci if (arg.salt_size > sizeof_field(struct code_sign_descriptor, salt)) 60862306a36Sopenharmony_ci return -EMSGSIZE; 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci if (arg.sig_size > FS_VERITY_MAX_SIGNATURE_SIZE) 61162306a36Sopenharmony_ci return -EMSGSIZE; 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci if (arg.pgtypeinfo_off > arg.data_size - arg.pgtypeinfo_size / 8) 61462306a36Sopenharmony_ci return -EINVAL; 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci return check_file_and_enable_verity(filp, (struct fsverity_enable_arg *)&arg); 61762306a36Sopenharmony_ci} 61862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(fsverity_ioctl_enable_code_sign); 61962306a36Sopenharmony_ci#endif /* CONFIG_SECURITY_CODE_SIGN */ 620