From 54475f531bb8d7078f63c159e5e0615d486c498c Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Mon, 5 Dec 2016 11:12:44 -0800 Subject: fscrypt: use ENOKEY when file cannot be created w/o key As part of an effort to clean up fscrypt-related error codes, make attempting to create a file in an encrypted directory that hasn't been "unlocked" fail with ENOKEY. Previously, several error codes were used for this case, including ENOENT, EACCES, and EPERM, and they were not consistent between and within filesystems. ENOKEY is a better choice because it expresses that the failure is due to lacking the encryption key. It also matches the error code returned when trying to open an encrypted regular file without the key. I am not aware of any users who might be relying on the previous inconsistent error codes, which were never documented anywhere. This failure case will be exercised by an xfstest. Signed-off-by: Eric Biggers Signed-off-by: Theodore Ts'o --- fs/crypto/fname.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'fs/crypto') diff --git a/fs/crypto/fname.c b/fs/crypto/fname.c index 56ad9d195f18..13052b85c393 100644 --- a/fs/crypto/fname.c +++ b/fs/crypto/fname.c @@ -332,7 +332,7 @@ int fscrypt_fname_usr_to_disk(struct inode *inode, * in a directory. Consequently, a user space name cannot be mapped to * a disk-space name */ - return -EACCES; + return -ENOKEY; } EXPORT_SYMBOL(fscrypt_fname_usr_to_disk); @@ -367,7 +367,7 @@ int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname, return 0; } if (!lookup) - return -EACCES; + return -ENOKEY; /* * We don't have the key and we are doing a lookup; decode the -- cgit v1.2.3 From dffd0cfa06d4ed83bb3ae8eb067989ceec5d18e1 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Mon, 5 Dec 2016 11:12:45 -0800 Subject: fscrypt: use ENOTDIR when setting encryption policy on nondirectory As part of an effort to clean up fscrypt-related error codes, make FS_IOC_SET_ENCRYPTION_POLICY fail with ENOTDIR when the file descriptor does not refer to a directory. This is more descriptive than EINVAL, which was ambiguous with some of the other error cases. I am not aware of any users who might be relying on the previous error code of EINVAL, which was never documented anywhere, and in some buggy kernels did not exist at all as the S_ISDIR() check was missing. This failure case will be exercised by an xfstest. Signed-off-by: Eric Biggers Signed-off-by: Theodore Ts'o --- fs/crypto/policy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs/crypto') diff --git a/fs/crypto/policy.c b/fs/crypto/policy.c index d6cd7ea4851d..40ecd7173e34 100644 --- a/fs/crypto/policy.c +++ b/fs/crypto/policy.c @@ -116,7 +116,7 @@ int fscrypt_ioctl_set_policy(struct file *filp, const void __user *arg) if (!inode_has_encryption_context(inode)) { if (!S_ISDIR(inode->i_mode)) - ret = -EINVAL; + ret = -ENOTDIR; else if (!inode->i_sb->s_cop->empty_dir) ret = -EOPNOTSUPP; else if (!inode->i_sb->s_cop->empty_dir(inode)) -- cgit v1.2.3 From 8488cd96ff88966ccb076e4f3654f59d84ba686d Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Mon, 5 Dec 2016 11:12:46 -0800 Subject: fscrypt: use EEXIST when file already uses different policy As part of an effort to clean up fscrypt-related error codes, make FS_IOC_SET_ENCRYPTION_POLICY fail with EEXIST when the file already uses a different encryption policy. This is more descriptive than EINVAL, which was ambiguous with some of the other error cases. I am not aware of any users who might be relying on the previous error code of EINVAL, which was never documented anywhere. This failure case will be exercised by an xfstest. Signed-off-by: Eric Biggers Signed-off-by: Theodore Ts'o --- fs/crypto/policy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs/crypto') diff --git a/fs/crypto/policy.c b/fs/crypto/policy.c index 40ecd7173e34..47f19800ceb7 100644 --- a/fs/crypto/policy.c +++ b/fs/crypto/policy.c @@ -129,7 +129,7 @@ int fscrypt_ioctl_set_policy(struct file *filp, const void __user *arg) printk(KERN_WARNING "%s: Policy inconsistent with encryption context\n", __func__); - ret = -EINVAL; + ret = -EEXIST; } inode_unlock(inode); -- cgit v1.2.3 From 868e1bc64d04294b76f1c0eedb79e0742be441c7 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Mon, 5 Dec 2016 11:12:47 -0800 Subject: fscrypt: remove user-triggerable warning messages Several warning messages were not rate limited and were user-triggerable from FS_IOC_SET_ENCRYPTION_POLICY. These shouldn't really have been there in the first place, but either way they aren't as useful now that the error codes have been improved. So just remove them. Signed-off-by: Eric Biggers Signed-off-by: Theodore Ts'o --- fs/crypto/policy.c | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) (limited to 'fs/crypto') diff --git a/fs/crypto/policy.c b/fs/crypto/policy.c index 47f19800ceb7..521b182dd902 100644 --- a/fs/crypto/policy.c +++ b/fs/crypto/policy.c @@ -66,20 +66,12 @@ static int create_encryption_context_from_policy(struct inode *inode, FS_KEY_DESCRIPTOR_SIZE); if (!fscrypt_valid_contents_enc_mode( - policy->contents_encryption_mode)) { - printk(KERN_WARNING - "%s: Invalid contents encryption mode %d\n", __func__, - policy->contents_encryption_mode); + policy->contents_encryption_mode)) return -EINVAL; - } if (!fscrypt_valid_filenames_enc_mode( - policy->filenames_encryption_mode)) { - printk(KERN_WARNING - "%s: Invalid filenames encryption mode %d\n", __func__, - policy->filenames_encryption_mode); + policy->filenames_encryption_mode)) return -EINVAL; - } if (policy->flags & ~FS_POLICY_FLAGS_VALID) return -EINVAL; @@ -126,9 +118,6 @@ int fscrypt_ioctl_set_policy(struct file *filp, const void __user *arg) &policy); } else if (!is_encryption_context_consistent_with_policy(inode, &policy)) { - printk(KERN_WARNING - "%s: Policy inconsistent with encryption context\n", - __func__); ret = -EEXIST; } -- cgit v1.2.3 From efee590e4a3fa7b66f78aa06eff33f59570ca96d Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Mon, 5 Dec 2016 11:12:48 -0800 Subject: fscrypt: pass up error codes from ->get_context() It was possible for the ->get_context() operation to fail with a specific error code, which was then not returned to the caller of FS_IOC_SET_ENCRYPTION_POLICY or FS_IOC_GET_ENCRYPTION_POLICY. Make sure to pass through these error codes. Also reorganize the code so that ->get_context() only needs to be called one time when setting an encryption policy, and handle contexts of unrecognized sizes more appropriately. Signed-off-by: Eric Biggers Signed-off-by: Theodore Ts'o --- fs/crypto/policy.c | 54 +++++++++++++++++++++++------------------------------- 1 file changed, 23 insertions(+), 31 deletions(-) (limited to 'fs/crypto') diff --git a/fs/crypto/policy.c b/fs/crypto/policy.c index 521b182dd902..4c99972899c7 100644 --- a/fs/crypto/policy.c +++ b/fs/crypto/policy.c @@ -13,37 +13,20 @@ #include #include "fscrypt_private.h" -static int inode_has_encryption_context(struct inode *inode) -{ - if (!inode->i_sb->s_cop->get_context) - return 0; - return (inode->i_sb->s_cop->get_context(inode, NULL, 0L) > 0); -} - /* - * check whether the policy is consistent with the encryption context - * for the inode + * check whether an encryption policy is consistent with an encryption context */ -static int is_encryption_context_consistent_with_policy(struct inode *inode, +static bool is_encryption_context_consistent_with_policy( + const struct fscrypt_context *ctx, const struct fscrypt_policy *policy) { - struct fscrypt_context ctx; - int res; - - if (!inode->i_sb->s_cop->get_context) - return 0; - - res = inode->i_sb->s_cop->get_context(inode, &ctx, sizeof(ctx)); - if (res != sizeof(ctx)) - return 0; - - return (memcmp(ctx.master_key_descriptor, policy->master_key_descriptor, - FS_KEY_DESCRIPTOR_SIZE) == 0 && - (ctx.flags == policy->flags) && - (ctx.contents_encryption_mode == - policy->contents_encryption_mode) && - (ctx.filenames_encryption_mode == - policy->filenames_encryption_mode)); + return memcmp(ctx->master_key_descriptor, policy->master_key_descriptor, + FS_KEY_DESCRIPTOR_SIZE) == 0 && + (ctx->flags == policy->flags) && + (ctx->contents_encryption_mode == + policy->contents_encryption_mode) && + (ctx->filenames_encryption_mode == + policy->filenames_encryption_mode); } static int create_encryption_context_from_policy(struct inode *inode, @@ -90,6 +73,7 @@ int fscrypt_ioctl_set_policy(struct file *filp, const void __user *arg) struct fscrypt_policy policy; struct inode *inode = file_inode(filp); int ret; + struct fscrypt_context ctx; if (copy_from_user(&policy, arg, sizeof(policy))) return -EFAULT; @@ -106,7 +90,8 @@ int fscrypt_ioctl_set_policy(struct file *filp, const void __user *arg) inode_lock(inode); - if (!inode_has_encryption_context(inode)) { + ret = inode->i_sb->s_cop->get_context(inode, &ctx, sizeof(ctx)); + if (ret == -ENODATA) { if (!S_ISDIR(inode->i_mode)) ret = -ENOTDIR; else if (!inode->i_sb->s_cop->empty_dir) @@ -116,8 +101,13 @@ int fscrypt_ioctl_set_policy(struct file *filp, const void __user *arg) else ret = create_encryption_context_from_policy(inode, &policy); - } else if (!is_encryption_context_consistent_with_policy(inode, - &policy)) { + } else if (ret == sizeof(ctx) && + is_encryption_context_consistent_with_policy(&ctx, + &policy)) { + /* The file already uses the same encryption policy. */ + ret = 0; + } else if (ret >= 0 || ret == -ERANGE) { + /* The file already uses a different encryption policy. */ ret = -EEXIST; } @@ -140,8 +130,10 @@ int fscrypt_ioctl_get_policy(struct file *filp, void __user *arg) return -ENODATA; res = inode->i_sb->s_cop->get_context(inode, &ctx, sizeof(ctx)); + if (res < 0 && res != -ERANGE) + return res; if (res != sizeof(ctx)) - return -ENODATA; + return -EINVAL; if (ctx.format != FS_ENCRYPTION_CONTEXT_FORMAT_V1) return -EINVAL; -- cgit v1.2.3 From 58ae74683ae2c07cd717a91799edb50231061938 Mon Sep 17 00:00:00 2001 From: Richard Weinberger Date: Mon, 19 Dec 2016 12:25:32 +0100 Subject: fscrypt: factor out bio specific functions That way we can get rid of the direct dependency on CONFIG_BLOCK. Fixes: d475a507457b ("ubifs: Add skeleton for fscrypto") Reported-by: Arnd Bergmann Reported-by: Randy Dunlap Reviewed-by: Eric Biggers Reviewed-by: Christoph Hellwig Reviewed-by: David Gstir Signed-off-by: Richard Weinberger Signed-off-by: Theodore Ts'o --- fs/crypto/Kconfig | 1 - fs/crypto/Makefile | 1 + fs/crypto/bio.c | 145 ++++++++++++++++++++++++++++++++++++++++ fs/crypto/crypto.c | 157 +++++--------------------------------------- fs/crypto/fscrypt_private.h | 16 ++++- 5 files changed, 177 insertions(+), 143 deletions(-) create mode 100644 fs/crypto/bio.c (limited to 'fs/crypto') diff --git a/fs/crypto/Kconfig b/fs/crypto/Kconfig index f514978f6688..08b46e6e3995 100644 --- a/fs/crypto/Kconfig +++ b/fs/crypto/Kconfig @@ -1,6 +1,5 @@ config FS_ENCRYPTION tristate "FS Encryption (Per-file encryption)" - depends on BLOCK select CRYPTO select CRYPTO_AES select CRYPTO_CBC diff --git a/fs/crypto/Makefile b/fs/crypto/Makefile index f17684c48739..9f6607f17b53 100644 --- a/fs/crypto/Makefile +++ b/fs/crypto/Makefile @@ -1,3 +1,4 @@ obj-$(CONFIG_FS_ENCRYPTION) += fscrypto.o fscrypto-y := crypto.o fname.o policy.o keyinfo.o +fscrypto-$(CONFIG_BLOCK) += bio.o diff --git a/fs/crypto/bio.c b/fs/crypto/bio.c new file mode 100644 index 000000000000..a409a84f1bca --- /dev/null +++ b/fs/crypto/bio.c @@ -0,0 +1,145 @@ +/* + * This contains encryption functions for per-file encryption. + * + * Copyright (C) 2015, Google, Inc. + * Copyright (C) 2015, Motorola Mobility + * + * Written by Michael Halcrow, 2014. + * + * Filename encryption additions + * Uday Savagaonkar, 2014 + * Encryption policy handling additions + * Ildar Muslukhov, 2014 + * Add fscrypt_pullback_bio_page() + * Jaegeuk Kim, 2015. + * + * This has not yet undergone a rigorous security audit. + * + * The usage of AES-XTS should conform to recommendations in NIST + * Special Publication 800-38E and IEEE P1619/D16. + */ + +#include +#include +#include +#include +#include "fscrypt_private.h" + +/* + * Call fscrypt_decrypt_page on every single page, reusing the encryption + * context. + */ +static void completion_pages(struct work_struct *work) +{ + struct fscrypt_ctx *ctx = + container_of(work, struct fscrypt_ctx, r.work); + struct bio *bio = ctx->r.bio; + struct bio_vec *bv; + int i; + + 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->index); + + if (ret) { + WARN_ON_ONCE(1); + SetPageError(page); + } else { + SetPageUptodate(page); + } + unlock_page(page); + } + fscrypt_release_ctx(ctx); + bio_put(bio); +} + +void fscrypt_decrypt_bio_pages(struct fscrypt_ctx *ctx, struct bio *bio) +{ + INIT_WORK(&ctx->r.work, completion_pages); + ctx->r.bio = bio; + queue_work(fscrypt_read_workqueue, &ctx->r.work); +} +EXPORT_SYMBOL(fscrypt_decrypt_bio_pages); + +void fscrypt_pullback_bio_page(struct page **page, bool restore) +{ + struct fscrypt_ctx *ctx; + struct page *bounce_page; + + /* The bounce data pages are unmapped. */ + if ((*page)->mapping) + return; + + /* The bounce data page is unmapped. */ + bounce_page = *page; + ctx = (struct fscrypt_ctx *)page_private(bounce_page); + + /* restore control page */ + *page = ctx->w.control_page; + + if (restore) + fscrypt_restore_control_page(bounce_page); +} +EXPORT_SYMBOL(fscrypt_pullback_bio_page); + +int fscrypt_zeroout_range(const struct inode *inode, pgoff_t lblk, + sector_t pblk, unsigned int len) +{ + struct fscrypt_ctx *ctx; + struct page *ciphertext_page = NULL; + struct bio *bio; + int ret, err = 0; + + BUG_ON(inode->i_sb->s_blocksize != PAGE_SIZE); + + ctx = fscrypt_get_ctx(inode, GFP_NOFS); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); + + ciphertext_page = fscrypt_alloc_bounce_page(ctx, GFP_NOWAIT); + if (IS_ERR(ciphertext_page)) { + err = PTR_ERR(ciphertext_page); + goto errout; + } + + while (len--) { + err = fscrypt_do_page_crypto(inode, FS_ENCRYPT, lblk, + ZERO_PAGE(0), ciphertext_page, + PAGE_SIZE, 0, GFP_NOFS); + if (err) + goto errout; + + bio = bio_alloc(GFP_NOWAIT, 1); + if (!bio) { + err = -ENOMEM; + goto errout; + } + bio->bi_bdev = inode->i_sb->s_bdev; + bio->bi_iter.bi_sector = + pblk << (inode->i_sb->s_blocksize_bits - 9); + bio_set_op_attrs(bio, REQ_OP_WRITE, 0); + ret = bio_add_page(bio, ciphertext_page, + inode->i_sb->s_blocksize, 0); + if (ret != inode->i_sb->s_blocksize) { + /* should never happen! */ + WARN_ON(1); + bio_put(bio); + err = -EIO; + goto errout; + } + err = submit_bio_wait(bio); + if ((err == 0) && bio->bi_error) + err = -EIO; + bio_put(bio); + if (err) + goto errout; + lblk++; + pblk++; + } + err = 0; +errout: + fscrypt_release_ctx(ctx); + return err; +} +EXPORT_SYMBOL(fscrypt_zeroout_range); diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c index ac8e4f6a3773..02a7a9286449 100644 --- a/fs/crypto/crypto.c +++ b/fs/crypto/crypto.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include "fscrypt_private.h" @@ -44,7 +43,7 @@ static mempool_t *fscrypt_bounce_page_pool = NULL; static LIST_HEAD(fscrypt_free_ctxs); static DEFINE_SPINLOCK(fscrypt_ctx_lock); -static struct workqueue_struct *fscrypt_read_workqueue; +struct workqueue_struct *fscrypt_read_workqueue; static DEFINE_MUTEX(fscrypt_init_mutex); static struct kmem_cache *fscrypt_ctx_cachep; @@ -141,16 +140,10 @@ static void page_crypt_complete(struct crypto_async_request *req, int res) complete(&ecr->completion); } -typedef enum { - FS_DECRYPT = 0, - FS_ENCRYPT, -} fscrypt_direction_t; - -static int do_page_crypto(const struct inode *inode, - fscrypt_direction_t rw, u64 lblk_num, - struct page *src_page, struct page *dest_page, - unsigned int len, unsigned int offs, - gfp_t gfp_flags) +int fscrypt_do_page_crypto(const struct inode *inode, fscrypt_direction_t rw, + u64 lblk_num, struct page *src_page, + struct page *dest_page, unsigned int len, + unsigned int offs, gfp_t gfp_flags) { struct { __le64 index; @@ -205,7 +198,8 @@ static int do_page_crypto(const struct inode *inode, return 0; } -static struct page *alloc_bounce_page(struct fscrypt_ctx *ctx, gfp_t gfp_flags) +struct page *fscrypt_alloc_bounce_page(struct fscrypt_ctx *ctx, + gfp_t gfp_flags) { ctx->w.bounce_page = mempool_alloc(fscrypt_bounce_page_pool, gfp_flags); if (ctx->w.bounce_page == NULL) @@ -260,9 +254,9 @@ struct page *fscrypt_encrypt_page(const struct inode *inode, if (inode->i_sb->s_cop->flags & FS_CFLG_OWN_PAGES) { /* with inplace-encryption we just encrypt the page */ - err = do_page_crypto(inode, FS_ENCRYPT, lblk_num, - page, ciphertext_page, - len, offs, gfp_flags); + err = fscrypt_do_page_crypto(inode, FS_ENCRYPT, lblk_num, page, + ciphertext_page, len, offs, + gfp_flags); if (err) return ERR_PTR(err); @@ -276,14 +270,14 @@ struct page *fscrypt_encrypt_page(const struct inode *inode, return (struct page *)ctx; /* The encryption operation will require a bounce page. */ - ciphertext_page = alloc_bounce_page(ctx, gfp_flags); + ciphertext_page = fscrypt_alloc_bounce_page(ctx, gfp_flags); if (IS_ERR(ciphertext_page)) goto errout; ctx->w.control_page = page; - err = do_page_crypto(inode, FS_ENCRYPT, lblk_num, - page, ciphertext_page, - len, offs, gfp_flags); + err = fscrypt_do_page_crypto(inode, FS_ENCRYPT, lblk_num, + page, ciphertext_page, len, offs, + gfp_flags); if (err) { ciphertext_page = ERR_PTR(err); goto errout; @@ -320,72 +314,11 @@ int fscrypt_decrypt_page(const struct inode *inode, struct page *page, if (!(inode->i_sb->s_cop->flags & FS_CFLG_OWN_PAGES)) BUG_ON(!PageLocked(page)); - return do_page_crypto(inode, FS_DECRYPT, lblk_num, page, page, len, - offs, GFP_NOFS); + return fscrypt_do_page_crypto(inode, FS_DECRYPT, lblk_num, page, page, + len, offs, GFP_NOFS); } EXPORT_SYMBOL(fscrypt_decrypt_page); -int fscrypt_zeroout_range(const struct inode *inode, pgoff_t lblk, - sector_t pblk, unsigned int len) -{ - struct fscrypt_ctx *ctx; - struct page *ciphertext_page = NULL; - struct bio *bio; - int ret, err = 0; - - BUG_ON(inode->i_sb->s_blocksize != PAGE_SIZE); - - ctx = fscrypt_get_ctx(inode, GFP_NOFS); - if (IS_ERR(ctx)) - return PTR_ERR(ctx); - - ciphertext_page = alloc_bounce_page(ctx, GFP_NOWAIT); - if (IS_ERR(ciphertext_page)) { - err = PTR_ERR(ciphertext_page); - goto errout; - } - - while (len--) { - err = do_page_crypto(inode, FS_ENCRYPT, lblk, - ZERO_PAGE(0), ciphertext_page, - PAGE_SIZE, 0, GFP_NOFS); - if (err) - goto errout; - - bio = bio_alloc(GFP_NOWAIT, 1); - if (!bio) { - err = -ENOMEM; - goto errout; - } - bio->bi_bdev = inode->i_sb->s_bdev; - bio->bi_iter.bi_sector = - pblk << (inode->i_sb->s_blocksize_bits - 9); - bio_set_op_attrs(bio, REQ_OP_WRITE, 0); - ret = bio_add_page(bio, ciphertext_page, - inode->i_sb->s_blocksize, 0); - if (ret != inode->i_sb->s_blocksize) { - /* should never happen! */ - WARN_ON(1); - bio_put(bio); - err = -EIO; - goto errout; - } - err = submit_bio_wait(bio); - if ((err == 0) && bio->bi_error) - err = -EIO; - bio_put(bio); - if (err) - goto errout; - lblk++; - pblk++; - } - err = 0; -errout: - fscrypt_release_ctx(ctx); - return err; -} -EXPORT_SYMBOL(fscrypt_zeroout_range); - /* * Validate dentries for encrypted directories to make sure we aren't * potentially caching stale data after a key has been added or @@ -442,64 +375,6 @@ const struct dentry_operations fscrypt_d_ops = { }; EXPORT_SYMBOL(fscrypt_d_ops); -/* - * Call fscrypt_decrypt_page on every single page, reusing the encryption - * context. - */ -static void completion_pages(struct work_struct *work) -{ - struct fscrypt_ctx *ctx = - container_of(work, struct fscrypt_ctx, r.work); - struct bio *bio = ctx->r.bio; - struct bio_vec *bv; - int i; - - 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->index); - - if (ret) { - WARN_ON_ONCE(1); - SetPageError(page); - } else { - SetPageUptodate(page); - } - unlock_page(page); - } - fscrypt_release_ctx(ctx); - bio_put(bio); -} - -void fscrypt_decrypt_bio_pages(struct fscrypt_ctx *ctx, struct bio *bio) -{ - INIT_WORK(&ctx->r.work, completion_pages); - ctx->r.bio = bio; - queue_work(fscrypt_read_workqueue, &ctx->r.work); -} -EXPORT_SYMBOL(fscrypt_decrypt_bio_pages); - -void fscrypt_pullback_bio_page(struct page **page, bool restore) -{ - struct fscrypt_ctx *ctx; - struct page *bounce_page; - - /* The bounce data pages are unmapped. */ - if ((*page)->mapping) - return; - - /* The bounce data page is unmapped. */ - bounce_page = *page; - ctx = (struct fscrypt_ctx *)page_private(bounce_page); - - /* restore control page */ - *page = ctx->w.control_page; - - if (restore) - fscrypt_restore_control_page(bounce_page); -} -EXPORT_SYMBOL(fscrypt_pullback_bio_page); - void fscrypt_restore_control_page(struct page *page) { struct fscrypt_ctx *ctx; diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h index aeab032d7d35..7bff7b4c7498 100644 --- a/fs/crypto/fscrypt_private.h +++ b/fs/crypto/fscrypt_private.h @@ -71,6 +71,11 @@ struct fscrypt_info { u8 ci_master_key[FS_KEY_DESCRIPTOR_SIZE]; }; +typedef enum { + FS_DECRYPT = 0, + FS_ENCRYPT, +} fscrypt_direction_t; + #define FS_CTX_REQUIRES_FREE_ENCRYPT_FL 0x00000001 #define FS_CTX_HAS_BOUNCE_BUFFER_FL 0x00000002 @@ -85,7 +90,16 @@ struct fscrypt_completion_result { /* crypto.c */ -int fscrypt_initialize(unsigned int cop_flags); +extern int fscrypt_initialize(unsigned int cop_flags); +extern struct workqueue_struct *fscrypt_read_workqueue; +extern int fscrypt_do_page_crypto(const struct inode *inode, + fscrypt_direction_t rw, u64 lblk_num, + struct page *src_page, + struct page *dest_page, + unsigned int len, unsigned int offs, + gfp_t gfp_flags); +extern struct page *fscrypt_alloc_bounce_page(struct fscrypt_ctx *ctx, + gfp_t gfp_flags); /* keyinfo.c */ extern int fscrypt_get_crypt_info(struct inode *); -- cgit v1.2.3 From 5bbdcbbb396196f1c94110ad7a041e90de95c4c2 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Mon, 2 Jan 2017 15:12:17 -0500 Subject: fscrypt: make test_dummy_encryption require a keyring key Currently, the test_dummy_encryption ext4 mount option, which exists only to test encrypted I/O paths with xfstests, overrides all per-inode encryption keys with a fixed key. This change minimizes test_dummy_encryption-specific code path changes by supplying a fake context for directories which are not encrypted for use when creating new directories, files, or symlinks. This allows us to properly exercise the keyring lookup, derivation, and context inheritance code paths. Before mounting a file system using test_dummy_encryption, userspace must execute the following shell commands: mode='\x00\x00\x00\x00' raw="$(printf ""\\\\x%02x"" $(seq 0 63))" if lscpu | grep "Byte Order" | grep -q Little ; then size='\x40\x00\x00\x00' else size='\x00\x00\x00\x40' fi key="${mode}${raw}${size}" keyctl new_session echo -n -e "${key}" | keyctl padd logon fscrypt:4242424242424242 @s Signed-off-by: Theodore Ts'o --- fs/crypto/keyinfo.c | 15 ++++++--------- fs/crypto/policy.c | 22 +++++++--------------- 2 files changed, 13 insertions(+), 24 deletions(-) (limited to 'fs/crypto') diff --git a/fs/crypto/keyinfo.c b/fs/crypto/keyinfo.c index 95cd4c3b06c3..80f145c8d550 100644 --- a/fs/crypto/keyinfo.c +++ b/fs/crypto/keyinfo.c @@ -206,12 +206,16 @@ retry: res = inode->i_sb->s_cop->get_context(inode, &ctx, sizeof(ctx)); if (res < 0) { - if (!fscrypt_dummy_context_enabled(inode)) + if (!fscrypt_dummy_context_enabled(inode) || + inode->i_sb->s_cop->is_encrypted(inode)) return res; + /* Fake up a context for an unencrypted directory */ + memset(&ctx, 0, sizeof(ctx)); ctx.format = FS_ENCRYPTION_CONTEXT_FORMAT_V1; ctx.contents_encryption_mode = FS_ENCRYPTION_MODE_AES_256_XTS; ctx.filenames_encryption_mode = FS_ENCRYPTION_MODE_AES_256_CTS; - ctx.flags = 0; + memset(ctx.master_key_descriptor, 0x42, FS_KEY_DESCRIPTOR_SIZE); + res = sizeof(ctx); } else if (res != sizeof(ctx)) { return -EINVAL; } @@ -247,12 +251,6 @@ retry: if (!raw_key) goto out; - if (fscrypt_dummy_context_enabled(inode)) { - memset(raw_key, 0x42, keysize/2); - memset(raw_key+keysize/2, 0x24, keysize - (keysize/2)); - goto got_key; - } - res = validate_user_key(crypt_info, &ctx, raw_key, FS_KEY_DESC_PREFIX, FS_KEY_DESC_PREFIX_SIZE); if (res && inode->i_sb->s_cop->key_prefix) { @@ -270,7 +268,6 @@ retry: } else if (res) { goto out; } -got_key: ctfm = crypto_alloc_skcipher(cipher_str, 0, 0); if (!ctfm || IS_ERR(ctfm)) { res = ctfm ? PTR_ERR(ctfm) : -ENOMEM; diff --git a/fs/crypto/policy.c b/fs/crypto/policy.c index 4c99972899c7..14b76da71269 100644 --- a/fs/crypto/policy.c +++ b/fs/crypto/policy.c @@ -198,9 +198,9 @@ EXPORT_SYMBOL(fscrypt_has_permitted_context); * @parent: Parent inode from which the context is inherited. * @child: Child inode that inherits the context from @parent. * @fs_data: private data given by FS. - * @preload: preload child i_crypt_info + * @preload: preload child i_crypt_info if true * - * Return: Zero on success, non-zero otherwise + * Return: 0 on success, -errno on failure */ int fscrypt_inherit_context(struct inode *parent, struct inode *child, void *fs_data, bool preload) @@ -221,19 +221,11 @@ int fscrypt_inherit_context(struct inode *parent, struct inode *child, return -ENOKEY; ctx.format = FS_ENCRYPTION_CONTEXT_FORMAT_V1; - if (fscrypt_dummy_context_enabled(parent)) { - ctx.contents_encryption_mode = FS_ENCRYPTION_MODE_AES_256_XTS; - ctx.filenames_encryption_mode = FS_ENCRYPTION_MODE_AES_256_CTS; - ctx.flags = 0; - memset(ctx.master_key_descriptor, 0x42, FS_KEY_DESCRIPTOR_SIZE); - res = 0; - } else { - ctx.contents_encryption_mode = ci->ci_data_mode; - ctx.filenames_encryption_mode = ci->ci_filename_mode; - ctx.flags = ci->ci_flags; - memcpy(ctx.master_key_descriptor, ci->ci_master_key, - FS_KEY_DESCRIPTOR_SIZE); - } + ctx.contents_encryption_mode = ci->ci_data_mode; + ctx.filenames_encryption_mode = ci->ci_filename_mode; + ctx.flags = ci->ci_flags; + memcpy(ctx.master_key_descriptor, ci->ci_master_key, + FS_KEY_DESCRIPTOR_SIZE); get_random_bytes(ctx.nonce, FS_KEY_DERIVATION_NONCE_SIZE); res = parent->i_sb->s_cop->set_context(child, &ctx, sizeof(ctx), fs_data); -- cgit v1.2.3 From a5d431eff2e0bb22156897435aa277ddc96074f7 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Thu, 5 Jan 2017 13:51:18 -0800 Subject: fscrypt: make fscrypt_operations.key_prefix a string There was an unnecessary amount of complexity around requesting the filesystem-specific key prefix. It was unclear why; perhaps it was envisioned that different instances of the same filesystem type could use different key prefixes, or that key prefixes could be binary. However, neither of those things were implemented or really make sense at all. So simplify the code by making key_prefix a const char *. Signed-off-by: Eric Biggers Reviewed-by: Richard Weinberger Signed-off-by: Theodore Ts'o --- fs/crypto/keyinfo.c | 31 +++++++++++-------------------- 1 file changed, 11 insertions(+), 20 deletions(-) (limited to 'fs/crypto') diff --git a/fs/crypto/keyinfo.c b/fs/crypto/keyinfo.c index 80f145c8d550..eeb6fd67ea17 100644 --- a/fs/crypto/keyinfo.c +++ b/fs/crypto/keyinfo.c @@ -77,26 +77,22 @@ out: static int validate_user_key(struct fscrypt_info *crypt_info, struct fscrypt_context *ctx, u8 *raw_key, - u8 *prefix, int prefix_size) + const char *prefix) { - u8 *full_key_descriptor; + char *description; struct key *keyring_key; struct fscrypt_key *master_key; const struct user_key_payload *ukp; - int full_key_len = prefix_size + (FS_KEY_DESCRIPTOR_SIZE * 2) + 1; int res; - full_key_descriptor = kmalloc(full_key_len, GFP_NOFS); - if (!full_key_descriptor) + description = kasprintf(GFP_NOFS, "%s%*phN", prefix, + FS_KEY_DESCRIPTOR_SIZE, + ctx->master_key_descriptor); + if (!description) return -ENOMEM; - memcpy(full_key_descriptor, prefix, prefix_size); - sprintf(full_key_descriptor + prefix_size, - "%*phN", FS_KEY_DESCRIPTOR_SIZE, - ctx->master_key_descriptor); - full_key_descriptor[full_key_len - 1] = '\0'; - keyring_key = request_key(&key_type_logon, full_key_descriptor, NULL); - kfree(full_key_descriptor); + keyring_key = request_key(&key_type_logon, description, NULL); + kfree(description); if (IS_ERR(keyring_key)) return PTR_ERR(keyring_key); @@ -251,15 +247,10 @@ retry: if (!raw_key) goto out; - res = validate_user_key(crypt_info, &ctx, raw_key, - FS_KEY_DESC_PREFIX, FS_KEY_DESC_PREFIX_SIZE); + res = validate_user_key(crypt_info, &ctx, raw_key, FS_KEY_DESC_PREFIX); if (res && inode->i_sb->s_cop->key_prefix) { - u8 *prefix = NULL; - int prefix_size, res2; - - prefix_size = inode->i_sb->s_cop->key_prefix(inode, &prefix); - res2 = validate_user_key(crypt_info, &ctx, raw_key, - prefix, prefix_size); + int res2 = validate_user_key(crypt_info, &ctx, raw_key, + inode->i_sb->s_cop->key_prefix); if (res2) { if (res2 == -ENOKEY) res = -ENOKEY; -- cgit v1.2.3 From 02680b31a0b3757e121d27223b6fe21778f52408 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 10 Jan 2017 16:57:32 +0000 Subject: fscrypt: remove redundant assignment of res res is assigned to sizeof(ctx), however, this is unused and res is updated later on without that assigned value to res ever being used. Remove this redundant assignment. Fixes CoverityScan CID#1395546 "Unused value" Signed-off-by: Colin Ian King Signed-off-by: Theodore Ts'o --- fs/crypto/keyinfo.c | 1 - 1 file changed, 1 deletion(-) (limited to 'fs/crypto') diff --git a/fs/crypto/keyinfo.c b/fs/crypto/keyinfo.c index eeb6fd67ea17..02eb6b9e4438 100644 --- a/fs/crypto/keyinfo.c +++ b/fs/crypto/keyinfo.c @@ -211,7 +211,6 @@ retry: ctx.contents_encryption_mode = FS_ENCRYPTION_MODE_AES_256_XTS; ctx.filenames_encryption_mode = FS_ENCRYPTION_MODE_AES_256_CTS; memset(ctx.master_key_descriptor, 0x42, FS_KEY_DESCRIPTOR_SIZE); - res = sizeof(ctx); } else if (res != sizeof(ctx)) { return -EINVAL; } -- cgit v1.2.3 From 46f47e48008b63f5fd3a3bad8b79ba1a89fb625f Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Tue, 24 Jan 2017 10:58:06 -0800 Subject: fscrypt: split supp and notsupp declarations into their own headers Previously, each filesystem configured without encryption support would define all the public fscrypt functions to their notsupp_* stubs. This list of #defines had to be updated in every filesystem whenever a change was made to the public fscrypt functions. To make things more maintainable now that we have three filesystems using fscrypt, split the old header fscrypto.h into several new headers. fscrypt_supp.h contains the real declarations and is included by filesystems when configured with encryption support, whereas fscrypt_notsupp.h contains the inline stubs and is included by filesystems when configured without encryption support. fscrypt_common.h contains common declarations needed by both. Signed-off-by: Eric Biggers Signed-off-by: Theodore Ts'o --- fs/crypto/fscrypt_private.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs/crypto') diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h index 7bff7b4c7498..e8a229e1d45d 100644 --- a/fs/crypto/fscrypt_private.h +++ b/fs/crypto/fscrypt_private.h @@ -11,7 +11,7 @@ #ifndef _FSCRYPT_PRIVATE_H #define _FSCRYPT_PRIVATE_H -#include +#include #define FS_FNAME_CRYPTO_DIGEST_SIZE 32 -- cgit v1.2.3 From b14c8e6afd873cae97060272efaac376efec77a4 Mon Sep 17 00:00:00 2001 From: Richard Weinberger Date: Wed, 1 Feb 2017 21:32:09 +0100 Subject: fscrypt: properly declare on-stack completion When a completion is declared on-stack we have to use COMPLETION_INITIALIZER_ONSTACK(). Fixes: 0b81d07790726 ("fs crypto: move per-file encryption from f2fs tree to fs/crypto") Signed-off-by: Richard Weinberger Signed-off-by: Theodore Ts'o --- fs/crypto/fscrypt_private.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs/crypto') diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h index e8a229e1d45d..fdbb8af32eaf 100644 --- a/fs/crypto/fscrypt_private.h +++ b/fs/crypto/fscrypt_private.h @@ -86,7 +86,7 @@ struct fscrypt_completion_result { #define DECLARE_FS_COMPLETION_RESULT(ecr) \ struct fscrypt_completion_result ecr = { \ - COMPLETION_INITIALIZER((ecr).completion), 0 } + COMPLETION_INITIALIZER_ONSTACK((ecr).completion), 0 } /* crypto.c */ -- cgit v1.2.3