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 | 308 | struct buffer_head *bh = ctx->bh; |
| 309 | 309 | bool valid; |
| 310 | 310 | |
| 311 | − valid = fsverity_verify_blocks(page_folio(bh->b_page), bh->b_size, | |
| 312 | − bh_offset(bh)); | |
| 311 | + valid = fsverity_verify_blocks(bh->b_folio, bh->b_size, bh_offset(bh)); | |
| 313 | 312 | end_buffer_async_read(bh, valid); |
| 314 | 313 | kfree(ctx); |
| 315 | 314 | } |
| 316 | 315 | |
| 317 | 316 | static bool need_fsverity(struct buffer_head *bh) |
| 318 | 317 | { |
| 319 | − struct page *page = bh->b_page; | |
| 320 | − struct inode *inode = page->mapping->host; | |
| 318 | + struct folio *folio = bh->b_folio; | |
| 319 | + struct inode *inode = folio->mapping->host; | |
| 321 | 320 | |
| 322 | 321 | return fsverity_active(inode) && |
| 323 | 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 | 326 | static void decrypt_bh(struct work_struct *work) |
| @@ -13,6 +13,7 @@ · 12 unmodified lines | ||
| 13 | 13 | |
| 14 | 14 | struct block_buffer { |
| 15 | 15 | u32 filled; |
| 16 | + bool is_root_hash; | |
| 16 | 17 | u8 *data; |
| 17 | 18 | }; |
| 18 | 19 | |
| @@ -24,6 +25,14 @@ static int hash_one_block(struct inode *inode, · 5 unmodified lines | ||
| 24 | 25 | struct block_buffer *next = cur + 1; |
| 25 | 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 | 36 | /* Zero-pad the block if it's shorter than the block size. */ |
| 28 | 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 | 108 | buffers[num_levels].data = root_hash; |
| 109 | + buffers[num_levels].is_root_hash = true; | |
| 100 | 110 | |
| 101 | 111 | BUILD_BUG_ON(sizeof(level_offset) != sizeof(params->level_start)); |
| 102 | 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 | 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 | 179 | err = -EINVAL; |
| 170 | 180 | goto out; |
| 171 | 181 | } |
| @@ -277,7 +287,7 @@ static int enable_verity(struct file *filp, · 105 unmodified lines | ||
| 277 | 287 | fsverity_err(inode, "%ps() failed with err %d", |
| 278 | 288 | vops->end_enable_verity, err); |
| 279 | 289 | fsverity_free_info(vi); |
| 280 | − } else if (WARN_ON(!IS_VERITY(inode))) { | |
| 290 | + } else if (WARN_ON_ONCE(!IS_VERITY(inode))) { | |
| 281 | 291 | err = -EINVAL; |
| 282 | 292 | fsverity_free_info(vi); |
| 283 | 293 | } else { |
| @@ -347,6 +357,13 @@ int fsverity_ioctl_enable(struct file *filp, const void __user *uarg) · 63 unmodified lines | ||
| 347 | 357 | err = file_permission(filp, MAY_WRITE); |
| 348 | 358 | if (err) |
| 349 | 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 | 368 | if (IS_APPEND(inode)) |
| 352 | 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 | 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 | 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 | 90 | goto err_free_tfm; |
| 91 | 91 | |
| 92 | 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 | 83 | params->log_blocks_per_page = PAGE_SHIFT - log_blocksize; |
| 84 | 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 | 87 | err = -EINVAL; |
| 88 | 88 | goto out_err; |
| 89 | 89 | } |
| @@ -88,12 +88,6 @@ int fsverity_verify_signature(const struct fsverity_info *vi, · 87 unmodified lines | ||
| 88 | 88 | #ifdef CONFIG_SYSCTL |
| 89 | 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 | 91 | static struct ctl_table fsverity_sysctl_table[] = { |
| 98 | 92 | { |
| 99 | 93 | .procname = "require_signatures", |
| @@ -109,8 +103,7 @@ static struct ctl_table fsverity_sysctl_table[] = { · 9 unmodified lines | ||
| 109 | 103 | |
| 110 | 104 | static int __init fsverity_sysctl_init(void) |
| 111 | 105 | { |
| 112 | − fsverity_sysctl_header = register_sysctl_paths(fsverity_sysctl_path, | |
| 113 | − fsverity_sysctl_table); | |
| 106 | + fsverity_sysctl_header = register_sysctl("fs/verity", fsverity_sysctl_table); | |
| 114 | 107 | if (!fsverity_sysctl_header) { |
| 115 | 108 | pr_err("sysctl registration failed!\n"); |
| 116 | 109 | return -ENOMEM; |
| @@ -233,18 +233,18 @@ static inline int fsverity_ioctl_read_metadata(struct file *filp, · 232 unmodified lines | ||
| 233 | 233 | static inline bool fsverity_verify_blocks(struct folio *folio, size_t len, |
| 234 | 234 | size_t offset) |
| 235 | 235 | { |
| 236 | − WARN_ON(1); | |
| 236 | + WARN_ON_ONCE(1); | |
| 237 | 237 | return false; |
| 238 | 238 | } |
| 239 | 239 | |
| 240 | 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 | 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 | 250 | #endif /* !CONFIG_FS_VERITY */ |