Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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

+30 -21
+4 -5
fs/buffer.c
··· 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)
+19 -2
fs/verity/enable.c
··· 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 23 { 25 24 struct block_buffer *next = cur + 1; 26 25 int err; 26 + 27 + /* 28 + * Safety check to prevent a buffer overflow in case of a filesystem bug 29 + * that allows the file size to change despite deny_write_access(), or a 30 + * bug in the Merkle tree logic itself 31 + */ 32 + if (WARN_ON_ONCE(next->is_root_hash && next->filled != 0)) 33 + return -EINVAL; 27 34 28 35 /* Zero-pad the block if it's shorter than the block size. */ 29 36 memset(&cur->data[cur->filled], 0, params->block_size - cur->filled); ··· 106 97 } 107 98 } 108 99 buffers[num_levels].data = root_hash; 100 + buffers[num_levels].is_root_hash = true; 109 101 110 102 BUILD_BUG_ON(sizeof(level_offset) != sizeof(params->level_start)); 111 103 memcpy(level_offset, params->level_start, sizeof(level_offset)); ··· 175 165 } 176 166 } 177 167 /* The root hash was filled by the last call to hash_one_block(). */ 178 - if (WARN_ON(buffers[num_levels].filled != params->digest_size)) { 168 + if (WARN_ON_ONCE(buffers[num_levels].filled != params->digest_size)) { 179 169 err = -EINVAL; 180 170 goto out; 181 171 } ··· 287 277 fsverity_err(inode, "%ps() failed with err %d", 288 278 vops->end_enable_verity, err); 289 279 fsverity_free_info(vi); 290 - } else if (WARN_ON(!IS_VERITY(inode))) { 280 + } else if (WARN_ON_ONCE(!IS_VERITY(inode))) { 291 281 err = -EINVAL; 292 282 fsverity_free_info(vi); 293 283 } else { ··· 357 347 err = file_permission(filp, MAY_WRITE); 358 348 if (err) 359 349 return err; 350 + /* 351 + * __kernel_read() is used while building the Merkle tree. So, we can't 352 + * allow file descriptors that were opened for ioctl access only, using 353 + * the special nonstandard access mode 3. O_RDONLY only, please! 354 + */ 355 + if (!(filp->f_mode & FMODE_READ)) 356 + return -EBADF; 360 357 361 358 if (IS_APPEND(inode)) 362 359 return -EPERM;
+2 -2
fs/verity/hash_algs.c
··· 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,
+1 -1
fs/verity/open.c
··· 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 }
+1 -8
fs/verity/signature.c
··· 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", ··· 103 109 104 110 static int __init fsverity_sysctl_init(void) 105 111 { 106 - fsverity_sysctl_header = register_sysctl_paths(fsverity_sysctl_path, 107 - fsverity_sysctl_table); 112 + fsverity_sysctl_header = register_sysctl("fs/verity", fsverity_sysctl_table); 108 113 if (!fsverity_sysctl_header) { 109 114 pr_err("sysctl registration failed!\n"); 110 115 return -ENOMEM;
+3 -3
include/linux/fsverity.h
··· 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 */