162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * fs/f2fs/verity.c: fs-verity support for f2fs 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright 2019 Google LLC 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci/* 962306a36Sopenharmony_ci * Implementation of fsverity_operations for f2fs. 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * Like ext4, f2fs stores the verity metadata (Merkle tree and 1262306a36Sopenharmony_ci * fsverity_descriptor) past the end of the file, starting at the first 64K 1362306a36Sopenharmony_ci * boundary beyond i_size. This approach works because (a) verity files are 1462306a36Sopenharmony_ci * readonly, and (b) pages fully beyond i_size aren't visible to userspace but 1562306a36Sopenharmony_ci * can be read/written internally by f2fs with only some relatively small 1662306a36Sopenharmony_ci * changes to f2fs. Extended attributes cannot be used because (a) f2fs limits 1762306a36Sopenharmony_ci * the total size of an inode's xattr entries to 4096 bytes, which wouldn't be 1862306a36Sopenharmony_ci * enough for even a single Merkle tree block, and (b) f2fs encryption doesn't 1962306a36Sopenharmony_ci * encrypt xattrs, yet the verity metadata *must* be encrypted when the file is 2062306a36Sopenharmony_ci * because it contains hashes of the plaintext data. 2162306a36Sopenharmony_ci * 2262306a36Sopenharmony_ci * Using a 64K boundary rather than a 4K one keeps things ready for 2362306a36Sopenharmony_ci * architectures with 64K pages, and it doesn't necessarily waste space on-disk 2462306a36Sopenharmony_ci * since there can be a hole between i_size and the start of the Merkle tree. 2562306a36Sopenharmony_ci */ 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#include <linux/f2fs_fs.h> 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#include "f2fs.h" 3062306a36Sopenharmony_ci#include "xattr.h" 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#define F2FS_VERIFY_VER (1) 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_cistatic inline loff_t f2fs_verity_metadata_pos(const struct inode *inode) 3562306a36Sopenharmony_ci{ 3662306a36Sopenharmony_ci return round_up(inode->i_size, 65536); 3762306a36Sopenharmony_ci} 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci/* 4062306a36Sopenharmony_ci * Read some verity metadata from the inode. __vfs_read() can't be used because 4162306a36Sopenharmony_ci * we need to read beyond i_size. 4262306a36Sopenharmony_ci */ 4362306a36Sopenharmony_cistatic int pagecache_read(struct inode *inode, void *buf, size_t count, 4462306a36Sopenharmony_ci loff_t pos) 4562306a36Sopenharmony_ci{ 4662306a36Sopenharmony_ci while (count) { 4762306a36Sopenharmony_ci size_t n = min_t(size_t, count, 4862306a36Sopenharmony_ci PAGE_SIZE - offset_in_page(pos)); 4962306a36Sopenharmony_ci struct page *page; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci page = read_mapping_page(inode->i_mapping, pos >> PAGE_SHIFT, 5262306a36Sopenharmony_ci NULL); 5362306a36Sopenharmony_ci if (IS_ERR(page)) 5462306a36Sopenharmony_ci return PTR_ERR(page); 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci memcpy_from_page(buf, page, offset_in_page(pos), n); 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci put_page(page); 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci buf += n; 6162306a36Sopenharmony_ci pos += n; 6262306a36Sopenharmony_ci count -= n; 6362306a36Sopenharmony_ci } 6462306a36Sopenharmony_ci return 0; 6562306a36Sopenharmony_ci} 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci/* 6862306a36Sopenharmony_ci * Write some verity metadata to the inode for FS_IOC_ENABLE_VERITY. 6962306a36Sopenharmony_ci * kernel_write() can't be used because the file descriptor is readonly. 7062306a36Sopenharmony_ci */ 7162306a36Sopenharmony_cistatic int pagecache_write(struct inode *inode, const void *buf, size_t count, 7262306a36Sopenharmony_ci loff_t pos) 7362306a36Sopenharmony_ci{ 7462306a36Sopenharmony_ci struct address_space *mapping = inode->i_mapping; 7562306a36Sopenharmony_ci const struct address_space_operations *aops = mapping->a_ops; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci if (pos + count > inode->i_sb->s_maxbytes) 7862306a36Sopenharmony_ci return -EFBIG; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci while (count) { 8162306a36Sopenharmony_ci size_t n = min_t(size_t, count, 8262306a36Sopenharmony_ci PAGE_SIZE - offset_in_page(pos)); 8362306a36Sopenharmony_ci struct page *page; 8462306a36Sopenharmony_ci void *fsdata = NULL; 8562306a36Sopenharmony_ci int res; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci res = aops->write_begin(NULL, mapping, pos, n, &page, &fsdata); 8862306a36Sopenharmony_ci if (res) 8962306a36Sopenharmony_ci return res; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci memcpy_to_page(page, offset_in_page(pos), buf, n); 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci res = aops->write_end(NULL, mapping, pos, n, n, page, fsdata); 9462306a36Sopenharmony_ci if (res < 0) 9562306a36Sopenharmony_ci return res; 9662306a36Sopenharmony_ci if (res != n) 9762306a36Sopenharmony_ci return -EIO; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci buf += n; 10062306a36Sopenharmony_ci pos += n; 10162306a36Sopenharmony_ci count -= n; 10262306a36Sopenharmony_ci } 10362306a36Sopenharmony_ci return 0; 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci/* 10762306a36Sopenharmony_ci * Format of f2fs verity xattr. This points to the location of the verity 10862306a36Sopenharmony_ci * descriptor within the file data rather than containing it directly because 10962306a36Sopenharmony_ci * the verity descriptor *must* be encrypted when f2fs encryption is used. But, 11062306a36Sopenharmony_ci * f2fs encryption does not encrypt xattrs. 11162306a36Sopenharmony_ci */ 11262306a36Sopenharmony_cistruct fsverity_descriptor_location { 11362306a36Sopenharmony_ci __le32 version; 11462306a36Sopenharmony_ci __le32 size; 11562306a36Sopenharmony_ci __le64 pos; 11662306a36Sopenharmony_ci}; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_cistatic int f2fs_begin_enable_verity(struct file *filp) 11962306a36Sopenharmony_ci{ 12062306a36Sopenharmony_ci struct inode *inode = file_inode(filp); 12162306a36Sopenharmony_ci int err; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci if (f2fs_verity_in_progress(inode)) 12462306a36Sopenharmony_ci return -EBUSY; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci if (f2fs_is_atomic_file(inode)) 12762306a36Sopenharmony_ci return -EOPNOTSUPP; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci /* 13062306a36Sopenharmony_ci * Since the file was opened readonly, we have to initialize the quotas 13162306a36Sopenharmony_ci * here and not rely on ->open() doing it. This must be done before 13262306a36Sopenharmony_ci * evicting the inline data. 13362306a36Sopenharmony_ci */ 13462306a36Sopenharmony_ci err = f2fs_dquot_initialize(inode); 13562306a36Sopenharmony_ci if (err) 13662306a36Sopenharmony_ci return err; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci err = f2fs_convert_inline_inode(inode); 13962306a36Sopenharmony_ci if (err) 14062306a36Sopenharmony_ci return err; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci set_inode_flag(inode, FI_VERITY_IN_PROGRESS); 14362306a36Sopenharmony_ci return 0; 14462306a36Sopenharmony_ci} 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_cistatic int f2fs_end_enable_verity(struct file *filp, const void *desc, 14762306a36Sopenharmony_ci size_t desc_size, u64 merkle_tree_size) 14862306a36Sopenharmony_ci{ 14962306a36Sopenharmony_ci struct inode *inode = file_inode(filp); 15062306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 15162306a36Sopenharmony_ci u64 desc_pos = f2fs_verity_metadata_pos(inode) + merkle_tree_size; 15262306a36Sopenharmony_ci struct fsverity_descriptor_location dloc = { 15362306a36Sopenharmony_ci .version = cpu_to_le32(F2FS_VERIFY_VER), 15462306a36Sopenharmony_ci .size = cpu_to_le32(desc_size), 15562306a36Sopenharmony_ci .pos = cpu_to_le64(desc_pos), 15662306a36Sopenharmony_ci }; 15762306a36Sopenharmony_ci int err = 0, err2 = 0; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci /* 16062306a36Sopenharmony_ci * If an error already occurred (which fs/verity/ signals by passing 16162306a36Sopenharmony_ci * desc == NULL), then only clean-up is needed. 16262306a36Sopenharmony_ci */ 16362306a36Sopenharmony_ci if (desc == NULL) 16462306a36Sopenharmony_ci goto cleanup; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci /* Append the verity descriptor. */ 16762306a36Sopenharmony_ci err = pagecache_write(inode, desc, desc_size, desc_pos); 16862306a36Sopenharmony_ci if (err) 16962306a36Sopenharmony_ci goto cleanup; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci /* 17262306a36Sopenharmony_ci * Write all pages (both data and verity metadata). Note that this must 17362306a36Sopenharmony_ci * happen before clearing FI_VERITY_IN_PROGRESS; otherwise pages beyond 17462306a36Sopenharmony_ci * i_size won't be written properly. For crash consistency, this also 17562306a36Sopenharmony_ci * must happen before the verity inode flag gets persisted. 17662306a36Sopenharmony_ci */ 17762306a36Sopenharmony_ci err = filemap_write_and_wait(inode->i_mapping); 17862306a36Sopenharmony_ci if (err) 17962306a36Sopenharmony_ci goto cleanup; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci /* Set the verity xattr. */ 18262306a36Sopenharmony_ci err = f2fs_setxattr(inode, F2FS_XATTR_INDEX_VERITY, 18362306a36Sopenharmony_ci F2FS_XATTR_NAME_VERITY, &dloc, sizeof(dloc), 18462306a36Sopenharmony_ci NULL, XATTR_CREATE); 18562306a36Sopenharmony_ci if (err) 18662306a36Sopenharmony_ci goto cleanup; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci /* Finally, set the verity inode flag. */ 18962306a36Sopenharmony_ci file_set_verity(inode); 19062306a36Sopenharmony_ci f2fs_set_inode_flags(inode); 19162306a36Sopenharmony_ci f2fs_mark_inode_dirty_sync(inode, true); 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci clear_inode_flag(inode, FI_VERITY_IN_PROGRESS); 19462306a36Sopenharmony_ci return 0; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_cicleanup: 19762306a36Sopenharmony_ci /* 19862306a36Sopenharmony_ci * Verity failed to be enabled, so clean up by truncating any verity 19962306a36Sopenharmony_ci * metadata that was written beyond i_size (both from cache and from 20062306a36Sopenharmony_ci * disk) and clearing FI_VERITY_IN_PROGRESS. 20162306a36Sopenharmony_ci * 20262306a36Sopenharmony_ci * Taking i_gc_rwsem[WRITE] is needed to stop f2fs garbage collection 20362306a36Sopenharmony_ci * from re-instantiating cached pages we are truncating (since unlike 20462306a36Sopenharmony_ci * normal file accesses, garbage collection isn't limited by i_size). 20562306a36Sopenharmony_ci */ 20662306a36Sopenharmony_ci f2fs_down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); 20762306a36Sopenharmony_ci truncate_inode_pages(inode->i_mapping, inode->i_size); 20862306a36Sopenharmony_ci err2 = f2fs_truncate(inode); 20962306a36Sopenharmony_ci if (err2) { 21062306a36Sopenharmony_ci f2fs_err(sbi, "Truncating verity metadata failed (errno=%d)", 21162306a36Sopenharmony_ci err2); 21262306a36Sopenharmony_ci set_sbi_flag(sbi, SBI_NEED_FSCK); 21362306a36Sopenharmony_ci } 21462306a36Sopenharmony_ci f2fs_up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); 21562306a36Sopenharmony_ci clear_inode_flag(inode, FI_VERITY_IN_PROGRESS); 21662306a36Sopenharmony_ci return err ?: err2; 21762306a36Sopenharmony_ci} 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_cistatic int f2fs_get_verity_descriptor(struct inode *inode, void *buf, 22062306a36Sopenharmony_ci size_t buf_size) 22162306a36Sopenharmony_ci{ 22262306a36Sopenharmony_ci struct fsverity_descriptor_location dloc; 22362306a36Sopenharmony_ci int res; 22462306a36Sopenharmony_ci u32 size; 22562306a36Sopenharmony_ci u64 pos; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci /* Get the descriptor location */ 22862306a36Sopenharmony_ci res = f2fs_getxattr(inode, F2FS_XATTR_INDEX_VERITY, 22962306a36Sopenharmony_ci F2FS_XATTR_NAME_VERITY, &dloc, sizeof(dloc), NULL); 23062306a36Sopenharmony_ci if (res < 0 && res != -ERANGE) 23162306a36Sopenharmony_ci return res; 23262306a36Sopenharmony_ci if (res != sizeof(dloc) || dloc.version != cpu_to_le32(F2FS_VERIFY_VER)) { 23362306a36Sopenharmony_ci f2fs_warn(F2FS_I_SB(inode), "unknown verity xattr format"); 23462306a36Sopenharmony_ci return -EINVAL; 23562306a36Sopenharmony_ci } 23662306a36Sopenharmony_ci size = le32_to_cpu(dloc.size); 23762306a36Sopenharmony_ci pos = le64_to_cpu(dloc.pos); 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci /* Get the descriptor */ 24062306a36Sopenharmony_ci if (pos + size < pos || pos + size > inode->i_sb->s_maxbytes || 24162306a36Sopenharmony_ci pos < f2fs_verity_metadata_pos(inode) || size > INT_MAX) { 24262306a36Sopenharmony_ci f2fs_warn(F2FS_I_SB(inode), "invalid verity xattr"); 24362306a36Sopenharmony_ci f2fs_handle_error(F2FS_I_SB(inode), 24462306a36Sopenharmony_ci ERROR_CORRUPTED_VERITY_XATTR); 24562306a36Sopenharmony_ci return -EFSCORRUPTED; 24662306a36Sopenharmony_ci } 24762306a36Sopenharmony_ci if (buf_size) { 24862306a36Sopenharmony_ci if (size > buf_size) 24962306a36Sopenharmony_ci return -ERANGE; 25062306a36Sopenharmony_ci res = pagecache_read(inode, buf, size, pos); 25162306a36Sopenharmony_ci if (res) 25262306a36Sopenharmony_ci return res; 25362306a36Sopenharmony_ci } 25462306a36Sopenharmony_ci return size; 25562306a36Sopenharmony_ci} 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_cistatic struct page *f2fs_read_merkle_tree_page(struct inode *inode, 25862306a36Sopenharmony_ci pgoff_t index, 25962306a36Sopenharmony_ci unsigned long num_ra_pages) 26062306a36Sopenharmony_ci{ 26162306a36Sopenharmony_ci struct page *page; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci index += f2fs_verity_metadata_pos(inode) >> PAGE_SHIFT; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci page = find_get_page_flags(inode->i_mapping, index, FGP_ACCESSED); 26662306a36Sopenharmony_ci if (!page || !PageUptodate(page)) { 26762306a36Sopenharmony_ci DEFINE_READAHEAD(ractl, NULL, NULL, inode->i_mapping, index); 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci if (page) 27062306a36Sopenharmony_ci put_page(page); 27162306a36Sopenharmony_ci else if (num_ra_pages > 1) 27262306a36Sopenharmony_ci page_cache_ra_unbounded(&ractl, num_ra_pages, 0); 27362306a36Sopenharmony_ci page = read_mapping_page(inode->i_mapping, index, NULL); 27462306a36Sopenharmony_ci } 27562306a36Sopenharmony_ci return page; 27662306a36Sopenharmony_ci} 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_cistatic int f2fs_write_merkle_tree_block(struct inode *inode, const void *buf, 27962306a36Sopenharmony_ci u64 pos, unsigned int size) 28062306a36Sopenharmony_ci{ 28162306a36Sopenharmony_ci pos += f2fs_verity_metadata_pos(inode); 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci return pagecache_write(inode, buf, size, pos); 28462306a36Sopenharmony_ci} 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ciconst struct fsverity_operations f2fs_verityops = { 28762306a36Sopenharmony_ci .begin_enable_verity = f2fs_begin_enable_verity, 28862306a36Sopenharmony_ci .end_enable_verity = f2fs_end_enable_verity, 28962306a36Sopenharmony_ci .get_verity_descriptor = f2fs_get_verity_descriptor, 29062306a36Sopenharmony_ci .read_merkle_tree_page = f2fs_read_merkle_tree_page, 29162306a36Sopenharmony_ci .write_merkle_tree_block = f2fs_write_merkle_tree_block, 29262306a36Sopenharmony_ci}; 293