fscrypt: add support for data_unit_size < fs_block_size
Subsystems (8)
Eric Biggers
maintainerv3 cover fscrypt: add support for data_unit_size < fs_block_size
This patchset adds support for configuring the granularity of file contents encryption (a.k.a. the "crypto data unit size") to be less than the filesystem block size on ext4 and f2fs. The main use case for this is to support inline crypto hardware that only supports a data unit size that is less than the FS block size being used. Another possible use case is to support direct I/O on encrypted files without the FS block alignment restriction. Note that decreasing the crypto data unit size decreases efficiency, so this feature should only be used when needed.
For full details, see patch 5 which adds the actual feature. Patches 1-4 are preparatory patches.
I've written an xfstest that verifies that when a sub-block data unit size is selected, the data on-disk is encrypted correctly with that data unit size. I'll be sending that out separately. Other testing of this patchset with xfstests has gone well, though it turns out that some additional changes will be needed for a sub-block data unit size to work with the IV_INO_LBLK_* encryption settings. See patch 5 for details. This patchset focuses on basic sub-block data unit size support first.
This patchset will cause some conflicts in the extent-based encryption patches that the btrfs folks are working on, as both are touching file contents encryption, but logically they are orthogonal features.
This patchset is based on v6.6-rc3.
Changed in v3:
- Shortened 'legacy_key_prefix_for_backcompat' to 'legacy_key_prefix'
- Other miscellaneous cleanups
- Rebased onto v6.6-rc3
Changed in v2:
- Rebased onto v6.6-rc1 and took into account CephFS's recent addition of support for fscrypt
- Narrowed the focus somewhat by dropping the attempted support for IV_INO_LBLK_32 and clearly documenting what is considered out of scope for now
- Other cleanups
Eric Biggers (5):
fscrypt: make it clearer that key_prefix is deprecated
fscrypt: make the bounce page pool opt-in instead of opt-out
fscrypt: compute max_lblk_bits from s_maxbytes and block size
fscrypt: replace get_ino_and_lblk_bits with just has_32bit_inodes
fscrypt: support crypto data unit size less than filesystem block size
Documentation/filesystems/fscrypt.rst | 117 ++++++++++++++------ fs/ceph/crypto.c | 1 + fs/crypto/bio.c | 39 ++++--- fs/crypto/crypto.c | 148 +++++++++++++++----------- fs/crypto/fscrypt_private.h | 58 ++++++++-- fs/crypto/inline_crypt.c | 19 ++-- fs/crypto/keysetup.c | 5 + fs/crypto/keysetup_v1.c | 5 +- fs/crypto/policy.c | 73 +++++++++---- fs/ext4/crypto.c | 13 +-- fs/f2fs/super.c | 13 +-- fs/ubifs/crypto.c | 3 +- include/linux/fscrypt.h | 72 ++++++++----- include/uapi/linux/fscrypt.h | 3 +- 14 files changed, 364 insertions(+), 205 deletions(-)
base-commit: 6465e260f48790807eef06b583b38ca9789b6072
Signature · 8 lines
2.42.0 _______________________________________________ Linux-f2fs-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
Eric Biggers
maintainerPATCH v3 1/5 fscrypt: make it clearer that key_prefix is deprecated
From: Eric Biggers <[email protected]>
fscrypt_operations::key_prefix should not be set by any filesystems that aren't setting it already. This is already documented, but apparently it's not sufficiently clear, as both ceph and btrfs have tried to set it. Rename the field to legacy_key_prefix and improve the documentation to hopefully make it clearer.
--- fs/crypto/keysetup_v1.c | 5 +++-- fs/ext4/crypto.c | 2 +- fs/f2fs/super.c | 2 +- fs/ubifs/crypto.c | 2 +- include/linux/fscrypt.h | 14 +++++++++----- 5 files changed, 15 insertions(+), 10 deletions(-)
fs/crypto/keysetup_v1.c +3 -2
@@ -292,29 +292,30 @@ static int setup_v1_file_key_derived(struct fscrypt_info *ci,int fscrypt_setup_v1_file_key (struct fscrypt_info *ci,const u8 *raw_master_key) {if (ci->ci_policy.v1.flags &FSCRYPT_POLICY_FLAG_DIRECT_KEY )return setup_v1_file_key_direct (ci, raw_master_key);else return setup_v1_file_key_derived (ci, raw_master_key); }int fscrypt_setup_v1_file_key_via_subscribed_keyrings (struct fscrypt_info *ci) { +const struct super_block *sb = ci->ci_inode->i_sb;struct key *key;const struct fscrypt_key *payload;int err; key =find_and_lock_process_key (FSCRYPT_KEY_DESC_PREFIX , ci->ci_policy.v1.master_key_descriptor, ci->ci_mode->keysize, &payload); -if (key ==ERR_PTR (-ENOKEY ) && ci->ci_inode->i_sb->s_cop->key_prefix) { - key =find_and_lock_process_key (ci->ci_inode->i_sb->s_cop->key_prefix, +if (key ==ERR_PTR (-ENOKEY ) && sb->s_cop->legacy_key_prefix) { + key =find_and_lock_process_key (sb->s_cop->legacy_key_prefix, ci->ci_policy.v1.master_key_descriptor, ci->ci_mode->keysize, &payload); }if (IS_ERR (key))return PTR_ERR (key); err =fscrypt_setup_v1_file_key (ci, payload->raw);up_read (&key->sem);key_put (key);return err;
fs/ext4/crypto.c +1 -1
@@ -233,18 +233,18 @@ static bool ext4_has_stable_inodes(struct super_block *sb) }static void ext4_get_ino_and_lblk_bits (struct super_block *sb,int *ino_bits_ret,int *lblk_bits_ret) { *ino_bits_ret =8 *sizeof (EXT4_SB (sb)->s_es->s_inodes_count); *lblk_bits_ret =8 *sizeof (ext4_lblk_t); }const struct fscrypt_operations ext4_cryptops = { - .key_prefix ="ext4:" , + .legacy_key_prefix ="ext4:" , .get_context = ext4_get_context, .set_context = ext4_set_context, .get_dummy_policy = ext4_get_dummy_policy, .empty_dir = ext4_empty_dir, .has_stable_inodes = ext4_has_stable_inodes, .get_ino_and_lblk_bits = ext4_get_ino_and_lblk_bits, };
fs/f2fs/super.c +1 -1
@@ -3224,21 +3224,21 @@ static struct block_device **f2fs_get_devices(struct super_block *sb,if (!devs)return ERR_PTR (-ENOMEM );for (i =0 ; i < sbi->s_ndevs; i++) devs[i] =FDEV (i).bdev; *num_devs = sbi->s_ndevs; return devs; }static const struct fscrypt_operations f2fs_cryptops = { - .key_prefix ="f2fs:" , + .legacy_key_prefix ="f2fs:" , .get_context = f2fs_get_context, .set_context = f2fs_set_context, .get_dummy_policy = f2fs_get_dummy_policy, .empty_dir = f2fs_empty_dir, .has_stable_inodes = f2fs_has_stable_inodes, .get_ino_and_lblk_bits = f2fs_get_ino_and_lblk_bits, .get_devices = f2fs_get_devices, };#endif
fs/ubifs/crypto.c +1 -1
@@ -82,15 +82,15 @@ int ubifs_decrypt(const struct inode *inode, struct ubifs_data_node *dn,ubifs_err (c,"fscrypt_decrypt_block_inplace() failed: %d" , err);return err; } *out_len = clen;return 0 ; }const struct fscrypt_operations ubifs_crypt_operations = { .flags =FS_CFLG_OWN_PAGES , - .key_prefix ="ubifs:" , + .legacy_key_prefix ="ubifs:" , .get_context = ubifs_crypt_get_context, .set_context = ubifs_crypt_set_context, .empty_dir = ubifs_crypt_empty_dir, };
include/linux/fscrypt.h +9 -5
@@ -66,26 +66,30 @@ struct fscrypt_name {*/ #define FS_CFLG_OWN_PAGES (1U << 1)/* Crypto operations for filesystems */ struct fscrypt_operations {/* Set of optional flags; see above for allowed flags */ unsigned int flags;/* -* If set, this is a filesystem-specific key description prefix that -* will be accepted for "logon" keys for v1 fscrypt policies, in -* addition to the generic prefix "fscrypt:". This functionality is -* deprecated, so new filesystems shouldn't set this field. +* This field exists only for backwards compatibility reasons and should +* only be set by the filesystems that are setting it already. It +* contains the filesystem-specific key description prefix that is +* accepted for "logon" keys for v1 fscrypt policies. This +* functionality is deprecated in favor of the generic prefix +* "fscrypt:", which itself is deprecated in favor of the filesystem +* keyring ioctls such as FS_IOC_ADD_ENCRYPTION_KEY. Filesystems that +* are newly adding fscrypt support should not set this field. */ -const char *key_prefix; +const char *legacy_key_prefix;/* * Get the fscrypt context of the given inode. * * @inode: the inode whose context to get * @ctx: the buffer into which to get the context * @len: length of the @ctx buffer in bytes * * Return: On success, returns the length of the context in bytes; this * may be less than @len. On failure, returns -ENODATA if the
base-commit: 6465e260f48790807eef06b583b38ca9789b6072
Signature · 1 line
2.42.0
Eric Biggers
maintainerPATCH v3 2/5 fscrypt: make the bounce page pool opt-in instead of opt-out
In reply to Eric BiggersFrom: Eric Biggers <[email protected]>
Replace FS_CFLG_OWN_PAGES with a bit flag 'needs_bounce_pages' which has the opposite meaning. I.e., filesystems now opt into the bounce page pool instead of opt out. Make fscrypt_alloc_bounce_page() check that the bounce page pool has been initialized.
I believe the opt-in makes more sense, since nothing else in fscrypt_operations is opt-out, and these days filesystems can choose to use blk-crypto which doesn't need the fscrypt bounce page pool. Also, I happen to be planning to add two more flags, and I wanted to fix the "FS_CFLG_" name anyway as it wasn't prefixed with "FSCRYPT_".
--- fs/ceph/crypto.c | 1 + fs/crypto/crypto.c | 9 ++++++++- fs/ext4/crypto.c | 1 + fs/f2fs/super.c | 1 + fs/ubifs/crypto.c | 1 - include/linux/fscrypt.h | 20 +++++++++++--------- 6 files changed, 22 insertions(+), 11 deletions(-)
fs/ceph/crypto.c +1 -0
@@ -126,20 +126,21 @@ static bool ceph_crypt_empty_dir(struct inode *inode)return ci->i_rsubdirs + ci->i_rfiles ==1 ; }static const union fscrypt_policy *ceph_get_dummy_policy (struct super_block *sb) {return ceph_sb_to_client (sb)->fsc_dummy_enc_policy.policy; }static struct fscrypt_operations ceph_fscrypt_ops = { + .needs_bounce_pages =1 , .get_context = ceph_crypt_get_context, .set_context = ceph_crypt_set_context, .get_dummy_policy = ceph_get_dummy_policy, .empty_dir = ceph_crypt_empty_dir, };void ceph_fscrypt_set_ops (struct super_block *sb) {fscrypt_set_ops (sb, &ceph_fscrypt_ops); }
fs/crypto/crypto.c +8 -1
@@ -42,20 +42,27 @@ static DEFINE_MUTEX(fscrypt_init_mutex);struct kmem_cache *fscrypt_info_cachep;void fscrypt_enqueue_decrypt_work (struct work_struct *work) {queue_work (fscrypt_read_workqueue, work); }EXPORT_SYMBOL (fscrypt_enqueue_decrypt_work);struct page *fscrypt_alloc_bounce_page (gfp_t gfp_flags) { +if (WARN_ON_ONCE (!fscrypt_bounce_page_pool)) { +/* +* Oops, the filesystem called a function that uses the bounce +* page pool, but it didn't set needs_bounce_pages. +*/ +return NULL ; + }return mempool_alloc (fscrypt_bounce_page_pool, gfp_flags); }/** * fscrypt_free_bounce_page() - free a ciphertext bounce page * @bounce_page: the bounce page to free, or NULL * * Free a bounce page that was allocated by fscrypt_encrypt_pagecache_blocks(), * or by fscrypt_alloc_bounce_page() directly. */
@@ -318,21 +325,21 @@ EXPORT_SYMBOL(fscrypt_decrypt_block_inplace);int fscrypt_initialize (struct super_block *sb) {int err =0 ;mempool_t *pool;/* pairs with smp_store_release() below */ if (likely (smp_load_acquire (&fscrypt_bounce_page_pool)))return 0 ;/* No need to allocate a bounce page pool if this FS won't use it. */ -if (sb->s_cop->flags &FS_CFLG_OWN_PAGES ) +if (!sb->s_cop->needs_bounce_pages)return 0 ;mutex_lock (&fscrypt_init_mutex);if (fscrypt_bounce_page_pool) goto out_unlock; err = -ENOMEM ; pool =mempool_create_page_pool (num_prealloc_crypto_pages,0 );if (!pool) goto out_unlock;
fs/ext4/crypto.c +1 -0
@@ -233,18 +233,19 @@ static bool ext4_has_stable_inodes(struct super_block *sb) }static void ext4_get_ino_and_lblk_bits (struct super_block *sb,int *ino_bits_ret,int *lblk_bits_ret) { *ino_bits_ret =8 *sizeof (EXT4_SB (sb)->s_es->s_inodes_count); *lblk_bits_ret =8 *sizeof (ext4_lblk_t); }const struct fscrypt_operations ext4_cryptops = { + .needs_bounce_pages =1 , .legacy_key_prefix ="ext4:" , .get_context = ext4_get_context, .set_context = ext4_set_context, .get_dummy_policy = ext4_get_dummy_policy, .empty_dir = ext4_empty_dir, .has_stable_inodes = ext4_has_stable_inodes, .get_ino_and_lblk_bits = ext4_get_ino_and_lblk_bits, };
fs/f2fs/super.c +1 -0
@@ -3224,20 +3224,21 @@ static struct block_device **f2fs_get_devices(struct super_block *sb,if (!devs)return ERR_PTR (-ENOMEM );for (i =0 ; i < sbi->s_ndevs; i++) devs[i] =FDEV (i).bdev; *num_devs = sbi->s_ndevs; return devs; }static const struct fscrypt_operations f2fs_cryptops = { + .needs_bounce_pages =1 , .legacy_key_prefix ="f2fs:" , .get_context = f2fs_get_context, .set_context = f2fs_set_context, .get_dummy_policy = f2fs_get_dummy_policy, .empty_dir = f2fs_empty_dir, .has_stable_inodes = f2fs_has_stable_inodes, .get_ino_and_lblk_bits = f2fs_get_ino_and_lblk_bits, .get_devices = f2fs_get_devices, };#endif
fs/ubifs/crypto.c +0 -1
@@ -81,16 +81,15 @@ int ubifs_decrypt(const struct inode *inode, struct ubifs_data_node *dn,if (err) {ubifs_err (c,"fscrypt_decrypt_block_inplace() failed: %d" , err);return err; } *out_len = clen;return 0 ; }const struct fscrypt_operations ubifs_crypt_operations = { - .flags =FS_CFLG_OWN_PAGES , .legacy_key_prefix ="ubifs:" , .get_context = ubifs_crypt_get_context, .set_context = ubifs_crypt_set_context, .empty_dir = ubifs_crypt_empty_dir, };
include/linux/fscrypt.h +11 -9
@@ -52,32 +52,34 @@ struct fscrypt_name {#define FSTR_INIT (n, l) { .name = n, .len = l }#define FSTR_TO_QSTR (f) QSTR_INIT((f)->name, (f)->len)#define fname_name (p) ((p)->disk_name.name)#define fname_len (p) ((p)->disk_name.len)/* Maximum value for the third parameter of fscrypt_operations.set_context(). */ #define FSCRYPT_SET_CONTEXT_MAX_SIZE 40 #ifdef CONFIG_FS_ENCRYPTION -/* - * If set, the fscrypt bounce page pool won't be allocated (unless another - * filesystem needs it). Set this if the filesystem always uses its own bounce - * pages for writes and therefore won't need the fscrypt bounce page pool. - */ -#define FS_CFLG_OWN_PAGES (1U << 1) - /* Crypto operations for filesystems */ struct fscrypt_operations { - /* Set of optional flags; see above for allowed flags */ - unsigned int flags; + /* + * If set, then fs/crypto/ will allocate a global bounce page pool the + * first time an encryption key is set up for a file. The bounce page + * pool is required by the following functions: + * + * - fscrypt_encrypt_pagecache_blocks() + * - fscrypt_zeroout_range() for files not using inline crypto + * + * If the filesystem doesn't use those, it doesn't need to set this. + */ + unsigned int needs_bounce_pages : 1; /* * This field exists only for backwards compatibility reasons and should * only be set by the filesystems that are setting it already. It * contains the filesystem-specific key description prefix that is * accepted for "logon" keys for v1 fscrypt policies. This * functionality is deprecated in favor of the generic prefix * "fscrypt:", which itself is deprecated in favor of the filesystem * keyring ioctls such as FS_IOC_ADD_ENCRYPTION_KEY. Filesystems that * are newly adding fscrypt support should not set this field.
Signature · 8 lines
2.42.0 _______________________________________________ Linux-f2fs-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
Eric Biggers
maintainerPATCH v3 3/5 fscrypt: compute max_lblk_bits from s_maxbytes and block size
In reply to Eric BiggersFrom: Eric Biggers <[email protected]>
For a given filesystem, the number of bits used by the maximum file logical block number is computable from the maximum file size and block size. These values are always present in struct super_block. Therefore, compute it this way instead of using the value from fscrypt_operations::get_ino_and_lblk_bits. Since filesystems always have to set the super_block fields anyway, this avoids having to provide this information redundantly via fscrypt_operations.
This change is in preparation for adding support for sub-block data units. For that, the value that is needed will become "the maximum file data unit index". A hardcoded value won't suffice for that; it will need to be computed anyway.
--- fs/crypto/fscrypt_private.h | 10 ++++++++++ fs/crypto/inline_crypt.c | 7 ++----- fs/crypto/policy.c | 18 ++++++++++-------- 3 files changed, 22 insertions(+), 13 deletions(-)
fs/crypto/fscrypt_private.h +10 -0
@@ -289,20 +289,30 @@ union fscrypt_iv {/* per-file nonce; only set in DIRECT_KEY mode */ u8 nonce[FSCRYPT_FILE_NONCE_SIZE ]; };u8 raw[FSCRYPT_MAX_IV_SIZE ];__le64 dun[FSCRYPT_MAX_IV_SIZE /sizeof (__le64)]; };void fscrypt_generate_iv (union fscrypt_iv *iv,u64 lblk_num,const struct fscrypt_info *ci); +/* +* Return the number of bits used by the maximum file logical block number that +* is possible on the given filesystem. +*/ +static inline int +fscrypt_max_file_lblk_bits (const struct super_block *sb) +{ +return fls64 (sb->s_maxbytes -1 ) - sb->s_blocksize_bits; +} +/* fname.c */ bool __fscrypt_fname_encrypted_size (const union fscrypt_policy *policy,u32 orig_len,u32 max_len,u32 *encrypted_len_ret);/* hkdf.c */ struct fscrypt_hkdf {struct crypto_shash *hmac_tfm; };
fs/crypto/inline_crypt.c +2 -5
@@ -34,37 +34,34 @@ static struct block_device **fscrypt_get_devices(struct super_block *sb, devs =kmalloc (sizeof (*devs),GFP_KERNEL );if (!devs)return ERR_PTR (-ENOMEM ); devs[0 ] = sb->s_bdev; *num_devs =1 ;return devs; }static unsigned int fscrypt_get_dun_bytes (const struct fscrypt_info *ci) { -struct super_block *sb = ci->ci_inode->i_sb; +const struct super_block *sb = ci->ci_inode->i_sb;unsigned int flags =fscrypt_policy_flags (&ci->ci_policy); -int ino_bits =64 , lblk_bits =64 ;if (flags &FSCRYPT_POLICY_FLAG_DIRECT_KEY ) return offsetofend(union fscrypt_iv, nonce);if (flags &FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64 )return sizeof (__le64);if (flags &FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32 )return sizeof (__le32);/* Default case: IVs are just the file logical block number */ -if (sb->s_cop->get_ino_and_lblk_bits) - sb->s_cop->get_ino_and_lblk_bits (sb, &ino_bits, &lblk_bits); -return DIV_ROUND_UP (lblk_bits,8 ); +return DIV_ROUND_UP (fscrypt_max_file_lblk_bits (sb),8 ); }/* * Log a message when starting to use blk-crypto (native) or blk-crypto-fallback * for an encryption mode for the first time. This is the blk-crypto * counterpart to the message logged when starting to use the crypto API for the * first time. A limitation is that these messages don't convey which specific * filesystems or files are using each implementation. However, *usually* * systems use just one implementation per mode, which makes these messages * helpful for debugging problems where the "wrong" implementation is used.
fs/crypto/policy.c +10 -8
@@ -112,22 +112,21 @@ static bool supported_direct_key_modes(const struct inode *inode, if (mode->ivsize < offsetofend(union fscrypt_iv, nonce)) {fscrypt_warn (inode,"Direct key flag not allowed with %s" , mode->friendly_name);return false; }return true; }static bool supported_iv_ino_lblk_policy (const struct fscrypt_policy_v2 *policy,const struct inode *inode, -const char *type, -int max_ino_bits,int max_lblk_bits) +const char *type,int max_ino_bits) {struct super_block *sb = inode->i_sb;int ino_bits =64 , lblk_bits =64 ;/* * IV_INO_LBLK_* exist only because of hardware limitations, and * currently the only known use case for them involves AES-256-XTS. * That's also all we test currently. For these reasons, for now only * allow AES-256-XTS here. This can be relaxed later if a use case for * IV_INO_LBLK_* with other encryption modes arises.
@@ -151,23 +150,28 @@ static bool supported_iv_ino_lblk_policy(const struct fscrypt_policy_v2 *policy,return false; }if (sb->s_cop->get_ino_and_lblk_bits) sb->s_cop->get_ino_and_lblk_bits (sb, &ino_bits, &lblk_bits);if (ino_bits > max_ino_bits) {fscrypt_warn (inode,"Can't use %s policy on filesystem '%s' because its inode numbers are too long" , type, sb->s_id);return false; } -if (lblk_bits > max_lblk_bits) { + +/* +* IV_INO_LBLK_64 and IV_INO_LBLK_32 both require that file logical +* block numbers fit in 32 bits. +*/ +if (fscrypt_max_file_lblk_bits (sb) >32 ) {fscrypt_warn (inode, -"Can't use %s policy on filesystem '%s' because its block numbers are too long" , +"Can't use %s policy on filesystem '%s' because its maximum file size is too large" , type, sb->s_id);return false; }return true; } static bool fscrypt_supported_v1_policy(const struct fscrypt_policy_v1 *policy, const struct inode *inode) { if (!fscrypt_valid_enc_modes_v1(policy->contents_encryption_mode,
@@ -232,33 +236,31 @@ static bool fscrypt_supported_v2_policy(const struct fscrypt_policy_v2 *policy, policy->flags);return false; }if ((policy->flags &FSCRYPT_POLICY_FLAG_DIRECT_KEY ) && !supported_direct_key_modes (inode, policy->contents_encryption_mode, policy->filenames_encryption_mode))return false;if ((policy->flags &FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64 ) && - !supported_iv_ino_lblk_policy (policy, inode,"IV_INO_LBLK_64" , -32 ,32 )) + !supported_iv_ino_lblk_policy (policy, inode,"IV_INO_LBLK_64" ,32 ))return false;/* * IV_INO_LBLK_32 hashes the inode number, so in principle it can * support any ino_bits. However, currently the inode number is gotten * from inode::i_ino which is 'unsigned long'. So for now the * implementation limit is 32 bits. */ if ((policy->flags &FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32 ) && - !supported_iv_ino_lblk_policy (policy, inode,"IV_INO_LBLK_32" , -32 ,32 )) + !supported_iv_ino_lblk_policy (policy, inode,"IV_INO_LBLK_32" ,32 ))return false;if (memchr_inv (policy->__reserved,0 ,sizeof (policy->__reserved))) {fscrypt_warn (inode,"Reserved bits set in encryption policy" );return false; }return true; }
Signature · 8 lines
2.42.0 _______________________________________________ Linux-f2fs-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
Eric Biggers
maintainerPATCH v3 4/5 fscrypt: replace get_ino_and_lblk_bits with just has_32bit_inodes
In reply to Eric BiggersFrom: Eric Biggers <[email protected]>
Now that fs/crypto/ computes the filesystem's lblk_bits from its maximum file size, it is no longer necessary for filesystems to provide lblk_bits via fscrypt_operations::get_ino_and_lblk_bits.
It is still necessary for fs/crypto/ to retrieve ino_bits from the filesystem. However, this is used only to decide whether inode numbers fit in 32 bits. Also, ino_bits is static for all relevant filesystems, i.e. it doesn't depend on the filesystem instance.
Therefore, in the interest of keeping things as simple as possible, replace 'get_ino_and_lblk_bits' with a flag 'has_32bit_inodes'. This can always be changed back to a function if a filesystem needs it to be dynamic, but for now a static flag is all that's needed.
--- fs/crypto/policy.c | 33 +++++++++++++++------------------ fs/ext4/crypto.c | 9 +-------- fs/f2fs/super.c | 9 +-------- include/linux/fscrypt.h | 26 +++++++++++--------------- 4 files changed, 28 insertions(+), 49 deletions(-)
fs/crypto/policy.c +15 -18
@@ -111,25 +111,25 @@ static bool supported_direct_key_modes(const struct inode *inode, if (mode->ivsize < offsetofend(union fscrypt_iv, nonce)) {fscrypt_warn (inode,"Direct key flag not allowed with %s" , mode->friendly_name);return false; }return true; }static bool supported_iv_ino_lblk_policy (const struct fscrypt_policy_v2 *policy, -const struct inode *inode, -const char *type,int max_ino_bits) +const struct inode *inode) { +const char *type = (policy->flags &FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64 ) + ?"IV_INO_LBLK_64" :"IV_INO_LBLK_32" ;struct super_block *sb = inode->i_sb; -int ino_bits =64 , lblk_bits =64 ;/* * IV_INO_LBLK_* exist only because of hardware limitations, and * currently the only known use case for them involves AES-256-XTS. * That's also all we test currently. For these reasons, for now only * allow AES-256-XTS here. This can be relaxed later if a use case for * IV_INO_LBLK_* with other encryption modes arises. */ if (policy->contents_encryption_mode !=FSCRYPT_MODE_AES_256_XTS ) { fscrypt_warn(inode,
@@ -142,23 +142,29 @@ static bool supported_iv_ino_lblk_policy(const struct fscrypt_policy_v2 *policy,* It's unsafe to include inode numbers in the IVs if the filesystem can * potentially renumber inodes, e.g. via filesystem shrinking. */ if (!sb->s_cop->has_stable_inodes || !sb->s_cop->has_stable_inodes (sb)) {fscrypt_warn (inode,"Can't use %s policy on filesystem '%s' because it doesn't have stable inode numbers" , type, sb->s_id);return false; } -if (sb->s_cop->get_ino_and_lblk_bits) - sb->s_cop->get_ino_and_lblk_bits (sb, &ino_bits, &lblk_bits); -if (ino_bits > max_ino_bits) { + +/* +* IV_INO_LBLK_64 and IV_INO_LBLK_32 both require that inode numbers fit +* in 32 bits. In principle, IV_INO_LBLK_32 could support longer inode +* numbers because it hashes the inode number; however, currently the +* inode number is gotten from inode::i_ino which is 'unsigned long'. +* So for now the implementation limit is 32 bits. +*/ +if (!sb->s_cop->has_32bit_inodes) {fscrypt_warn (inode,"Can't use %s policy on filesystem '%s' because its inode numbers are too long" , type, sb->s_id);return false; }/* * IV_INO_LBLK_64 and IV_INO_LBLK_32 both require that file logical * block numbers fit in 32 bits. */
@@ -235,32 +241,23 @@ static bool fscrypt_supported_v2_policy(const struct fscrypt_policy_v2 *policy,fscrypt_warn (inode,"Mutually exclusive encryption flags (0x%02x)" , policy->flags);return false; }if ((policy->flags &FSCRYPT_POLICY_FLAG_DIRECT_KEY ) && !supported_direct_key_modes (inode, policy->contents_encryption_mode, policy->filenames_encryption_mode))return false; -if ((policy->flags &FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64 ) && - !supported_iv_ino_lblk_policy (policy, inode,"IV_INO_LBLK_64" ,32 )) -return false; - -/* -* IV_INO_LBLK_32 hashes the inode number, so in principle it can -* support any ino_bits. However, currently the inode number is gotten -* from inode::i_ino which is 'unsigned long'. So for now the -* implementation limit is 32 bits. -*/ -if ((policy->flags &FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32 ) && - !supported_iv_ino_lblk_policy (policy, inode,"IV_INO_LBLK_32" ,32 )) +if ((policy->flags & (FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64 | +FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32 )) && + !supported_iv_ino_lblk_policy (policy, inode))return false;if (memchr_inv (policy->__reserved,0 ,sizeof (policy->__reserved))) {fscrypt_warn (inode,"Reserved bits set in encryption policy" );return false; }return true; }
fs/ext4/crypto.c +1 -8
@@ -225,27 +225,20 @@ static int ext4_set_context(struct inode *inode, const void *ctx, size_t len,static const union fscrypt_policy *ext4_get_dummy_policy (struct super_block *sb) {return EXT4_SB (sb)->s_dummy_enc_policy.policy; }static bool ext4_has_stable_inodes (struct super_block *sb) {return ext4_has_feature_stable_inodes (sb); } -static void ext4_get_ino_and_lblk_bits (struct super_block *sb, -int *ino_bits_ret,int *lblk_bits_ret) -{ - *ino_bits_ret =8 *sizeof (EXT4_SB (sb)->s_es->s_inodes_count); - *lblk_bits_ret =8 *sizeof (ext4_lblk_t); -} -const struct fscrypt_operations ext4_cryptops = { .needs_bounce_pages =1 , + .has_32bit_inodes =1 , .legacy_key_prefix ="ext4:" , .get_context = ext4_get_context, .set_context = ext4_set_context, .get_dummy_policy = ext4_get_dummy_policy, .empty_dir = ext4_empty_dir, .has_stable_inodes = ext4_has_stable_inodes, - .get_ino_and_lblk_bits = ext4_get_ino_and_lblk_bits, };
fs/f2fs/super.c +1 -8
@@ -3196,27 +3196,20 @@ static int f2fs_set_context(struct inode *inode, const void *ctx, size_t len,static const union fscrypt_policy *f2fs_get_dummy_policy (struct super_block *sb) {return F2FS_OPTION (F2FS_SB (sb)).dummy_enc_policy.policy; }static bool f2fs_has_stable_inodes (struct super_block *sb) {return true; } -static void f2fs_get_ino_and_lblk_bits (struct super_block *sb, -int *ino_bits_ret,int *lblk_bits_ret) -{ - *ino_bits_ret =8 *sizeof (nid_t); - *lblk_bits_ret =8 *sizeof (block_t); -} -static struct block_device **f2fs_get_devices (struct super_block *sb,unsigned int *num_devs) {struct f2fs_sb_info *sbi =F2FS_SB (sb);struct block_device **devs;int i;if (!f2fs_is_multi_device (sbi))return NULL ;
@@ -3225,27 +3218,27 @@ static struct block_device **f2fs_get_devices(struct super_block *sb,return ERR_PTR (-ENOMEM );for (i =0 ; i < sbi->s_ndevs; i++) devs[i] =FDEV (i).bdev; *num_devs = sbi->s_ndevs; return devs; }static const struct fscrypt_operations f2fs_cryptops = { .needs_bounce_pages =1 , + .has_32bit_inodes =1 , .legacy_key_prefix ="f2fs:" , .get_context = f2fs_get_context, .set_context = f2fs_set_context, .get_dummy_policy = f2fs_get_dummy_policy, .empty_dir = f2fs_empty_dir, .has_stable_inodes = f2fs_has_stable_inodes, - .get_ino_and_lblk_bits = f2fs_get_ino_and_lblk_bits, .get_devices = f2fs_get_devices, };#endif static struct inode *f2fs_nfs_get_inode (struct super_block *sb,u64 ino,u32 generation) {struct f2fs_sb_info *sbi =F2FS_SB (sb);struct inode *inode;
include/linux/fscrypt.h +11 -15
@@ -67,20 +67,31 @@ struct fscrypt_operations {* first time an encryption key is set up for a file. The bounce page * pool is required by the following functions: * * - fscrypt_encrypt_pagecache_blocks() * - fscrypt_zeroout_range() for files not using inline crypto * * If the filesystem doesn't use those, it doesn't need to set this. */ unsigned int needs_bounce_pages : 1; +/* +* If set, then fs/crypto/ will allow the use of encryption settings +* that assume inode numbers fit in 32 bits (i.e. +* FSCRYPT_POLICY_FLAG_IV_INO_LBLK_{32,64}), provided that the other +* prerequisites for these settings are also met. This is only useful +* if the filesystem wants to support inline encryption hardware that is +* limited to 32-bit or 64-bit data unit numbers and where programming +* keyslots is very slow. +*/ + unsigned int has_32bit_inodes : 1; +/* * This field exists only for backwards compatibility reasons and should * only be set by the filesystems that are setting it already. It * contains the filesystem-specific key description prefix that is * accepted for "logon" keys for v1 fscrypt policies. This * functionality is deprecated in favor of the generic prefix * "fscrypt:", which itself is deprecated in favor of the filesystem * keyring ioctls such as FS_IOC_ADD_ENCRYPTION_KEY. Filesystems that * are newly adding fscrypt support should not set this field. */
@@ -144,35 +155,20 @@ struct fscrypt_operations {* Filesystems only need to implement this function if they want to * support the FSCRYPT_POLICY_FLAG_IV_INO_LBLK_{32,64} flags. These * flags are designed to work around the limitations of UFS and eMMC * inline crypto hardware, and they shouldn't be used in scenarios where * such hardware isn't being used. * * Leaving this NULL is equivalent to always returning false. */ bool (*has_stable_inodes)(struct super_block *sb); -/* -* Get the number of bits that the filesystem uses to represent inode -* numbers and file logical block numbers. -* -* By default, both of these are assumed to be 64-bit. This function -* can be implemented to declare that either or both of these numbers is -* shorter, which may allow the use of the -* FSCRYPT_POLICY_FLAG_IV_INO_LBLK_{32,64} flags and/or the use of -* inline crypto hardware whose maximum DUN length is less than 64 bits -* (e.g., eMMC v5.2 spec compliant hardware). This function only needs -* to be implemented if support for one of these features is needed. -*/ -void (*get_ino_and_lblk_bits)(struct super_block *sb, -int *ino_bits_ret,int *lblk_bits_ret); -/* * Return an array of pointers to the block devices to which the * filesystem may write encrypted file contents, NULL if the filesystem * only has a single such block device, or an ERR_PTR() on error. * * On successful non-NULL return, *num_devs is set to the number of * devices in the returned array. The caller must free the returned * array using kfree(). * * If the filesystem can use multiple block devices (other than block
Signature · 8 lines
2.42.0 _______________________________________________ Linux-f2fs-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
Eric Biggers
maintainerPATCH v3 5/5 fscrypt: support crypto data unit size less than filesystem block size
In reply to Eric BiggersFrom: Eric Biggers <[email protected]>
Until now, fscrypt has always used the filesystem block size as the granularity of file contents encryption. Two scenarios have come up where a sub-block granularity of contents encryption would be useful:
1. Inline crypto hardware that only supports a crypto data unit size that is less than the filesystem block size.
2. Support for direct I/O at a granularity less than the filesystem block size, for example at the block device's logical block size in order to match the traditional direct I/O alignment requirement.
(1) first came up with older eMMC inline crypto hardware that only supports a crypto data unit size of 512 bytes. That specific case ultimately went away because all systems with that hardware continued using out of tree code and never actually upgraded to the upstream inline crypto framework. But, now it's coming back in a new way: some current UFS controllers only support a data unit size of 4096 bytes, and there is a proposal to increase the filesystem block size to 16K.
(2) was discussed as a "nice to have" feature, though not essential, when support for direct I/O on encrypted files was being upstreamed.
Still, the fact that this feature has come up several times does suggest it would be wise to have available. Therefore, this patch implements it by using one of the reserved bytes in fscrypt_policy_v2 to allow users to select a sub-block data unit size. Supported data unit sizes are powers of 2 between 512 and the filesystem block size, inclusively. Support is implemented for both the FS-layer and inline crypto cases.
This patch focuses on the basic support for sub-block data units. Some things are out of scope for this patch but may be addressed later:
- Supporting sub-block data units in combination with FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64, in most cases. Unfortunately this combination usually causes data unit indices to exceed 32 bits, and thus fscrypt_supported_policy() correctly disallows it. The users who potentially need this combination are using f2fs. To support it, f2fs would need to provide an option to slightly reduce its max file size.
- Supporting sub-block data units in combination with FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32. This has the same problem described above, but also it will need special code to make DUN wraparound still happen on a FS block boundary.
- Supporting use case (2) mentioned above. The encrypted direct I/O code will need to stop requiring and assuming FS block alignment. This won't be hard, but it belongs in a separate patch.
- Supporting this feature on filesystems other than ext4 and f2fs. (Filesystems declare support for it via their fscrypt_operations.) On UBIFS, sub-block data units don't make sense because UBIFS encrypts variable-length blocks as a result of compression. CephFS could support it, but a bit more work would be needed to make the fscrypt_*_block_inplace functions play nicely with sub-block data units. I don't think there's a use case for this on CephFS anyway.
--- Documentation/filesystems/fscrypt.rst | 117 ++++++++++++++++------ fs/crypto/bio.c | 39 ++++---- fs/crypto/crypto.c | 139 ++++++++++++++------------ fs/crypto/fscrypt_private.h | 56 ++++++++--- fs/crypto/inline_crypt.c | 14 ++- fs/crypto/keysetup.c | 5 + fs/crypto/policy.c | 34 ++++++- fs/ext4/crypto.c | 1 + fs/f2fs/super.c | 1 + include/linux/fscrypt.h | 12 +++ include/uapi/linux/fscrypt.h | 3 +- 11 files changed, 288 insertions(+), 133 deletions(-)
Documentation/filesystems/fscrypt.rst +86 -31
@@ -254,23 +254,23 @@ significant advantages to key wrapping. In particular, currently there is no requirement to support unlocking a file with multiple alternative master keys or to support rotating master keys. Instead, the master keys may be wrapped in userspace, e.g. as is done by the `fscrypt <https://github.com/google/fscrypt>`_ tool. DIRECT_KEY policies ------------------- The Adiantum encryption mode (see `Encryption modes and usage`_) is suitable for both contents and filenames encryption, and it accepts -long IVs --- long enough to hold both an 8-byte logical block number -and a 16-byte per-file nonce. Also, the overhead of each Adiantum key -is greater than that of an AES-256-XTS key. +long IVs --- long enough to hold both an 8-byte data unit index and a +16-byte per-file nonce. Also, the overhead of each Adiantum key is +greater than that of an AES-256-XTS key. Therefore, to improve performance and save memory, for Adiantum a "direct key" configuration is supported. When the user has enabled this by setting FSCRYPT_POLICY_FLAG_DIRECT_KEY in the fscrypt policy, per-file encryption keys are not used. Instead, whenever any data (contents or filenames) is encrypted, the file's 16-byte nonce is included in the IV. Moreover: - For v1 encryption policies, the encryption is done directly with the master key. Because of this, users **must not** use the same master
@@ -293,22 +293,22 @@ Consequently, shrinking the filesystem may not be allowed. This format is optimized for use with inline encryption hardware compliant with the UFS standard, which supports only 64 IV bits per I/O request and may have only a small number of keyslots. IV_INO_LBLK_32 policies ----------------------- IV_INO_LBLK_32 policies work like IV_INO_LBLK_64, except that for IV_INO_LBLK_32, the inode number is hashed with SipHash-2-4 (where the -SipHash key is derived from the master key) and added to the file -logical block number mod 2^32 to produce a 32-bit IV. +SipHash key is derived from the master key) and added to the file data +unit index mod 2^32 to produce a 32-bit IV. This format is optimized for use with inline encryption hardware compliant with the eMMC v5.2 standard, which supports only 32 IV bits per I/O request and may have only a small number of keyslots. This format results in some level of IV reuse, so it should only be used when necessary due to hardware limitations. Key identifiers ---------------
@@ -444,45 +444,76 @@ fscrypt also uses HMAC-SHA512 for key derivation, so enabling SHA-512 acceleration is recommended: - SHA-512 - Recommended: - arm64: CONFIG_CRYPTO_SHA512_ARM64_CE - x86: CONFIG_CRYPTO_SHA512_SSSE3 Contents encryption ------------------- -For file contents, each filesystem block is encrypted independently. -Starting from Linux kernel 5.5, encryption of filesystems with block -size less than system's page size is supported. - -Each block's IV is set to the logical block number within the file as -a little endian number, except that: - -- With CBC mode encryption, ESSIV is also used. Specifically, each IV - is encrypted with AES-256 where the AES-256 key is the SHA-256 hash - of the file's data encryption key. - -- With `DIRECT_KEY policies`_, the file's nonce is appended to the IV. - Currently this is only allowed with the Adiantum encryption mode. - -- With `IV_INO_LBLK_64 policies`_, the logical block number is limited - to 32 bits and is placed in bits 0-31 of the IV. The inode number - (which is also limited to 32 bits) is placed in bits 32-63. - -- With `IV_INO_LBLK_32 policies`_, the logical block number is limited - to 32 bits and is placed in bits 0-31 of the IV. The inode number - is then hashed and added mod 2^32. - -Note that because file logical block numbers are included in the IVs, -filesystems must enforce that blocks are never shifted around within -encrypted files, e.g. via "collapse range" or "insert range". +For contents encryption, each file's contents is divided into "data +units". Each data unit is encrypted independently. The IV for each +data unit incorporates the zero-based index of the data unit within +the file. This ensures that each data unit within a file is encrypted +differently, which is essential to prevent leaking information. + +Note: the encryption depending on the offset into the file means that +operations like "collapse range" and "insert range" that rearrange the +extent mapping of files are not supported on encrypted files. + +There are two cases for the sizes of the data units: + +* Fixed-size data units. This is how all filesystems other than UBIFS + work. A file's data units are all the same size; the last data unit + is zero-padded if needed. By default, the data unit size is equal + to the filesystem block size. On some filesystems, users can select + a sub-block data unit size via the ``log2_data_unit_size`` field of + the encryption policy; see `FS_IOC_SET_ENCRYPTION_POLICY`_. + +* Variable-size data units. This is what UBIFS does. Each "UBIFS + data node" is treated as a crypto data unit. Each contains variable + length, possibly compressed data, zero-padded to the next 16-byte + boundary. Users cannot select a sub-block data unit size on UBIFS. + +In the case of compression + encryption, the compressed data is +encrypted. UBIFS compression works as described above. f2fs +compression works a bit differently; it compresses a number of +filesystem blocks into a smaller number of filesystem blocks. +Therefore a f2fs-compressed file still uses fixed-size data units, and +it is encrypted in a similar way to a file containing holes. + +As mentioned in `Key hierarchy`_, the default encryption setting uses +per-file keys. In this case, the IV for each data unit is simply the +index of the data unit in the file. However, users can select an +encryption setting that does not use per-file keys. For these, some +kind of file identifier is incorporated into the IVs as follows: + +- With `DIRECT_KEY policies`_, the data unit index is placed in bits + 0-63 of the IV, and the file's nonce is placed in bits 64-191. + +- With `IV_INO_LBLK_64 policies`_, the data unit index is placed in + bits 0-31 of the IV, and the file's inode number is placed in bits + 32-63. This setting is only allowed when data unit indices and + inode numbers fit in 32 bits. + +- With `IV_INO_LBLK_32 policies`_, the file's inode number is hashed + and added to the data unit index. The resulting value is truncated + to 32 bits and placed in bits 0-31 of the IV. This setting is only + allowed when data unit indices and inode numbers fit in 32 bits. + +The byte order of the IV is always little endian. + +If the user selects FSCRYPT_MODE_AES_128_CBC for the contents mode, an +ESSIV layer is automatically included. In this case, before the IV is +passed to AES-128-CBC, it is encrypted with AES-256 where the AES-256 +key is the SHA-256 hash of the file's contents encryption key. Filenames encryption -------------------- For filenames, each full filename is encrypted at once. Because of the requirements to retain support for efficient directory lookups and filenames of up to 255 bytes, the same IV is used for every filename in a directory. However, each encrypted directory still uses a unique key, or
@@ -537,21 +568,22 @@ follows:: }; #define fscrypt_policy fscrypt_policy_v1 #define FSCRYPT_POLICY_V2 2 #define FSCRYPT_KEY_IDENTIFIER_SIZE 16 struct fscrypt_policy_v2 { __u8 version; __u8 contents_encryption_mode; __u8 filenames_encryption_mode; __u8 flags; - __u8 __reserved[4]; + __u8 log2_data_unit_size; + __u8 __reserved[3]; __u8 master_key_identifier[FSCRYPT_KEY_IDENTIFIER_SIZE]; }; This structure must be initialized as follows: - ``version`` must be FSCRYPT_POLICY_V1 (0) if struct fscrypt_policy_v1 is used or FSCRYPT_POLICY_V2 (2) if struct fscrypt_policy_v2 is used. (Note: we refer to the original policy version as "v1", though its version code is really 0.) For new encrypted directories, use v2 policies.
@@ -579,20 +611,43 @@ This structure must be initialized as follows: policies`_. - FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32: See `IV_INO_LBLK_32 policies`_. v1 encryption policies only support the PAD_* and DIRECT_KEY flags. The other flags are only supported by v2 encryption policies. The DIRECT_KEY, IV_INO_LBLK_64, and IV_INO_LBLK_32 flags are mutually exclusive. +- ``log2_data_unit_size`` is the log2 of the data unit size in bytes, + or 0 to select the default data unit size. The data unit size is + the granularity of file contents encryption. For example, setting + ``log2_data_unit_size`` to 12 causes file contents be passed to the + underlying encryption algorithm (such as AES-256-XTS) in 4096-byte + data units, each with its own IV. + + Not all filesystems support setting ``log2_data_unit_size``. ext4 + and f2fs support it since Linux v6.7. On filesystems that support + it, the supported nonzero values are 9 through the log2 of the + filesystem block size, inclusively. The default value of 0 selects + the filesystem block size. + + The main use case for ``log2_data_unit_size`` is for selecting a + data unit size smaller than the filesystem block size for + compatibility with inline encryption hardware that only supports + smaller data unit sizes. ``/sys/block/$disk/queue/crypto/`` may be + useful for checking which data unit sizes are supported by a + particular system's inline encryption hardware. + + Leave this field zeroed unless you are certain you need it. Using + an unnecessarily small data unit size reduces performance. + - For v2 encryption policies, ``__reserved`` must be zeroed. - For v1 encryption policies, ``master_key_descriptor`` specifies how to find the master key in a keyring; see `Adding keys`_. It is up to userspace to choose a unique ``master_key_descriptor`` for each master key. The e4crypt and fscrypt tools use the first 8 bytes of ``SHA-512(SHA-512(master_key))``, but this particular scheme is not required. Also, the master key need not be in the keyring yet when FS_IOC_SET_ENCRYPTION_POLICY is executed. However, it must be added before any files can be created in the encrypted directory.
fs/crypto/bio.c +22 -17
@@ -104,41 +104,45 @@ static int fscrypt_zeroout_range_inline_crypt(const struct inode *inode,* filesystem only uses a single block device, ->s_bdev. * * Note that since each block uses a different IV, this involves writing a * different ciphertext to each block; we can't simply reuse the same one. * * Return: 0 on success; -errno on failure. */ int fscrypt_zeroout_range (const struct inode *inode,pgoff_t lblk,sector_t pblk,unsigned int len) { -const unsigned int blockbits = inode->i_blkbits; -const unsigned int blocksize =1 << blockbits; -const unsigned int blocks_per_page_bits =PAGE_SHIFT - blockbits; -const unsigned int blocks_per_page =1 << blocks_per_page_bits; +const struct fscrypt_info *ci = inode->i_crypt_info; +const unsigned int du_bits = ci->ci_data_unit_bits; +const unsigned int du_size =1U << du_bits; +const unsigned int du_per_page_bits =PAGE_SHIFT - du_bits; +const unsigned int du_per_page =1U << du_per_page_bits; +u64 du_index = (u64 )lblk << (inode->i_blkbits - du_bits); +u64 du_remaining = (u64 )len << (inode->i_blkbits - du_bits); +sector_t sector = pblk << (inode->i_blkbits -SECTOR_SHIFT );struct page *pages[16 ];/* write up to 16 pages at a time */ unsigned int nr_pages;unsigned int i;unsigned int offset;struct bio *bio;int ret, err;if (len ==0 )return 0 ;if (fscrypt_inode_uses_inline_crypto (inode))return fscrypt_zeroout_range_inline_crypt (inode, lblk, pblk, len);BUILD_BUG_ON (ARRAY_SIZE (pages) >BIO_MAX_VECS ); - nr_pages = min_t(unsigned int, ARRAY_SIZE(pages), - (len + blocks_per_page -1 ) >> blocks_per_page_bits); + nr_pages =min_t (u64,ARRAY_SIZE (pages), + (du_remaining + du_per_page -1 ) >> du_per_page_bits);/* * We need at least one page for ciphertext. Allocate the first one * from a mempool, with __GFP_DIRECT_RECLAIM set so that it can't fail. * * Any additional page allocations are allowed to fail, as they only * help performance, and waiting on the mempool for them could deadlock. */ for (i =0 ; i < nr_pages; i++) { pages[i] = fscrypt_alloc_bounce_page(i == 0 ? GFP_NOFS :
@@ -147,47 +151,48 @@ int fscrypt_zeroout_range(const struct inode *inode, pgoff_t lblk,break ; } nr_pages = i;if (WARN_ON_ONCE (nr_pages <=0 ))return -EINVAL ;/* This always succeeds since __GFP_DIRECT_RECLAIM is set. */ bio =bio_alloc (inode->i_sb->s_bdev, nr_pages,REQ_OP_WRITE ,GFP_NOFS );do { - bio->bi_iter.bi_sector = pblk << (blockbits -9 ); + bio->bi_iter.bi_sector = sector; i =0 ; offset =0 ;do { - err =fscrypt_crypt_block (inode,FS_ENCRYPT , lblk, -ZERO_PAGE (0 ), pages[i], - blocksize, offset,GFP_NOFS ); + err =fscrypt_crypt_data_unit (ci,FS_ENCRYPT , du_index, +ZERO_PAGE (0 ), pages[i], + du_size, offset, +GFP_NOFS );if (err) goto out; - lblk++; - pblk++; - len--; - offset += blocksize; -if (offset ==PAGE_SIZE || len ==0 ) { + du_index++; + sector +=1U << (du_bits -SECTOR_SHIFT ); + du_remaining--; + offset += du_size; +if (offset ==PAGE_SIZE || du_remaining ==0 ) { ret =bio_add_page (bio, pages[i++], offset,0 );if (WARN_ON_ONCE (ret != offset)) { err = -EIO ; goto out; } offset =0 ; } - }while (i != nr_pages && len !=0 ); + }while (i != nr_pages && du_remaining !=0 ); err =submit_bio_wait (bio);if (err) goto out;bio_reset (bio, inode->i_sb->s_bdev,REQ_OP_WRITE ); - }while (len !=0 ); + }while (du_remaining !=0 ); err =0 ; out:bio_put (bio);for (i =0 ; i < nr_pages; i++)fscrypt_free_bounce_page (pages[i]);return err; }EXPORT_SYMBOL (fscrypt_zeroout_range);
fs/crypto/crypto.c +75 -64
321 lines not on this page · raw message
fs/crypto/fscrypt_private.h +44 -12
164 lines not on this page · raw message
fs/crypto/inline_crypt.c +9 -5
@@ -36,32 +36,34 @@ static struct block_device **fscrypt_get_devices(struct super_block *sb,return ERR_PTR (-ENOMEM ); devs[0 ] = sb->s_bdev; *num_devs =1 ;return devs; }static unsigned int fscrypt_get_dun_bytes (const struct fscrypt_info *ci) {const struct super_block *sb = ci->ci_inode->i_sb;unsigned int flags =fscrypt_policy_flags (&ci->ci_policy); +int dun_bits;if (flags &FSCRYPT_POLICY_FLAG_DIRECT_KEY ) return offsetofend(union fscrypt_iv, nonce);if (flags &FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64 )return sizeof (__le64);if (flags &FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32 )return sizeof (__le32); -/* Default case: IVs are just the file logical block number */ -return DIV_ROUND_UP (fscrypt_max_file_lblk_bits (sb),8 ); +/* Default case: IVs are just the file data unit index */ + dun_bits =fscrypt_max_file_dun_bits (sb, ci->ci_data_unit_bits); +return DIV_ROUND_UP (dun_bits,8 ); }/* * Log a message when starting to use blk-crypto (native) or blk-crypto-fallback * for an encryption mode for the first time. This is the blk-crypto * counterpart to the message logged when starting to use the crypto API for the * first time. A limitation is that these messages don't convey which specific * filesystems or files are using each implementation. However, *usually* * systems use just one implementation per mode, which makes these messages * helpful for debugging problems where the "wrong" implementation is used.
@@ -119,21 +121,21 @@ int fscrypt_select_encryption_impl(struct fscrypt_info *ci)if ((fscrypt_policy_flags (&ci->ci_policy) &FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32 ) && sb->s_blocksize !=PAGE_SIZE )return 0 ;/* * On all the filesystem's block devices, blk-crypto must support the * crypto configuration that the file would use. */ crypto_cfg.crypto_mode = ci->ci_mode->blk_crypto_mode; - crypto_cfg.data_unit_size = sb->s_blocksize; + crypto_cfg.data_unit_size =1U << ci->ci_data_unit_bits; crypto_cfg.dun_bytes =fscrypt_get_dun_bytes (ci); devs =fscrypt_get_devices (sb, &num_devs);if (IS_ERR (devs))return PTR_ERR (devs);for (i =0 ; i < num_devs; i++) {if (!blk_crypto_config_supported (devs[i], &crypto_cfg)) goto out_free_devs; }
@@ -158,21 +160,22 @@ int fscrypt_prepare_inline_crypt_key(struct fscrypt_prepared_key *prep_key,struct block_device **devs;unsigned int num_devs;unsigned int i;int err; blk_key =kmalloc (sizeof (*blk_key),GFP_KERNEL );if (!blk_key)return -ENOMEM ; err =blk_crypto_init_key (blk_key, raw_key, crypto_mode, -fscrypt_get_dun_bytes (ci), sb->s_blocksize); +fscrypt_get_dun_bytes (ci), +1U << ci->ci_data_unit_bits);if (err) {fscrypt_err (inode,"error %d initializing blk-crypto key" , err); goto fail; }/* Start using blk-crypto on all the filesystem's block devices. */ devs =fscrypt_get_devices (sb, &num_devs);if (IS_ERR (devs)) { err =PTR_ERR (devs); goto fail;
@@ -225,24 +228,25 @@ void fscrypt_destroy_inline_crypt_key(struct super_block *sb,bool __fscrypt_inode_uses_inline_crypto (const struct inode *inode) {return inode->i_crypt_info->ci_inlinecrypt; }EXPORT_SYMBOL_GPL (__fscrypt_inode_uses_inline_crypto);static void fscrypt_generate_dun (const struct fscrypt_info *ci,u64 lblk_num,u64 dun[BLK_CRYPTO_DUN_ARRAY_SIZE ]) { +u64 index = lblk_num << ci->ci_data_units_per_block_bits;union fscrypt_iv iv;int i; -fscrypt_generate_iv (&iv, lblk_num, ci); +fscrypt_generate_iv (&iv, index, ci);BUILD_BUG_ON (FSCRYPT_MAX_IV_SIZE >BLK_CRYPTO_MAX_IV_SIZE );memset (dun,0 ,BLK_CRYPTO_MAX_IV_SIZE );for (i =0 ; i < ci->ci_mode->ivsize/sizeof (dun[0 ]); i++) dun[i] =le64_to_cpu (iv.dun[i]); }/** * fscrypt_set_bio_crypt_ctx() - prepare a file contents bio for inline crypto * @bio: a bio which will eventually be submitted to the file
fs/crypto/keysetup.c +5 -0
@@ -573,20 +573,25 @@ fscrypt_setup_encryption_info(struct inode *inode,memcpy (crypt_info->ci_nonce, nonce,FSCRYPT_FILE_NONCE_SIZE ); mode =select_encryption_mode (&crypt_info->ci_policy, inode);if (IS_ERR (mode)) { res =PTR_ERR (mode); goto out; }WARN_ON_ONCE (mode->ivsize >FSCRYPT_MAX_IV_SIZE ); crypt_info->ci_mode = mode; + crypt_info->ci_data_unit_bits = +fscrypt_policy_du_bits (&crypt_info->ci_policy, inode); + crypt_info->ci_data_units_per_block_bits = + inode->i_blkbits - crypt_info->ci_data_unit_bits; + res =setup_file_encryption_key (crypt_info, need_dirhash_key, &mk);if (res) goto out;/* * For existing inodes, multiple tasks may race to set ->i_crypt_info. * So use cmpxchg_release(). This pairs with the smp_load_acquire() in * fscrypt_get_info(). I.e., here we publish ->i_crypt_info with a * RELEASE barrier so that other tasks can ACQUIRE it. */
fs/crypto/policy.c +31 -3
@@ -158,24 +158,25 @@ static bool supported_iv_ino_lblk_policy(const struct fscrypt_policy_v2 *policy,* So for now the implementation limit is 32 bits. */ if (!sb->s_cop->has_32bit_inodes) {fscrypt_warn (inode,"Can't use %s policy on filesystem '%s' because its inode numbers are too long" , type, sb->s_id);return false; }/* -* IV_INO_LBLK_64 and IV_INO_LBLK_32 both require that file logical -* block numbers fit in 32 bits. +* IV_INO_LBLK_64 and IV_INO_LBLK_32 both require that file data unit +* indices fit in 32 bits. */ -if (fscrypt_max_file_lblk_bits (sb) >32 ) { +if (fscrypt_max_file_dun_bits (sb, +fscrypt_policy_v2_du_bits (policy, inode)) >32 ) {fscrypt_warn (inode,"Can't use %s policy on filesystem '%s' because its maximum file size is too large" , type, sb->s_id);return false; }return true; }static bool fscrypt_supported_v1_policy (const struct fscrypt_policy_v1 *policy,const struct inode *inode)
@@ -236,20 +237,45 @@ static bool fscrypt_supported_v2_policy(const struct fscrypt_policy_v2 *policy, count += !!(policy->flags &FSCRYPT_POLICY_FLAG_DIRECT_KEY ); count += !!(policy->flags &FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64 ); count += !!(policy->flags &FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32 );if (count >1 ) {fscrypt_warn (inode,"Mutually exclusive encryption flags (0x%02x)" , policy->flags);return false; } +if (policy->log2_data_unit_size) { +if (!inode->i_sb->s_cop->supports_subblock_data_units) { +fscrypt_warn (inode, +"Filesystem does not support configuring crypto data unit size" ); +return false; + } +if (policy->log2_data_unit_size > inode->i_blkbits || + policy->log2_data_unit_size <SECTOR_SHIFT /* 9 */ ) { +fscrypt_warn (inode, +"Unsupported log2_data_unit_size in encryption policy: %d" , + policy->log2_data_unit_size); +return false; + } +if (policy->log2_data_unit_size != inode->i_blkbits && + (policy->flags &FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32 )) { +/* +* Not safe to enable yet, as we need to ensure that DUN +* wraparound can only occur on a FS block boundary. +*/ +fscrypt_warn (inode, +"Sub-block data units not yet supported with IV_INO_LBLK_32" ); +return false; + } + } +if ((policy->flags &FSCRYPT_POLICY_FLAG_DIRECT_KEY ) && !supported_direct_key_modes (inode, policy->contents_encryption_mode, policy->filenames_encryption_mode))return false;if ((policy->flags & (FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64 |FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32 )) && !supported_iv_ino_lblk_policy (policy, inode))return false;
@@ -322,20 +348,21 @@ static int fscrypt_new_context(union fscrypt_context *ctx_u,case FSCRYPT_POLICY_V2 : {const struct fscrypt_policy_v2 *policy = &policy_u->v2;struct fscrypt_context_v2 *ctx = &ctx_u->v2; ctx->version =FSCRYPT_CONTEXT_V2 ; ctx->contents_encryption_mode = policy->contents_encryption_mode; ctx->filenames_encryption_mode = policy->filenames_encryption_mode; ctx->flags = policy->flags; + ctx->log2_data_unit_size = policy->log2_data_unit_size;memcpy (ctx->master_key_identifier, policy->master_key_identifier,sizeof (ctx->master_key_identifier));memcpy (ctx->nonce, nonce,FSCRYPT_FILE_NONCE_SIZE );return sizeof (*ctx); } }BUG (); }
@@ -382,20 +409,21 @@ int fscrypt_policy_from_context(union fscrypt_policy *policy_u,case FSCRYPT_CONTEXT_V2 : {const struct fscrypt_context_v2 *ctx = &ctx_u->v2;struct fscrypt_policy_v2 *policy = &policy_u->v2; policy->version =FSCRYPT_POLICY_V2 ; policy->contents_encryption_mode = ctx->contents_encryption_mode; policy->filenames_encryption_mode = ctx->filenames_encryption_mode; policy->flags = ctx->flags; + policy->log2_data_unit_size = ctx->log2_data_unit_size;memcpy (policy->__reserved, ctx->__reserved,sizeof (policy->__reserved));memcpy (policy->master_key_identifier, ctx->master_key_identifier,sizeof (policy->master_key_identifier));return 0 ; } }/* unreachable */ return -EINVAL ;
fs/ext4/crypto.c +1 -0
@@ -228,17 +228,18 @@ static const union fscrypt_policy *ext4_get_dummy_policy(struct super_block *sb) }static bool ext4_has_stable_inodes (struct super_block *sb) {return ext4_has_feature_stable_inodes (sb); }const struct fscrypt_operations ext4_cryptops = { .needs_bounce_pages =1 , .has_32bit_inodes =1 , + .supports_subblock_data_units =1 , .legacy_key_prefix ="ext4:" , .get_context = ext4_get_context, .set_context = ext4_set_context, .get_dummy_policy = ext4_get_dummy_policy, .empty_dir = ext4_empty_dir, .has_stable_inodes = ext4_has_stable_inodes, };
fs/f2fs/super.c +1 -0
@@ -3219,20 +3219,21 @@ static struct block_device **f2fs_get_devices(struct super_block *sb,for (i =0 ; i < sbi->s_ndevs; i++) devs[i] =FDEV (i).bdev; *num_devs = sbi->s_ndevs; return devs; }static const struct fscrypt_operations f2fs_cryptops = { .needs_bounce_pages =1 , .has_32bit_inodes =1 , + .supports_subblock_data_units =1 , .legacy_key_prefix ="f2fs:" , .get_context = f2fs_get_context, .set_context = f2fs_set_context, .get_dummy_policy = f2fs_get_dummy_policy, .empty_dir = f2fs_empty_dir, .has_stable_inodes = f2fs_has_stable_inodes, .get_devices = f2fs_get_devices, };#endif
include/linux/fscrypt.h +12 -0
@@ -78,20 +78,32 @@ struct fscrypt_operations {* If set, then fs/crypto/ will allow the use of encryption settings * that assume inode numbers fit in 32 bits (i.e. * FSCRYPT_POLICY_FLAG_IV_INO_LBLK_{32,64}), provided that the other * prerequisites for these settings are also met. This is only useful * if the filesystem wants to support inline encryption hardware that is * limited to 32-bit or 64-bit data unit numbers and where programming * keyslots is very slow. */ unsigned int has_32bit_inodes : 1; +/* +* If set, then fs/crypto/ will allow users to select a crypto data unit +* size that is less than the filesystem block size. This is done via +* the log2_data_unit_size field of the fscrypt policy. This flag is +* not compatible with filesystems that encrypt variable-length blocks +* (i.e. blocks that aren't all equal to filesystem's block size), for +* example as a result of compression. It's also not compatible with +* the fscrypt_encrypt_block_inplace() and +* fscrypt_decrypt_block_inplace() functions. +*/ + unsigned int supports_subblock_data_units : 1; +/* * This field exists only for backwards compatibility reasons and should * only be set by the filesystems that are setting it already. It * contains the filesystem-specific key description prefix that is * accepted for "logon" keys for v1 fscrypt policies. This * functionality is deprecated in favor of the generic prefix * "fscrypt:", which itself is deprecated in favor of the filesystem * keyring ioctls such as FS_IOC_ADD_ENCRYPTION_KEY. Filesystems that * are newly adding fscrypt support should not set this field. */
include/uapi/linux/fscrypt.h +2 -1
@@ -64,21 +64,22 @@ struct fscrypt_key {/* * New policy version with HKDF and key verification (recommended). */ #define FSCRYPT_POLICY_V2 2#define FSCRYPT_KEY_IDENTIFIER_SIZE 16struct fscrypt_policy_v2 {__u8 version;__u8 contents_encryption_mode;__u8 filenames_encryption_mode;__u8 flags; -__u8 __reserved[4 ]; +__u8 log2_data_unit_size; +__u8 __reserved[3 ];__u8 master_key_identifier[FSCRYPT_KEY_IDENTIFIER_SIZE ]; };/* Struct passed to FS_IOC_GET_ENCRYPTION_POLICY_EX */ struct fscrypt_get_policy_ex_arg {__u64 policy_size;/* input/output */ union {__u8 version;struct fscrypt_policy_v1 v1;struct fscrypt_policy_v2 v2;
Signature · 8 lines
2.42.0 _______________________________________________ Linux-f2fs-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel