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
Unified · Split
| @@ -308,20 +308,19 @@ static void verify_bh(struct work_struct *work) · 307 unmodified lines | |||
| 308 | struct buffer_head *bh = ctx->bh; | 308 | struct buffer_head *bh = ctx->bh; |
| 309 | bool valid; | 309 | bool valid; |
| 310 | 310 | ||
| 311 | valid = fsverity_verify_blocks(page_folio(bh->b_page), bh->b_size, | 311 | valid = fsverity_verify_blocks(bh->b_folio, bh->b_size, bh_offset(bh)); |
| 312 | bh_offset(bh)); | ||
| 313 | end_buffer_async_read(bh, valid); | 312 | end_buffer_async_read(bh, valid); |
| 314 | kfree(ctx); | 313 | kfree(ctx); |
| 315 | } | 314 | } |
| 316 | 315 | ||
| 317 | static bool need_fsverity(struct buffer_head *bh) | 316 | static bool need_fsverity(struct buffer_head *bh) |
| 318 | { | 317 | { |
| 319 | struct page *page = bh->b_page; | 318 | struct folio *folio = bh->b_folio; |
| 320 | struct inode *inode = page->mapping->host; | 319 | struct inode *inode = folio->mapping->host; |
| 321 | 320 | ||
| 322 | return fsverity_active(inode) && | 321 | return fsverity_active(inode) && |
| 323 | /* needed by ext4 */ | 322 | /* needed by ext4 */ |
| 324 | page->index < DIV_ROUND_UP(inode->i_size, PAGE_SIZE); | 323 | folio->index < DIV_ROUND_UP(inode->i_size, PAGE_SIZE); |
| 325 | } | 324 | } |
| 326 | 325 | ||
| 327 | static void decrypt_bh(struct work_struct *work) | 326 | static void decrypt_bh(struct work_struct *work) |
| @@ -13,6 +13,7 @@ · 12 unmodified lines | |||
| 13 | 13 | ||
| 14 | struct block_buffer { | 14 | struct block_buffer { |
| 15 | u32 filled; | 15 | u32 filled; |
| 16 | bool is_root_hash; | ||
| 16 | u8 *data; | 17 | u8 *data; |
| 17 | }; | 18 | }; |
| 18 | 19 | ||
| @@ -24,6 +25,14 @@ static int hash_one_block(struct inode *inode, · 5 unmodified lines | |||
| 24 | struct block_buffer *next = cur + 1; | 25 | struct block_buffer *next = cur + 1; |
| 25 | int err; | 26 | int err; |
| 26 | 27 | ||
| 28 | /* | ||
| 29 | * Safety check to prevent a buffer overflow in case of a filesystem bug | ||
| 30 | * that allows the file size to change despite deny_write_access(), or a | ||
| 31 | * bug in the Merkle tree logic itself | ||
| 32 | */ | ||
| 33 | if (WARN_ON_ONCE(next->is_root_hash && next->filled != 0)) | ||
| 34 | return -EINVAL; | ||
| 35 | |||
| 27 | /* Zero-pad the block if it's shorter than the block size. */ | 36 | /* Zero-pad the block if it's shorter than the block size. */ |
| 28 | memset(&cur->data[cur->filled], 0, params->block_size - cur->filled); | 37 | memset(&cur->data[cur->filled], 0, params->block_size - cur->filled); |
| 29 | 38 | ||
| @@ -97,6 +106,7 @@ static int build_merkle_tree(struct file *filp, · 67 unmodified lines | |||
| 97 | } | 106 | } |
| 98 | } | 107 | } |
| 99 | buffers[num_levels].data = root_hash; | 108 | buffers[num_levels].data = root_hash; |
| 109 | buffers[num_levels].is_root_hash = true; | ||
| 100 | 110 | ||
| 101 | BUILD_BUG_ON(sizeof(level_offset) != sizeof(params->level_start)); | 111 | BUILD_BUG_ON(sizeof(level_offset) != sizeof(params->level_start)); |
| 102 | memcpy(level_offset, params->level_start, sizeof(level_offset)); | 112 | memcpy(level_offset, params->level_start, sizeof(level_offset)); |
| @@ -165,7 +175,7 @@ static int build_merkle_tree(struct file *filp, · 62 unmodified lines | |||
| 165 | } | 175 | } |
| 166 | } | 176 | } |
| 167 | /* The root hash was filled by the last call to hash_one_block(). */ | 177 | /* The root hash was filled by the last call to hash_one_block(). */ |
| 168 | if (WARN_ON(buffers[num_levels].filled != params->digest_size)) { | 178 | if (WARN_ON_ONCE(buffers[num_levels].filled != params->digest_size)) { |
| 169 | err = -EINVAL; | 179 | err = -EINVAL; |
| 170 | goto out; | 180 | goto out; |
| 171 | } | 181 | } |
| @@ -277,7 +287,7 @@ static int enable_verity(struct file *filp, · 105 unmodified lines | |||
| 277 | fsverity_err(inode, "%ps() failed with err %d", | 287 | fsverity_err(inode, "%ps() failed with err %d", |
| 278 | vops->end_enable_verity, err); | 288 | vops->end_enable_verity, err); |
| 279 | fsverity_free_info(vi); | 289 | fsverity_free_info(vi); |
| 280 | } else if (WARN_ON(!IS_VERITY(inode))) { | 290 | } else if (WARN_ON_ONCE(!IS_VERITY(inode))) { |
| 281 | err = -EINVAL; | 291 | err = -EINVAL; |
| 282 | fsverity_free_info(vi); | 292 | fsverity_free_info(vi); |
| 283 | } else { | 293 | } else { |
| @@ -347,6 +357,13 @@ int fsverity_ioctl_enable(struct file *filp, const void __user *uarg) · 63 unmodified lines | |||
| 347 | err = file_permission(filp, MAY_WRITE); | 357 | err = file_permission(filp, MAY_WRITE); |
| 348 | if (err) | 358 | if (err) |
| 349 | return err; | 359 | return err; |
| 360 | /* | ||
| 361 | * __kernel_read() is used while building the Merkle tree. So, we can't | ||
| 362 | * allow file descriptors that were opened for ioctl access only, using | ||
| 363 | * the special nonstandard access mode 3. O_RDONLY only, please! | ||
| 364 | */ | ||
| 365 | if (!(filp->f_mode & FMODE_READ)) | ||
| 366 | return -EBADF; | ||
| 350 | 367 | ||
| 351 | if (IS_APPEND(inode)) | 368 | if (IS_APPEND(inode)) |
| 352 | return -EPERM; | 369 | return -EPERM; |
| @@ -84,9 +84,9 @@ struct fsverity_hash_alg *fsverity_get_hash_alg(const struct inode *inode, · 83 unmodified lines | |||
| 84 | } | 84 | } |
| 85 | 85 | ||
| 86 | err = -EINVAL; | 86 | err = -EINVAL; |
| 87 | if (WARN_ON(alg->digest_size != crypto_ahash_digestsize(tfm))) | 87 | if (WARN_ON_ONCE(alg->digest_size != crypto_ahash_digestsize(tfm))) |
| 88 | goto err_free_tfm; | 88 | goto err_free_tfm; |
| 89 | if (WARN_ON(alg->block_size != crypto_ahash_blocksize(tfm))) | 89 | if (WARN_ON_ONCE(alg->block_size != crypto_ahash_blocksize(tfm))) |
| 90 | goto err_free_tfm; | 90 | goto err_free_tfm; |
| 91 | 91 | ||
| 92 | err = mempool_init_kmalloc_pool(&alg->req_pool, 1, | 92 | err = mempool_init_kmalloc_pool(&alg->req_pool, 1, |
| @@ -83,7 +83,7 @@ int fsverity_init_merkle_tree_params(struct merkle_tree_params *params, · 82 unmodified lines | |||
| 83 | params->log_blocks_per_page = PAGE_SHIFT - log_blocksize; | 83 | params->log_blocks_per_page = PAGE_SHIFT - log_blocksize; |
| 84 | params->blocks_per_page = 1 << params->log_blocks_per_page; | 84 | params->blocks_per_page = 1 << params->log_blocks_per_page; |
| 85 | 85 | ||
| 86 | if (WARN_ON(!is_power_of_2(params->digest_size))) { | 86 | if (WARN_ON_ONCE(!is_power_of_2(params->digest_size))) { |
| 87 | err = -EINVAL; | 87 | err = -EINVAL; |
| 88 | goto out_err; | 88 | goto out_err; |
| 89 | } | 89 | } |
| @@ -88,12 +88,6 @@ int fsverity_verify_signature(const struct fsverity_info *vi, · 87 unmodified lines | |||
| 88 | #ifdef CONFIG_SYSCTL | 88 | #ifdef CONFIG_SYSCTL |
| 89 | static struct ctl_table_header *fsverity_sysctl_header; | 89 | static struct ctl_table_header *fsverity_sysctl_header; |
| 90 | 90 | ||
| 91 | static const struct ctl_path fsverity_sysctl_path[] = { | ||
| 92 | { .procname = "fs", }, | ||
| 93 | { .procname = "verity", }, | ||
| 94 | { } | ||
| 95 | }; | ||
| 96 | |||
| 97 | static struct ctl_table fsverity_sysctl_table[] = { | 91 | static struct ctl_table fsverity_sysctl_table[] = { |
| 98 | { | 92 | { |
| 99 | .procname = "require_signatures", | 93 | .procname = "require_signatures", |
| @@ -109,8 +103,7 @@ static struct ctl_table fsverity_sysctl_table[] = { · 9 unmodified lines | |||
| 109 | 103 | ||
| 110 | static int __init fsverity_sysctl_init(void) | 104 | static int __init fsverity_sysctl_init(void) |
| 111 | { | 105 | { |
| 112 | fsverity_sysctl_header = register_sysctl_paths(fsverity_sysctl_path, | 106 | fsverity_sysctl_header = register_sysctl("fs/verity", fsverity_sysctl_table); |
| 113 | fsverity_sysctl_table); | ||
| 114 | if (!fsverity_sysctl_header) { | 107 | if (!fsverity_sysctl_header) { |
| 115 | pr_err("sysctl registration failed!\n"); | 108 | pr_err("sysctl registration failed!\n"); |
| 116 | return -ENOMEM; | 109 | return -ENOMEM; |
| @@ -233,18 +233,18 @@ static inline int fsverity_ioctl_read_metadata(struct file *filp, · 232 unmodified lines | |||
| 233 | static inline bool fsverity_verify_blocks(struct folio *folio, size_t len, | 233 | static inline bool fsverity_verify_blocks(struct folio *folio, size_t len, |
| 234 | size_t offset) | 234 | size_t offset) |
| 235 | { | 235 | { |
| 236 | WARN_ON(1); | 236 | WARN_ON_ONCE(1); |
| 237 | return false; | 237 | return false; |
| 238 | } | 238 | } |
| 239 | 239 | ||
| 240 | static inline void fsverity_verify_bio(struct bio *bio) | 240 | static inline void fsverity_verify_bio(struct bio *bio) |
| 241 | { | 241 | { |
| 242 | WARN_ON(1); | 242 | WARN_ON_ONCE(1); |
| 243 | } | 243 | } |
| 244 | 244 | ||
| 245 | static inline void fsverity_enqueue_verify_work(struct work_struct *work) | 245 | static inline void fsverity_enqueue_verify_work(struct work_struct *work) |
| 246 | { | 246 | { |
| 247 | WARN_ON(1); | 247 | WARN_ON_ONCE(1); |
| 248 | } | 248 | } |
| 249 | 249 | ||
| 250 | #endif /* !CONFIG_FS_VERITY */ | 250 | #endif /* !CONFIG_FS_VERITY */ |