Commit c3558a6b authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'fsverity-for-linus' of git://git.kernel.org/pub/scm/fs/fsverity/linux

Pull fsverity updates from Eric Biggers:
 "Several cleanups and fixes for fs/verity/, including a couple minor
  fixes to the changes in 6.3 that added support for Merkle tree block
  sizes less than the page size"

* tag 'fsverity-for-linus' of git://git.kernel.org/pub/scm/fs/fsverity/linux:
  fsverity: reject FS_IOC_ENABLE_VERITY on mode 3 fds
  fsverity: explicitly check for buffer overflow in build_merkle_tree()
  fsverity: use WARN_ON_ONCE instead of WARN_ON
  fs-verity: simplify sysctls with register_sysctl()
  fs/buffer.c: use b_folio for fsverity work
parents dbe0e78d 04839139
...@@ -308,20 +308,19 @@ static void verify_bh(struct work_struct *work) ...@@ -308,20 +308,19 @@ static void verify_bh(struct work_struct *work)
struct buffer_head *bh = ctx->bh; struct buffer_head *bh = ctx->bh;
bool valid; bool valid;
valid = fsverity_verify_blocks(page_folio(bh->b_page), bh->b_size, valid = fsverity_verify_blocks(bh->b_folio, bh->b_size, bh_offset(bh));
bh_offset(bh));
end_buffer_async_read(bh, valid); end_buffer_async_read(bh, valid);
kfree(ctx); kfree(ctx);
} }
static bool need_fsverity(struct buffer_head *bh) static bool need_fsverity(struct buffer_head *bh)
{ {
struct page *page = bh->b_page; struct folio *folio = bh->b_folio;
struct inode *inode = page->mapping->host; struct inode *inode = folio->mapping->host;
return fsverity_active(inode) && return fsverity_active(inode) &&
/* needed by ext4 */ /* needed by ext4 */
page->index < DIV_ROUND_UP(inode->i_size, PAGE_SIZE); folio->index < DIV_ROUND_UP(inode->i_size, PAGE_SIZE);
} }
static void decrypt_bh(struct work_struct *work) static void decrypt_bh(struct work_struct *work)
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
struct block_buffer { struct block_buffer {
u32 filled; u32 filled;
bool is_root_hash;
u8 *data; u8 *data;
}; };
...@@ -24,6 +25,14 @@ static int hash_one_block(struct inode *inode, ...@@ -24,6 +25,14 @@ static int hash_one_block(struct inode *inode,
struct block_buffer *next = cur + 1; struct block_buffer *next = cur + 1;
int err; int err;
/*
* Safety check to prevent a buffer overflow in case of a filesystem bug
* that allows the file size to change despite deny_write_access(), or a
* bug in the Merkle tree logic itself
*/
if (WARN_ON_ONCE(next->is_root_hash && next->filled != 0))
return -EINVAL;
/* Zero-pad the block if it's shorter than the block size. */ /* Zero-pad the block if it's shorter than the block size. */
memset(&cur->data[cur->filled], 0, params->block_size - cur->filled); memset(&cur->data[cur->filled], 0, params->block_size - cur->filled);
...@@ -97,6 +106,7 @@ static int build_merkle_tree(struct file *filp, ...@@ -97,6 +106,7 @@ static int build_merkle_tree(struct file *filp,
} }
} }
buffers[num_levels].data = root_hash; buffers[num_levels].data = root_hash;
buffers[num_levels].is_root_hash = true;
BUILD_BUG_ON(sizeof(level_offset) != sizeof(params->level_start)); BUILD_BUG_ON(sizeof(level_offset) != sizeof(params->level_start));
memcpy(level_offset, params->level_start, sizeof(level_offset)); memcpy(level_offset, params->level_start, sizeof(level_offset));
...@@ -165,7 +175,7 @@ static int build_merkle_tree(struct file *filp, ...@@ -165,7 +175,7 @@ static int build_merkle_tree(struct file *filp,
} }
} }
/* The root hash was filled by the last call to hash_one_block(). */ /* The root hash was filled by the last call to hash_one_block(). */
if (WARN_ON(buffers[num_levels].filled != params->digest_size)) { if (WARN_ON_ONCE(buffers[num_levels].filled != params->digest_size)) {
err = -EINVAL; err = -EINVAL;
goto out; goto out;
} }
...@@ -277,7 +287,7 @@ static int enable_verity(struct file *filp, ...@@ -277,7 +287,7 @@ static int enable_verity(struct file *filp,
fsverity_err(inode, "%ps() failed with err %d", fsverity_err(inode, "%ps() failed with err %d",
vops->end_enable_verity, err); vops->end_enable_verity, err);
fsverity_free_info(vi); fsverity_free_info(vi);
} else if (WARN_ON(!IS_VERITY(inode))) { } else if (WARN_ON_ONCE(!IS_VERITY(inode))) {
err = -EINVAL; err = -EINVAL;
fsverity_free_info(vi); fsverity_free_info(vi);
} else { } else {
...@@ -347,6 +357,13 @@ int fsverity_ioctl_enable(struct file *filp, const void __user *uarg) ...@@ -347,6 +357,13 @@ int fsverity_ioctl_enable(struct file *filp, const void __user *uarg)
err = file_permission(filp, MAY_WRITE); err = file_permission(filp, MAY_WRITE);
if (err) if (err)
return err; return err;
/*
* __kernel_read() is used while building the Merkle tree. So, we can't
* allow file descriptors that were opened for ioctl access only, using
* the special nonstandard access mode 3. O_RDONLY only, please!
*/
if (!(filp->f_mode & FMODE_READ))
return -EBADF;
if (IS_APPEND(inode)) if (IS_APPEND(inode))
return -EPERM; return -EPERM;
......
...@@ -84,9 +84,9 @@ struct fsverity_hash_alg *fsverity_get_hash_alg(const struct inode *inode, ...@@ -84,9 +84,9 @@ struct fsverity_hash_alg *fsverity_get_hash_alg(const struct inode *inode,
} }
err = -EINVAL; err = -EINVAL;
if (WARN_ON(alg->digest_size != crypto_ahash_digestsize(tfm))) if (WARN_ON_ONCE(alg->digest_size != crypto_ahash_digestsize(tfm)))
goto err_free_tfm; goto err_free_tfm;
if (WARN_ON(alg->block_size != crypto_ahash_blocksize(tfm))) if (WARN_ON_ONCE(alg->block_size != crypto_ahash_blocksize(tfm)))
goto err_free_tfm; goto err_free_tfm;
err = mempool_init_kmalloc_pool(&alg->req_pool, 1, err = mempool_init_kmalloc_pool(&alg->req_pool, 1,
......
...@@ -83,7 +83,7 @@ int fsverity_init_merkle_tree_params(struct merkle_tree_params *params, ...@@ -83,7 +83,7 @@ int fsverity_init_merkle_tree_params(struct merkle_tree_params *params,
params->log_blocks_per_page = PAGE_SHIFT - log_blocksize; params->log_blocks_per_page = PAGE_SHIFT - log_blocksize;
params->blocks_per_page = 1 << params->log_blocks_per_page; params->blocks_per_page = 1 << params->log_blocks_per_page;
if (WARN_ON(!is_power_of_2(params->digest_size))) { if (WARN_ON_ONCE(!is_power_of_2(params->digest_size))) {
err = -EINVAL; err = -EINVAL;
goto out_err; goto out_err;
} }
......
...@@ -88,12 +88,6 @@ int fsverity_verify_signature(const struct fsverity_info *vi, ...@@ -88,12 +88,6 @@ int fsverity_verify_signature(const struct fsverity_info *vi,
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
static struct ctl_table_header *fsverity_sysctl_header; static struct ctl_table_header *fsverity_sysctl_header;
static const struct ctl_path fsverity_sysctl_path[] = {
{ .procname = "fs", },
{ .procname = "verity", },
{ }
};
static struct ctl_table fsverity_sysctl_table[] = { static struct ctl_table fsverity_sysctl_table[] = {
{ {
.procname = "require_signatures", .procname = "require_signatures",
...@@ -109,8 +103,7 @@ static struct ctl_table fsverity_sysctl_table[] = { ...@@ -109,8 +103,7 @@ static struct ctl_table fsverity_sysctl_table[] = {
static int __init fsverity_sysctl_init(void) static int __init fsverity_sysctl_init(void)
{ {
fsverity_sysctl_header = register_sysctl_paths(fsverity_sysctl_path, fsverity_sysctl_header = register_sysctl("fs/verity", fsverity_sysctl_table);
fsverity_sysctl_table);
if (!fsverity_sysctl_header) { if (!fsverity_sysctl_header) {
pr_err("sysctl registration failed!\n"); pr_err("sysctl registration failed!\n");
return -ENOMEM; return -ENOMEM;
......
...@@ -233,18 +233,18 @@ static inline int fsverity_ioctl_read_metadata(struct file *filp, ...@@ -233,18 +233,18 @@ static inline int fsverity_ioctl_read_metadata(struct file *filp,
static inline bool fsverity_verify_blocks(struct folio *folio, size_t len, static inline bool fsverity_verify_blocks(struct folio *folio, size_t len,
size_t offset) size_t offset)
{ {
WARN_ON(1); WARN_ON_ONCE(1);
return false; return false;
} }
static inline void fsverity_verify_bio(struct bio *bio) static inline void fsverity_verify_bio(struct bio *bio)
{ {
WARN_ON(1); WARN_ON_ONCE(1);
} }
static inline void fsverity_enqueue_verify_work(struct work_struct *work) static inline void fsverity_enqueue_verify_work(struct work_struct *work)
{ {
WARN_ON(1); WARN_ON_ONCE(1);
} }
#endif /* !CONFIG_FS_VERITY */ #endif /* !CONFIG_FS_VERITY */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment