From 1c7dcf69eea3224474fe884a03b3e19b82d1101e Mon Sep 17 00:00:00 2001 From: David Gstir Date: Sun, 13 Nov 2016 22:20:44 +0100 Subject: [PATCH 1/7] fscrypt: Add in-place encryption mode ext4 and f2fs require a bounce page when encrypting pages. However, not all filesystems will need that (eg. UBIFS). This is handled via a flag on fscrypt_operations where a fs implementation can select in-place encryption over using a bounce page (which is the default). Signed-off-by: David Gstir Signed-off-by: Richard Weinberger Signed-off-by: Theodore Ts'o --- fs/crypto/crypto.c | 25 +++++++++++++++---------- include/linux/fscrypto.h | 6 ++++++ 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c index 98f87fe8f186..f38dc8aac2fe 100644 --- a/fs/crypto/crypto.c +++ b/fs/crypto/crypto.c @@ -217,8 +217,9 @@ static struct page *alloc_bounce_page(struct fscrypt_ctx *ctx, gfp_t gfp_flags) * @plaintext_page: The page to encrypt. Must be locked. * @gfp_flags: The gfp flag for memory allocation * - * Allocates a ciphertext page and encrypts plaintext_page into it using the ctx - * encryption context. + * Encrypts plaintext_page using the ctx encryption context. If + * the filesystem supports it, encryption is performed in-place, otherwise a + * new ciphertext_page is allocated and returned. * * Called on the page write path. The caller must call * fscrypt_restore_control_page() on the returned ciphertext page to @@ -231,7 +232,7 @@ struct page *fscrypt_encrypt_page(struct inode *inode, struct page *plaintext_page, gfp_t gfp_flags) { struct fscrypt_ctx *ctx; - struct page *ciphertext_page = NULL; + struct page *ciphertext_page = plaintext_page; int err; BUG_ON(!PageLocked(plaintext_page)); @@ -240,10 +241,12 @@ struct page *fscrypt_encrypt_page(struct inode *inode, if (IS_ERR(ctx)) return (struct page *)ctx; - /* The encryption operation will require a bounce page. */ - ciphertext_page = alloc_bounce_page(ctx, gfp_flags); - if (IS_ERR(ciphertext_page)) - goto errout; + if (!(inode->i_sb->s_cop->flags & FS_CFLG_INPLACE_ENCRYPTION)) { + /* The encryption operation will require a bounce page. */ + ciphertext_page = alloc_bounce_page(ctx, gfp_flags); + if (IS_ERR(ciphertext_page)) + goto errout; + } ctx->w.control_page = plaintext_page; err = do_page_crypto(inode, FS_ENCRYPT, plaintext_page->index, @@ -253,9 +256,11 @@ struct page *fscrypt_encrypt_page(struct inode *inode, ciphertext_page = ERR_PTR(err); goto errout; } - SetPagePrivate(ciphertext_page); - set_page_private(ciphertext_page, (unsigned long)ctx); - lock_page(ciphertext_page); + if (!(inode->i_sb->s_cop->flags & FS_CFLG_INPLACE_ENCRYPTION)) { + SetPagePrivate(ciphertext_page); + set_page_private(ciphertext_page, (unsigned long)ctx); + lock_page(ciphertext_page); + } return ciphertext_page; errout: diff --git a/include/linux/fscrypto.h b/include/linux/fscrypto.h index ff8b11b26f31..5a65b0e3773f 100644 --- a/include/linux/fscrypto.h +++ b/include/linux/fscrypto.h @@ -153,10 +153,16 @@ struct fscrypt_name { #define fname_name(p) ((p)->disk_name.name) #define fname_len(p) ((p)->disk_name.len) +/* + * fscrypt superblock flags + */ +#define FS_CFLG_INPLACE_ENCRYPTION (1U << 1) + /* * crypto opertions for filesystems */ struct fscrypt_operations { + unsigned int flags; int (*get_context)(struct inode *, void *, size_t); int (*key_prefix)(struct inode *, u8 **); int (*prepare_context)(struct inode *); From b50f7b268bad8088dfe7579a65cd910d8cc5c40f Mon Sep 17 00:00:00 2001 From: David Gstir Date: Sun, 13 Nov 2016 22:20:45 +0100 Subject: [PATCH 2/7] fscrypt: Allow fscrypt_decrypt_page() to function with non-writeback pages Some filesystem might pass pages which do not have page->mapping->host set to the encrypted inode. We want the caller to explicitly pass the corresponding inode. Signed-off-by: David Gstir Signed-off-by: Richard Weinberger Signed-off-by: Theodore Ts'o --- fs/crypto/crypto.c | 11 ++++++----- fs/ext4/inode.c | 5 +++-- include/linux/fscrypto.h | 5 +++-- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c index f38dc8aac2fe..222a70520565 100644 --- a/fs/crypto/crypto.c +++ b/fs/crypto/crypto.c @@ -271,7 +271,8 @@ EXPORT_SYMBOL(fscrypt_encrypt_page); /** * f2crypt_decrypt_page() - Decrypts a page in-place - * @page: The page to decrypt. Must be locked. + * @inode: The encrypted inode to decrypt. + * @page: The page to decrypt. Must be locked. * * Decrypts page in-place using the ctx encryption context. * @@ -279,12 +280,12 @@ EXPORT_SYMBOL(fscrypt_encrypt_page); * * Return: Zero on success, non-zero otherwise. */ -int fscrypt_decrypt_page(struct page *page) +int fscrypt_decrypt_page(struct inode *inode, struct page *page) { BUG_ON(!PageLocked(page)); - return do_page_crypto(page->mapping->host, - FS_DECRYPT, page->index, page, page, GFP_NOFS); + return do_page_crypto(inode, FS_DECRYPT, page->index, page, page, + GFP_NOFS); } EXPORT_SYMBOL(fscrypt_decrypt_page); @@ -419,7 +420,7 @@ static void completion_pages(struct work_struct *work) bio_for_each_segment_all(bv, bio, i) { struct page *page = bv->bv_page; - int ret = fscrypt_decrypt_page(page); + int ret = fscrypt_decrypt_page(page->mapping->host, page); if (ret) { WARN_ON_ONCE(1); diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 9c064727ed62..4b7b842ec024 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -1166,7 +1166,7 @@ static int ext4_block_write_begin(struct page *page, loff_t pos, unsigned len, if (unlikely(err)) page_zero_new_buffers(page, from, to); else if (decrypt) - err = fscrypt_decrypt_page(page); + err = fscrypt_decrypt_page(page->mapping->host, page); return err; } #endif @@ -3743,7 +3743,8 @@ static int __ext4_block_zero_page_range(handle_t *handle, /* We expect the key to be set. */ BUG_ON(!fscrypt_has_encryption_key(inode)); BUG_ON(blocksize != PAGE_SIZE); - WARN_ON_ONCE(fscrypt_decrypt_page(page)); + WARN_ON_ONCE(fscrypt_decrypt_page(page->mapping->host, + page)); } } if (ext4_should_journal_data(inode)) { diff --git a/include/linux/fscrypto.h b/include/linux/fscrypto.h index 5a65b0e3773f..8be8e9657c63 100644 --- a/include/linux/fscrypto.h +++ b/include/linux/fscrypto.h @@ -249,7 +249,7 @@ int fscrypt_initialize(void); extern struct fscrypt_ctx *fscrypt_get_ctx(struct inode *, gfp_t); extern void fscrypt_release_ctx(struct fscrypt_ctx *); extern struct page *fscrypt_encrypt_page(struct inode *, struct page *, gfp_t); -extern int fscrypt_decrypt_page(struct page *); +extern int fscrypt_decrypt_page(struct inode *, struct page *); extern void fscrypt_decrypt_bio_pages(struct fscrypt_ctx *, struct bio *); extern void fscrypt_pullback_bio_page(struct page **, bool); extern void fscrypt_restore_control_page(struct page *); @@ -298,7 +298,8 @@ static inline struct page *fscrypt_notsupp_encrypt_page(struct inode *i, return ERR_PTR(-EOPNOTSUPP); } -static inline int fscrypt_notsupp_decrypt_page(struct page *p) +static inline int fscrypt_notsupp_decrypt_page(struct inode *i, + struct page *p) { return -EOPNOTSUPP; } From 7821d4dd4589ce5af54f3e46d04a29439ba3c2e5 Mon Sep 17 00:00:00 2001 From: David Gstir Date: Sun, 13 Nov 2016 22:20:46 +0100 Subject: [PATCH 3/7] fscrypt: Enable partial page encryption Not all filesystems work on full pages, thus we should allow them to hand partial pages to fscrypt for en/decryption. Signed-off-by: David Gstir Signed-off-by: Richard Weinberger Signed-off-by: Theodore Ts'o --- fs/crypto/crypto.c | 42 +++++++++++++++++++++++++--------------- fs/ext4/inode.c | 6 ++++-- fs/ext4/page-io.c | 2 +- fs/f2fs/data.c | 2 ++ include/linux/fscrypto.h | 16 ++++++++++----- 5 files changed, 44 insertions(+), 24 deletions(-) diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c index 222a70520565..e170aa05011d 100644 --- a/fs/crypto/crypto.c +++ b/fs/crypto/crypto.c @@ -149,6 +149,7 @@ typedef enum { static int do_page_crypto(struct inode *inode, fscrypt_direction_t rw, pgoff_t index, struct page *src_page, struct page *dest_page, + unsigned int src_len, unsigned int src_offset, gfp_t gfp_flags) { struct { @@ -179,10 +180,10 @@ static int do_page_crypto(struct inode *inode, memset(xts_tweak.padding, 0, sizeof(xts_tweak.padding)); sg_init_table(&dst, 1); - sg_set_page(&dst, dest_page, PAGE_SIZE, 0); + sg_set_page(&dst, dest_page, src_len, src_offset); sg_init_table(&src, 1); - sg_set_page(&src, src_page, PAGE_SIZE, 0); - skcipher_request_set_crypt(req, &src, &dst, PAGE_SIZE, &xts_tweak); + sg_set_page(&src, src_page, src_len, src_offset); + skcipher_request_set_crypt(req, &src, &dst, src_len, &xts_tweak); if (rw == FS_DECRYPT) res = crypto_skcipher_decrypt(req); else @@ -213,9 +214,11 @@ static struct page *alloc_bounce_page(struct fscrypt_ctx *ctx, gfp_t gfp_flags) /** * fscypt_encrypt_page() - Encrypts a page - * @inode: The inode for which the encryption should take place - * @plaintext_page: The page to encrypt. Must be locked. - * @gfp_flags: The gfp flag for memory allocation + * @inode: The inode for which the encryption should take place + * @plaintext_page: The page to encrypt. Must be locked. + * @plaintext_len: Length of plaintext within page + * @plaintext_offset: Offset of plaintext within page + * @gfp_flags: The gfp flag for memory allocation * * Encrypts plaintext_page using the ctx encryption context. If * the filesystem supports it, encryption is performed in-place, otherwise a @@ -229,13 +232,17 @@ static struct page *alloc_bounce_page(struct fscrypt_ctx *ctx, gfp_t gfp_flags) * error value or NULL. */ struct page *fscrypt_encrypt_page(struct inode *inode, - struct page *plaintext_page, gfp_t gfp_flags) + struct page *plaintext_page, + unsigned int plaintext_len, + unsigned int plaintext_offset, + gfp_t gfp_flags) + { struct fscrypt_ctx *ctx; struct page *ciphertext_page = plaintext_page; int err; - BUG_ON(!PageLocked(plaintext_page)); + BUG_ON(plaintext_len % FS_CRYPTO_BLOCK_SIZE != 0); ctx = fscrypt_get_ctx(inode, gfp_flags); if (IS_ERR(ctx)) @@ -251,6 +258,7 @@ struct page *fscrypt_encrypt_page(struct inode *inode, ctx->w.control_page = plaintext_page; err = do_page_crypto(inode, FS_ENCRYPT, plaintext_page->index, plaintext_page, ciphertext_page, + plaintext_len, plaintext_offset, gfp_flags); if (err) { ciphertext_page = ERR_PTR(err); @@ -270,9 +278,11 @@ errout: EXPORT_SYMBOL(fscrypt_encrypt_page); /** - * f2crypt_decrypt_page() - Decrypts a page in-place - * @inode: The encrypted inode to decrypt. + * fscrypt_decrypt_page() - Decrypts a page in-place + * @inode: Encrypted inode to decrypt. * @page: The page to decrypt. Must be locked. + * @len: Number of bytes in @page to be decrypted. + * @offs: Start of data in @page. * * Decrypts page in-place using the ctx encryption context. * @@ -280,11 +290,10 @@ EXPORT_SYMBOL(fscrypt_encrypt_page); * * Return: Zero on success, non-zero otherwise. */ -int fscrypt_decrypt_page(struct inode *inode, struct page *page) +int fscrypt_decrypt_page(struct inode *inode, struct page *page, + unsigned int len, unsigned int offs) { - BUG_ON(!PageLocked(page)); - - return do_page_crypto(inode, FS_DECRYPT, page->index, page, page, + return do_page_crypto(inode, FS_DECRYPT, page->index, page, page, len, offs, GFP_NOFS); } EXPORT_SYMBOL(fscrypt_decrypt_page); @@ -312,7 +321,7 @@ int fscrypt_zeroout_range(struct inode *inode, pgoff_t lblk, while (len--) { err = do_page_crypto(inode, FS_ENCRYPT, lblk, ZERO_PAGE(0), ciphertext_page, - GFP_NOFS); + PAGE_SIZE, 0, GFP_NOFS); if (err) goto errout; @@ -420,7 +429,8 @@ static void completion_pages(struct work_struct *work) bio_for_each_segment_all(bv, bio, i) { struct page *page = bv->bv_page; - int ret = fscrypt_decrypt_page(page->mapping->host, page); + int ret = fscrypt_decrypt_page(page->mapping->host, page, + PAGE_SIZE, 0); if (ret) { WARN_ON_ONCE(1); diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 4b7b842ec024..1d498c5e2990 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -1166,7 +1166,8 @@ static int ext4_block_write_begin(struct page *page, loff_t pos, unsigned len, if (unlikely(err)) page_zero_new_buffers(page, from, to); else if (decrypt) - err = fscrypt_decrypt_page(page->mapping->host, page); + err = fscrypt_decrypt_page(page->mapping->host, page, + PAGE_SIZE, 0); return err; } #endif @@ -3743,8 +3744,9 @@ static int __ext4_block_zero_page_range(handle_t *handle, /* We expect the key to be set. */ BUG_ON(!fscrypt_has_encryption_key(inode)); BUG_ON(blocksize != PAGE_SIZE); + BUG_ON(!PageLocked(page)); WARN_ON_ONCE(fscrypt_decrypt_page(page->mapping->host, - page)); + page, PAGE_SIZE, 0)); } } if (ext4_should_journal_data(inode)) { diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c index 0094923e5ebf..3d1d3d0f4303 100644 --- a/fs/ext4/page-io.c +++ b/fs/ext4/page-io.c @@ -470,7 +470,7 @@ int ext4_bio_write_page(struct ext4_io_submit *io, gfp_t gfp_flags = GFP_NOFS; retry_encrypt: - data_page = fscrypt_encrypt_page(inode, page, gfp_flags); + data_page = fscrypt_encrypt_page(inode, page, PAGE_SIZE, 0, gfp_flags); if (IS_ERR(data_page)) { ret = PTR_ERR(data_page); if (ret == -ENOMEM && wbc->sync_mode == WB_SYNC_ALL) { diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 9ae194fd2fdb..fac207254e8d 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -1194,7 +1194,9 @@ int do_write_data_page(struct f2fs_io_info *fio) f2fs_wait_on_encrypted_page_writeback(F2FS_I_SB(inode), fio->old_blkaddr); retry_encrypt: + BUG_ON(!PageLocked(fio->page)); fio->encrypted_page = fscrypt_encrypt_page(inode, fio->page, + PAGE_SIZE, 0, gfp_flags); if (IS_ERR(fio->encrypted_page)) { err = PTR_ERR(fio->encrypted_page); diff --git a/include/linux/fscrypto.h b/include/linux/fscrypto.h index 8be8e9657c63..e05931272cea 100644 --- a/include/linux/fscrypto.h +++ b/include/linux/fscrypto.h @@ -248,8 +248,11 @@ int fscrypt_initialize(void); extern struct fscrypt_ctx *fscrypt_get_ctx(struct inode *, gfp_t); extern void fscrypt_release_ctx(struct fscrypt_ctx *); -extern struct page *fscrypt_encrypt_page(struct inode *, struct page *, gfp_t); -extern int fscrypt_decrypt_page(struct inode *, struct page *); +extern struct page *fscrypt_encrypt_page(struct inode *, struct page *, + unsigned int, unsigned int, + gfp_t); +extern int fscrypt_decrypt_page(struct inode *, struct page *, unsigned int, + unsigned int); extern void fscrypt_decrypt_bio_pages(struct fscrypt_ctx *, struct bio *); extern void fscrypt_pullback_bio_page(struct page **, bool); extern void fscrypt_restore_control_page(struct page *); @@ -293,13 +296,16 @@ static inline void fscrypt_notsupp_release_ctx(struct fscrypt_ctx *c) } static inline struct page *fscrypt_notsupp_encrypt_page(struct inode *i, - struct page *p, gfp_t f) + struct page *p, + unsigned int len, + unsigned int offs, + gfp_t f) { return ERR_PTR(-EOPNOTSUPP); } -static inline int fscrypt_notsupp_decrypt_page(struct inode *i, - struct page *p) +static inline int fscrypt_notsupp_decrypt_page(struct inode *i, struct page *p, + unsigned int len, unsigned int offs) { return -EOPNOTSUPP; } From 0b93e1b94b86f826d18a2aaf219a53e271274d49 Mon Sep 17 00:00:00 2001 From: David Gstir Date: Sun, 13 Nov 2016 22:20:47 +0100 Subject: [PATCH 4/7] fscrypt: Constify struct inode pointer Some filesystems, such as UBIFS, maintain a const pointer for struct inode. Signed-off-by: David Gstir Signed-off-by: Richard Weinberger Signed-off-by: Theodore Ts'o --- fs/crypto/crypto.c | 10 +++++----- fs/crypto/fname.c | 4 ++-- include/linux/fscrypto.h | 22 +++++++++++----------- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c index e170aa05011d..f5c5e84ea9db 100644 --- a/fs/crypto/crypto.c +++ b/fs/crypto/crypto.c @@ -88,7 +88,7 @@ EXPORT_SYMBOL(fscrypt_release_ctx); * Return: An allocated and initialized encryption context on success; error * value or NULL otherwise. */ -struct fscrypt_ctx *fscrypt_get_ctx(struct inode *inode, gfp_t gfp_flags) +struct fscrypt_ctx *fscrypt_get_ctx(const struct inode *inode, gfp_t gfp_flags) { struct fscrypt_ctx *ctx = NULL; struct fscrypt_info *ci = inode->i_crypt_info; @@ -146,7 +146,7 @@ typedef enum { FS_ENCRYPT, } fscrypt_direction_t; -static int do_page_crypto(struct inode *inode, +static int do_page_crypto(const struct inode *inode, fscrypt_direction_t rw, pgoff_t index, struct page *src_page, struct page *dest_page, unsigned int src_len, unsigned int src_offset, @@ -231,7 +231,7 @@ static struct page *alloc_bounce_page(struct fscrypt_ctx *ctx, gfp_t gfp_flags) * Return: An allocated page with the encrypted content on success. Else, an * error value or NULL. */ -struct page *fscrypt_encrypt_page(struct inode *inode, +struct page *fscrypt_encrypt_page(const struct inode *inode, struct page *plaintext_page, unsigned int plaintext_len, unsigned int plaintext_offset, @@ -290,7 +290,7 @@ EXPORT_SYMBOL(fscrypt_encrypt_page); * * Return: Zero on success, non-zero otherwise. */ -int fscrypt_decrypt_page(struct inode *inode, struct page *page, +int fscrypt_decrypt_page(const struct inode *inode, struct page *page, unsigned int len, unsigned int offs) { return do_page_crypto(inode, FS_DECRYPT, page->index, page, page, len, offs, @@ -298,7 +298,7 @@ int fscrypt_decrypt_page(struct inode *inode, struct page *page, } EXPORT_SYMBOL(fscrypt_decrypt_page); -int fscrypt_zeroout_range(struct inode *inode, pgoff_t lblk, +int fscrypt_zeroout_range(const struct inode *inode, pgoff_t lblk, sector_t pblk, unsigned int len) { struct fscrypt_ctx *ctx; diff --git a/fs/crypto/fname.c b/fs/crypto/fname.c index 9a28133ac3b8..faeaf0be9400 100644 --- a/fs/crypto/fname.c +++ b/fs/crypto/fname.c @@ -220,7 +220,7 @@ static int digest_decode(const char *src, int len, char *dst) return cp - dst; } -u32 fscrypt_fname_encrypted_size(struct inode *inode, u32 ilen) +u32 fscrypt_fname_encrypted_size(const struct inode *inode, u32 ilen) { int padding = 32; struct fscrypt_info *ci = inode->i_crypt_info; @@ -238,7 +238,7 @@ EXPORT_SYMBOL(fscrypt_fname_encrypted_size); * Allocates an output buffer that is sufficient for the crypto operation * specified by the context and the direction. */ -int fscrypt_fname_alloc_buffer(struct inode *inode, +int fscrypt_fname_alloc_buffer(const struct inode *inode, u32 ilen, struct fscrypt_str *crypto_str) { unsigned int olen = fscrypt_fname_encrypted_size(inode, ilen); diff --git a/include/linux/fscrypto.h b/include/linux/fscrypto.h index e05931272cea..e9be944a324c 100644 --- a/include/linux/fscrypto.h +++ b/include/linux/fscrypto.h @@ -212,7 +212,7 @@ static inline struct page *fscrypt_control_page(struct page *page) #endif } -static inline int fscrypt_has_encryption_key(struct inode *inode) +static inline int fscrypt_has_encryption_key(const struct inode *inode) { #if IS_ENABLED(CONFIG_FS_ENCRYPTION) return (inode->i_crypt_info != NULL); @@ -246,17 +246,17 @@ static inline void fscrypt_set_d_op(struct dentry *dentry) extern struct kmem_cache *fscrypt_info_cachep; int fscrypt_initialize(void); -extern struct fscrypt_ctx *fscrypt_get_ctx(struct inode *, gfp_t); +extern struct fscrypt_ctx *fscrypt_get_ctx(const struct inode *, gfp_t); extern void fscrypt_release_ctx(struct fscrypt_ctx *); -extern struct page *fscrypt_encrypt_page(struct inode *, struct page *, +extern struct page *fscrypt_encrypt_page(const struct inode *, struct page *, unsigned int, unsigned int, gfp_t); -extern int fscrypt_decrypt_page(struct inode *, struct page *, unsigned int, +extern int fscrypt_decrypt_page(const struct inode *, struct page *, unsigned int, unsigned int); extern void fscrypt_decrypt_bio_pages(struct fscrypt_ctx *, struct bio *); extern void fscrypt_pullback_bio_page(struct page **, bool); extern void fscrypt_restore_control_page(struct page *); -extern int fscrypt_zeroout_range(struct inode *, pgoff_t, sector_t, +extern int fscrypt_zeroout_range(const struct inode *, pgoff_t, sector_t, unsigned int); /* policy.c */ extern int fscrypt_process_policy(struct file *, const struct fscrypt_policy *); @@ -273,8 +273,8 @@ extern void fscrypt_put_encryption_info(struct inode *, struct fscrypt_info *); extern int fscrypt_setup_filename(struct inode *, const struct qstr *, int lookup, struct fscrypt_name *); extern void fscrypt_free_filename(struct fscrypt_name *); -extern u32 fscrypt_fname_encrypted_size(struct inode *, u32); -extern int fscrypt_fname_alloc_buffer(struct inode *, u32, +extern u32 fscrypt_fname_encrypted_size(const struct inode *, u32); +extern int fscrypt_fname_alloc_buffer(const struct inode *, u32, struct fscrypt_str *); extern void fscrypt_fname_free_buffer(struct fscrypt_str *); extern int fscrypt_fname_disk_to_usr(struct inode *, u32, u32, @@ -284,7 +284,7 @@ extern int fscrypt_fname_usr_to_disk(struct inode *, const struct qstr *, #endif /* crypto.c */ -static inline struct fscrypt_ctx *fscrypt_notsupp_get_ctx(struct inode *i, +static inline struct fscrypt_ctx *fscrypt_notsupp_get_ctx(const struct inode *i, gfp_t f) { return ERR_PTR(-EOPNOTSUPP); @@ -295,7 +295,7 @@ static inline void fscrypt_notsupp_release_ctx(struct fscrypt_ctx *c) return; } -static inline struct page *fscrypt_notsupp_encrypt_page(struct inode *i, +static inline struct page *fscrypt_notsupp_encrypt_page(const struct inode *i, struct page *p, unsigned int len, unsigned int offs, @@ -304,7 +304,7 @@ static inline struct page *fscrypt_notsupp_encrypt_page(struct inode *i, return ERR_PTR(-EOPNOTSUPP); } -static inline int fscrypt_notsupp_decrypt_page(struct inode *i, struct page *p, +static inline int fscrypt_notsupp_decrypt_page(const struct inode *i, struct page *p, unsigned int len, unsigned int offs) { return -EOPNOTSUPP; @@ -326,7 +326,7 @@ static inline void fscrypt_notsupp_restore_control_page(struct page *p) return; } -static inline int fscrypt_notsupp_zeroout_range(struct inode *i, pgoff_t p, +static inline int fscrypt_notsupp_zeroout_range(const struct inode *i, pgoff_t p, sector_t s, unsigned int f) { return -EOPNOTSUPP; From 9c4bb8a3a9b4de21753053d667310c2b7cb39916 Mon Sep 17 00:00:00 2001 From: David Gstir Date: Sun, 13 Nov 2016 22:20:48 +0100 Subject: [PATCH 5/7] fscrypt: Let fs select encryption index/tweak Avoid re-use of page index as tweak for AES-XTS when multiple parts of same page are encrypted. This will happen on multiple (partial) calls of fscrypt_encrypt_page on same page. page->index is only valid for writeback pages. Signed-off-by: David Gstir Signed-off-by: Richard Weinberger Signed-off-by: Theodore Ts'o --- fs/crypto/crypto.c | 11 +++++++---- fs/ext4/inode.c | 4 ++-- fs/ext4/page-io.c | 3 ++- fs/f2fs/data.c | 5 +++-- include/linux/fscrypto.h | 9 +++++---- 5 files changed, 19 insertions(+), 13 deletions(-) diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c index f5c5e84ea9db..b6029785714c 100644 --- a/fs/crypto/crypto.c +++ b/fs/crypto/crypto.c @@ -218,6 +218,8 @@ static struct page *alloc_bounce_page(struct fscrypt_ctx *ctx, gfp_t gfp_flags) * @plaintext_page: The page to encrypt. Must be locked. * @plaintext_len: Length of plaintext within page * @plaintext_offset: Offset of plaintext within page + * @index: Index for encryption. This is mainly the page index, but + * but might be different for multiple calls on same page. * @gfp_flags: The gfp flag for memory allocation * * Encrypts plaintext_page using the ctx encryption context. If @@ -235,7 +237,7 @@ struct page *fscrypt_encrypt_page(const struct inode *inode, struct page *plaintext_page, unsigned int plaintext_len, unsigned int plaintext_offset, - gfp_t gfp_flags) + pgoff_t index, gfp_t gfp_flags) { struct fscrypt_ctx *ctx; @@ -256,7 +258,7 @@ struct page *fscrypt_encrypt_page(const struct inode *inode, } ctx->w.control_page = plaintext_page; - err = do_page_crypto(inode, FS_ENCRYPT, plaintext_page->index, + err = do_page_crypto(inode, FS_ENCRYPT, index, plaintext_page, ciphertext_page, plaintext_len, plaintext_offset, gfp_flags); @@ -283,6 +285,7 @@ EXPORT_SYMBOL(fscrypt_encrypt_page); * @page: The page to decrypt. Must be locked. * @len: Number of bytes in @page to be decrypted. * @offs: Start of data in @page. + * @index: Index for encryption. * * Decrypts page in-place using the ctx encryption context. * @@ -291,7 +294,7 @@ EXPORT_SYMBOL(fscrypt_encrypt_page); * Return: Zero on success, non-zero otherwise. */ int fscrypt_decrypt_page(const struct inode *inode, struct page *page, - unsigned int len, unsigned int offs) + unsigned int len, unsigned int offs, pgoff_t index) { return do_page_crypto(inode, FS_DECRYPT, page->index, page, page, len, offs, GFP_NOFS); @@ -430,7 +433,7 @@ static void completion_pages(struct work_struct *work) bio_for_each_segment_all(bv, bio, i) { struct page *page = bv->bv_page; int ret = fscrypt_decrypt_page(page->mapping->host, page, - PAGE_SIZE, 0); + PAGE_SIZE, 0, page->index); if (ret) { WARN_ON_ONCE(1); diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 1d498c5e2990..1485ac273bfb 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -1167,7 +1167,7 @@ static int ext4_block_write_begin(struct page *page, loff_t pos, unsigned len, page_zero_new_buffers(page, from, to); else if (decrypt) err = fscrypt_decrypt_page(page->mapping->host, page, - PAGE_SIZE, 0); + PAGE_SIZE, 0, page->index); return err; } #endif @@ -3746,7 +3746,7 @@ static int __ext4_block_zero_page_range(handle_t *handle, BUG_ON(blocksize != PAGE_SIZE); BUG_ON(!PageLocked(page)); WARN_ON_ONCE(fscrypt_decrypt_page(page->mapping->host, - page, PAGE_SIZE, 0)); + page, PAGE_SIZE, 0, page->index)); } } if (ext4_should_journal_data(inode)) { diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c index 3d1d3d0f4303..902a3e3059b3 100644 --- a/fs/ext4/page-io.c +++ b/fs/ext4/page-io.c @@ -470,7 +470,8 @@ int ext4_bio_write_page(struct ext4_io_submit *io, gfp_t gfp_flags = GFP_NOFS; retry_encrypt: - data_page = fscrypt_encrypt_page(inode, page, PAGE_SIZE, 0, gfp_flags); + data_page = fscrypt_encrypt_page(inode, page, PAGE_SIZE, 0, + page->index, gfp_flags); if (IS_ERR(data_page)) { ret = PTR_ERR(data_page); if (ret == -ENOMEM && wbc->sync_mode == WB_SYNC_ALL) { diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index fac207254e8d..435590c4b341 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -1196,8 +1196,9 @@ int do_write_data_page(struct f2fs_io_info *fio) retry_encrypt: BUG_ON(!PageLocked(fio->page)); fio->encrypted_page = fscrypt_encrypt_page(inode, fio->page, - PAGE_SIZE, 0, - gfp_flags); + PAGE_SIZE, 0, + fio->page->index, + gfp_flags); if (IS_ERR(fio->encrypted_page)) { err = PTR_ERR(fio->encrypted_page); if (err == -ENOMEM) { diff --git a/include/linux/fscrypto.h b/include/linux/fscrypto.h index e9be944a324c..98c71e973a96 100644 --- a/include/linux/fscrypto.h +++ b/include/linux/fscrypto.h @@ -250,9 +250,9 @@ extern struct fscrypt_ctx *fscrypt_get_ctx(const struct inode *, gfp_t); extern void fscrypt_release_ctx(struct fscrypt_ctx *); extern struct page *fscrypt_encrypt_page(const struct inode *, struct page *, unsigned int, unsigned int, - gfp_t); + pgoff_t, gfp_t); extern int fscrypt_decrypt_page(const struct inode *, struct page *, unsigned int, - unsigned int); + unsigned int, pgoff_t); extern void fscrypt_decrypt_bio_pages(struct fscrypt_ctx *, struct bio *); extern void fscrypt_pullback_bio_page(struct page **, bool); extern void fscrypt_restore_control_page(struct page *); @@ -299,13 +299,14 @@ static inline struct page *fscrypt_notsupp_encrypt_page(const struct inode *i, struct page *p, unsigned int len, unsigned int offs, - gfp_t f) + pgoff_t index, gfp_t f) { return ERR_PTR(-EOPNOTSUPP); } static inline int fscrypt_notsupp_decrypt_page(const struct inode *i, struct page *p, - unsigned int len, unsigned int offs) + unsigned int len, unsigned int offs, + pgoff_t index) { return -EOPNOTSUPP; } From 08ae877f4e9123ee2a70e8e16cc8c3131ba07dba Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sun, 13 Nov 2016 20:35:52 -0500 Subject: [PATCH 6/7] fscrypto: don't use on-stack buffer for filename encryption With the new (in 4.9) option to use a virtually-mapped stack (CONFIG_VMAP_STACK), stack buffers cannot be used as input/output for the scatterlist crypto API because they may not be directly mappable to struct page. For short filenames, fname_encrypt() was encrypting a stack buffer holding the padded filename. Fix it by encrypting the filename in-place in the output buffer, thereby making the temporary buffer unnecessary. This bug could most easily be observed in a CONFIG_DEBUG_SG kernel because this allowed the BUG in sg_set_buf() to be triggered. Cc: stable@vger.kernel.org Signed-off-by: Eric Biggers Signed-off-by: Theodore Ts'o --- fs/crypto/fname.c | 53 +++++++++++++++++++---------------------------- 1 file changed, 21 insertions(+), 32 deletions(-) diff --git a/fs/crypto/fname.c b/fs/crypto/fname.c index faeaf0be9400..6b45d9caeeb0 100644 --- a/fs/crypto/fname.c +++ b/fs/crypto/fname.c @@ -39,65 +39,54 @@ static void fname_crypt_complete(struct crypto_async_request *req, int res) static int fname_encrypt(struct inode *inode, const struct qstr *iname, struct fscrypt_str *oname) { - u32 ciphertext_len; struct skcipher_request *req = NULL; DECLARE_FS_COMPLETION_RESULT(ecr); struct fscrypt_info *ci = inode->i_crypt_info; struct crypto_skcipher *tfm = ci->ci_ctfm; int res = 0; char iv[FS_CRYPTO_BLOCK_SIZE]; - struct scatterlist src_sg, dst_sg; + struct scatterlist sg; int padding = 4 << (ci->ci_flags & FS_POLICY_FLAGS_PAD_MASK); - char *workbuf, buf[32], *alloc_buf = NULL; - unsigned lim; + unsigned int lim; + unsigned int cryptlen; lim = inode->i_sb->s_cop->max_namelen(inode); if (iname->len <= 0 || iname->len > lim) return -EIO; - ciphertext_len = max(iname->len, (u32)FS_CRYPTO_BLOCK_SIZE); - ciphertext_len = round_up(ciphertext_len, padding); - ciphertext_len = min(ciphertext_len, lim); + /* + * Copy the filename to the output buffer for encrypting in-place and + * pad it with the needed number of NUL bytes. + */ + cryptlen = max_t(unsigned int, iname->len, FS_CRYPTO_BLOCK_SIZE); + cryptlen = round_up(cryptlen, padding); + cryptlen = min(cryptlen, lim); + memcpy(oname->name, iname->name, iname->len); + memset(oname->name + iname->len, 0, cryptlen - iname->len); - if (ciphertext_len <= sizeof(buf)) { - workbuf = buf; - } else { - alloc_buf = kmalloc(ciphertext_len, GFP_NOFS); - if (!alloc_buf) - return -ENOMEM; - workbuf = alloc_buf; - } + /* Initialize the IV */ + memset(iv, 0, FS_CRYPTO_BLOCK_SIZE); - /* Allocate request */ + /* Set up the encryption request */ req = skcipher_request_alloc(tfm, GFP_NOFS); if (!req) { printk_ratelimited(KERN_ERR - "%s: crypto_request_alloc() failed\n", __func__); - kfree(alloc_buf); + "%s: skcipher_request_alloc() failed\n", __func__); return -ENOMEM; } skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, fname_crypt_complete, &ecr); + sg_init_one(&sg, oname->name, cryptlen); + skcipher_request_set_crypt(req, &sg, &sg, cryptlen, iv); - /* Copy the input */ - memcpy(workbuf, iname->name, iname->len); - if (iname->len < ciphertext_len) - memset(workbuf + iname->len, 0, ciphertext_len - iname->len); - - /* Initialize IV */ - memset(iv, 0, FS_CRYPTO_BLOCK_SIZE); - - /* Create encryption request */ - sg_init_one(&src_sg, workbuf, ciphertext_len); - sg_init_one(&dst_sg, oname->name, ciphertext_len); - skcipher_request_set_crypt(req, &src_sg, &dst_sg, ciphertext_len, iv); + /* Do the encryption */ res = crypto_skcipher_encrypt(req); if (res == -EINPROGRESS || res == -EBUSY) { + /* Request is being completed asynchronously; wait for it */ wait_for_completion(&ecr.completion); res = ecr.res; } - kfree(alloc_buf); skcipher_request_free(req); if (res < 0) { printk_ratelimited(KERN_ERR @@ -105,7 +94,7 @@ static int fname_encrypt(struct inode *inode, return res; } - oname->len = ciphertext_len; + oname->len = cryptlen; return 0; } From a6e08912861757b8b335cc49b093a51ec025c5de Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sun, 13 Nov 2016 20:41:09 -0500 Subject: [PATCH 7/7] fscrypto: don't use on-stack buffer for key derivation With the new (in 4.9) option to use a virtually-mapped stack (CONFIG_VMAP_STACK), stack buffers cannot be used as input/output for the scatterlist crypto API because they may not be directly mappable to struct page. get_crypt_info() was using a stack buffer to hold the output from the encryption operation used to derive the per-file key. Fix it by using a heap buffer. This bug could most easily be observed in a CONFIG_DEBUG_SG kernel because this allowed the BUG in sg_set_buf() to be triggered. Cc: stable@vger.kernel.org Signed-off-by: Eric Biggers Signed-off-by: Theodore Ts'o --- fs/crypto/keyinfo.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/fs/crypto/keyinfo.c b/fs/crypto/keyinfo.c index 82f0285f5d08..67fb6d8876d0 100644 --- a/fs/crypto/keyinfo.c +++ b/fs/crypto/keyinfo.c @@ -185,7 +185,7 @@ int get_crypt_info(struct inode *inode) struct crypto_skcipher *ctfm; const char *cipher_str; int keysize; - u8 raw_key[FS_MAX_KEY_SIZE]; + u8 *raw_key = NULL; int res; res = fscrypt_initialize(); @@ -238,6 +238,15 @@ retry: if (res) goto out; + /* + * This cannot be a stack buffer because it is passed to the scatterlist + * crypto API as part of key derivation. + */ + res = -ENOMEM; + raw_key = kmalloc(FS_MAX_KEY_SIZE, GFP_NOFS); + if (!raw_key) + goto out; + if (fscrypt_dummy_context_enabled(inode)) { memset(raw_key, 0x42, FS_AES_256_XTS_KEY_SIZE); goto got_key; @@ -276,7 +285,8 @@ got_key: if (res) goto out; - memzero_explicit(raw_key, sizeof(raw_key)); + kzfree(raw_key); + raw_key = NULL; if (cmpxchg(&inode->i_crypt_info, NULL, crypt_info) != NULL) { put_crypt_info(crypt_info); goto retry; @@ -287,7 +297,7 @@ out: if (res == -ENOKEY) res = 0; put_crypt_info(crypt_info); - memzero_explicit(raw_key, sizeof(raw_key)); + kzfree(raw_key); return res; }