Message ID | 20191221143020.hbgeixvlmzt7nh54@gondor.apana.org.au (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
Series | fscrypt: Restore modular support | expand |
On Sat, Dec 21, 2019 at 10:30:20PM +0800, Herbert Xu wrote: > The commit 643fa9612bf1 ("fscrypt: remove filesystem specific > build config option") removed modular support for fs/crypto. This > causes the Crypto API to be built-in whenever fscrypt is enabled. > This makes it very difficult for me to test modular builds of > the Crypto API without disabling fscrypt which is a pain. > > AFAICS there is no reason why fscrypt has to be built-in. The > commit above appears to have done this way purely for the sake of > simplicity. In fact some simple Kconfig tweaking is sufficient > to retain a single FS_ENCRYPTION option while maintaining modularity. > > This patch restores modular support to fscrypt by adding a new > hidden FS_ENCRYPTION_TRI tristate option that is selected by all > the FS_ENCRYPTION users. > > Subsequent to the above commit, some core code has been introduced > to fs/buffer.c that makes restoring modular support non-trivial. > This patch deals with this by adding a function pointer that defaults > to end_buffer_async_read function until fscrypt is loaded. When > fscrypt is loaded it modifies the function pointer to its own > function which used to be end_buffer_async_read_io but now resides > in fscrypt. When it is unloaded the function pointer is restored. > > In order for this to be safe with respect to module removal, the > check for whether the host inode is encrypted has been moved into > mark_buffer_async_read. The assumption is that as long as the > bh is alive the calling filesystem module will be resident. The > calling filesystem would then guarantee that fscrypt is loaded. > > Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> I'm not sure this is a good idea, since there will probably need to be more places where built-in code calls into fs/crypto/ too. There's actually already fscrypt_sb_free(), which this patch forgets to handle: void fscrypt_sb_free(struct super_block *sb) { key_put(sb->s_master_keys); sb->s_master_keys = NULL; } Though we could make that an inline function. But there's also a patch under review which adds inline encryption support to ext4 and f2fs, which requires calling into fs/crypto/ from fs/buffer.c in order to set an encryption context on bios: https://lkml.kernel.org/linux-fscrypt/20191218145136.172774-10-satyat@google.com/ If we also add direct I/O support for inline encryption (which is planned), it would require calling into fs/crypto/ from fs/direct-io.c and fs/iomap/direct-io.c as well. Another thing I've been thinking about is adding decryption support to __block_write_begin(), which would allow us to delete ext4_block_write_begin(), which was copied from __block_write_begin() to add decryption support. So more broadly, the issue is that a lot of the filesystem I/O helpers (fs/buffer.c, fs/iomap/, fs/direct-io.c, fs/mpage.c) are already built-in, and it can be necessary to call into fs/crypto/ from such places. Is it really much of an issue to just disable CONFIG_FS_ENCRYPTION when you want to test building the crypto API as a module? > diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c > index 3719efa546c6..6bf7f05120bd 100644 > --- a/fs/crypto/crypto.c > +++ b/fs/crypto/crypto.c > @@ -20,6 +20,7 @@ > * Special Publication 800-38E and IEEE P1619/D16. > */ > > +#include <linux/buffer_head.h> > #include <linux/pagemap.h> > #include <linux/mempool.h> > #include <linux/module.h> > @@ -286,6 +287,41 @@ int fscrypt_decrypt_block_inplace(const struct inode *inode, struct page *page, > } > EXPORT_SYMBOL(fscrypt_decrypt_block_inplace); > > +struct decrypt_bh_ctx { > + struct work_struct work; > + struct buffer_head *bh; > +}; > + > +static void decrypt_bh(struct work_struct *work) > +{ > + struct decrypt_bh_ctx *ctx = > + container_of(work, struct decrypt_bh_ctx, work); > + struct buffer_head *bh = ctx->bh; > + int err; > + > + err = fscrypt_decrypt_pagecache_blocks(bh->b_page, bh->b_size, > + bh_offset(bh)); > + end_buffer_async_read(bh, err == 0); > + kfree(ctx); > +} > + > +static void fscrypt_end_buffer_async_read(struct buffer_head *bh, int uptodate) > +{ > + /* Decrypt if needed */ > + if (uptodate) { > + struct decrypt_bh_ctx *ctx = kmalloc(sizeof(*ctx), GFP_ATOMIC); > + > + if (ctx) { > + INIT_WORK(&ctx->work, decrypt_bh); > + ctx->bh = bh; > + fscrypt_enqueue_decrypt_work(&ctx->work); > + return; > + } > + uptodate = 0; > + } > + end_buffer_async_read(bh, uptodate); > +} > + > /* > * Validate dentries in encrypted directories to make sure we aren't potentially > * caching stale dentries after a key has been added. > @@ -418,6 +454,8 @@ static int __init fscrypt_init(void) > if (err) > goto fail_free_info; > > + end_buffer_async_read_io = fscrypt_end_buffer_async_read; > + > return 0; This code would actually need to go into fs/crypto/bio.c because it depends on CONFIG_BLOCK. UBIFS uses fs/crypto/ without CONFIG_BLOCK necessarily being set. > +/** > + * fscrypt_exit() - Shutdown the fs encryption system > + */ > +static void __exit fscrypt_exit(void) > +{ > + end_buffer_async_read_io = end_buffer_async_read; > + > + kmem_cache_destroy(fscrypt_info_cachep); > + destroy_workqueue(fscrypt_read_workqueue); > +} > +module_exit(fscrypt_exit); There's a bit more that would need to be done here: mempool_destroy(fscrypt_bounce_page_pool); and fscrypt_exit_keyring() => unregister_key_type(&key_type_fscrypt); => unregister_key_type(&key_type_fscrypt_user); - Eric
Hi Herbert, I love your patch! Yet something to improve: [auto build test ERROR on linux/master] [also build test ERROR on f2fs/dev-test linus/master v5.5-rc3 next-20191220] [cannot apply to ext4/dev tytso-fscrypt/master] [if your patch is applied to the wrong git tree, please drop us a note to help improve the system. BTW, we also suggest to use '--base' option to specify the base tree in git format-patch, please see https://stackoverflow.com/a/37406982] url: https://github.com/0day-ci/linux/commits/Herbert-Xu/fscrypt-Restore-modular-support/20191224-164226 base: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 1522d9da40bdfe502c91163e6d769332897201fa config: x86_64-kexec (attached as .config) compiler: gcc-7 (Debian 7.5.0-3) 7.5.0 reproduce: # save the attached .config to linux build tree make ARCH=x86_64 If you fix the issue, kindly add following tag Reported-by: kbuild test robot <lkp@intel.com> All errors (new ones prefixed by >>): ld: fs/super.o: in function `__put_super': fs/super.c:296: undefined reference to `fscrypt_sb_free' ld: fs/ext4/dir.o: in function `ext4_dir_open': fs/ext4/dir.c:617: undefined reference to `fscrypt_get_encryption_info' ld: fs/ext4/dir.o: in function `ext4_readdir': fs/ext4/dir.c:118: undefined reference to `fscrypt_get_encryption_info' ld: fs/ext4/dir.c:145: undefined reference to `fscrypt_fname_alloc_buffer' ld: fs/ext4/dir.c:263: undefined reference to `fscrypt_fname_disk_to_usr' ld: fs/ext4/dir.c:288: undefined reference to `fscrypt_fname_free_buffer' ld: fs/ext4/file.o: in function `ext4_file_open': fs/ext4/file.c:716: undefined reference to `fscrypt_file_open' ld: fs/ext4/ialloc.o: in function `__ext4_new_inode': fs/ext4/ialloc.c:772: undefined reference to `fscrypt_get_encryption_info' ld: fs/ext4/ialloc.c:1145: undefined reference to `fscrypt_inherit_context' ld: fs/ext4/inode.o: in function `ext4_block_write_begin': fs/ext4/inode.c:1097: undefined reference to `fscrypt_decrypt_pagecache_blocks' ld: fs/ext4/inode.o: in function `__ext4_block_zero_page_range': fs/ext4/inode.c:3704: undefined reference to `fscrypt_decrypt_pagecache_blocks' ld: fs/ext4/inode.o: in function `fscrypt_require_key': include/linux/fscrypt.h:548: undefined reference to `fscrypt_get_encryption_info' ld: fs/ext4/inode.o: in function `ext4_issue_zeroout': fs/ext4/inode.c:406: undefined reference to `fscrypt_zeroout_range' ld: fs/ext4/ioctl.o: in function `ext4_ioctl': fs/ext4/ioctl.c:1141: undefined reference to `fscrypt_ioctl_set_policy' ld: fs/ext4/ioctl.c:1186: undefined reference to `fscrypt_ioctl_get_policy' ld: fs/ext4/ioctl.c:1191: undefined reference to `fscrypt_ioctl_get_policy_ex' ld: fs/ext4/ioctl.c:1196: undefined reference to `fscrypt_ioctl_add_key' ld: fs/ext4/ioctl.c:1201: undefined reference to `fscrypt_ioctl_remove_key' ld: fs/ext4/ioctl.c:1206: undefined reference to `fscrypt_ioctl_remove_key_all_users' ld: fs/ext4/ioctl.c:1211: undefined reference to `fscrypt_ioctl_get_key_status' ld: fs/ext4/namei.o: in function `ext4_fname_setup_filename': fs/ext4/ext4.h:2380: undefined reference to `fscrypt_setup_filename' ld: fs/ext4/namei.o: in function `fscrypt_prepare_lookup': include/linux/fscrypt.h:642: undefined reference to `__fscrypt_prepare_lookup' ld: fs/ext4/namei.o: in function `htree_dirblock_to_tree': >> fs/ext4/namei.c:1008: undefined reference to `fscrypt_get_encryption_info' ld: fs/ext4/namei.c:1013: undefined reference to `fscrypt_fname_alloc_buffer' ld: fs/ext4/namei.c:1048: undefined reference to `fscrypt_fname_disk_to_usr' >> ld: fs/ext4/namei.c:1069: undefined reference to `fscrypt_fname_free_buffer' ld: fs/ext4/namei.o: in function `ext4_lookup': fs/ext4/namei.c:1709: undefined reference to `fscrypt_has_permitted_context' ld: fs/ext4/namei.o: in function `fscrypt_prepare_rename': include/linux/fscrypt.h:613: undefined reference to `__fscrypt_prepare_rename' ld: fs/ext4/namei.o: in function `fscrypt_prepare_symlink': include/linux/fscrypt.h:706: undefined reference to `__fscrypt_prepare_symlink' ld: fs/ext4/namei.o: in function `fscrypt_encrypt_symlink': include/linux/fscrypt.h:736: undefined reference to `__fscrypt_encrypt_symlink' ld: fs/ext4/namei.o: in function `fscrypt_prepare_link': include/linux/fscrypt.h:581: undefined reference to `__fscrypt_prepare_link' ld: fs/ext4/page-io.o: in function `ext4_finish_bio': fs/ext4/page-io.c:147: undefined reference to `fscrypt_free_bounce_page' ld: fs/ext4/page-io.o: in function `ext4_bio_write_page': fs/ext4/page-io.c:516: undefined reference to `fscrypt_encrypt_pagecache_blocks' ld: fs/ext4/readpage.o: in function `decrypt_work': fs/ext4/readpage.c:100: undefined reference to `fscrypt_decrypt_bio' ld: fs/ext4/readpage.o: in function `bio_post_read_processing': fs/ext4/readpage.c:126: undefined reference to `fscrypt_enqueue_decrypt_work' ld: fs/ext4/super.o: in function `ext4_drop_inode': fs/ext4/super.c:1111: undefined reference to `fscrypt_drop_inode' ld: fs/ext4/super.o: in function `ext4_free_in_core_inode': fs/ext4/super.c:1119: undefined reference to `fscrypt_free_inode' ld: fs/ext4/super.o: in function `ext4_clear_inode': fs/ext4/super.c:1184: undefined reference to `fscrypt_put_encryption_info' ld: fs/ext4/symlink.o: in function `ext4_encrypted_get_link': fs/ext4/symlink.c:49: undefined reference to `fscrypt_get_symlink' vim +1008 fs/ext4/namei.c ac27a0ec112a08 Dave Kleikamp 2006-10-11 978 ac27a0ec112a08 Dave Kleikamp 2006-10-11 979 ac27a0ec112a08 Dave Kleikamp 2006-10-11 980 /* ac27a0ec112a08 Dave Kleikamp 2006-10-11 981 * This function fills a red-black tree with information from a ac27a0ec112a08 Dave Kleikamp 2006-10-11 982 * directory block. It returns the number directory entries loaded ac27a0ec112a08 Dave Kleikamp 2006-10-11 983 * into the tree. If there is an error it is returned in err. ac27a0ec112a08 Dave Kleikamp 2006-10-11 984 */ ac27a0ec112a08 Dave Kleikamp 2006-10-11 985 static int htree_dirblock_to_tree(struct file *dir_file, 725d26d3f09ccb Aneesh Kumar K.V 2008-01-28 986 struct inode *dir, ext4_lblk_t block, ac27a0ec112a08 Dave Kleikamp 2006-10-11 987 struct dx_hash_info *hinfo, ac27a0ec112a08 Dave Kleikamp 2006-10-11 988 __u32 start_hash, __u32 start_minor_hash) ac27a0ec112a08 Dave Kleikamp 2006-10-11 989 { ac27a0ec112a08 Dave Kleikamp 2006-10-11 990 struct buffer_head *bh; 617ba13b31fbf5 Mingming Cao 2006-10-11 991 struct ext4_dir_entry_2 *de, *top; 90b0a97323f42e Carlos Maiolino 2012-09-17 992 int err = 0, count = 0; a7550b30ab709f Jaegeuk Kim 2016-07-10 993 struct fscrypt_str fname_crypto_str = FSTR_INIT(NULL, 0), tmp_str; ac27a0ec112a08 Dave Kleikamp 2006-10-11 994 725d26d3f09ccb Aneesh Kumar K.V 2008-01-28 995 dxtrace(printk(KERN_INFO "In htree dirblock_to_tree: block %lu\n", 725d26d3f09ccb Aneesh Kumar K.V 2008-01-28 996 (unsigned long)block)); 4e19d6b65fb4fc Theodore Ts'o 2019-06-20 997 bh = ext4_read_dirblock(dir, block, DIRENT_HTREE); dc6982ff4db1f4 Theodore Ts'o 2013-02-14 998 if (IS_ERR(bh)) dc6982ff4db1f4 Theodore Ts'o 2013-02-14 999 return PTR_ERR(bh); b0336e8d2108e6 Darrick J. Wong 2012-04-29 1000 617ba13b31fbf5 Mingming Cao 2006-10-11 1001 de = (struct ext4_dir_entry_2 *) bh->b_data; 617ba13b31fbf5 Mingming Cao 2006-10-11 1002 top = (struct ext4_dir_entry_2 *) ((char *) de + ac27a0ec112a08 Dave Kleikamp 2006-10-11 1003 dir->i_sb->s_blocksize - 617ba13b31fbf5 Mingming Cao 2006-10-11 1004 EXT4_DIR_REC_LEN(0)); 643fa9612bf1a2 Chandan Rajendra 2018-12-12 1005 #ifdef CONFIG_FS_ENCRYPTION 1f3862b5575b13 Michael Halcrow 2015-04-12 1006 /* Check if the directory is encrypted */ 592ddec7578a33 Chandan Rajendra 2018-12-12 1007 if (IS_ENCRYPTED(dir)) { a7550b30ab709f Jaegeuk Kim 2016-07-10 @1008 err = fscrypt_get_encryption_info(dir); c936e1ec2879e4 Theodore Ts'o 2015-05-31 1009 if (err < 0) { 1f3862b5575b13 Michael Halcrow 2015-04-12 1010 brelse(bh); 1f3862b5575b13 Michael Halcrow 2015-04-12 1011 return err; 1f3862b5575b13 Michael Halcrow 2015-04-12 1012 } a7550b30ab709f Jaegeuk Kim 2016-07-10 1013 err = fscrypt_fname_alloc_buffer(dir, EXT4_NAME_LEN, 1f3862b5575b13 Michael Halcrow 2015-04-12 1014 &fname_crypto_str); 1f3862b5575b13 Michael Halcrow 2015-04-12 1015 if (err < 0) { 1f3862b5575b13 Michael Halcrow 2015-04-12 1016 brelse(bh); 1f3862b5575b13 Michael Halcrow 2015-04-12 1017 return err; 1f3862b5575b13 Michael Halcrow 2015-04-12 1018 } 1f3862b5575b13 Michael Halcrow 2015-04-12 1019 } 1f3862b5575b13 Michael Halcrow 2015-04-12 1020 #endif 3d0518f4758eca Wei Yongjun 2009-02-14 1021 for (; de < top; de = ext4_next_entry(de, dir->i_sb->s_blocksize)) { f7c21177af0b32 Theodore Ts'o 2011-01-10 1022 if (ext4_check_dir_entry(dir, NULL, de, bh, 226ba972b08637 Tao Ma 2012-12-10 1023 bh->b_data, bh->b_size, e6c4021190c828 Eric Sandeen 2006-12-06 1024 (block<<EXT4_BLOCK_SIZE_BITS(dir->i_sb)) e6c4021190c828 Eric Sandeen 2006-12-06 1025 + ((char *)de - bh->b_data))) { 64cb927371cd2e Al Viro 2013-07-01 1026 /* silently ignore the rest of the block */ 64cb927371cd2e Al Viro 2013-07-01 1027 break; e6c4021190c828 Eric Sandeen 2006-12-06 1028 } b886ee3e778ec2 Gabriel Krisman Bertazi 2019-04-25 1029 ext4fs_dirhash(dir, de->name, de->name_len, hinfo); ac27a0ec112a08 Dave Kleikamp 2006-10-11 1030 if ((hinfo->hash < start_hash) || ac27a0ec112a08 Dave Kleikamp 2006-10-11 1031 ((hinfo->hash == start_hash) && ac27a0ec112a08 Dave Kleikamp 2006-10-11 1032 (hinfo->minor_hash < start_minor_hash))) ac27a0ec112a08 Dave Kleikamp 2006-10-11 1033 continue; ac27a0ec112a08 Dave Kleikamp 2006-10-11 1034 if (de->inode == 0) ac27a0ec112a08 Dave Kleikamp 2006-10-11 1035 continue; 592ddec7578a33 Chandan Rajendra 2018-12-12 1036 if (!IS_ENCRYPTED(dir)) { 2f61830ae33e29 Theodore Ts'o 2015-04-12 1037 tmp_str.name = de->name; 2f61830ae33e29 Theodore Ts'o 2015-04-12 1038 tmp_str.len = de->name_len; 2f61830ae33e29 Theodore Ts'o 2015-04-12 1039 err = ext4_htree_store_dirent(dir_file, 1f3862b5575b13 Michael Halcrow 2015-04-12 1040 hinfo->hash, hinfo->minor_hash, de, 1f3862b5575b13 Michael Halcrow 2015-04-12 1041 &tmp_str); 1f3862b5575b13 Michael Halcrow 2015-04-12 1042 } else { d229959072eba4 Theodore Ts'o 2015-05-18 1043 int save_len = fname_crypto_str.len; a7550b30ab709f Jaegeuk Kim 2016-07-10 1044 struct fscrypt_str de_name = FSTR_INIT(de->name, a7550b30ab709f Jaegeuk Kim 2016-07-10 1045 de->name_len); d229959072eba4 Theodore Ts'o 2015-05-18 1046 1f3862b5575b13 Michael Halcrow 2015-04-12 1047 /* Directory is encrypted */ a7550b30ab709f Jaegeuk Kim 2016-07-10 1048 err = fscrypt_fname_disk_to_usr(dir, hinfo->hash, a7550b30ab709f Jaegeuk Kim 2016-07-10 1049 hinfo->minor_hash, &de_name, 1f3862b5575b13 Michael Halcrow 2015-04-12 1050 &fname_crypto_str); ef1eb3aa50930f Eric Biggers 2016-09-15 1051 if (err) { 1f3862b5575b13 Michael Halcrow 2015-04-12 1052 count = err; 1f3862b5575b13 Michael Halcrow 2015-04-12 1053 goto errout; 1f3862b5575b13 Michael Halcrow 2015-04-12 1054 } 1f3862b5575b13 Michael Halcrow 2015-04-12 1055 err = ext4_htree_store_dirent(dir_file, 1f3862b5575b13 Michael Halcrow 2015-04-12 1056 hinfo->hash, hinfo->minor_hash, de, 1f3862b5575b13 Michael Halcrow 2015-04-12 1057 &fname_crypto_str); d229959072eba4 Theodore Ts'o 2015-05-18 1058 fname_crypto_str.len = save_len; 1f3862b5575b13 Michael Halcrow 2015-04-12 1059 } 2f61830ae33e29 Theodore Ts'o 2015-04-12 1060 if (err != 0) { 1f3862b5575b13 Michael Halcrow 2015-04-12 1061 count = err; 1f3862b5575b13 Michael Halcrow 2015-04-12 1062 goto errout; ac27a0ec112a08 Dave Kleikamp 2006-10-11 1063 } ac27a0ec112a08 Dave Kleikamp 2006-10-11 1064 count++; ac27a0ec112a08 Dave Kleikamp 2006-10-11 1065 } 1f3862b5575b13 Michael Halcrow 2015-04-12 1066 errout: ac27a0ec112a08 Dave Kleikamp 2006-10-11 1067 brelse(bh); 643fa9612bf1a2 Chandan Rajendra 2018-12-12 1068 #ifdef CONFIG_FS_ENCRYPTION a7550b30ab709f Jaegeuk Kim 2016-07-10 @1069 fscrypt_fname_free_buffer(&fname_crypto_str); 1f3862b5575b13 Michael Halcrow 2015-04-12 1070 #endif ac27a0ec112a08 Dave Kleikamp 2006-10-11 1071 return count; ac27a0ec112a08 Dave Kleikamp 2006-10-11 1072 } ac27a0ec112a08 Dave Kleikamp 2006-10-11 1073 :::::: The code at line 1008 was first introduced by commit :::::: a7550b30ab709ffb9bbe48669adf7d8556f3698f ext4 crypto: migrate into vfs's crypto engine :::::: TO: Jaegeuk Kim <jaegeuk@kernel.org> :::::: CC: Theodore Ts'o <tytso@mit.edu> --- 0-DAY kernel test infrastructure Open Source Technology Center https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org Intel Corporation
Hi Herbert, I love your patch! Yet something to improve: [auto build test ERROR on linux/master] [cannot apply to ext4/dev f2fs/dev-test linus/master tytso-fscrypt/master v5.5-rc3 next-20191220] [if your patch is applied to the wrong git tree, please drop us a note to help improve the system. BTW, we also suggest to use '--base' option to specify the base tree in git format-patch, please see https://stackoverflow.com/a/37406982] url: https://github.com/0day-ci/linux/commits/Herbert-Xu/fscrypt-Restore-modular-support/20191224-164226 base: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 1522d9da40bdfe502c91163e6d769332897201fa config: x86_64-rhel (attached as .config) compiler: gcc-7 (Debian 7.5.0-3) 7.5.0 reproduce: # save the attached .config to linux build tree make ARCH=x86_64 If you fix the issue, kindly add following tag Reported-by: kbuild test robot <lkp@intel.com> All errors (new ones prefixed by >>): ld: fs/super.o: in function `__put_super': fs/super.c:296: undefined reference to `fscrypt_sb_free' ld: fs/ext4/dir.o: in function `ext4_dir_open': >> fs/ext4/dir.c:617: undefined reference to `fscrypt_get_encryption_info' ld: fs/ext4/dir.o: in function `ext4_readdir': fs/ext4/dir.c:118: undefined reference to `fscrypt_get_encryption_info' >> ld: fs/ext4/dir.c:263: undefined reference to `fscrypt_fname_disk_to_usr' >> ld: fs/ext4/dir.c:288: undefined reference to `fscrypt_fname_free_buffer' >> ld: fs/ext4/dir.c:288: undefined reference to `fscrypt_fname_free_buffer' >> ld: fs/ext4/dir.c:288: undefined reference to `fscrypt_fname_free_buffer' >> ld: fs/ext4/dir.c:145: undefined reference to `fscrypt_fname_alloc_buffer' >> ld: fs/ext4/dir.c:288: undefined reference to `fscrypt_fname_free_buffer' >> ld: fs/ext4/dir.c:288: undefined reference to `fscrypt_fname_free_buffer' ld: fs/ext4/file.o: in function `ext4_file_open': >> fs/ext4/file.c:716: undefined reference to `fscrypt_file_open' ld: fs/ext4/ialloc.o: in function `__ext4_new_inode': >> fs/ext4/ialloc.c:772: undefined reference to `fscrypt_get_encryption_info' >> ld: fs/ext4/ialloc.c:1145: undefined reference to `fscrypt_inherit_context' ld: fs/ext4/inode.o: in function `ext4_block_write_begin': >> fs/ext4/inode.c:1097: undefined reference to `fscrypt_decrypt_pagecache_blocks' ld: fs/ext4/inode.o: in function `__ext4_block_zero_page_range': fs/ext4/inode.c:3704: undefined reference to `fscrypt_decrypt_pagecache_blocks' ld: fs/ext4/inode.o: in function `fscrypt_require_key': >> include/linux/fscrypt.h:548: undefined reference to `fscrypt_get_encryption_info' ld: fs/ext4/inode.o: in function `ext4_issue_zeroout': >> fs/ext4/inode.c:406: undefined reference to `fscrypt_zeroout_range' ld: fs/ext4/ioctl.o: in function `ext4_ioctl': >> fs/ext4/ioctl.c:1141: undefined reference to `fscrypt_ioctl_set_policy' >> ld: fs/ext4/ioctl.c:1211: undefined reference to `fscrypt_ioctl_get_key_status' >> ld: fs/ext4/ioctl.c:1186: undefined reference to `fscrypt_ioctl_get_policy' >> ld: fs/ext4/ioctl.c:1206: undefined reference to `fscrypt_ioctl_remove_key_all_users' >> ld: fs/ext4/ioctl.c:1201: undefined reference to `fscrypt_ioctl_remove_key' >> ld: fs/ext4/ioctl.c:1196: undefined reference to `fscrypt_ioctl_add_key' vim +1097 fs/ext4/inode.c ac27a0ec112a08 Dave Kleikamp 2006-10-11 1013 643fa9612bf1a2 Chandan Rajendra 2018-12-12 1014 #ifdef CONFIG_FS_ENCRYPTION 2058f83a728adf Michael Halcrow 2015-04-12 1015 static int ext4_block_write_begin(struct page *page, loff_t pos, unsigned len, 2058f83a728adf Michael Halcrow 2015-04-12 1016 get_block_t *get_block) 2058f83a728adf Michael Halcrow 2015-04-12 1017 { 09cbfeaf1a5a67 Kirill A. Shutemov 2016-04-01 1018 unsigned from = pos & (PAGE_SIZE - 1); 2058f83a728adf Michael Halcrow 2015-04-12 1019 unsigned to = from + len; 2058f83a728adf Michael Halcrow 2015-04-12 1020 struct inode *inode = page->mapping->host; 2058f83a728adf Michael Halcrow 2015-04-12 1021 unsigned block_start, block_end; 2058f83a728adf Michael Halcrow 2015-04-12 1022 sector_t block; 2058f83a728adf Michael Halcrow 2015-04-12 1023 int err = 0; 2058f83a728adf Michael Halcrow 2015-04-12 1024 unsigned blocksize = inode->i_sb->s_blocksize; 2058f83a728adf Michael Halcrow 2015-04-12 1025 unsigned bbits; 0b578f358a6a7a Chandan Rajendra 2019-05-20 1026 struct buffer_head *bh, *head, *wait[2]; 0b578f358a6a7a Chandan Rajendra 2019-05-20 1027 int nr_wait = 0; 0b578f358a6a7a Chandan Rajendra 2019-05-20 1028 int i; 2058f83a728adf Michael Halcrow 2015-04-12 1029 2058f83a728adf Michael Halcrow 2015-04-12 1030 BUG_ON(!PageLocked(page)); 09cbfeaf1a5a67 Kirill A. Shutemov 2016-04-01 1031 BUG_ON(from > PAGE_SIZE); 09cbfeaf1a5a67 Kirill A. Shutemov 2016-04-01 1032 BUG_ON(to > PAGE_SIZE); 2058f83a728adf Michael Halcrow 2015-04-12 1033 BUG_ON(from > to); 2058f83a728adf Michael Halcrow 2015-04-12 1034 2058f83a728adf Michael Halcrow 2015-04-12 1035 if (!page_has_buffers(page)) 2058f83a728adf Michael Halcrow 2015-04-12 1036 create_empty_buffers(page, blocksize, 0); 2058f83a728adf Michael Halcrow 2015-04-12 1037 head = page_buffers(page); 2058f83a728adf Michael Halcrow 2015-04-12 1038 bbits = ilog2(blocksize); 09cbfeaf1a5a67 Kirill A. Shutemov 2016-04-01 1039 block = (sector_t)page->index << (PAGE_SHIFT - bbits); 2058f83a728adf Michael Halcrow 2015-04-12 1040 2058f83a728adf Michael Halcrow 2015-04-12 1041 for (bh = head, block_start = 0; bh != head || !block_start; 2058f83a728adf Michael Halcrow 2015-04-12 1042 block++, block_start = block_end, bh = bh->b_this_page) { 2058f83a728adf Michael Halcrow 2015-04-12 1043 block_end = block_start + blocksize; 2058f83a728adf Michael Halcrow 2015-04-12 1044 if (block_end <= from || block_start >= to) { 2058f83a728adf Michael Halcrow 2015-04-12 1045 if (PageUptodate(page)) { 2058f83a728adf Michael Halcrow 2015-04-12 1046 if (!buffer_uptodate(bh)) 2058f83a728adf Michael Halcrow 2015-04-12 1047 set_buffer_uptodate(bh); 2058f83a728adf Michael Halcrow 2015-04-12 1048 } 2058f83a728adf Michael Halcrow 2015-04-12 1049 continue; 2058f83a728adf Michael Halcrow 2015-04-12 1050 } 2058f83a728adf Michael Halcrow 2015-04-12 1051 if (buffer_new(bh)) 2058f83a728adf Michael Halcrow 2015-04-12 1052 clear_buffer_new(bh); 2058f83a728adf Michael Halcrow 2015-04-12 1053 if (!buffer_mapped(bh)) { 2058f83a728adf Michael Halcrow 2015-04-12 1054 WARN_ON(bh->b_size != blocksize); 2058f83a728adf Michael Halcrow 2015-04-12 1055 err = get_block(inode, block, bh, 1); 2058f83a728adf Michael Halcrow 2015-04-12 1056 if (err) 2058f83a728adf Michael Halcrow 2015-04-12 1057 break; 2058f83a728adf Michael Halcrow 2015-04-12 1058 if (buffer_new(bh)) { 2058f83a728adf Michael Halcrow 2015-04-12 1059 if (PageUptodate(page)) { 2058f83a728adf Michael Halcrow 2015-04-12 1060 clear_buffer_new(bh); 2058f83a728adf Michael Halcrow 2015-04-12 1061 set_buffer_uptodate(bh); 2058f83a728adf Michael Halcrow 2015-04-12 1062 mark_buffer_dirty(bh); 2058f83a728adf Michael Halcrow 2015-04-12 1063 continue; 2058f83a728adf Michael Halcrow 2015-04-12 1064 } 2058f83a728adf Michael Halcrow 2015-04-12 1065 if (block_end > to || block_start < from) 2058f83a728adf Michael Halcrow 2015-04-12 1066 zero_user_segments(page, to, block_end, 2058f83a728adf Michael Halcrow 2015-04-12 1067 block_start, from); 2058f83a728adf Michael Halcrow 2015-04-12 1068 continue; 2058f83a728adf Michael Halcrow 2015-04-12 1069 } 2058f83a728adf Michael Halcrow 2015-04-12 1070 } 2058f83a728adf Michael Halcrow 2015-04-12 1071 if (PageUptodate(page)) { 2058f83a728adf Michael Halcrow 2015-04-12 1072 if (!buffer_uptodate(bh)) 2058f83a728adf Michael Halcrow 2015-04-12 1073 set_buffer_uptodate(bh); 2058f83a728adf Michael Halcrow 2015-04-12 1074 continue; 2058f83a728adf Michael Halcrow 2015-04-12 1075 } 2058f83a728adf Michael Halcrow 2015-04-12 1076 if (!buffer_uptodate(bh) && !buffer_delay(bh) && 2058f83a728adf Michael Halcrow 2015-04-12 1077 !buffer_unwritten(bh) && 2058f83a728adf Michael Halcrow 2015-04-12 1078 (block_start < from || block_end > to)) { dfec8a14fc9043 Mike Christie 2016-06-05 1079 ll_rw_block(REQ_OP_READ, 0, 1, &bh); 0b578f358a6a7a Chandan Rajendra 2019-05-20 1080 wait[nr_wait++] = bh; 2058f83a728adf Michael Halcrow 2015-04-12 1081 } 2058f83a728adf Michael Halcrow 2015-04-12 1082 } 2058f83a728adf Michael Halcrow 2015-04-12 1083 /* 2058f83a728adf Michael Halcrow 2015-04-12 1084 * If we issued read requests, let them complete. 2058f83a728adf Michael Halcrow 2015-04-12 1085 */ 0b578f358a6a7a Chandan Rajendra 2019-05-20 1086 for (i = 0; i < nr_wait; i++) { 0b578f358a6a7a Chandan Rajendra 2019-05-20 1087 wait_on_buffer(wait[i]); 0b578f358a6a7a Chandan Rajendra 2019-05-20 1088 if (!buffer_uptodate(wait[i])) 2058f83a728adf Michael Halcrow 2015-04-12 1089 err = -EIO; 2058f83a728adf Michael Halcrow 2015-04-12 1090 } 7e0785fce14f75 Chandan Rajendra 2019-05-20 1091 if (unlikely(err)) { 2058f83a728adf Michael Halcrow 2015-04-12 1092 page_zero_new_buffers(page, from, to); 0b578f358a6a7a Chandan Rajendra 2019-05-20 1093 } else if (IS_ENCRYPTED(inode) && S_ISREG(inode->i_mode)) { 0b578f358a6a7a Chandan Rajendra 2019-05-20 1094 for (i = 0; i < nr_wait; i++) { 0b578f358a6a7a Chandan Rajendra 2019-05-20 1095 int err2; 0b578f358a6a7a Chandan Rajendra 2019-05-20 1096 0b578f358a6a7a Chandan Rajendra 2019-05-20 @1097 err2 = fscrypt_decrypt_pagecache_blocks(page, blocksize, 0b578f358a6a7a Chandan Rajendra 2019-05-20 1098 bh_offset(wait[i])); 0b578f358a6a7a Chandan Rajendra 2019-05-20 1099 if (err2) { 0b578f358a6a7a Chandan Rajendra 2019-05-20 1100 clear_buffer_uptodate(wait[i]); 0b578f358a6a7a Chandan Rajendra 2019-05-20 1101 err = err2; 0b578f358a6a7a Chandan Rajendra 2019-05-20 1102 } 0b578f358a6a7a Chandan Rajendra 2019-05-20 1103 } 7e0785fce14f75 Chandan Rajendra 2019-05-20 1104 } 7e0785fce14f75 Chandan Rajendra 2019-05-20 1105 2058f83a728adf Michael Halcrow 2015-04-12 1106 return err; 2058f83a728adf Michael Halcrow 2015-04-12 1107 } 2058f83a728adf Michael Halcrow 2015-04-12 1108 #endif 2058f83a728adf Michael Halcrow 2015-04-12 1109 :::::: The code at line 1097 was first introduced by commit :::::: 0b578f358a6a7afee2ddc48dd39c2972726187de ext4: decrypt only the needed blocks in ext4_block_write_begin() :::::: TO: Chandan Rajendra <chandan@linux.ibm.com> :::::: CC: Eric Biggers <ebiggers@google.com> --- 0-DAY kernel test infrastructure Open Source Technology Center https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org Intel Corporation
diff --git a/fs/buffer.c b/fs/buffer.c index d8c7242426bb..eb3553fb5877 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -47,10 +47,13 @@ #include <linux/pagevec.h> #include <linux/sched/mm.h> #include <trace/events/block.h> -#include <linux/fscrypt.h> #include "internal.h" +void (*end_buffer_async_read_io)(struct buffer_head *bh, int uptodate) = + end_buffer_async_read; +EXPORT_SYMBOL_GPL(end_buffer_async_read_io); + static int fsync_buffers_list(spinlock_t *lock, struct list_head *list); static int submit_bh_wbc(int op, int op_flags, struct buffer_head *bh, enum rw_hint hint, struct writeback_control *wbc); @@ -249,7 +252,11 @@ __find_get_block_slow(struct block_device *bdev, sector_t block) return ret; } -static void end_buffer_async_read(struct buffer_head *bh, int uptodate) +/* + * I/O completion handler for block_read_full_page() - pages + * which come unlocked at the end of I/O. + */ +void end_buffer_async_read(struct buffer_head *bh, int uptodate) { unsigned long flags; struct buffer_head *first; @@ -305,47 +312,7 @@ static void end_buffer_async_read(struct buffer_head *bh, int uptodate) local_irq_restore(flags); return; } - -struct decrypt_bh_ctx { - struct work_struct work; - struct buffer_head *bh; -}; - -static void decrypt_bh(struct work_struct *work) -{ - struct decrypt_bh_ctx *ctx = - container_of(work, struct decrypt_bh_ctx, work); - struct buffer_head *bh = ctx->bh; - int err; - - err = fscrypt_decrypt_pagecache_blocks(bh->b_page, bh->b_size, - bh_offset(bh)); - end_buffer_async_read(bh, err == 0); - kfree(ctx); -} - -/* - * I/O completion handler for block_read_full_page() - pages - * which come unlocked at the end of I/O. - */ -static void end_buffer_async_read_io(struct buffer_head *bh, int uptodate) -{ - /* Decrypt if needed */ - if (uptodate && IS_ENABLED(CONFIG_FS_ENCRYPTION) && - IS_ENCRYPTED(bh->b_page->mapping->host) && - S_ISREG(bh->b_page->mapping->host->i_mode)) { - struct decrypt_bh_ctx *ctx = kmalloc(sizeof(*ctx), GFP_ATOMIC); - - if (ctx) { - INIT_WORK(&ctx->work, decrypt_bh); - ctx->bh = bh; - fscrypt_enqueue_decrypt_work(&ctx->work); - return; - } - uptodate = 0; - } - end_buffer_async_read(bh, uptodate); -} +EXPORT_SYMBOL_GPL(end_buffer_async_read); /* * Completion handler for block_write_full_page() - pages which are unlocked @@ -419,7 +386,11 @@ EXPORT_SYMBOL(end_buffer_async_write); */ static void mark_buffer_async_read(struct buffer_head *bh) { - bh->b_end_io = end_buffer_async_read_io; + bh->b_end_io = end_buffer_async_read; + if (IS_ENABLED(CONFIG_FS_ENCRYPTION) && + IS_ENCRYPTED(bh->b_page->mapping->host) && + S_ISREG(bh->b_page->mapping->host->i_mode)) + bh->b_end_io = end_buffer_async_read_io; set_buffer_async_read(bh); } diff --git a/fs/crypto/Kconfig b/fs/crypto/Kconfig index ff5a1746cbae..5c32902ed50f 100644 --- a/fs/crypto/Kconfig +++ b/fs/crypto/Kconfig @@ -1,6 +1,16 @@ # SPDX-License-Identifier: GPL-2.0-only config FS_ENCRYPTION bool "FS Encryption (Per-file encryption)" + select KEYS + help + Enable encryption of files and directories. This + feature is similar to ecryptfs, but it is more memory + efficient since it avoids caching the encrypted and + decrypted pages in the page cache. Currently Ext4, + F2FS and UBIFS make use of this feature. + +config FS_ENCRYPTION_TRI + tristate select CRYPTO select CRYPTO_AES select CRYPTO_CBC @@ -9,10 +19,3 @@ config FS_ENCRYPTION select CRYPTO_CTS select CRYPTO_SHA512 select CRYPTO_HMAC - select KEYS - help - Enable encryption of files and directories. This - feature is similar to ecryptfs, but it is more memory - efficient since it avoids caching the encrypted and - decrypted pages in the page cache. Currently Ext4, - F2FS and UBIFS make use of this feature. diff --git a/fs/crypto/Makefile b/fs/crypto/Makefile index 232e2bb5a337..9e0513e8626f 100644 --- a/fs/crypto/Makefile +++ b/fs/crypto/Makefile @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0-only -obj-$(CONFIG_FS_ENCRYPTION) += fscrypto.o +obj-$(CONFIG_FS_ENCRYPTION_TRI) += fscrypto.o fscrypto-y := crypto.o \ fname.o \ diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c index 3719efa546c6..6bf7f05120bd 100644 --- a/fs/crypto/crypto.c +++ b/fs/crypto/crypto.c @@ -20,6 +20,7 @@ * Special Publication 800-38E and IEEE P1619/D16. */ +#include <linux/buffer_head.h> #include <linux/pagemap.h> #include <linux/mempool.h> #include <linux/module.h> @@ -286,6 +287,41 @@ int fscrypt_decrypt_block_inplace(const struct inode *inode, struct page *page, } EXPORT_SYMBOL(fscrypt_decrypt_block_inplace); +struct decrypt_bh_ctx { + struct work_struct work; + struct buffer_head *bh; +}; + +static void decrypt_bh(struct work_struct *work) +{ + struct decrypt_bh_ctx *ctx = + container_of(work, struct decrypt_bh_ctx, work); + struct buffer_head *bh = ctx->bh; + int err; + + err = fscrypt_decrypt_pagecache_blocks(bh->b_page, bh->b_size, + bh_offset(bh)); + end_buffer_async_read(bh, err == 0); + kfree(ctx); +} + +static void fscrypt_end_buffer_async_read(struct buffer_head *bh, int uptodate) +{ + /* Decrypt if needed */ + if (uptodate) { + struct decrypt_bh_ctx *ctx = kmalloc(sizeof(*ctx), GFP_ATOMIC); + + if (ctx) { + INIT_WORK(&ctx->work, decrypt_bh); + ctx->bh = bh; + fscrypt_enqueue_decrypt_work(&ctx->work); + return; + } + uptodate = 0; + } + end_buffer_async_read(bh, uptodate); +} + /* * Validate dentries in encrypted directories to make sure we aren't potentially * caching stale dentries after a key has been added. @@ -418,6 +454,8 @@ static int __init fscrypt_init(void) if (err) goto fail_free_info; + end_buffer_async_read_io = fscrypt_end_buffer_async_read; + return 0; fail_free_info: @@ -427,4 +465,18 @@ static int __init fscrypt_init(void) fail: return err; } -late_initcall(fscrypt_init) +module_init(fscrypt_init) + +/** + * fscrypt_exit() - Shutdown the fs encryption system + */ +static void __exit fscrypt_exit(void) +{ + end_buffer_async_read_io = end_buffer_async_read; + + kmem_cache_destroy(fscrypt_info_cachep); + destroy_workqueue(fscrypt_read_workqueue); +} +module_exit(fscrypt_exit); + +MODULE_LICENSE("GPL"); diff --git a/fs/ext4/Kconfig b/fs/ext4/Kconfig index ef42ab040905..5de0bcc50d37 100644 --- a/fs/ext4/Kconfig +++ b/fs/ext4/Kconfig @@ -10,6 +10,7 @@ config EXT3_FS select CRC16 select CRYPTO select CRYPTO_CRC32C + select FS_ENCRYPTION_TRI if FS_ENCRYPTION help This config option is here only for backward compatibility. ext3 filesystem is now handled by the ext4 driver. diff --git a/fs/f2fs/Kconfig b/fs/f2fs/Kconfig index 652fd2e2b23d..9ccaec60af47 100644 --- a/fs/f2fs/Kconfig +++ b/fs/f2fs/Kconfig @@ -6,6 +6,7 @@ config F2FS_FS select CRYPTO select CRYPTO_CRC32 select F2FS_FS_XATTR if FS_ENCRYPTION + select FS_ENCRYPTION_TRI if FS_ENCRYPTION help F2FS is based on Log-structured File System (LFS), which supports versatile "flash-friendly" features. The design has been focused on diff --git a/fs/ubifs/Kconfig b/fs/ubifs/Kconfig index 69932bcfa920..ea2d43829c18 100644 --- a/fs/ubifs/Kconfig +++ b/fs/ubifs/Kconfig @@ -12,6 +12,7 @@ config UBIFS_FS select CRYPTO_ZSTD if UBIFS_FS_ZSTD select CRYPTO_HASH_INFO select UBIFS_FS_XATTR if FS_ENCRYPTION + select FS_ENCRYPTION_TRI if FS_ENCRYPTION depends on MTD_UBI help UBIFS is a file system for flash devices which works on top of UBI. diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h index 7b73ef7f902d..66249a98e003 100644 --- a/include/linux/buffer_head.h +++ b/include/linux/buffer_head.h @@ -164,6 +164,8 @@ void create_empty_buffers(struct page *, unsigned long, unsigned long b_state); void end_buffer_read_sync(struct buffer_head *bh, int uptodate); void end_buffer_write_sync(struct buffer_head *bh, int uptodate); +extern void (*end_buffer_async_read_io)(struct buffer_head *bh, int uptodate); +void end_buffer_async_read(struct buffer_head *bh, int uptodate); void end_buffer_async_write(struct buffer_head *bh, int uptodate); /* Things to do with buffers at mapping->private_list */
The commit 643fa9612bf1 ("fscrypt: remove filesystem specific build config option") removed modular support for fs/crypto. This causes the Crypto API to be built-in whenever fscrypt is enabled. This makes it very difficult for me to test modular builds of the Crypto API without disabling fscrypt which is a pain. AFAICS there is no reason why fscrypt has to be built-in. The commit above appears to have done this way purely for the sake of simplicity. In fact some simple Kconfig tweaking is sufficient to retain a single FS_ENCRYPTION option while maintaining modularity. This patch restores modular support to fscrypt by adding a new hidden FS_ENCRYPTION_TRI tristate option that is selected by all the FS_ENCRYPTION users. Subsequent to the above commit, some core code has been introduced to fs/buffer.c that makes restoring modular support non-trivial. This patch deals with this by adding a function pointer that defaults to end_buffer_async_read function until fscrypt is loaded. When fscrypt is loaded it modifies the function pointer to its own function which used to be end_buffer_async_read_io but now resides in fscrypt. When it is unloaded the function pointer is restored. In order for this to be safe with respect to module removal, the check for whether the host inode is encrypted has been moved into mark_buffer_async_read. The assumption is that as long as the bh is alive the calling filesystem module will be resident. The calling filesystem would then guarantee that fscrypt is loaded. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>