diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2019-09-18 19:59:14 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-09-18 19:59:14 -0400 |
commit | f60c55a94e1d127186566f06294f2dadd966e9b4 (patch) | |
tree | 2d3dbd572c0096d24f87f581194563ff76e07a6e /fs/f2fs | |
parent | 734d1ed83e1f9b7bafb650033fb87c657858cf5b (diff) | |
parent | 95ae251fe82838b85c6d37e5a1775006e2a42ae0 (diff) |
Merge tag 'fsverity-for-linus' of git://git.kernel.org/pub/scm/fs/fscrypt/fscrypt
Pull fs-verity support from Eric Biggers:
"fs-verity is a filesystem feature that provides Merkle tree based
hashing (similar to dm-verity) for individual readonly files, mainly
for the purpose of efficient authenticity verification.
This pull request includes:
(a) The fs/verity/ support layer and documentation.
(b) fs-verity support for ext4 and f2fs.
Compared to the original fs-verity patchset from last year, the UAPI
to enable fs-verity on a file has been greatly simplified. Lots of
other things were cleaned up too.
fs-verity is planned to be used by two different projects on Android;
most of the userspace code is in place already. Another userspace tool
("fsverity-utils"), and xfstests, are also available. e2fsprogs and
f2fs-tools already have fs-verity support. Other people have shown
interest in using fs-verity too.
I've tested this on ext4 and f2fs with xfstests, both the existing
tests and the new fs-verity tests. This has also been in linux-next
since July 30 with no reported issues except a couple minor ones I
found myself and folded in fixes for.
Ted and I will be co-maintaining fs-verity"
* tag 'fsverity-for-linus' of git://git.kernel.org/pub/scm/fs/fscrypt/fscrypt:
f2fs: add fs-verity support
ext4: update on-disk format documentation for fs-verity
ext4: add fs-verity read support
ext4: add basic fs-verity support
fs-verity: support builtin file signatures
fs-verity: add SHA-512 support
fs-verity: implement FS_IOC_MEASURE_VERITY ioctl
fs-verity: implement FS_IOC_ENABLE_VERITY ioctl
fs-verity: add data verification hooks for ->readpages()
fs-verity: add the hook for file ->setattr()
fs-verity: add the hook for file ->open()
fs-verity: add inode and superblock fields
fs-verity: add Kconfig and the helper functions for hashing
fs: uapi: define verity bit for FS_IOC_GETFLAGS
fs-verity: add UAPI header
fs-verity: add MAINTAINERS file entry
fs-verity: add a documentation file
Diffstat (limited to 'fs/f2fs')
-rw-r--r-- | fs/f2fs/Makefile | 1 | ||||
-rw-r--r-- | fs/f2fs/data.c | 75 | ||||
-rw-r--r-- | fs/f2fs/f2fs.h | 20 | ||||
-rw-r--r-- | fs/f2fs/file.c | 43 | ||||
-rw-r--r-- | fs/f2fs/inode.c | 5 | ||||
-rw-r--r-- | fs/f2fs/super.c | 3 | ||||
-rw-r--r-- | fs/f2fs/sysfs.c | 11 | ||||
-rw-r--r-- | fs/f2fs/verity.c | 247 | ||||
-rw-r--r-- | fs/f2fs/xattr.h | 2 |
9 files changed, 392 insertions, 15 deletions
diff --git a/fs/f2fs/Makefile b/fs/f2fs/Makefile index 776c4b936504..2aaecc63834f 100644 --- a/fs/f2fs/Makefile +++ b/fs/f2fs/Makefile | |||
@@ -8,3 +8,4 @@ f2fs-$(CONFIG_F2FS_STAT_FS) += debug.o | |||
8 | f2fs-$(CONFIG_F2FS_FS_XATTR) += xattr.o | 8 | f2fs-$(CONFIG_F2FS_FS_XATTR) += xattr.o |
9 | f2fs-$(CONFIG_F2FS_FS_POSIX_ACL) += acl.o | 9 | f2fs-$(CONFIG_F2FS_FS_POSIX_ACL) += acl.o |
10 | f2fs-$(CONFIG_F2FS_IO_TRACE) += trace.o | 10 | f2fs-$(CONFIG_F2FS_IO_TRACE) += trace.o |
11 | f2fs-$(CONFIG_FS_VERITY) += verity.o | ||
diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index abbf14e9bd72..54cad80acb7d 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c | |||
@@ -74,6 +74,7 @@ static enum count_type __read_io_type(struct page *page) | |||
74 | enum bio_post_read_step { | 74 | enum bio_post_read_step { |
75 | STEP_INITIAL = 0, | 75 | STEP_INITIAL = 0, |
76 | STEP_DECRYPT, | 76 | STEP_DECRYPT, |
77 | STEP_VERITY, | ||
77 | }; | 78 | }; |
78 | 79 | ||
79 | struct bio_post_read_ctx { | 80 | struct bio_post_read_ctx { |
@@ -120,8 +121,23 @@ static void decrypt_work(struct work_struct *work) | |||
120 | bio_post_read_processing(ctx); | 121 | bio_post_read_processing(ctx); |
121 | } | 122 | } |
122 | 123 | ||
124 | static void verity_work(struct work_struct *work) | ||
125 | { | ||
126 | struct bio_post_read_ctx *ctx = | ||
127 | container_of(work, struct bio_post_read_ctx, work); | ||
128 | |||
129 | fsverity_verify_bio(ctx->bio); | ||
130 | |||
131 | bio_post_read_processing(ctx); | ||
132 | } | ||
133 | |||
123 | static void bio_post_read_processing(struct bio_post_read_ctx *ctx) | 134 | static void bio_post_read_processing(struct bio_post_read_ctx *ctx) |
124 | { | 135 | { |
136 | /* | ||
137 | * We use different work queues for decryption and for verity because | ||
138 | * verity may require reading metadata pages that need decryption, and | ||
139 | * we shouldn't recurse to the same workqueue. | ||
140 | */ | ||
125 | switch (++ctx->cur_step) { | 141 | switch (++ctx->cur_step) { |
126 | case STEP_DECRYPT: | 142 | case STEP_DECRYPT: |
127 | if (ctx->enabled_steps & (1 << STEP_DECRYPT)) { | 143 | if (ctx->enabled_steps & (1 << STEP_DECRYPT)) { |
@@ -131,6 +147,14 @@ static void bio_post_read_processing(struct bio_post_read_ctx *ctx) | |||
131 | } | 147 | } |
132 | ctx->cur_step++; | 148 | ctx->cur_step++; |
133 | /* fall-through */ | 149 | /* fall-through */ |
150 | case STEP_VERITY: | ||
151 | if (ctx->enabled_steps & (1 << STEP_VERITY)) { | ||
152 | INIT_WORK(&ctx->work, verity_work); | ||
153 | fsverity_enqueue_verify_work(&ctx->work); | ||
154 | return; | ||
155 | } | ||
156 | ctx->cur_step++; | ||
157 | /* fall-through */ | ||
134 | default: | 158 | default: |
135 | __read_end_io(ctx->bio); | 159 | __read_end_io(ctx->bio); |
136 | } | 160 | } |
@@ -608,8 +632,15 @@ out: | |||
608 | up_write(&io->io_rwsem); | 632 | up_write(&io->io_rwsem); |
609 | } | 633 | } |
610 | 634 | ||
635 | static inline bool f2fs_need_verity(const struct inode *inode, pgoff_t idx) | ||
636 | { | ||
637 | return fsverity_active(inode) && | ||
638 | idx < DIV_ROUND_UP(inode->i_size, PAGE_SIZE); | ||
639 | } | ||
640 | |||
611 | static struct bio *f2fs_grab_read_bio(struct inode *inode, block_t blkaddr, | 641 | static struct bio *f2fs_grab_read_bio(struct inode *inode, block_t blkaddr, |
612 | unsigned nr_pages, unsigned op_flag) | 642 | unsigned nr_pages, unsigned op_flag, |
643 | pgoff_t first_idx) | ||
613 | { | 644 | { |
614 | struct f2fs_sb_info *sbi = F2FS_I_SB(inode); | 645 | struct f2fs_sb_info *sbi = F2FS_I_SB(inode); |
615 | struct bio *bio; | 646 | struct bio *bio; |
@@ -625,6 +656,10 @@ static struct bio *f2fs_grab_read_bio(struct inode *inode, block_t blkaddr, | |||
625 | 656 | ||
626 | if (f2fs_encrypted_file(inode)) | 657 | if (f2fs_encrypted_file(inode)) |
627 | post_read_steps |= 1 << STEP_DECRYPT; | 658 | post_read_steps |= 1 << STEP_DECRYPT; |
659 | |||
660 | if (f2fs_need_verity(inode, first_idx)) | ||
661 | post_read_steps |= 1 << STEP_VERITY; | ||
662 | |||
628 | if (post_read_steps) { | 663 | if (post_read_steps) { |
629 | ctx = mempool_alloc(bio_post_read_ctx_pool, GFP_NOFS); | 664 | ctx = mempool_alloc(bio_post_read_ctx_pool, GFP_NOFS); |
630 | if (!ctx) { | 665 | if (!ctx) { |
@@ -646,7 +681,7 @@ static int f2fs_submit_page_read(struct inode *inode, struct page *page, | |||
646 | struct f2fs_sb_info *sbi = F2FS_I_SB(inode); | 681 | struct f2fs_sb_info *sbi = F2FS_I_SB(inode); |
647 | struct bio *bio; | 682 | struct bio *bio; |
648 | 683 | ||
649 | bio = f2fs_grab_read_bio(inode, blkaddr, 1, 0); | 684 | bio = f2fs_grab_read_bio(inode, blkaddr, 1, 0, page->index); |
650 | if (IS_ERR(bio)) | 685 | if (IS_ERR(bio)) |
651 | return PTR_ERR(bio); | 686 | return PTR_ERR(bio); |
652 | 687 | ||
@@ -1569,6 +1604,15 @@ out: | |||
1569 | return ret; | 1604 | return ret; |
1570 | } | 1605 | } |
1571 | 1606 | ||
1607 | static inline loff_t f2fs_readpage_limit(struct inode *inode) | ||
1608 | { | ||
1609 | if (IS_ENABLED(CONFIG_FS_VERITY) && | ||
1610 | (IS_VERITY(inode) || f2fs_verity_in_progress(inode))) | ||
1611 | return inode->i_sb->s_maxbytes; | ||
1612 | |||
1613 | return i_size_read(inode); | ||
1614 | } | ||
1615 | |||
1572 | static int f2fs_read_single_page(struct inode *inode, struct page *page, | 1616 | static int f2fs_read_single_page(struct inode *inode, struct page *page, |
1573 | unsigned nr_pages, | 1617 | unsigned nr_pages, |
1574 | struct f2fs_map_blocks *map, | 1618 | struct f2fs_map_blocks *map, |
@@ -1587,7 +1631,7 @@ static int f2fs_read_single_page(struct inode *inode, struct page *page, | |||
1587 | 1631 | ||
1588 | block_in_file = (sector_t)page_index(page); | 1632 | block_in_file = (sector_t)page_index(page); |
1589 | last_block = block_in_file + nr_pages; | 1633 | last_block = block_in_file + nr_pages; |
1590 | last_block_in_file = (i_size_read(inode) + blocksize - 1) >> | 1634 | last_block_in_file = (f2fs_readpage_limit(inode) + blocksize - 1) >> |
1591 | blkbits; | 1635 | blkbits; |
1592 | if (last_block > last_block_in_file) | 1636 | if (last_block > last_block_in_file) |
1593 | last_block = last_block_in_file; | 1637 | last_block = last_block_in_file; |
@@ -1632,6 +1676,11 @@ got_it: | |||
1632 | } else { | 1676 | } else { |
1633 | zero_out: | 1677 | zero_out: |
1634 | zero_user_segment(page, 0, PAGE_SIZE); | 1678 | zero_user_segment(page, 0, PAGE_SIZE); |
1679 | if (f2fs_need_verity(inode, page->index) && | ||
1680 | !fsverity_verify_page(page)) { | ||
1681 | ret = -EIO; | ||
1682 | goto out; | ||
1683 | } | ||
1635 | if (!PageUptodate(page)) | 1684 | if (!PageUptodate(page)) |
1636 | SetPageUptodate(page); | 1685 | SetPageUptodate(page); |
1637 | unlock_page(page); | 1686 | unlock_page(page); |
@@ -1650,7 +1699,7 @@ submit_and_realloc: | |||
1650 | } | 1699 | } |
1651 | if (bio == NULL) { | 1700 | if (bio == NULL) { |
1652 | bio = f2fs_grab_read_bio(inode, block_nr, nr_pages, | 1701 | bio = f2fs_grab_read_bio(inode, block_nr, nr_pages, |
1653 | is_readahead ? REQ_RAHEAD : 0); | 1702 | is_readahead ? REQ_RAHEAD : 0, page->index); |
1654 | if (IS_ERR(bio)) { | 1703 | if (IS_ERR(bio)) { |
1655 | ret = PTR_ERR(bio); | 1704 | ret = PTR_ERR(bio); |
1656 | bio = NULL; | 1705 | bio = NULL; |
@@ -2052,7 +2101,7 @@ static int __write_data_page(struct page *page, bool *submitted, | |||
2052 | if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING))) | 2101 | if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING))) |
2053 | goto redirty_out; | 2102 | goto redirty_out; |
2054 | 2103 | ||
2055 | if (page->index < end_index) | 2104 | if (page->index < end_index || f2fs_verity_in_progress(inode)) |
2056 | goto write; | 2105 | goto write; |
2057 | 2106 | ||
2058 | /* | 2107 | /* |
@@ -2427,7 +2476,8 @@ static void f2fs_write_failed(struct address_space *mapping, loff_t to) | |||
2427 | struct inode *inode = mapping->host; | 2476 | struct inode *inode = mapping->host; |
2428 | loff_t i_size = i_size_read(inode); | 2477 | loff_t i_size = i_size_read(inode); |
2429 | 2478 | ||
2430 | if (to > i_size) { | 2479 | /* In the fs-verity case, f2fs_end_enable_verity() does the truncate */ |
2480 | if (to > i_size && !f2fs_verity_in_progress(inode)) { | ||
2431 | down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); | 2481 | down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); |
2432 | down_write(&F2FS_I(inode)->i_mmap_sem); | 2482 | down_write(&F2FS_I(inode)->i_mmap_sem); |
2433 | 2483 | ||
@@ -2458,7 +2508,8 @@ static int prepare_write_begin(struct f2fs_sb_info *sbi, | |||
2458 | * the block addresses when there is no need to fill the page. | 2508 | * the block addresses when there is no need to fill the page. |
2459 | */ | 2509 | */ |
2460 | if (!f2fs_has_inline_data(inode) && len == PAGE_SIZE && | 2510 | if (!f2fs_has_inline_data(inode) && len == PAGE_SIZE && |
2461 | !is_inode_flag_set(inode, FI_NO_PREALLOC)) | 2511 | !is_inode_flag_set(inode, FI_NO_PREALLOC) && |
2512 | !f2fs_verity_in_progress(inode)) | ||
2462 | return 0; | 2513 | return 0; |
2463 | 2514 | ||
2464 | /* f2fs_lock_op avoids race between write CP and convert_inline_page */ | 2515 | /* f2fs_lock_op avoids race between write CP and convert_inline_page */ |
@@ -2597,7 +2648,8 @@ repeat: | |||
2597 | if (len == PAGE_SIZE || PageUptodate(page)) | 2648 | if (len == PAGE_SIZE || PageUptodate(page)) |
2598 | return 0; | 2649 | return 0; |
2599 | 2650 | ||
2600 | if (!(pos & (PAGE_SIZE - 1)) && (pos + len) >= i_size_read(inode)) { | 2651 | if (!(pos & (PAGE_SIZE - 1)) && (pos + len) >= i_size_read(inode) && |
2652 | !f2fs_verity_in_progress(inode)) { | ||
2601 | zero_user_segment(page, len, PAGE_SIZE); | 2653 | zero_user_segment(page, len, PAGE_SIZE); |
2602 | return 0; | 2654 | return 0; |
2603 | } | 2655 | } |
@@ -2660,7 +2712,8 @@ static int f2fs_write_end(struct file *file, | |||
2660 | 2712 | ||
2661 | set_page_dirty(page); | 2713 | set_page_dirty(page); |
2662 | 2714 | ||
2663 | if (pos + copied > i_size_read(inode)) | 2715 | if (pos + copied > i_size_read(inode) && |
2716 | !f2fs_verity_in_progress(inode)) | ||
2664 | f2fs_i_size_write(inode, pos + copied); | 2717 | f2fs_i_size_write(inode, pos + copied); |
2665 | unlock_out: | 2718 | unlock_out: |
2666 | f2fs_put_page(page, 1); | 2719 | f2fs_put_page(page, 1); |
@@ -3104,7 +3157,9 @@ void f2fs_clear_page_cache_dirty_tag(struct page *page) | |||
3104 | 3157 | ||
3105 | int __init f2fs_init_post_read_processing(void) | 3158 | int __init f2fs_init_post_read_processing(void) |
3106 | { | 3159 | { |
3107 | bio_post_read_ctx_cache = KMEM_CACHE(bio_post_read_ctx, 0); | 3160 | bio_post_read_ctx_cache = |
3161 | kmem_cache_create("f2fs_bio_post_read_ctx", | ||
3162 | sizeof(struct bio_post_read_ctx), 0, 0, NULL); | ||
3108 | if (!bio_post_read_ctx_cache) | 3163 | if (!bio_post_read_ctx_cache) |
3109 | goto fail; | 3164 | goto fail; |
3110 | bio_post_read_ctx_pool = | 3165 | bio_post_read_ctx_pool = |
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 17382da7f0bd..7c5f121edac5 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <crypto/hash.h> | 25 | #include <crypto/hash.h> |
26 | 26 | ||
27 | #include <linux/fscrypt.h> | 27 | #include <linux/fscrypt.h> |
28 | #include <linux/fsverity.h> | ||
28 | 29 | ||
29 | #ifdef CONFIG_F2FS_CHECK_FS | 30 | #ifdef CONFIG_F2FS_CHECK_FS |
30 | #define f2fs_bug_on(sbi, condition) BUG_ON(condition) | 31 | #define f2fs_bug_on(sbi, condition) BUG_ON(condition) |
@@ -151,7 +152,7 @@ struct f2fs_mount_info { | |||
151 | #define F2FS_FEATURE_QUOTA_INO 0x0080 | 152 | #define F2FS_FEATURE_QUOTA_INO 0x0080 |
152 | #define F2FS_FEATURE_INODE_CRTIME 0x0100 | 153 | #define F2FS_FEATURE_INODE_CRTIME 0x0100 |
153 | #define F2FS_FEATURE_LOST_FOUND 0x0200 | 154 | #define F2FS_FEATURE_LOST_FOUND 0x0200 |
154 | #define F2FS_FEATURE_VERITY 0x0400 /* reserved */ | 155 | #define F2FS_FEATURE_VERITY 0x0400 |
155 | #define F2FS_FEATURE_SB_CHKSUM 0x0800 | 156 | #define F2FS_FEATURE_SB_CHKSUM 0x0800 |
156 | 157 | ||
157 | #define __F2FS_HAS_FEATURE(raw_super, mask) \ | 158 | #define __F2FS_HAS_FEATURE(raw_super, mask) \ |
@@ -630,7 +631,7 @@ enum { | |||
630 | #define FADVISE_ENC_NAME_BIT 0x08 | 631 | #define FADVISE_ENC_NAME_BIT 0x08 |
631 | #define FADVISE_KEEP_SIZE_BIT 0x10 | 632 | #define FADVISE_KEEP_SIZE_BIT 0x10 |
632 | #define FADVISE_HOT_BIT 0x20 | 633 | #define FADVISE_HOT_BIT 0x20 |
633 | #define FADVISE_VERITY_BIT 0x40 /* reserved */ | 634 | #define FADVISE_VERITY_BIT 0x40 |
634 | 635 | ||
635 | #define FADVISE_MODIFIABLE_BITS (FADVISE_COLD_BIT | FADVISE_HOT_BIT) | 636 | #define FADVISE_MODIFIABLE_BITS (FADVISE_COLD_BIT | FADVISE_HOT_BIT) |
636 | 637 | ||
@@ -650,6 +651,8 @@ enum { | |||
650 | #define file_is_hot(inode) is_file(inode, FADVISE_HOT_BIT) | 651 | #define file_is_hot(inode) is_file(inode, FADVISE_HOT_BIT) |
651 | #define file_set_hot(inode) set_file(inode, FADVISE_HOT_BIT) | 652 | #define file_set_hot(inode) set_file(inode, FADVISE_HOT_BIT) |
652 | #define file_clear_hot(inode) clear_file(inode, FADVISE_HOT_BIT) | 653 | #define file_clear_hot(inode) clear_file(inode, FADVISE_HOT_BIT) |
654 | #define file_is_verity(inode) is_file(inode, FADVISE_VERITY_BIT) | ||
655 | #define file_set_verity(inode) set_file(inode, FADVISE_VERITY_BIT) | ||
653 | 656 | ||
654 | #define DEF_DIR_LEVEL 0 | 657 | #define DEF_DIR_LEVEL 0 |
655 | 658 | ||
@@ -2412,6 +2415,7 @@ enum { | |||
2412 | FI_PROJ_INHERIT, /* indicate file inherits projectid */ | 2415 | FI_PROJ_INHERIT, /* indicate file inherits projectid */ |
2413 | FI_PIN_FILE, /* indicate file should not be gced */ | 2416 | FI_PIN_FILE, /* indicate file should not be gced */ |
2414 | FI_ATOMIC_REVOKE_REQUEST, /* request to drop atomic data */ | 2417 | FI_ATOMIC_REVOKE_REQUEST, /* request to drop atomic data */ |
2418 | FI_VERITY_IN_PROGRESS, /* building fs-verity Merkle tree */ | ||
2415 | }; | 2419 | }; |
2416 | 2420 | ||
2417 | static inline void __mark_inode_dirty_flag(struct inode *inode, | 2421 | static inline void __mark_inode_dirty_flag(struct inode *inode, |
@@ -2451,6 +2455,12 @@ static inline void clear_inode_flag(struct inode *inode, int flag) | |||
2451 | __mark_inode_dirty_flag(inode, flag, false); | 2455 | __mark_inode_dirty_flag(inode, flag, false); |
2452 | } | 2456 | } |
2453 | 2457 | ||
2458 | static inline bool f2fs_verity_in_progress(struct inode *inode) | ||
2459 | { | ||
2460 | return IS_ENABLED(CONFIG_FS_VERITY) && | ||
2461 | is_inode_flag_set(inode, FI_VERITY_IN_PROGRESS); | ||
2462 | } | ||
2463 | |||
2454 | static inline void set_acl_inode(struct inode *inode, umode_t mode) | 2464 | static inline void set_acl_inode(struct inode *inode, umode_t mode) |
2455 | { | 2465 | { |
2456 | F2FS_I(inode)->i_acl_mode = mode; | 2466 | F2FS_I(inode)->i_acl_mode = mode; |
@@ -3521,6 +3531,9 @@ void f2fs_exit_sysfs(void); | |||
3521 | int f2fs_register_sysfs(struct f2fs_sb_info *sbi); | 3531 | int f2fs_register_sysfs(struct f2fs_sb_info *sbi); |
3522 | void f2fs_unregister_sysfs(struct f2fs_sb_info *sbi); | 3532 | void f2fs_unregister_sysfs(struct f2fs_sb_info *sbi); |
3523 | 3533 | ||
3534 | /* verity.c */ | ||
3535 | extern const struct fsverity_operations f2fs_verityops; | ||
3536 | |||
3524 | /* | 3537 | /* |
3525 | * crypto support | 3538 | * crypto support |
3526 | */ | 3539 | */ |
@@ -3543,7 +3556,7 @@ static inline void f2fs_set_encrypted_inode(struct inode *inode) | |||
3543 | */ | 3556 | */ |
3544 | static inline bool f2fs_post_read_required(struct inode *inode) | 3557 | static inline bool f2fs_post_read_required(struct inode *inode) |
3545 | { | 3558 | { |
3546 | return f2fs_encrypted_file(inode); | 3559 | return f2fs_encrypted_file(inode) || fsverity_active(inode); |
3547 | } | 3560 | } |
3548 | 3561 | ||
3549 | #define F2FS_FEATURE_FUNCS(name, flagname) \ | 3562 | #define F2FS_FEATURE_FUNCS(name, flagname) \ |
@@ -3561,6 +3574,7 @@ F2FS_FEATURE_FUNCS(flexible_inline_xattr, FLEXIBLE_INLINE_XATTR); | |||
3561 | F2FS_FEATURE_FUNCS(quota_ino, QUOTA_INO); | 3574 | F2FS_FEATURE_FUNCS(quota_ino, QUOTA_INO); |
3562 | F2FS_FEATURE_FUNCS(inode_crtime, INODE_CRTIME); | 3575 | F2FS_FEATURE_FUNCS(inode_crtime, INODE_CRTIME); |
3563 | F2FS_FEATURE_FUNCS(lost_found, LOST_FOUND); | 3576 | F2FS_FEATURE_FUNCS(lost_found, LOST_FOUND); |
3577 | F2FS_FEATURE_FUNCS(verity, VERITY); | ||
3564 | F2FS_FEATURE_FUNCS(sb_chksum, SB_CHKSUM); | 3578 | F2FS_FEATURE_FUNCS(sb_chksum, SB_CHKSUM); |
3565 | 3579 | ||
3566 | #ifdef CONFIG_BLK_DEV_ZONED | 3580 | #ifdef CONFIG_BLK_DEV_ZONED |
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 6a7349f9ac15..39fffc19e00c 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c | |||
@@ -496,6 +496,10 @@ static int f2fs_file_open(struct inode *inode, struct file *filp) | |||
496 | if (err) | 496 | if (err) |
497 | return err; | 497 | return err; |
498 | 498 | ||
499 | err = fsverity_file_open(inode, filp); | ||
500 | if (err) | ||
501 | return err; | ||
502 | |||
499 | filp->f_mode |= FMODE_NOWAIT; | 503 | filp->f_mode |= FMODE_NOWAIT; |
500 | 504 | ||
501 | return dquot_file_open(inode, filp); | 505 | return dquot_file_open(inode, filp); |
@@ -778,6 +782,10 @@ int f2fs_setattr(struct dentry *dentry, struct iattr *attr) | |||
778 | if (err) | 782 | if (err) |
779 | return err; | 783 | return err; |
780 | 784 | ||
785 | err = fsverity_prepare_setattr(dentry, attr); | ||
786 | if (err) | ||
787 | return err; | ||
788 | |||
781 | if (is_quota_modification(inode, attr)) { | 789 | if (is_quota_modification(inode, attr)) { |
782 | err = dquot_initialize(inode); | 790 | err = dquot_initialize(inode); |
783 | if (err) | 791 | if (err) |
@@ -1705,7 +1713,8 @@ static const struct { | |||
1705 | FS_PROJINHERIT_FL | \ | 1713 | FS_PROJINHERIT_FL | \ |
1706 | FS_ENCRYPT_FL | \ | 1714 | FS_ENCRYPT_FL | \ |
1707 | FS_INLINE_DATA_FL | \ | 1715 | FS_INLINE_DATA_FL | \ |
1708 | FS_NOCOW_FL) | 1716 | FS_NOCOW_FL | \ |
1717 | FS_VERITY_FL) | ||
1709 | 1718 | ||
1710 | #define F2FS_SETTABLE_FS_FL ( \ | 1719 | #define F2FS_SETTABLE_FS_FL ( \ |
1711 | FS_SYNC_FL | \ | 1720 | FS_SYNC_FL | \ |
@@ -1750,6 +1759,8 @@ static int f2fs_ioc_getflags(struct file *filp, unsigned long arg) | |||
1750 | 1759 | ||
1751 | if (IS_ENCRYPTED(inode)) | 1760 | if (IS_ENCRYPTED(inode)) |
1752 | fsflags |= FS_ENCRYPT_FL; | 1761 | fsflags |= FS_ENCRYPT_FL; |
1762 | if (IS_VERITY(inode)) | ||
1763 | fsflags |= FS_VERITY_FL; | ||
1753 | if (f2fs_has_inline_data(inode) || f2fs_has_inline_dentry(inode)) | 1764 | if (f2fs_has_inline_data(inode) || f2fs_has_inline_dentry(inode)) |
1754 | fsflags |= FS_INLINE_DATA_FL; | 1765 | fsflags |= FS_INLINE_DATA_FL; |
1755 | if (is_inode_flag_set(inode, FI_PIN_FILE)) | 1766 | if (is_inode_flag_set(inode, FI_PIN_FILE)) |
@@ -3103,6 +3114,30 @@ static int f2fs_ioc_resize_fs(struct file *filp, unsigned long arg) | |||
3103 | return ret; | 3114 | return ret; |
3104 | } | 3115 | } |
3105 | 3116 | ||
3117 | static int f2fs_ioc_enable_verity(struct file *filp, unsigned long arg) | ||
3118 | { | ||
3119 | struct inode *inode = file_inode(filp); | ||
3120 | |||
3121 | f2fs_update_time(F2FS_I_SB(inode), REQ_TIME); | ||
3122 | |||
3123 | if (!f2fs_sb_has_verity(F2FS_I_SB(inode))) { | ||
3124 | f2fs_warn(F2FS_I_SB(inode), | ||
3125 | "Can't enable fs-verity on inode %lu: the verity feature is not enabled on this filesystem.\n", | ||
3126 | inode->i_ino); | ||
3127 | return -EOPNOTSUPP; | ||
3128 | } | ||
3129 | |||
3130 | return fsverity_ioctl_enable(filp, (const void __user *)arg); | ||
3131 | } | ||
3132 | |||
3133 | static int f2fs_ioc_measure_verity(struct file *filp, unsigned long arg) | ||
3134 | { | ||
3135 | if (!f2fs_sb_has_verity(F2FS_I_SB(file_inode(filp)))) | ||
3136 | return -EOPNOTSUPP; | ||
3137 | |||
3138 | return fsverity_ioctl_measure(filp, (void __user *)arg); | ||
3139 | } | ||
3140 | |||
3106 | long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) | 3141 | long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) |
3107 | { | 3142 | { |
3108 | if (unlikely(f2fs_cp_error(F2FS_I_SB(file_inode(filp))))) | 3143 | if (unlikely(f2fs_cp_error(F2FS_I_SB(file_inode(filp))))) |
@@ -3171,6 +3206,10 @@ long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) | |||
3171 | return f2fs_ioc_precache_extents(filp, arg); | 3206 | return f2fs_ioc_precache_extents(filp, arg); |
3172 | case F2FS_IOC_RESIZE_FS: | 3207 | case F2FS_IOC_RESIZE_FS: |
3173 | return f2fs_ioc_resize_fs(filp, arg); | 3208 | return f2fs_ioc_resize_fs(filp, arg); |
3209 | case FS_IOC_ENABLE_VERITY: | ||
3210 | return f2fs_ioc_enable_verity(filp, arg); | ||
3211 | case FS_IOC_MEASURE_VERITY: | ||
3212 | return f2fs_ioc_measure_verity(filp, arg); | ||
3174 | default: | 3213 | default: |
3175 | return -ENOTTY; | 3214 | return -ENOTTY; |
3176 | } | 3215 | } |
@@ -3290,6 +3329,8 @@ long f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
3290 | case F2FS_IOC_SET_PIN_FILE: | 3329 | case F2FS_IOC_SET_PIN_FILE: |
3291 | case F2FS_IOC_PRECACHE_EXTENTS: | 3330 | case F2FS_IOC_PRECACHE_EXTENTS: |
3292 | case F2FS_IOC_RESIZE_FS: | 3331 | case F2FS_IOC_RESIZE_FS: |
3332 | case FS_IOC_ENABLE_VERITY: | ||
3333 | case FS_IOC_MEASURE_VERITY: | ||
3293 | break; | 3334 | break; |
3294 | default: | 3335 | default: |
3295 | return -ENOIOCTLCMD; | 3336 | return -ENOIOCTLCMD; |
diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c index a33d7a849b2d..06da75d418e0 100644 --- a/fs/f2fs/inode.c +++ b/fs/f2fs/inode.c | |||
@@ -46,9 +46,11 @@ void f2fs_set_inode_flags(struct inode *inode) | |||
46 | new_fl |= S_DIRSYNC; | 46 | new_fl |= S_DIRSYNC; |
47 | if (file_is_encrypt(inode)) | 47 | if (file_is_encrypt(inode)) |
48 | new_fl |= S_ENCRYPTED; | 48 | new_fl |= S_ENCRYPTED; |
49 | if (file_is_verity(inode)) | ||
50 | new_fl |= S_VERITY; | ||
49 | inode_set_flags(inode, new_fl, | 51 | inode_set_flags(inode, new_fl, |
50 | S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC| | 52 | S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC| |
51 | S_ENCRYPTED); | 53 | S_ENCRYPTED|S_VERITY); |
52 | } | 54 | } |
53 | 55 | ||
54 | static void __get_inode_rdev(struct inode *inode, struct f2fs_inode *ri) | 56 | static void __get_inode_rdev(struct inode *inode, struct f2fs_inode *ri) |
@@ -733,6 +735,7 @@ no_delete: | |||
733 | } | 735 | } |
734 | out_clear: | 736 | out_clear: |
735 | fscrypt_put_encryption_info(inode); | 737 | fscrypt_put_encryption_info(inode); |
738 | fsverity_cleanup_inode(inode); | ||
736 | clear_inode(inode); | 739 | clear_inode(inode); |
737 | } | 740 | } |
738 | 741 | ||
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index e15bd29bd453..f43befda0e1a 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c | |||
@@ -3146,6 +3146,9 @@ try_onemore: | |||
3146 | #ifdef CONFIG_FS_ENCRYPTION | 3146 | #ifdef CONFIG_FS_ENCRYPTION |
3147 | sb->s_cop = &f2fs_cryptops; | 3147 | sb->s_cop = &f2fs_cryptops; |
3148 | #endif | 3148 | #endif |
3149 | #ifdef CONFIG_FS_VERITY | ||
3150 | sb->s_vop = &f2fs_verityops; | ||
3151 | #endif | ||
3149 | sb->s_xattr = f2fs_xattr_handlers; | 3152 | sb->s_xattr = f2fs_xattr_handlers; |
3150 | sb->s_export_op = &f2fs_export_ops; | 3153 | sb->s_export_op = &f2fs_export_ops; |
3151 | sb->s_magic = F2FS_SUPER_MAGIC; | 3154 | sb->s_magic = F2FS_SUPER_MAGIC; |
diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c index 3aeacd0aacfd..0cd64f994068 100644 --- a/fs/f2fs/sysfs.c +++ b/fs/f2fs/sysfs.c | |||
@@ -131,6 +131,9 @@ static ssize_t features_show(struct f2fs_attr *a, | |||
131 | if (f2fs_sb_has_lost_found(sbi)) | 131 | if (f2fs_sb_has_lost_found(sbi)) |
132 | len += snprintf(buf + len, PAGE_SIZE - len, "%s%s", | 132 | len += snprintf(buf + len, PAGE_SIZE - len, "%s%s", |
133 | len ? ", " : "", "lost_found"); | 133 | len ? ", " : "", "lost_found"); |
134 | if (f2fs_sb_has_verity(sbi)) | ||
135 | len += snprintf(buf + len, PAGE_SIZE - len, "%s%s", | ||
136 | len ? ", " : "", "verity"); | ||
134 | if (f2fs_sb_has_sb_chksum(sbi)) | 137 | if (f2fs_sb_has_sb_chksum(sbi)) |
135 | len += snprintf(buf + len, PAGE_SIZE - len, "%s%s", | 138 | len += snprintf(buf + len, PAGE_SIZE - len, "%s%s", |
136 | len ? ", " : "", "sb_checksum"); | 139 | len ? ", " : "", "sb_checksum"); |
@@ -364,6 +367,7 @@ enum feat_id { | |||
364 | FEAT_QUOTA_INO, | 367 | FEAT_QUOTA_INO, |
365 | FEAT_INODE_CRTIME, | 368 | FEAT_INODE_CRTIME, |
366 | FEAT_LOST_FOUND, | 369 | FEAT_LOST_FOUND, |
370 | FEAT_VERITY, | ||
367 | FEAT_SB_CHECKSUM, | 371 | FEAT_SB_CHECKSUM, |
368 | }; | 372 | }; |
369 | 373 | ||
@@ -381,6 +385,7 @@ static ssize_t f2fs_feature_show(struct f2fs_attr *a, | |||
381 | case FEAT_QUOTA_INO: | 385 | case FEAT_QUOTA_INO: |
382 | case FEAT_INODE_CRTIME: | 386 | case FEAT_INODE_CRTIME: |
383 | case FEAT_LOST_FOUND: | 387 | case FEAT_LOST_FOUND: |
388 | case FEAT_VERITY: | ||
384 | case FEAT_SB_CHECKSUM: | 389 | case FEAT_SB_CHECKSUM: |
385 | return snprintf(buf, PAGE_SIZE, "supported\n"); | 390 | return snprintf(buf, PAGE_SIZE, "supported\n"); |
386 | } | 391 | } |
@@ -470,6 +475,9 @@ F2FS_FEATURE_RO_ATTR(flexible_inline_xattr, FEAT_FLEXIBLE_INLINE_XATTR); | |||
470 | F2FS_FEATURE_RO_ATTR(quota_ino, FEAT_QUOTA_INO); | 475 | F2FS_FEATURE_RO_ATTR(quota_ino, FEAT_QUOTA_INO); |
471 | F2FS_FEATURE_RO_ATTR(inode_crtime, FEAT_INODE_CRTIME); | 476 | F2FS_FEATURE_RO_ATTR(inode_crtime, FEAT_INODE_CRTIME); |
472 | F2FS_FEATURE_RO_ATTR(lost_found, FEAT_LOST_FOUND); | 477 | F2FS_FEATURE_RO_ATTR(lost_found, FEAT_LOST_FOUND); |
478 | #ifdef CONFIG_FS_VERITY | ||
479 | F2FS_FEATURE_RO_ATTR(verity, FEAT_VERITY); | ||
480 | #endif | ||
473 | F2FS_FEATURE_RO_ATTR(sb_checksum, FEAT_SB_CHECKSUM); | 481 | F2FS_FEATURE_RO_ATTR(sb_checksum, FEAT_SB_CHECKSUM); |
474 | 482 | ||
475 | #define ATTR_LIST(name) (&f2fs_attr_##name.attr) | 483 | #define ATTR_LIST(name) (&f2fs_attr_##name.attr) |
@@ -534,6 +542,9 @@ static struct attribute *f2fs_feat_attrs[] = { | |||
534 | ATTR_LIST(quota_ino), | 542 | ATTR_LIST(quota_ino), |
535 | ATTR_LIST(inode_crtime), | 543 | ATTR_LIST(inode_crtime), |
536 | ATTR_LIST(lost_found), | 544 | ATTR_LIST(lost_found), |
545 | #ifdef CONFIG_FS_VERITY | ||
546 | ATTR_LIST(verity), | ||
547 | #endif | ||
537 | ATTR_LIST(sb_checksum), | 548 | ATTR_LIST(sb_checksum), |
538 | NULL, | 549 | NULL, |
539 | }; | 550 | }; |
diff --git a/fs/f2fs/verity.c b/fs/f2fs/verity.c new file mode 100644 index 000000000000..a401ef72bc82 --- /dev/null +++ b/fs/f2fs/verity.c | |||
@@ -0,0 +1,247 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | /* | ||
3 | * fs/f2fs/verity.c: fs-verity support for f2fs | ||
4 | * | ||
5 | * Copyright 2019 Google LLC | ||
6 | */ | ||
7 | |||
8 | /* | ||
9 | * Implementation of fsverity_operations for f2fs. | ||
10 | * | ||
11 | * Like ext4, f2fs stores the verity metadata (Merkle tree and | ||
12 | * fsverity_descriptor) past the end of the file, starting at the first 64K | ||
13 | * boundary beyond i_size. This approach works because (a) verity files are | ||
14 | * readonly, and (b) pages fully beyond i_size aren't visible to userspace but | ||
15 | * can be read/written internally by f2fs with only some relatively small | ||
16 | * changes to f2fs. Extended attributes cannot be used because (a) f2fs limits | ||
17 | * the total size of an inode's xattr entries to 4096 bytes, which wouldn't be | ||
18 | * enough for even a single Merkle tree block, and (b) f2fs encryption doesn't | ||
19 | * encrypt xattrs, yet the verity metadata *must* be encrypted when the file is | ||
20 | * because it contains hashes of the plaintext data. | ||
21 | * | ||
22 | * Using a 64K boundary rather than a 4K one keeps things ready for | ||
23 | * architectures with 64K pages, and it doesn't necessarily waste space on-disk | ||
24 | * since there can be a hole between i_size and the start of the Merkle tree. | ||
25 | */ | ||
26 | |||
27 | #include <linux/f2fs_fs.h> | ||
28 | |||
29 | #include "f2fs.h" | ||
30 | #include "xattr.h" | ||
31 | |||
32 | static inline loff_t f2fs_verity_metadata_pos(const struct inode *inode) | ||
33 | { | ||
34 | return round_up(inode->i_size, 65536); | ||
35 | } | ||
36 | |||
37 | /* | ||
38 | * Read some verity metadata from the inode. __vfs_read() can't be used because | ||
39 | * we need to read beyond i_size. | ||
40 | */ | ||
41 | static int pagecache_read(struct inode *inode, void *buf, size_t count, | ||
42 | loff_t pos) | ||
43 | { | ||
44 | while (count) { | ||
45 | size_t n = min_t(size_t, count, | ||
46 | PAGE_SIZE - offset_in_page(pos)); | ||
47 | struct page *page; | ||
48 | void *addr; | ||
49 | |||
50 | page = read_mapping_page(inode->i_mapping, pos >> PAGE_SHIFT, | ||
51 | NULL); | ||
52 | if (IS_ERR(page)) | ||
53 | return PTR_ERR(page); | ||
54 | |||
55 | addr = kmap_atomic(page); | ||
56 | memcpy(buf, addr + offset_in_page(pos), n); | ||
57 | kunmap_atomic(addr); | ||
58 | |||
59 | put_page(page); | ||
60 | |||
61 | buf += n; | ||
62 | pos += n; | ||
63 | count -= n; | ||
64 | } | ||
65 | return 0; | ||
66 | } | ||
67 | |||
68 | /* | ||
69 | * Write some verity metadata to the inode for FS_IOC_ENABLE_VERITY. | ||
70 | * kernel_write() can't be used because the file descriptor is readonly. | ||
71 | */ | ||
72 | static int pagecache_write(struct inode *inode, const void *buf, size_t count, | ||
73 | loff_t pos) | ||
74 | { | ||
75 | if (pos + count > inode->i_sb->s_maxbytes) | ||
76 | return -EFBIG; | ||
77 | |||
78 | while (count) { | ||
79 | size_t n = min_t(size_t, count, | ||
80 | PAGE_SIZE - offset_in_page(pos)); | ||
81 | struct page *page; | ||
82 | void *fsdata; | ||
83 | void *addr; | ||
84 | int res; | ||
85 | |||
86 | res = pagecache_write_begin(NULL, inode->i_mapping, pos, n, 0, | ||
87 | &page, &fsdata); | ||
88 | if (res) | ||
89 | return res; | ||
90 | |||
91 | addr = kmap_atomic(page); | ||
92 | memcpy(addr + offset_in_page(pos), buf, n); | ||
93 | kunmap_atomic(addr); | ||
94 | |||
95 | res = pagecache_write_end(NULL, inode->i_mapping, pos, n, n, | ||
96 | page, fsdata); | ||
97 | if (res < 0) | ||
98 | return res; | ||
99 | if (res != n) | ||
100 | return -EIO; | ||
101 | |||
102 | buf += n; | ||
103 | pos += n; | ||
104 | count -= n; | ||
105 | } | ||
106 | return 0; | ||
107 | } | ||
108 | |||
109 | /* | ||
110 | * Format of f2fs verity xattr. This points to the location of the verity | ||
111 | * descriptor within the file data rather than containing it directly because | ||
112 | * the verity descriptor *must* be encrypted when f2fs encryption is used. But, | ||
113 | * f2fs encryption does not encrypt xattrs. | ||
114 | */ | ||
115 | struct fsverity_descriptor_location { | ||
116 | __le32 version; | ||
117 | __le32 size; | ||
118 | __le64 pos; | ||
119 | }; | ||
120 | |||
121 | static int f2fs_begin_enable_verity(struct file *filp) | ||
122 | { | ||
123 | struct inode *inode = file_inode(filp); | ||
124 | int err; | ||
125 | |||
126 | if (f2fs_verity_in_progress(inode)) | ||
127 | return -EBUSY; | ||
128 | |||
129 | if (f2fs_is_atomic_file(inode) || f2fs_is_volatile_file(inode)) | ||
130 | return -EOPNOTSUPP; | ||
131 | |||
132 | /* | ||
133 | * Since the file was opened readonly, we have to initialize the quotas | ||
134 | * here and not rely on ->open() doing it. This must be done before | ||
135 | * evicting the inline data. | ||
136 | */ | ||
137 | err = dquot_initialize(inode); | ||
138 | if (err) | ||
139 | return err; | ||
140 | |||
141 | err = f2fs_convert_inline_inode(inode); | ||
142 | if (err) | ||
143 | return err; | ||
144 | |||
145 | set_inode_flag(inode, FI_VERITY_IN_PROGRESS); | ||
146 | return 0; | ||
147 | } | ||
148 | |||
149 | static int f2fs_end_enable_verity(struct file *filp, const void *desc, | ||
150 | size_t desc_size, u64 merkle_tree_size) | ||
151 | { | ||
152 | struct inode *inode = file_inode(filp); | ||
153 | u64 desc_pos = f2fs_verity_metadata_pos(inode) + merkle_tree_size; | ||
154 | struct fsverity_descriptor_location dloc = { | ||
155 | .version = cpu_to_le32(1), | ||
156 | .size = cpu_to_le32(desc_size), | ||
157 | .pos = cpu_to_le64(desc_pos), | ||
158 | }; | ||
159 | int err = 0; | ||
160 | |||
161 | if (desc != NULL) { | ||
162 | /* Succeeded; write the verity descriptor. */ | ||
163 | err = pagecache_write(inode, desc, desc_size, desc_pos); | ||
164 | |||
165 | /* Write all pages before clearing FI_VERITY_IN_PROGRESS. */ | ||
166 | if (!err) | ||
167 | err = filemap_write_and_wait(inode->i_mapping); | ||
168 | } | ||
169 | |||
170 | /* If we failed, truncate anything we wrote past i_size. */ | ||
171 | if (desc == NULL || err) | ||
172 | f2fs_truncate(inode); | ||
173 | |||
174 | clear_inode_flag(inode, FI_VERITY_IN_PROGRESS); | ||
175 | |||
176 | if (desc != NULL && !err) { | ||
177 | err = f2fs_setxattr(inode, F2FS_XATTR_INDEX_VERITY, | ||
178 | F2FS_XATTR_NAME_VERITY, &dloc, sizeof(dloc), | ||
179 | NULL, XATTR_CREATE); | ||
180 | if (!err) { | ||
181 | file_set_verity(inode); | ||
182 | f2fs_set_inode_flags(inode); | ||
183 | f2fs_mark_inode_dirty_sync(inode, true); | ||
184 | } | ||
185 | } | ||
186 | return err; | ||
187 | } | ||
188 | |||
189 | static int f2fs_get_verity_descriptor(struct inode *inode, void *buf, | ||
190 | size_t buf_size) | ||
191 | { | ||
192 | struct fsverity_descriptor_location dloc; | ||
193 | int res; | ||
194 | u32 size; | ||
195 | u64 pos; | ||
196 | |||
197 | /* Get the descriptor location */ | ||
198 | res = f2fs_getxattr(inode, F2FS_XATTR_INDEX_VERITY, | ||
199 | F2FS_XATTR_NAME_VERITY, &dloc, sizeof(dloc), NULL); | ||
200 | if (res < 0 && res != -ERANGE) | ||
201 | return res; | ||
202 | if (res != sizeof(dloc) || dloc.version != cpu_to_le32(1)) { | ||
203 | f2fs_warn(F2FS_I_SB(inode), "unknown verity xattr format"); | ||
204 | return -EINVAL; | ||
205 | } | ||
206 | size = le32_to_cpu(dloc.size); | ||
207 | pos = le64_to_cpu(dloc.pos); | ||
208 | |||
209 | /* Get the descriptor */ | ||
210 | if (pos + size < pos || pos + size > inode->i_sb->s_maxbytes || | ||
211 | pos < f2fs_verity_metadata_pos(inode) || size > INT_MAX) { | ||
212 | f2fs_warn(F2FS_I_SB(inode), "invalid verity xattr"); | ||
213 | return -EFSCORRUPTED; | ||
214 | } | ||
215 | if (buf_size) { | ||
216 | if (size > buf_size) | ||
217 | return -ERANGE; | ||
218 | res = pagecache_read(inode, buf, size, pos); | ||
219 | if (res) | ||
220 | return res; | ||
221 | } | ||
222 | return size; | ||
223 | } | ||
224 | |||
225 | static struct page *f2fs_read_merkle_tree_page(struct inode *inode, | ||
226 | pgoff_t index) | ||
227 | { | ||
228 | index += f2fs_verity_metadata_pos(inode) >> PAGE_SHIFT; | ||
229 | |||
230 | return read_mapping_page(inode->i_mapping, index, NULL); | ||
231 | } | ||
232 | |||
233 | static int f2fs_write_merkle_tree_block(struct inode *inode, const void *buf, | ||
234 | u64 index, int log_blocksize) | ||
235 | { | ||
236 | loff_t pos = f2fs_verity_metadata_pos(inode) + (index << log_blocksize); | ||
237 | |||
238 | return pagecache_write(inode, buf, 1 << log_blocksize, pos); | ||
239 | } | ||
240 | |||
241 | const struct fsverity_operations f2fs_verityops = { | ||
242 | .begin_enable_verity = f2fs_begin_enable_verity, | ||
243 | .end_enable_verity = f2fs_end_enable_verity, | ||
244 | .get_verity_descriptor = f2fs_get_verity_descriptor, | ||
245 | .read_merkle_tree_page = f2fs_read_merkle_tree_page, | ||
246 | .write_merkle_tree_block = f2fs_write_merkle_tree_block, | ||
247 | }; | ||
diff --git a/fs/f2fs/xattr.h b/fs/f2fs/xattr.h index a90920e2f949..de0c600b9cab 100644 --- a/fs/f2fs/xattr.h +++ b/fs/f2fs/xattr.h | |||
@@ -34,8 +34,10 @@ | |||
34 | #define F2FS_XATTR_INDEX_ADVISE 7 | 34 | #define F2FS_XATTR_INDEX_ADVISE 7 |
35 | /* Should be same as EXT4_XATTR_INDEX_ENCRYPTION */ | 35 | /* Should be same as EXT4_XATTR_INDEX_ENCRYPTION */ |
36 | #define F2FS_XATTR_INDEX_ENCRYPTION 9 | 36 | #define F2FS_XATTR_INDEX_ENCRYPTION 9 |
37 | #define F2FS_XATTR_INDEX_VERITY 11 | ||
37 | 38 | ||
38 | #define F2FS_XATTR_NAME_ENCRYPTION_CONTEXT "c" | 39 | #define F2FS_XATTR_NAME_ENCRYPTION_CONTEXT "c" |
40 | #define F2FS_XATTR_NAME_VERITY "v" | ||
39 | 41 | ||
40 | struct f2fs_xattr_header { | 42 | struct f2fs_xattr_header { |
41 | __le32 h_magic; /* magic number for identification */ | 43 | __le32 h_magic; /* magic number for identification */ |