mirror of
https://github.com/tbsdtv/linux_media.git
synced 2025-07-23 12:43:29 +02:00
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
This commit is contained in:
@@ -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 @@
|
|||||||
|
|
||||||
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,
|
|||||||
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,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
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,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* 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,
|
|||||||
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)
|
|||||||
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,
|
|||||||
}
|
}
|
||||||
|
|
||||||
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,
|
|||||||
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,
|
|||||||
#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[] = {
|
|||||||
|
|
||||||
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,
|
|||||||
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 */
|
||||||
|
Reference in New Issue
Block a user