Skip to content

Commit 5fee360

Browse files
Satya Tangiralaebiggers
Satya Tangirala
authored andcommitted
fscrypt: add inline encryption support
Add support for inline encryption to fs/crypto/. With "inline encryption", the block layer handles the decryption/encryption as part of the bio, instead of the filesystem doing the crypto itself via Linux's crypto API. This model is needed in order to take advantage of the inline encryption hardware present on most modern mobile SoCs. To use inline encryption, the filesystem needs to be mounted with '-o inlinecrypt'. Blk-crypto will then be used instead of the traditional filesystem-layer crypto whenever possible to encrypt the contents of any encrypted files in that filesystem. Fscrypt still provides the key and IV to use, and the actual ciphertext on-disk is still the same; therefore it's testable using the existing fscrypt ciphertext verification tests. Note that since blk-crypto has a fallback to Linux's crypto API, and also supports all the encryption modes currently supported by fscrypt, this feature is usable and testable even without actual inline encryption hardware. Per-filesystem changes will be needed to set encryption contexts when submitting bios and to implement the 'inlinecrypt' mount option. This patch just adds the common code. Signed-off-by: Satya Tangirala <[email protected]> Reviewed-by: Jaegeuk Kim <[email protected]> Reviewed-by: Eric Biggers <[email protected]> Reviewed-by: Theodore Ts'o <[email protected]> Link: https://lore.kernel.org/r/[email protected] Co-developed-by: Eric Biggers <[email protected]> Signed-off-by: Eric Biggers <[email protected]>
1 parent 457e7a1 commit 5fee360

File tree

12 files changed

+673
-47
lines changed

12 files changed

+673
-47
lines changed

Documentation/filesystems/fscrypt.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1255,6 +1255,7 @@ f2fs encryption using `kvm-xfstests
12551255
<https://github.com/tytso/xfstests-bld/blob/master/Documentation/kvm-quickstart.md>`_::
12561256

12571257
kvm-xfstests -c ext4,f2fs -g encrypt
1258+
kvm-xfstests -c ext4,f2fs -g encrypt -m inlinecrypt
12581259

12591260
UBIFS encryption can also be tested this way, but it should be done in
12601261
a separate command, and it takes some time for kvm-xfstests to set up
@@ -1276,10 +1277,12 @@ This tests the encrypted I/O paths more thoroughly. To do this with
12761277
kvm-xfstests, use the "encrypt" filesystem configuration::
12771278

12781279
kvm-xfstests -c ext4/encrypt,f2fs/encrypt -g auto
1280+
kvm-xfstests -c ext4/encrypt,f2fs/encrypt -g auto -m inlinecrypt
12791281

12801282
Because this runs many more tests than "-g encrypt" does, it takes
12811283
much longer to run; so also consider using `gce-xfstests
12821284
<https://github.com/tytso/xfstests-bld/blob/master/Documentation/gce-xfstests.md>`_
12831285
instead of kvm-xfstests::
12841286

12851287
gce-xfstests -c ext4/encrypt,f2fs/encrypt -g auto
1288+
gce-xfstests -c ext4/encrypt,f2fs/encrypt -g auto -m inlinecrypt

fs/crypto/Kconfig

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,9 @@ config FS_ENCRYPTION_ALGS
2424
select CRYPTO_SHA256
2525
select CRYPTO_SHA512
2626
select CRYPTO_XTS
27+
28+
config FS_ENCRYPTION_INLINE_CRYPT
29+
bool "Enable fscrypt to use inline crypto"
30+
depends on FS_ENCRYPTION && BLK_INLINE_ENCRYPTION
31+
help
32+
Enable fscrypt to use inline encryption hardware if available.

fs/crypto/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@ fscrypto-y := crypto.o \
1111
policy.o
1212

1313
fscrypto-$(CONFIG_BLOCK) += bio.o
14+
fscrypto-$(CONFIG_FS_ENCRYPTION_INLINE_CRYPT) += inline_crypt.o

fs/crypto/bio.c

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,53 @@ void fscrypt_decrypt_bio(struct bio *bio)
4141
}
4242
EXPORT_SYMBOL(fscrypt_decrypt_bio);
4343

44+
static int fscrypt_zeroout_range_inline_crypt(const struct inode *inode,
45+
pgoff_t lblk, sector_t pblk,
46+
unsigned int len)
47+
{
48+
const unsigned int blockbits = inode->i_blkbits;
49+
const unsigned int blocks_per_page = 1 << (PAGE_SHIFT - blockbits);
50+
struct bio *bio;
51+
int ret, err = 0;
52+
int num_pages = 0;
53+
54+
/* This always succeeds since __GFP_DIRECT_RECLAIM is set. */
55+
bio = bio_alloc(GFP_NOFS, BIO_MAX_PAGES);
56+
57+
while (len) {
58+
unsigned int blocks_this_page = min(len, blocks_per_page);
59+
unsigned int bytes_this_page = blocks_this_page << blockbits;
60+
61+
if (num_pages == 0) {
62+
fscrypt_set_bio_crypt_ctx(bio, inode, lblk, GFP_NOFS);
63+
bio_set_dev(bio, inode->i_sb->s_bdev);
64+
bio->bi_iter.bi_sector =
65+
pblk << (blockbits - SECTOR_SHIFT);
66+
bio_set_op_attrs(bio, REQ_OP_WRITE, 0);
67+
}
68+
ret = bio_add_page(bio, ZERO_PAGE(0), bytes_this_page, 0);
69+
if (WARN_ON(ret != bytes_this_page)) {
70+
err = -EIO;
71+
goto out;
72+
}
73+
num_pages++;
74+
len -= blocks_this_page;
75+
lblk += blocks_this_page;
76+
pblk += blocks_this_page;
77+
if (num_pages == BIO_MAX_PAGES || !len ||
78+
!fscrypt_mergeable_bio(bio, inode, lblk)) {
79+
err = submit_bio_wait(bio);
80+
if (err)
81+
goto out;
82+
bio_reset(bio);
83+
num_pages = 0;
84+
}
85+
}
86+
out:
87+
bio_put(bio);
88+
return err;
89+
}
90+
4491
/**
4592
* fscrypt_zeroout_range() - zero out a range of blocks in an encrypted file
4693
* @inode: the file's inode
@@ -75,6 +122,10 @@ int fscrypt_zeroout_range(const struct inode *inode, pgoff_t lblk,
75122
if (len == 0)
76123
return 0;
77124

125+
if (fscrypt_inode_uses_inline_crypto(inode))
126+
return fscrypt_zeroout_range_inline_crypt(inode, lblk, pblk,
127+
len);
128+
78129
BUILD_BUG_ON(ARRAY_SIZE(pages) > BIO_MAX_PAGES);
79130
nr_pages = min_t(unsigned int, ARRAY_SIZE(pages),
80131
(len + blocks_per_page - 1) >> blocks_per_page_bits);

fs/crypto/crypto.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ int fscrypt_crypt_block(const struct inode *inode, fscrypt_direction_t rw,
100100
DECLARE_CRYPTO_WAIT(wait);
101101
struct scatterlist dst, src;
102102
struct fscrypt_info *ci = inode->i_crypt_info;
103-
struct crypto_skcipher *tfm = ci->ci_ctfm;
103+
struct crypto_skcipher *tfm = ci->ci_enc_key.tfm;
104104
int res = 0;
105105

106106
if (WARN_ON_ONCE(len <= 0))

fs/crypto/fname.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ int fscrypt_fname_encrypt(const struct inode *inode, const struct qstr *iname,
115115
struct skcipher_request *req = NULL;
116116
DECLARE_CRYPTO_WAIT(wait);
117117
const struct fscrypt_info *ci = inode->i_crypt_info;
118-
struct crypto_skcipher *tfm = ci->ci_ctfm;
118+
struct crypto_skcipher *tfm = ci->ci_enc_key.tfm;
119119
union fscrypt_iv iv;
120120
struct scatterlist sg;
121121
int res;
@@ -171,7 +171,7 @@ static int fname_decrypt(const struct inode *inode,
171171
DECLARE_CRYPTO_WAIT(wait);
172172
struct scatterlist src_sg, dst_sg;
173173
const struct fscrypt_info *ci = inode->i_crypt_info;
174-
struct crypto_skcipher *tfm = ci->ci_ctfm;
174+
struct crypto_skcipher *tfm = ci->ci_enc_key.tfm;
175175
union fscrypt_iv iv;
176176
int res;
177177

fs/crypto/fscrypt_private.h

Lines changed: 105 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <linux/fscrypt.h>
1515
#include <linux/siphash.h>
1616
#include <crypto/hash.h>
17+
#include <linux/blk-crypto.h>
1718

1819
#define CONST_STRLEN(str) (sizeof(str) - 1)
1920

@@ -166,6 +167,20 @@ struct fscrypt_symlink_data {
166167
char encrypted_path[1];
167168
} __packed;
168169

170+
/**
171+
* struct fscrypt_prepared_key - a key prepared for actual encryption/decryption
172+
* @tfm: crypto API transform object
173+
* @blk_key: key for blk-crypto
174+
*
175+
* Normally only one of the fields will be non-NULL.
176+
*/
177+
struct fscrypt_prepared_key {
178+
struct crypto_skcipher *tfm;
179+
#ifdef CONFIG_FS_ENCRYPTION_INLINE_CRYPT
180+
struct fscrypt_blk_crypto_key *blk_key;
181+
#endif
182+
};
183+
169184
/*
170185
* fscrypt_info - the "encryption key" for an inode
171186
*
@@ -175,12 +190,20 @@ struct fscrypt_symlink_data {
175190
*/
176191
struct fscrypt_info {
177192

178-
/* The actual crypto transform used for encryption and decryption */
179-
struct crypto_skcipher *ci_ctfm;
193+
/* The key in a form prepared for actual encryption/decryption */
194+
struct fscrypt_prepared_key ci_enc_key;
180195

181-
/* True if the key should be freed when this fscrypt_info is freed */
196+
/* True if ci_enc_key should be freed when this fscrypt_info is freed */
182197
bool ci_owns_key;
183198

199+
#ifdef CONFIG_FS_ENCRYPTION_INLINE_CRYPT
200+
/*
201+
* True if this inode will use inline encryption (blk-crypto) instead of
202+
* the traditional filesystem-layer encryption.
203+
*/
204+
bool ci_inlinecrypt;
205+
#endif
206+
184207
/*
185208
* Encryption mode used for this inode. It corresponds to either the
186209
* contents or filenames encryption mode, depending on the inode type.
@@ -205,7 +228,7 @@ struct fscrypt_info {
205228

206229
/*
207230
* If non-NULL, then encryption is done using the master key directly
208-
* and ci_ctfm will equal ci_direct_key->dk_ctfm.
231+
* and ci_enc_key will equal ci_direct_key->dk_key.
209232
*/
210233
struct fscrypt_direct_key *ci_direct_key;
211234

@@ -260,6 +283,7 @@ union fscrypt_iv {
260283
u8 nonce[FS_KEY_DERIVATION_NONCE_SIZE];
261284
};
262285
u8 raw[FSCRYPT_MAX_IV_SIZE];
286+
__le64 dun[FSCRYPT_MAX_IV_SIZE / sizeof(__le64)];
263287
};
264288

265289
void fscrypt_generate_iv(union fscrypt_iv *iv, u64 lblk_num,
@@ -302,6 +326,75 @@ int fscrypt_hkdf_expand(const struct fscrypt_hkdf *hkdf, u8 context,
302326

303327
void fscrypt_destroy_hkdf(struct fscrypt_hkdf *hkdf);
304328

329+
/* inline_crypt.c */
330+
#ifdef CONFIG_FS_ENCRYPTION_INLINE_CRYPT
331+
int fscrypt_select_encryption_impl(struct fscrypt_info *ci);
332+
333+
static inline bool
334+
fscrypt_using_inline_encryption(const struct fscrypt_info *ci)
335+
{
336+
return ci->ci_inlinecrypt;
337+
}
338+
339+
int fscrypt_prepare_inline_crypt_key(struct fscrypt_prepared_key *prep_key,
340+
const u8 *raw_key,
341+
const struct fscrypt_info *ci);
342+
343+
void fscrypt_destroy_inline_crypt_key(struct fscrypt_prepared_key *prep_key);
344+
345+
/*
346+
* Check whether the crypto transform or blk-crypto key has been allocated in
347+
* @prep_key, depending on which encryption implementation the file will use.
348+
*/
349+
static inline bool
350+
fscrypt_is_key_prepared(struct fscrypt_prepared_key *prep_key,
351+
const struct fscrypt_info *ci)
352+
{
353+
/*
354+
* The READ_ONCE() here pairs with the smp_store_release() in
355+
* fscrypt_prepare_key(). (This only matters for the per-mode keys,
356+
* which are shared by multiple inodes.)
357+
*/
358+
if (fscrypt_using_inline_encryption(ci))
359+
return READ_ONCE(prep_key->blk_key) != NULL;
360+
return READ_ONCE(prep_key->tfm) != NULL;
361+
}
362+
363+
#else /* CONFIG_FS_ENCRYPTION_INLINE_CRYPT */
364+
365+
static inline int fscrypt_select_encryption_impl(struct fscrypt_info *ci)
366+
{
367+
return 0;
368+
}
369+
370+
static inline bool
371+
fscrypt_using_inline_encryption(const struct fscrypt_info *ci)
372+
{
373+
return false;
374+
}
375+
376+
static inline int
377+
fscrypt_prepare_inline_crypt_key(struct fscrypt_prepared_key *prep_key,
378+
const u8 *raw_key,
379+
const struct fscrypt_info *ci)
380+
{
381+
WARN_ON(1);
382+
return -EOPNOTSUPP;
383+
}
384+
385+
static inline void
386+
fscrypt_destroy_inline_crypt_key(struct fscrypt_prepared_key *prep_key)
387+
{
388+
}
389+
390+
static inline bool
391+
fscrypt_is_key_prepared(struct fscrypt_prepared_key *prep_key,
392+
const struct fscrypt_info *ci)
393+
{
394+
return READ_ONCE(prep_key->tfm) != NULL;
395+
}
396+
#endif /* !CONFIG_FS_ENCRYPTION_INLINE_CRYPT */
397+
305398
/* keyring.c */
306399

307400
/*
@@ -395,9 +488,9 @@ struct fscrypt_master_key {
395488
* Per-mode encryption keys for the various types of encryption policies
396489
* that use them. Allocated and derived on-demand.
397490
*/
398-
struct crypto_skcipher *mk_direct_keys[__FSCRYPT_MODE_MAX + 1];
399-
struct crypto_skcipher *mk_iv_ino_lblk_64_keys[__FSCRYPT_MODE_MAX + 1];
400-
struct crypto_skcipher *mk_iv_ino_lblk_32_keys[__FSCRYPT_MODE_MAX + 1];
491+
struct fscrypt_prepared_key mk_direct_keys[__FSCRYPT_MODE_MAX + 1];
492+
struct fscrypt_prepared_key mk_iv_ino_lblk_64_keys[__FSCRYPT_MODE_MAX + 1];
493+
struct fscrypt_prepared_key mk_iv_ino_lblk_32_keys[__FSCRYPT_MODE_MAX + 1];
401494

402495
/* Hash key for inode numbers. Initialized only when needed. */
403496
siphash_key_t mk_ino_hash_key;
@@ -461,13 +554,15 @@ struct fscrypt_mode {
461554
int keysize;
462555
int ivsize;
463556
int logged_impl_name;
557+
enum blk_crypto_mode_num blk_crypto_mode;
464558
};
465559

466560
extern struct fscrypt_mode fscrypt_modes[];
467561

468-
struct crypto_skcipher *fscrypt_allocate_skcipher(struct fscrypt_mode *mode,
469-
const u8 *raw_key,
470-
const struct inode *inode);
562+
int fscrypt_prepare_key(struct fscrypt_prepared_key *prep_key,
563+
const u8 *raw_key, const struct fscrypt_info *ci);
564+
565+
void fscrypt_destroy_prepared_key(struct fscrypt_prepared_key *prep_key);
471566

472567
int fscrypt_set_per_file_enc_key(struct fscrypt_info *ci, const u8 *raw_key);
473568

0 commit comments

Comments
 (0)