File-level Encryption Support by VFS
Jaegeuk Kim
maintainerv3 cover File-level Encryption Support by VFS
Change log from v2:
- add missing Kconfig
- support module compilation
- change some data types to u8
Jaegeuk Kim (10):
fs crypto: add basic definitions for per-file encryption fs crypto: add crypto.c for encrypt/decrypt functions fs crypto: add policy.c to handle contexts
fs crypto: add keyinfo.c to handle permissions fs crypto: add fname.c to support filename encryption fs crypto: add Makefile and Kconfig
fs crypto: add dentry revalidation facility in crypto f2fs crypto: migrate into vfs's crypto engine f2fs crypto: sync ext4_lookup and ext4_file_open ext4 crypto: migrate into vfs's crypto engine
fs/Kconfig | 2 + fs/Makefile | 1 + fs/crypto/Kconfig | 18 ++ fs/crypto/Makefile | 3 + fs/crypto/crypto.c | 556 +++++++++++++++++++++++++++++++++++++++++++++++ fs/crypto/fname.c | 427 ++++++++++++++++++++++++++++++++++++ fs/crypto/keyinfo.c | 278 ++++++++++++++++++++++++ fs/crypto/policy.c | 229 +++++++++++++++++++ fs/ext4/Kconfig | 12 +- fs/ext4/Makefile | 2 - fs/ext4/crypto.c | 525 -------------------------------------------- fs/ext4/crypto_fname.c | 470 --------------------------------------- fs/ext4/crypto_key.c | 276 ----------------------- fs/ext4/crypto_policy.c | 229 ------------------- fs/ext4/dir.c | 26 ++- fs/ext4/ext4.h | 195 ++++++----------- fs/ext4/ext4_crypto.h | 159 -------------- fs/ext4/file.c | 10 +- fs/ext4/ialloc.c | 7 +- fs/ext4/inline.c | 14 +- fs/ext4/inode.c | 8 +- fs/ext4/ioctl.c | 20 +- fs/ext4/namei.c | 120 +++++----- fs/ext4/page-io.c | 13 +- fs/ext4/readpage.c | 45 +--- fs/ext4/super.c | 85 +++++++- fs/ext4/symlink.c | 33 ++- fs/f2fs/Kconfig | 10 +- fs/f2fs/Makefile | 2 - fs/f2fs/crypto.c | 473 ---------------------------------------- fs/f2fs/crypto_fname.c | 446 ------------------------------------- fs/f2fs/crypto_key.c | 267 ----------------------- fs/f2fs/crypto_policy.c | 210 ------------------ fs/f2fs/data.c | 31 ++- fs/f2fs/dir.c | 46 ++-- fs/f2fs/f2fs.h | 172 +++------------ fs/f2fs/f2fs_crypto.h | 151 ------------- fs/f2fs/file.c | 40 ++-- fs/f2fs/inline.c | 4 +- fs/f2fs/inode.c | 5 +- fs/f2fs/namei.c | 79 ++++--- fs/f2fs/super.c | 55 +++-- include/linux/dcache.h | 2 + include/linux/fs.h | 8 + include/linux/fscrypto.h | 433 ++++++++++++++++++++++++++++++++++++ include/uapi/linux/fs.h | 18 ++ 46 files changed, 2423 insertions(+), 3792 deletions(-) create mode 100644 fs/crypto/Kconfig create mode 100644 fs/crypto/Makefile create mode 100644 fs/crypto/crypto.c create mode 100644 fs/crypto/fname.c create mode 100644 fs/crypto/keyinfo.c create mode 100644 fs/crypto/policy.c delete mode 100644 fs/ext4/crypto.c delete mode 100644 fs/ext4/crypto_fname.c delete mode 100644 fs/ext4/crypto_key.c delete mode 100644 fs/ext4/crypto_policy.c delete mode 100644 fs/ext4/ext4_crypto.h delete mode 100644 fs/f2fs/crypto.c delete mode 100644 fs/f2fs/crypto_fname.c delete mode 100644 fs/f2fs/crypto_key.c delete mode 100644 fs/f2fs/crypto_policy.c delete mode 100644 fs/f2fs/f2fs_crypto.h create mode 100644 include/linux/fscrypto.h
Signature · 1 line
2.6.3
Jaegeuk Kim
maintainerPATCH v3 1/10 fs crypto: add basic definitions for per-file encryption
This patch adds definitions for per-file encryption used by ext4 and f2fs.
--- include/linux/fs.h | 8 ++ include/linux/fscrypto.h | 239 +++++++++++++++++++++++++++++++++++++++++++++++ include/uapi/linux/fs.h | 18 ++++ 3 files changed, 265 insertions(+) create mode 100644 include/linux/fscrypto.h
include/linux/fs.h +8 -0
@@ -53,6 +53,8 @@ struct swap_info_struct;struct seq_file ;struct workqueue_struct ;struct iov_iter ; +struct fscrypt_info ; +struct fscrypt_operations ;extern void __init inode_init (void );extern void __init inode_init_early (void );
@@ -678,6 +680,10 @@ struct inode {struct hlist_head i_fsnotify_marks;#endif +#if IS_ENABLED (CONFIG_FS_ENCRYPTION ) +struct fscrypt_info *i_crypt_info; +#endif +void *i_private;/* fs or device private pointer */ };
@@ -1323,6 +1329,8 @@ struct super_block {#endif const struct xattr_handler **s_xattr; +const struct fscrypt_operations *s_cop; +struct hlist_bl_head s_anon;/* anonymous dentries for (nfs) exporting */ struct list_head s_mounts;/* list of mounts; _not_ for fs use */ struct block_device *s_bdev;
include/linux/fscrypto.h new file +239 -0
239 lines not on this page · raw message
include/uapi/linux/fs.h +18 -0
@@ -247,6 +247,24 @@ struct fsxattr {#define FS_IOC_FSSETXATTR _IOW ('X', 32, struct fsxattr)/* +* File system encryption support +*/ +/* Policy provided via an ioctl on the topmost directory */ +#define FS_KEY_DESCRIPTOR_SIZE 8 + +struct fscrypt_policy { +u8 version; +u8 contents_encryption_mode; +u8 filenames_encryption_mode; +u8 flags; +u8 master_key_descriptor[FS_KEY_DESCRIPTOR_SIZE ]; +} __packed; + +#define FS_IOC_SET_ENCRYPTION_POLICY _IOR('f', 19, struct fscrypt_policy) +#define FS_IOC_GET_ENCRYPTION_PWSALT _IOW('f', 20, __u8[16]) +#define FS_IOC_GET_ENCRYPTION_POLICY _IOW('f', 21, struct fscrypt_policy) + +/* * Inode flags (FS_IOC_GETFLAGS / FS_IOC_SETFLAGS) * * Note: for historical reasons, these flags were originally used and
Signature · 1 line
2.6.3
Jaegeuk Kim
maintainerPATCH v3 2/10 fs crypto: add crypto.c for encrypt/decrypt functions
In reply to Jaegeuk KimThis patch adds crypto.c supporting encrypting and decrypting functions.
1. IO preparation:
- fscrypt_get_ctx / fscrypt_release_ctx
2. before IOs:
- fscrypt_encrypt_page
- fscrypt_decrypt_page
- fscrypt_zeroout_range
3. after IOs:
- fscrypt_decrypt_bio_pages
- fscrypt_pullback_bio_page
- fscrypt_restore_control_page
--- fs/crypto/crypto.c | 507 +++++++++++++++++++++++++++++++++++++++++++++++ include/linux/fscrypto.h | 60 ++++++ 2 files changed, 567 insertions(+) create mode 100644 fs/crypto/crypto.c
fs/crypto/crypto.c new file +507 -0
@@ -0,0 +1,507 @@ +/* +* 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 <linux/crypto.h> +#include <linux/ecryptfs.h> +#include <linux/pagemap.h> +#include <linux/mempool.h> +#include <linux/module.h> +#include <linux/scatterlist.h> +#include <linux/ratelimit.h> +#include <linux/bio.h> +#include <linux/fscrypto.h> + +static unsigned int num_prealloc_crypto_pages =32 ; +static unsigned int num_prealloc_crypto_ctxs =128 ; + +module_param (num_prealloc_crypto_pages, uint,0444 ); +MODULE_PARM_DESC (num_prealloc_crypto_pages, +"Number of crypto pages to preallocate" ); +module_param (num_prealloc_crypto_ctxs, uint,0444 ); +MODULE_PARM_DESC (num_prealloc_crypto_ctxs, +"Number of crypto contexts to preallocate" ); + +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; +static DEFINE_MUTEX (fscrypt_init_mutex); + +static struct kmem_cache *fscrypt_ctx_cachep; +struct kmem_cache *fscrypt_info_cachep; + +/** +* fscrypt_release_ctx() - Releases an encryption context +* @ctx: The encryption context to release. +* +* If the encryption context was allocated from the pre-allocated pool, returns +* it to that pool. Else, frees it. +* +* If there's a bounce page in the context, this frees that. +*/ +void fscrypt_release_ctx (struct fscrypt_ctx *ctx) +{ +unsigned long flags; + +if (ctx->flags &FS_WRITE_PATH_FL && ctx->w.bounce_page) { +mempool_free (ctx->w.bounce_page, fscrypt_bounce_page_pool); + ctx->w.bounce_page =NULL ; + } + ctx->w.control_page =NULL ; +if (ctx->flags &FS_CTX_REQUIRES_FREE_ENCRYPT_FL ) { +kmem_cache_free (fscrypt_ctx_cachep, ctx); + }else { +spin_lock_irqsave (&fscrypt_ctx_lock, flags); +list_add (&ctx->free_list, &fscrypt_free_ctxs); +spin_unlock_irqrestore (&fscrypt_ctx_lock, flags); + } +} +EXPORT_SYMBOL (fscrypt_release_ctx); + +/** +* fscrypt_get_ctx() - Gets an encryption context +* @inode: The inode for which we are doing the crypto +* +* Allocates and initializes an encryption context. +* +* Return: An allocated and initialized encryption context on success; error +* value or NULL otherwise. +*/ +struct fscrypt_ctx *fscrypt_get_ctx (struct inode *inode) +{ +struct fscrypt_ctx *ctx =NULL ; +struct fscrypt_info *ci = inode->i_crypt_info; +unsigned long flags; + +if (ci ==NULL ) +return ERR_PTR (-ENOKEY ); + +/* +* We first try getting the ctx from a free list because in +* the common case the ctx will have an allocated and +* initialized crypto tfm, so it's probably a worthwhile +* optimization. For the bounce page, we first try getting it +* from the kernel allocator because that's just about as fast +* as getting it from a list and because a cache of free pages +* should generally be a "last resort" option for a filesystem +* to be able to do its job. +*/ +spin_lock_irqsave (&fscrypt_ctx_lock, flags); + ctx =list_first_entry_or_null (&fscrypt_free_ctxs, + struct fscrypt_ctx, free_list); +if (ctx) +list_del (&ctx->free_list); +spin_unlock_irqrestore (&fscrypt_ctx_lock, flags); +if (!ctx) { + ctx =kmem_cache_zalloc (fscrypt_ctx_cachep,GFP_NOFS ); +if (!ctx) +return ERR_PTR (-ENOMEM ); + ctx->flags |=FS_CTX_REQUIRES_FREE_ENCRYPT_FL ; + }else { + ctx->flags &= ~FS_CTX_REQUIRES_FREE_ENCRYPT_FL ; + } + ctx->flags &= ~FS_WRITE_PATH_FL ; +return ctx; +} +EXPORT_SYMBOL (fscrypt_get_ctx); + +/** +* fscrypt_complete() - The completion callback for page encryption +* @req: The asynchronous encryption request context +* @res: The result of the encryption operation +*/ +static void fscrypt_complete (struct crypto_async_request *req,int res) +{ +struct fscrypt_completion_result *ecr = req->data; + +if (res == -EINPROGRESS ) +return ; + ecr->res = res; +complete (&ecr->completion); +} + +typedef enum { +FS_DECRYPT =0 , +FS_ENCRYPT , +}fscrypt_direction_t ; + +static int do_page_crypto (struct inode *inode, +fscrypt_direction_t rw,pgoff_t index, +struct page *src_page,struct page *dest_page) +{ +u8 xts_tweak[FS_XTS_TWEAK_SIZE ]; +struct ablkcipher_request *req =NULL ; +DECLARE_FS_COMPLETION_RESULT (ecr); +struct scatterlist dst, src; +struct fscrypt_info *ci = inode->i_crypt_info; +struct crypto_ablkcipher *tfm = ci->ci_ctfm; +int res =0 ; + + req =ablkcipher_request_alloc (tfm,GFP_NOFS ); +if (!req) { +printk_ratelimited (KERN_ERR +"%s: crypto_request_alloc() failed\n" , + __func__); +return -ENOMEM ; + } + +ablkcipher_request_set_callback ( + req,CRYPTO_TFM_REQ_MAY_BACKLOG |CRYPTO_TFM_REQ_MAY_SLEEP , + fscrypt_complete, &ecr); + +BUILD_BUG_ON (FS_XTS_TWEAK_SIZE <sizeof (index)); +memcpy (xts_tweak, &inode->i_ino,sizeof (index)); +memset (&xts_tweak[sizeof (index)],0 , +FS_XTS_TWEAK_SIZE -sizeof (index)); + +sg_init_table (&dst,1 ); +sg_set_page (&dst, dest_page,PAGE_CACHE_SIZE ,0 ); +sg_init_table (&src,1 ); +sg_set_page (&src, src_page,PAGE_CACHE_SIZE ,0 ); +ablkcipher_request_set_crypt (req, &src, &dst,PAGE_CACHE_SIZE , + xts_tweak); +if (rw ==FS_DECRYPT ) + res =crypto_ablkcipher_decrypt (req); +else + res =crypto_ablkcipher_encrypt (req); +if (res == -EINPROGRESS || res == -EBUSY ) { +BUG_ON (req->base.data != &ecr); +wait_for_completion (&ecr.completion); + res = ecr.res; + } +ablkcipher_request_free (req); +if (res) { +printk_ratelimited (KERN_ERR +"%s: crypto_ablkcipher_encrypt() returned %d\n" , + __func__, res); +return res; + } +return 0 ; +} + +static struct page *alloc_bounce_page (struct fscrypt_ctx *ctx) +{ + ctx->w.bounce_page =mempool_alloc (fscrypt_bounce_page_pool, +GFP_NOWAIT ); +if (ctx->w.bounce_page ==NULL ) +return ERR_PTR (-ENOMEM ); + ctx->flags |=FS_WRITE_PATH_FL ; +return ctx->w.bounce_page; +} + +/** +* 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. +* +* Allocates a ciphertext page and encrypts plaintext_page into it using the ctx +* encryption context. +* +* Called on the page write path. The caller must call +* fscrypt_restore_control_page() on the returned ciphertext page to +* release the bounce buffer and the encryption context. +* +* 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 *plaintext_page) +{ +struct fscrypt_ctx *ctx; +struct page *ciphertext_page =NULL ; +int err; + +BUG_ON (!PageLocked (plaintext_page)); + + ctx =fscrypt_get_ctx (inode); +if (IS_ERR (ctx)) +return (struct page *)ctx; + +/* The encryption operation will require a bounce page. */ + ciphertext_page =alloc_bounce_page (ctx); +if (IS_ERR (ciphertext_page)) + goto errout; + + ctx->w.control_page = plaintext_page; + err =do_page_crypto (inode,FS_ENCRYPT , plaintext_page->index, + plaintext_page, ciphertext_page); +if (err) { + ciphertext_page =ERR_PTR (err); + goto errout; + } +SetPagePrivate (ciphertext_page); +set_page_private (ciphertext_page, (unsigned long )ctx); +lock_page (ciphertext_page); +return ciphertext_page; + +errout: +fscrypt_release_ctx (ctx); +return ciphertext_page; +} +EXPORT_SYMBOL (fscrypt_encrypt_page); + +/** +* f2crypt_decrypt_page() - Decrypts a page in-place +* @page: The page to decrypt. Must be locked. +* +* Decrypts page in-place using the ctx encryption context. +* +* Called from the read completion callback. +* +* Return: Zero on success, non-zero otherwise. +*/ +int fscrypt_decrypt_page (struct page *page) +{ +BUG_ON (!PageLocked (page)); + +return do_page_crypto (page->mapping->host, +FS_DECRYPT , page->index, page, page); +} +EXPORT_SYMBOL (fscrypt_decrypt_page); + +int fscrypt_zeroout_range (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_CACHE_SIZE ); + + ctx =fscrypt_get_ctx (inode); +if (IS_ERR (ctx)) +return PTR_ERR (ctx); + + ciphertext_page =alloc_bounce_page (ctx); +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); +if (err) + goto errout; + + bio =bio_alloc (GFP_KERNEL ,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 ); + 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 (WRITE , 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); + +/* +* 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); + +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; + + ctx = (struct fscrypt_ctx *)page_private (page); +set_page_private (page, (unsigned long )NULL ); +ClearPagePrivate (page); +unlock_page (page); +fscrypt_release_ctx (ctx); +} +EXPORT_SYMBOL (fscrypt_restore_control_page); + +static void fscrypt_destroy (void ) +{ +struct fscrypt_ctx *pos, *n; + +list_for_each_entry_safe (pos, n, &fscrypt_free_ctxs, free_list) +kmem_cache_free (fscrypt_ctx_cachep, pos); +INIT_LIST_HEAD (&fscrypt_free_ctxs); +mempool_destroy (fscrypt_bounce_page_pool); + fscrypt_bounce_page_pool =NULL ; +} + +/** +* fscrypt_initialize() - allocate major buffers for fs encryption. +* +* We only call this when we start accessing encrypted files, since it +* results in memory getting allocated that wouldn't otherwise be used. +* +* Return: Zero on success, non-zero otherwise. +*/ +int fscrypt_initialize (void ) +{ +int i, res = -ENOMEM ; + +if (fscrypt_bounce_page_pool) +return 0 ; + +mutex_lock (&fscrypt_init_mutex); +if (fscrypt_bounce_page_pool) + goto already_initialized; + +for (i =0 ; i < num_prealloc_crypto_ctxs; i++) { +struct fscrypt_ctx *ctx; + + ctx =kmem_cache_zalloc (fscrypt_ctx_cachep,GFP_NOFS ); +if (!ctx) + goto fail; +list_add (&ctx->free_list, &fscrypt_free_ctxs); + } + + fscrypt_bounce_page_pool = +mempool_create_page_pool (num_prealloc_crypto_pages,0 ); +if (!fscrypt_bounce_page_pool) + goto fail; + +already_initialized: +mutex_unlock (&fscrypt_init_mutex); +return 0 ; +fail: +fscrypt_destroy (); +mutex_unlock (&fscrypt_init_mutex); +return res; +} +EXPORT_SYMBOL (fscrypt_initialize); + +/** +* fscrypt_init() - Set up for fs encryption. +*/ +int __init fscrypt_init (void ) +{ + fscrypt_read_workqueue =alloc_workqueue ("fscrypt_read_queue" , +WQ_HIGHPRI ,0 ); +if (!fscrypt_read_workqueue) + goto fail; + + fscrypt_ctx_cachep =KMEM_CACHE (fscrypt_ctx,SLAB_RECLAIM_ACCOUNT ); +if (!fscrypt_ctx_cachep) + goto fail_free_queue; + + fscrypt_info_cachep =KMEM_CACHE (fscrypt_info,SLAB_RECLAIM_ACCOUNT ); +if (!fscrypt_info_cachep) + goto fail_free_ctx; + +return 0 ; + +fail_free_ctx: +kmem_cache_destroy (fscrypt_ctx_cachep); +fail_free_queue: +destroy_workqueue (fscrypt_read_workqueue); +fail: +return -ENOMEM ; +} +module_init (fscrypt_init) + +/** +* fscrypt_exit() - Shutdown the fs encryption system +*/ +void __exit fscrypt_exit(void) +{ +fscrypt_destroy (); + +if (fscrypt_read_workqueue) +destroy_workqueue (fscrypt_read_workqueue); +kmem_cache_destroy (fscrypt_ctx_cachep); +kmem_cache_destroy (fscrypt_info_cachep); +} +module_exit (fscrypt_exit); + +MODULE_LICENSE ("GPL" );
include/linux/fscrypto.h +60 -0
64 lines not on this page · raw message
Signature · 1 line
2.6.3
Jaegeuk Kim
maintainerPATCH v3 3/10 fs crypto: add policy.c to handle contexts
In reply to Jaegeuk KimThis patch adds policy.c supporting context management.
1. For ioctls:
- fscrypt_process_policy
- fscrypt_get_policy
2. For context permission
- fscrypt_has_permitted_context
- fscrypt_inherit_context
--- fs/crypto/policy.c | 229 +++++++++++++++++++++++++++++++++++++++++++++++ include/linux/fscrypto.h | 32 +++++++ 2 files changed, 261 insertions(+) create mode 100644 fs/crypto/policy.c
fs/crypto/policy.c new file +229 -0
@@ -0,0 +1,229 @@ +/* +* Encryption policy functions for per-file encryption support. +* +* Copyright (C) 2015, Google, Inc. +* Copyright (C) 2015, Motorola Mobility. +* +* Written by Michael Halcrow, 2015. +* Modified by Jaegeuk Kim, 2015. +*/ + +#include <linux/random.h> +#include <linux/string.h> +#include <linux/fscrypto.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 +*/ +static int is_encryption_context_consistent_with_policy (struct inode *inode, +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)); +} + +static int create_encryption_context_from_policy (struct inode *inode, +const struct fscrypt_policy *policy) +{ +struct fscrypt_context ctx; +int res; + +if (!inode->i_sb->s_cop->set_context) +return -EOPNOTSUPP ; + +if (inode->i_sb->s_cop->prepare_context) { + res = inode->i_sb->s_cop->prepare_context (inode); +if (res) +return res; + } + + ctx.format =FS_ENCRYPTION_CONTEXT_FORMAT_V1 ; +memcpy (ctx.master_key_descriptor, policy->master_key_descriptor, +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); +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); +return -EINVAL ; + } + +if (policy->flags & ~FS_POLICY_FLAGS_VALID ) +return -EINVAL ; + + ctx.contents_encryption_mode = policy->contents_encryption_mode; + ctx.filenames_encryption_mode = policy->filenames_encryption_mode; + ctx.flags = policy->flags; +BUILD_BUG_ON (sizeof (ctx.nonce) !=FS_KEY_DERIVATION_NONCE_SIZE ); +get_random_bytes (ctx.nonce,FS_KEY_DERIVATION_NONCE_SIZE ); + +return inode->i_sb->s_cop->set_context (inode, &ctx,sizeof (ctx),NULL ); +} + +int fscrypt_process_policy (struct inode *inode, +const struct fscrypt_policy *policy) +{ +if (policy->version !=0 ) +return -EINVAL ; + +if (!inode_has_encryption_context (inode)) { +if (!inode->i_sb->s_cop->empty_dir) +return -EOPNOTSUPP ; +if (!inode->i_sb->s_cop->empty_dir (inode)) +return -ENOTEMPTY ; +return create_encryption_context_from_policy (inode, policy); + } + +if (is_encryption_context_consistent_with_policy (inode, policy)) +return 0 ; + +printk (KERN_WARNING "%s: Policy inconsistent with encryption context\n" , + __func__); +return -EINVAL ; +} +EXPORT_SYMBOL (fscrypt_process_policy); + +int fscrypt_get_policy (struct inode *inode,struct fscrypt_policy *policy) +{ +struct fscrypt_context ctx; +int res; + +if (!inode->i_sb->s_cop->get_context || + !inode->i_sb->s_cop->is_encrypted (inode)) +return -ENODATA ; + + res = inode->i_sb->s_cop->get_context (inode, &ctx,sizeof (ctx)); +if (res !=sizeof (ctx)) +return -ENODATA ; +if (ctx.format !=FS_ENCRYPTION_CONTEXT_FORMAT_V1 ) +return -EINVAL ; + + policy->version =0 ; + policy->contents_encryption_mode = ctx.contents_encryption_mode; + policy->filenames_encryption_mode = ctx.filenames_encryption_mode; + policy->flags = ctx.flags; +memcpy (&policy->master_key_descriptor, ctx.master_key_descriptor, +FS_KEY_DESCRIPTOR_SIZE ); +return 0 ; +} +EXPORT_SYMBOL (fscrypt_get_policy); + +int fscrypt_has_permitted_context (struct inode *parent,struct inode *child) +{ +struct fscrypt_info *parent_ci, *child_ci; +int res; + +if ((parent ==NULL ) || (child ==NULL )) { +printk (KERN_ERR "parent %p child %p\n" , parent, child); +BUG_ON (1 ); + } + +/* no restrictions if the parent directory is not encrypted */ +if (!parent->i_sb->s_cop->is_encrypted (parent)) +return 1 ; +/* if the child directory is not encrypted, this is always a problem */ +if (!parent->i_sb->s_cop->is_encrypted (child)) +return 0 ; + res =fscrypt_get_encryption_info (parent); +if (res) +return 0 ; + res =fscrypt_get_encryption_info (child); +if (res) +return 0 ; + parent_ci = parent->i_crypt_info; + child_ci = child->i_crypt_info; +if (!parent_ci && !child_ci) +return 1 ; +if (!parent_ci || !child_ci) +return 0 ; + +return (memcmp (parent_ci->ci_master_key, + child_ci->ci_master_key, +FS_KEY_DESCRIPTOR_SIZE ) ==0 && + (parent_ci->ci_data_mode == child_ci->ci_data_mode) && + (parent_ci->ci_filename_mode == child_ci->ci_filename_mode) && + (parent_ci->ci_flags == child_ci->ci_flags)); +} +EXPORT_SYMBOL (fscrypt_has_permitted_context); + +/** +* fscrypt_inherit_context() - Sets a child context from its parent +* @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 +* +* Return: Zero on success, non-zero otherwise +*/ +int fscrypt_inherit_context (struct inode *parent,struct inode *child, +void *fs_data,bool preload) +{ +struct fscrypt_context ctx; +struct fscrypt_info *ci; +int res; + +if (!parent->i_sb->s_cop->set_context) +return -EOPNOTSUPP ; + + res =fscrypt_get_encryption_info (parent); +if (res <0 ) +return res; + + ci = parent->i_crypt_info; +if (ci ==NULL ) +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 ); + } +get_random_bytes (ctx.nonce,FS_KEY_DERIVATION_NONCE_SIZE ); + res = parent->i_sb->s_cop->set_context (child, &ctx, +sizeof (ctx), fs_data); +if (res) +return res; +return preload ?fscrypt_get_encryption_info (child):0 ; +} +EXPORT_SYMBOL (fscrypt_inherit_context);
include/linux/fscrypto.h +32 -0
@@ -251,6 +251,13 @@ 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 ,unsigned int ); +/* policy.c */ +extern int fscrypt_process_policy (struct inode *, +const struct fscrypt_policy *); +extern int fscrypt_get_policy (struct inode *,struct fscrypt_policy *); +extern int fscrypt_has_permitted_context (struct inode *,struct inode *); +extern int fscrypt_inherit_context (struct inode *,struct inode *, +void *,bool );#endif /* crypto.c */
@@ -296,4 +303,29 @@ static inline int fscrypt_notsupp_zeroout_range(struct inode *i, pgoff_t p, {return -EOPNOTSUPP ; } + +/* policy.c */ +static inline int fscrypt_notsupp_process_policy (struct inode *i, +const struct fscrypt_policy *p) +{ +return -EOPNOTSUPP ; +} + +static inline int fscrypt_notsupp_get_policy (struct inode *i, +struct fscrypt_policy *p) +{ +return -EOPNOTSUPP ; +} + +static inline int fscrypt_notsupp_has_permitted_context (struct inode *p, +struct inode *i) +{ +return 0 ; +} + +static inline int fscrypt_notsupp_inherit_context (struct inode *p, +struct inode *i,void *v,bool b) +{ +return -EOPNOTSUPP ; +}#endif /* _LINUX_FSCRYPTO_H */
Signature · 1 line
2.6.3
Jaegeuk Kim
maintainerPATCH v3 4/10 fs crypto: add keyinfo.c to handle permissions
In reply to Jaegeuk KimThis patch adds keyinfo.c supporting key management.
- fscrypt_get_encryption_info
- fscrypt_free_encryption_info
--- fs/crypto/keyinfo.c | 278 +++++++++++++++++++++++++++++++++++++++++++++++ include/linux/fscrypto.h | 16 +++ 2 files changed, 294 insertions(+) create mode 100644 fs/crypto/keyinfo.c
fs/crypto/keyinfo.c new file +278 -0
@@ -0,0 +1,278 @@ +/* +* key management facility for FS encryption support. +* +* Copyright (C) 2015, Google, Inc. +* +* This contains encryption key functions. +* +* Written by Michael Halcrow, Ildar Muslukhov, and Uday Savagaonkar, 2015. +*/ + +#include <keys/encrypted-type.h> +#include <keys/user-type.h> +#include <linux/random.h> +#include <linux/scatterlist.h> +#include <uapi/linux/keyctl.h> +#include <crypto/hash.h> +#include <linux/fscrypto.h> + +static void derive_crypt_complete (struct crypto_async_request *req,int rc) +{ +struct fscrypt_completion_result *ecr = req->data; + +if (rc == -EINPROGRESS ) +return ; + + ecr->res = rc; +complete (&ecr->completion); +} + +/** +* derive_key_aes() - Derive a key using AES-128-ECB +* @deriving_key: Encryption key used for derivation. +* @source_key: Source key to which to apply derivation. +* @derived_key: Derived key. +* +* Return: Zero on success; non-zero otherwise. +*/ +static int derive_key_aes (u8 deriving_key[FS_AES_128_ECB_KEY_SIZE ], +u8 source_key[FS_AES_256_XTS_KEY_SIZE ], +u8 derived_key[FS_AES_256_XTS_KEY_SIZE ]) +{ +int res =0 ; +struct ablkcipher_request *req =NULL ; +DECLARE_FS_COMPLETION_RESULT (ecr); +struct scatterlist src_sg, dst_sg; +struct crypto_ablkcipher *tfm =crypto_alloc_ablkcipher ("ecb(aes)" ,0 , +0 ); + +if (IS_ERR (tfm)) { + res =PTR_ERR (tfm); + tfm =NULL ; + goto out; + } +crypto_ablkcipher_set_flags (tfm,CRYPTO_TFM_REQ_WEAK_KEY ); + req =ablkcipher_request_alloc (tfm,GFP_NOFS ); +if (!req) { + res = -ENOMEM ; + goto out; + } +ablkcipher_request_set_callback (req, +CRYPTO_TFM_REQ_MAY_BACKLOG |CRYPTO_TFM_REQ_MAY_SLEEP , + derive_crypt_complete, &ecr); + res =crypto_ablkcipher_setkey (tfm, deriving_key, +FS_AES_128_ECB_KEY_SIZE ); +if (res <0 ) + goto out; + +sg_init_one (&src_sg, source_key,FS_AES_256_XTS_KEY_SIZE ); +sg_init_one (&dst_sg, derived_key,FS_AES_256_XTS_KEY_SIZE ); +ablkcipher_request_set_crypt (req, &src_sg, &dst_sg, +FS_AES_256_XTS_KEY_SIZE ,NULL ); + res =crypto_ablkcipher_encrypt (req); +if (res == -EINPROGRESS || res == -EBUSY ) { +wait_for_completion (&ecr.completion); + res = ecr.res; + } +out: +if (req) +ablkcipher_request_free (req); +if (tfm) +crypto_free_ablkcipher (tfm); +return res; +} + +static void put_crypt_info (struct fscrypt_info *ci) +{ +if (!ci) +return ; + +if (ci->ci_keyring_key) +key_put (ci->ci_keyring_key); +crypto_free_ablkcipher (ci->ci_ctfm); +kmem_cache_free (fscrypt_info_cachep, ci); +} + +int get_crypt_info (struct inode *inode) +{ +struct fscrypt_info *crypt_info; +u8 full_key_descriptor[FS_KEY_DESC_PREFIX_SIZE + + (FS_KEY_DESCRIPTOR_SIZE *2 ) +1 ]; +struct key *keyring_key =NULL ; +struct fscrypt_key *master_key; +struct fscrypt_context ctx; +const struct user_key_payload *ukp; +struct crypto_ablkcipher *ctfm; +const char *cipher_str; +u8 raw_key[FS_MAX_KEY_SIZE ]; +u8 mode; +int res; + + res =fscrypt_initialize (); +if (res) +return res; + +if (!inode->i_sb->s_cop->get_context) +return -EOPNOTSUPP ; +retry: + crypt_info =ACCESS_ONCE (inode->i_crypt_info); +if (crypt_info) { +if (!crypt_info->ci_keyring_key || +key_validate (crypt_info->ci_keyring_key) ==0 ) +return 0 ; +fscrypt_put_encryption_info (inode, crypt_info); + goto retry; + } + + res = inode->i_sb->s_cop->get_context (inode, &ctx,sizeof (ctx)); +if (res <0 ) { +if (!fscrypt_dummy_context_enabled (inode)) +return res; + ctx.contents_encryption_mode =FS_ENCRYPTION_MODE_AES_256_XTS ; + ctx.filenames_encryption_mode =FS_ENCRYPTION_MODE_AES_256_CTS ; + ctx.flags =0 ; + }else if (res !=sizeof (ctx)) { +return -EINVAL ; + } + res =0 ; + + crypt_info =kmem_cache_alloc (fscrypt_info_cachep,GFP_NOFS ); +if (!crypt_info) +return -ENOMEM ; + + crypt_info->ci_flags = ctx.flags; + crypt_info->ci_data_mode = ctx.contents_encryption_mode; + crypt_info->ci_filename_mode = ctx.filenames_encryption_mode; + crypt_info->ci_ctfm =NULL ; + crypt_info->ci_keyring_key =NULL ; +memcpy (crypt_info->ci_master_key, ctx.master_key_descriptor, +sizeof (crypt_info->ci_master_key)); +if (S_ISREG (inode->i_mode)) + mode = crypt_info->ci_data_mode; +else if (S_ISDIR (inode->i_mode) ||S_ISLNK (inode->i_mode)) + mode = crypt_info->ci_filename_mode; +else +BUG (); + +switch (mode) { +case FS_ENCRYPTION_MODE_AES_256_XTS : + cipher_str ="xts(aes)" ; +break ; +case FS_ENCRYPTION_MODE_AES_256_CTS : + cipher_str ="cts(cbc(aes))" ; +break ; +default : +printk_once (KERN_WARNING +"%s: unsupported key mode %d (ino %u)\n" , + __func__, mode, (unsigned ) inode->i_ino); + res = -ENOKEY ; + goto out; + } +if (fscrypt_dummy_context_enabled (inode)) { +memset (raw_key,0x42 ,FS_AES_256_XTS_KEY_SIZE ); + goto got_key; + } +memcpy (full_key_descriptor,FS_KEY_DESC_PREFIX , +FS_KEY_DESC_PREFIX_SIZE ); +sprintf (full_key_descriptor +FS_KEY_DESC_PREFIX_SIZE , +"%*phN" ,FS_KEY_DESCRIPTOR_SIZE , + ctx.master_key_descriptor); + full_key_descriptor[FS_KEY_DESC_PREFIX_SIZE + + (2 *FS_KEY_DESCRIPTOR_SIZE )] ='\0' ; + keyring_key =request_key (&key_type_logon, full_key_descriptor,NULL ); +if (IS_ERR (keyring_key)) { + res =PTR_ERR (keyring_key); + keyring_key =NULL ; + goto out; + } + crypt_info->ci_keyring_key = keyring_key; +if (keyring_key->type != &key_type_logon) { +printk_once (KERN_WARNING +"%s: key type must be logon\n" , __func__); + res = -ENOKEY ; + goto out; + } +down_read (&keyring_key->sem); + ukp =user_key_payload (keyring_key); +if (ukp->datalen !=sizeof (struct fscrypt_key )) { + res = -EINVAL ; +up_read (&keyring_key->sem); + goto out; + } + master_key = (struct fscrypt_key *)ukp->data; +BUILD_BUG_ON (FS_AES_128_ECB_KEY_SIZE !=FS_KEY_DERIVATION_NONCE_SIZE ); + +if (master_key->size !=FS_AES_256_XTS_KEY_SIZE ) { +printk_once (KERN_WARNING +"%s: key size incorrect: %d\n" , + __func__, master_key->size); + res = -ENOKEY ; +up_read (&keyring_key->sem); + goto out; + } + res =derive_key_aes (ctx.nonce, master_key->raw, raw_key); +up_read (&keyring_key->sem); +if (res) + goto out; +got_key: + ctfm =crypto_alloc_ablkcipher (cipher_str,0 ,0 ); +if (!ctfm ||IS_ERR (ctfm)) { + res = ctfm ?PTR_ERR (ctfm) : -ENOMEM ; +printk (KERN_DEBUG +"%s: error %d (inode %u) allocating crypto tfm\n" , + __func__, res, (unsigned ) inode->i_ino); + goto out; + } + crypt_info->ci_ctfm = ctfm; +crypto_ablkcipher_clear_flags (ctfm, ~0 ); +crypto_tfm_set_flags (crypto_ablkcipher_tfm (ctfm), +CRYPTO_TFM_REQ_WEAK_KEY ); + res =crypto_ablkcipher_setkey (ctfm, raw_key,fscrypt_key_size (mode)); +if (res) + goto out; + +memzero_explicit (raw_key,sizeof (raw_key)); +if (cmpxchg (&inode->i_crypt_info,NULL , crypt_info) !=NULL ) { +put_crypt_info (crypt_info); + goto retry; + } +return 0 ; + +out: +if (res == -ENOKEY ) + res =0 ; +put_crypt_info (crypt_info); +memzero_explicit (raw_key,sizeof (raw_key)); +return res; +} + +void fscrypt_put_encryption_info (struct inode *inode,struct fscrypt_info *ci) +{ +struct fscrypt_info *prev; + +if (ci ==NULL ) + ci =ACCESS_ONCE (inode->i_crypt_info); +if (ci ==NULL ) +return ; + + prev =cmpxchg (&inode->i_crypt_info, ci,NULL ); +if (prev != ci) +return ; + +put_crypt_info (ci); +} +EXPORT_SYMBOL (fscrypt_put_encryption_info); + +int fscrypt_get_encryption_info (struct inode *inode) +{ +struct fscrypt_info *ci = inode->i_crypt_info; + +if (!ci || + (ci->ci_keyring_key && + (ci->ci_keyring_key->flags & ((1 <<KEY_FLAG_INVALIDATED ) | + (1 <<KEY_FLAG_REVOKED ) | + (1 <<KEY_FLAG_DEAD ))))) +return get_crypt_info (inode); +return 0 ; +} +EXPORT_SYMBOL (fscrypt_get_encryption_info);
include/linux/fscrypto.h +16 -0
@@ -258,6 +258,10 @@ extern int fscrypt_get_policy(struct inode *, struct fscrypt_policy *);extern int fscrypt_has_permitted_context (struct inode *,struct inode *);extern int fscrypt_inherit_context (struct inode *,struct inode *,void *,bool ); +/* keyinfo.c */ +extern int get_crypt_info (struct inode *); +extern int fscrypt_get_encryption_info (struct inode *); +extern void fscrypt_put_encryption_info (struct inode *,struct fscrypt_info *);#endif /* crypto.c */
@@ -328,4 +332,16 @@ static inline int fscrypt_notsupp_inherit_context(struct inode *p, {return -EOPNOTSUPP ; } + +/* keyinfo.c */ +static inline int fscrypt_notsupp_get_encryption_info (struct inode *i) +{ +return -EOPNOTSUPP ; +} + +static inline void fscrypt_notsupp_put_encryption_info (struct inode *i, +struct fscrypt_info *f) +{ +return ; +}#endif /* _LINUX_FSCRYPTO_H */
Signature · 1 line
2.6.3
Jaegeuk Kim
maintainerPATCH v3 5/10 fs crypto: add fname.c to support filename encryption
In reply to Jaegeuk KimThis patch adds fname.c supporting filename encryption.
1. general wrapper functions
- fscrypt_fname_disk_to_usr
- fscrypt_fname_usr_to_disk
- fscrypt_setup_filename
- fscrypt_free_filename
2. specific filename handling functions
- fscrypt_fname_alloc_buffer
- fscrypt_fname_free_buffer
--- fs/crypto/fname.c | 427 +++++++++++++++++++++++++++++++++++++++++++++++ include/linux/fscrypto.h | 66 ++++++++ 2 files changed, 493 insertions(+) create mode 100644 fs/crypto/fname.c
fs/crypto/fname.c new file +427 -0
@@ -0,0 +1,427 @@ +/* +* This contains functions for filename crypto management +* +* Copyright (C) 2015, Google, Inc. +* Copyright (C) 2015, Motorola Mobility +* +* Written by Uday Savagaonkar, 2014. +* Modified by Jaegeuk Kim, 2015. +* +* This has not yet undergone a rigorous security audit. +*/ + +#include <crypto/hash.h> +#include <crypto/sha.h> +#include <keys/encrypted-type.h> +#include <keys/user-type.h> +#include <linux/crypto.h> +#include <linux/scatterlist.h> +#include <linux/ratelimit.h> +#include <linux/fscrypto.h> + +static u32 size_round_up (size_t size,size_t blksize) +{ +return ((size + blksize -1 ) / blksize) * blksize; +} + +/** +* dir_crypt_complete() - +*/ +static void dir_crypt_complete (struct crypto_async_request *req,int res) +{ +struct fscrypt_completion_result *ecr = req->data; + +if (res == -EINPROGRESS ) +return ; + ecr->res = res; +complete (&ecr->completion); +} + +/** +* fname_encrypt() - +* +* This function encrypts the input filename, and returns the length of the +* ciphertext. Errors are returned as negative numbers. We trust the caller to +* allocate sufficient memory to oname string. +*/ +static int fname_encrypt (struct inode *inode, +const struct qstr *iname,struct fscrypt_str *oname) +{ +u32 ciphertext_len; +struct ablkcipher_request *req =NULL ; +DECLARE_FS_COMPLETION_RESULT (ecr); +struct fscrypt_info *ci = inode->i_crypt_info; +struct crypto_ablkcipher *tfm = ci->ci_ctfm; +int res =0 ; +char iv[FS_CRYPTO_BLOCK_SIZE ]; +struct scatterlist src_sg, dst_sg; +int padding =4 << (ci->ci_flags &FS_POLICY_FLAGS_PAD_MASK ); +char *workbuf, buf[32 ], *alloc_buf =NULL ; +unsigned lim; + + lim = inode->i_sb->s_cop->max_namelen (inode); +if (iname->len <=0 || iname->len > lim) +return -EIO ; + + ciphertext_len = (iname->len <FS_CRYPTO_BLOCK_SIZE ) ? +FS_CRYPTO_BLOCK_SIZE : iname->len; + ciphertext_len =size_round_up (ciphertext_len, padding); + ciphertext_len = (ciphertext_len > lim) ? lim : ciphertext_len; + +if (ciphertext_len <=sizeof (buf)) { + workbuf = buf; + }else { + alloc_buf =kmalloc (ciphertext_len,GFP_NOFS ); +if (!alloc_buf) +return -ENOMEM ; + workbuf = alloc_buf; + } + +/* Allocate request */ + req =ablkcipher_request_alloc (tfm,GFP_NOFS ); +if (!req) { +printk_ratelimited (KERN_ERR +"%s: crypto_request_alloc() failed\n" , __func__); +kfree (alloc_buf); +return -ENOMEM ; + } +ablkcipher_request_set_callback (req, +CRYPTO_TFM_REQ_MAY_BACKLOG |CRYPTO_TFM_REQ_MAY_SLEEP , + dir_crypt_complete, &ecr); + +/* 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); +ablkcipher_request_set_crypt (req, &src_sg, &dst_sg, ciphertext_len, iv); + res =crypto_ablkcipher_encrypt (req); +if (res == -EINPROGRESS || res == -EBUSY ) { +wait_for_completion (&ecr.completion); + res = ecr.res; + } +kfree (alloc_buf); +ablkcipher_request_free (req); +if (res <0 ) +printk_ratelimited (KERN_ERR +"%s: Error (error code %d)\n" , __func__, res); + + oname->len = ciphertext_len; +return res; +} + +/* +* fname_decrypt() +* This function decrypts the input filename, and returns +* the length of the plaintext. +* Errors are returned as negative numbers. +* We trust the caller to allocate sufficient memory to oname string. +*/ +static int fname_decrypt (struct inode *inode, +const struct fscrypt_str *iname, +struct fscrypt_str *oname) +{ +struct ablkcipher_request *req =NULL ; +DECLARE_FS_COMPLETION_RESULT (ecr); +struct scatterlist src_sg, dst_sg; +struct fscrypt_info *ci = inode->i_crypt_info; +struct crypto_ablkcipher *tfm = ci->ci_ctfm; +int res =0 ; +char iv[FS_CRYPTO_BLOCK_SIZE ]; +unsigned lim; + + lim = inode->i_sb->s_cop->max_namelen (inode); +if (iname->len <=0 || iname->len > lim) +return -EIO ; + +/* Allocate request */ + req =ablkcipher_request_alloc (tfm,GFP_NOFS ); +if (!req) { +printk_ratelimited (KERN_ERR +"%s: crypto_request_alloc() failed\n" , __func__); +return -ENOMEM ; + } +ablkcipher_request_set_callback (req, +CRYPTO_TFM_REQ_MAY_BACKLOG |CRYPTO_TFM_REQ_MAY_SLEEP , + dir_crypt_complete, &ecr); + +/* Initialize IV */ +memset (iv,0 ,FS_CRYPTO_BLOCK_SIZE ); + +/* Create decryption request */ +sg_init_one (&src_sg, iname->name, iname->len); +sg_init_one (&dst_sg, oname->name, oname->len); +ablkcipher_request_set_crypt (req, &src_sg, &dst_sg, iname->len, iv); + res =crypto_ablkcipher_decrypt (req); +if (res == -EINPROGRESS || res == -EBUSY ) { +wait_for_completion (&ecr.completion); + res = ecr.res; + } +ablkcipher_request_free (req); +if (res <0 ) { +printk_ratelimited (KERN_ERR +"%s: Error (error code %d)\n" , __func__, res); +return res; + } + + oname->len =strnlen (oname->name, iname->len); +return oname->len; +} + +static const char *lookup_table = +"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+," ; + +/** +* digest_encode() - +* +* Encodes the input digest using characters from the set [a-zA-Z0-9_+]. +* The encoded string is roughly 4/3 times the size of the input string. +*/ +static int digest_encode (const char *src,int len,char *dst) +{ +int i =0 , bits =0 , ac =0 ; +char *cp = dst; + +while (i < len) { + ac += (((unsigned char ) src[i]) << bits); + bits +=8 ; +do { + *cp++ = lookup_table[ac &0x3f ]; + ac >>=6 ; + bits -=6 ; + }while (bits >=6 ); + i++; + } +if (bits) + *cp++ = lookup_table[ac &0x3f ]; +return cp - dst; +} + +static int digest_decode (const char *src,int len,char *dst) +{ +int i =0 , bits =0 , ac =0 ; +const char *p; +char *cp = dst; + +while (i < len) { + p =strchr (lookup_table, src[i]); +if (p ==NULL || src[i] ==0 ) +return -2 ; + ac += (p - lookup_table) << bits; + bits +=6 ; +if (bits >=8 ) { + *cp++ = ac &0xff ; + ac >>=8 ; + bits -=8 ; + } + i++; + } +if (ac) +return -1 ; +return cp - dst; +} + +u32 fscrypt_fname_encrypted_size (struct inode *inode,u32 ilen) +{ +int padding =32 ; +struct fscrypt_info *ci = inode->i_crypt_info; + +if (ci) + padding =4 << (ci->ci_flags &FS_POLICY_FLAGS_PAD_MASK ); +if (ilen <FS_CRYPTO_BLOCK_SIZE ) + ilen =FS_CRYPTO_BLOCK_SIZE ; +return size_round_up (ilen, padding); +} +EXPORT_SYMBOL (fscrypt_fname_encrypted_size); + +/** +* fscrypt_fname_crypto_alloc_obuff() - +* +* 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, +u32 ilen,struct fscrypt_str *crypto_str) +{ +unsigned int olen =fscrypt_fname_encrypted_size (inode, ilen); + + crypto_str->len = olen; +if (olen <FS_FNAME_CRYPTO_DIGEST_SIZE *2 ) + olen =FS_FNAME_CRYPTO_DIGEST_SIZE *2 ; +/* +* Allocated buffer can hold one more character to null-terminate the +* string +*/ + crypto_str->name =kmalloc (olen +1 ,GFP_NOFS ); +if (!(crypto_str->name)) +return -ENOMEM ; +return 0 ; +} +EXPORT_SYMBOL (fscrypt_fname_alloc_buffer); + +/** +* fscrypt_fname_crypto_free_buffer() - +* +* Frees the buffer allocated for crypto operation. +*/ +void fscrypt_fname_free_buffer (struct fscrypt_str *crypto_str) +{ +if (!crypto_str) +return ; +kfree (crypto_str->name); + crypto_str->name =NULL ; +} +EXPORT_SYMBOL (fscrypt_fname_free_buffer); + +/** +* fscrypt_fname_disk_to_usr() - converts a filename from disk space to user +* space +*/ +int fscrypt_fname_disk_to_usr (struct inode *inode, +u32 hash,u32 minor_hash, +const struct fscrypt_str *iname, +struct fscrypt_str *oname) +{ +const struct qstr qname =FSTR_TO_QSTR (iname); +char buf[24 ]; +int ret; + +if (fscrypt_is_dot_dotdot (&qname)) { + oname->name[0 ] ='.' ; + oname->name[iname->len -1 ] ='.' ; + oname->len = iname->len; +return oname->len; + } + +if (iname->len <FS_CRYPTO_BLOCK_SIZE ) +return -EUCLEAN ; + +if (inode->i_crypt_info) +return fname_decrypt (inode, iname, oname); + +if (iname->len <=FS_FNAME_CRYPTO_DIGEST_SIZE ) { + ret =digest_encode (iname->name, iname->len, oname->name); + oname->len = ret; +return ret; + } +if (hash) { +memcpy (buf, &hash,4 ); +memcpy (buf +4 , &minor_hash,4 ); + }else { +memset (buf,0 ,8 ); + } +memcpy (buf +8 , iname->name + iname->len -16 ,16 ); + oname->name[0 ] ='_' ; + ret =digest_encode (buf,24 , oname->name +1 ); + oname->len = ret +1 ; +return ret +1 ; +} +EXPORT_SYMBOL (fscrypt_fname_disk_to_usr); + +/** +* fscrypt_fname_usr_to_disk() - converts a filename from user space to disk +* space +*/ +int fscrypt_fname_usr_to_disk (struct inode *inode, +const struct qstr *iname, +struct fscrypt_str *oname) +{ +if (fscrypt_is_dot_dotdot (iname)) { + oname->name[0 ] ='.' ; + oname->name[iname->len -1 ] ='.' ; + oname->len = iname->len; +return oname->len; + } +if (inode->i_crypt_info) +return fname_encrypt (inode, iname, oname); +/* +* Without a proper key, a user is not allowed to modify the filenames +* in a directory. Consequently, a user space name cannot be mapped to +* a disk-space name +*/ +return -EACCES ; +} +EXPORT_SYMBOL (fscrypt_fname_usr_to_disk); + +int fscrypt_setup_filename (struct inode *dir,const struct qstr *iname, +int lookup,struct fscrypt_name *fname) +{ +int ret =0 , bigname =0 ; + +memset (fname,0 ,sizeof (struct fscrypt_name )); + fname->usr_fname = iname; + +if (!dir->i_sb->s_cop->is_encrypted (dir) || +fscrypt_is_dot_dotdot (iname)) { + fname->disk_name.name = (unsigned char *)iname->name; + fname->disk_name.len = iname->len; +return 0 ; + } + ret =get_crypt_info (dir); +if (ret && ret != -EOPNOTSUPP ) +return ret; + +if (dir->i_crypt_info) { + ret =fscrypt_fname_alloc_buffer (dir, iname->len, + &fname->crypto_buf); +if (ret <0 ) +return ret; + ret =fname_encrypt (dir, iname, &fname->crypto_buf); +if (ret <0 ) + goto errout; + fname->disk_name.name = fname->crypto_buf.name; + fname->disk_name.len = fname->crypto_buf.len; +return 0 ; + } +if (!lookup) +return -EACCES ; + +/* +* We don't have the key and we are doing a lookup; decode the +* user-supplied name +*/ +if (iname->name[0 ] =='_' ) + bigname =1 ; +if ((bigname && (iname->len !=33 )) || (!bigname && (iname->len >43 ))) +return -ENOENT ; + + fname->crypto_buf.name =kmalloc (32 ,GFP_KERNEL ); +if (fname->crypto_buf.name ==NULL ) +return -ENOMEM ; + + ret =digest_decode (iname->name + bigname, iname->len - bigname, + fname->crypto_buf.name); +if (ret <0 ) { + ret = -ENOENT ; + goto errout; + } + fname->crypto_buf.len = ret; +if (bigname) { +memcpy (&fname->hash, fname->crypto_buf.name,4 ); +memcpy (&fname->minor_hash, fname->crypto_buf.name +4 ,4 ); + }else { + fname->disk_name.name = fname->crypto_buf.name; + fname->disk_name.len = fname->crypto_buf.len; + } +return 0 ; + +errout: +fscrypt_fname_free_buffer (&fname->crypto_buf); +return ret; +} +EXPORT_SYMBOL (fscrypt_setup_filename); + +void fscrypt_free_filename (struct fscrypt_name *fname) +{ +kfree (fname->crypto_buf.name); + fname->crypto_buf.name =NULL ; + fname->usr_fname =NULL ; + fname->disk_name.name =NULL ; +} +EXPORT_SYMBOL (fscrypt_free_filename);
include/linux/fscrypto.h +66 -0
76 lines not on this page · raw message
Signature · 1 line
2.6.3
Jaegeuk Kim
maintainerPATCH v3 6/10 fs crypto: add Makefile and Kconfig
In reply to Jaegeuk KimThis patch adds a facility to enable per-file encryption.
Arnd fixes a missing CONFIG_BLOCK check in the original patch. "The newly added generic crypto abstraction for file systems operates on 'struct bio' objects, which do not exist when CONFIG_BLOCK is disabled:
fs/crypto/crypto.c: In function 'fscrypt_zeroout_range':fs/crypto/crypto.c:308:9: error: implicit declaration of function 'bio_alloc' [-Werror=implicit-function-declaration]
This adds a Kconfig dependency that prevents FS_ENCRYPTION from being enabled without BLOCK."
--- fs/Kconfig | 2 ++ fs/Makefile | 1 + fs/crypto/Kconfig | 18 ++++++++++++++++++ fs/crypto/Makefile | 3 +++ 4 files changed, 24 insertions(+) create mode 100644 fs/crypto/Kconfig create mode 100644 fs/crypto/Makefile
fs/Kconfig +2 -0
@@ -84,6 +84,8 @@ config MANDATORY_FILE_LOCKING To the best of my knowledge this is dead code that no one cares about. +source "fs/crypto/Kconfig" + source "fs/notify/Kconfig" source "fs/quota/Kconfig"
fs/Makefile +1 -0
@@ -30,6 +30,7 @@ obj-$(CONFIG_EVENTFD) += eventfd.o obj-$(CONFIG_USERFAULTFD) += userfaultfd.o obj-$(CONFIG_AIO) += aio.o obj-$(CONFIG_FS_DAX) += dax.o +obj-$(CONFIG_FS_ENCRYPTION) += crypto/ obj-$(CONFIG_FILE_LOCKING) += locks.o obj-$(CONFIG_COMPAT) += compat.o compat_ioctl.o obj-$(CONFIG_BINFMT_AOUT) += binfmt_aout.o
fs/crypto/Kconfig new file +18 -0
@@ -0,0 +1,18 @@ +config FS_ENCRYPTION + tristate "FS Encryption (Per-file encryption)" + depends on BLOCK + select CRYPTO + select CRYPTO_AES + select CRYPTO_CBC + select CRYPTO_ECB + select CRYPTO_XTS + select CRYPTO_CTS + select CRYPTO_CTR + select CRYPTO_SHA256 + select KEYS + select ENCRYPTED_KEYS + help + Enable encryption of files and directories. This + feature is similar to ecryptfs, but it is more memory + efficient since it avoids caching the encrypted and + decrypted pages in the page cache.
fs/crypto/Makefile new file +3 -0
@@ -0,0 +1,3 @@ +obj-$(CONFIG_FS_ENCRYPTION) += fscrypto.o + +fscrypto-y := crypto.o fname.o policy.o keyinfo.o
Signature · 1 line
2.6.3
Jaegeuk Kim
maintainerPATCH v3 7/10 fs crypto: add dentry revalidation facility in crypto
In reply to Jaegeuk KimThis patch is to support the following ext4 crypto change.
commit 28b4c263961c47da84ed8b5be0b5116bad1133eb
Author: Theodore Ts'o <[email protected]> Date: Sun Feb 7 19:35:05 2016 -0500
ext4 crypto: revalidate dentry after adding or removing the key
--- fs/crypto/crypto.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/dcache.h | 2 ++ include/linux/fscrypto.h | 20 ++++++++++++++++++++ 3 files changed, 71 insertions(+)
fs/crypto/crypto.c +49 -0
@@ -27,6 +27,7 @@#include <linux/scatterlist.h> #include <linux/ratelimit.h> #include <linux/bio.h> +#include <linux/dcache.h> #include <linux/fscrypto.h> static unsigned int num_prealloc_crypto_pages =32 ;
@@ -339,6 +340,54 @@ errout: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 +* removed. +*/ +static int fscrypt_d_revalidate (struct dentry *dentry,unsigned int flags) +{ +struct inode *dir =d_inode (dentry->d_parent); +struct fscrypt_info *ci = dir->i_crypt_info; +int dir_has_key, cached_with_key; + +if (!dir->i_sb->s_cop->is_encrypted (dir)) +return 0 ; + +if (ci && ci->ci_keyring_key && + (ci->ci_keyring_key->flags & ((1 <<KEY_FLAG_INVALIDATED ) | + (1 <<KEY_FLAG_REVOKED ) | + (1 <<KEY_FLAG_DEAD )))) + ci =NULL ; + +/* this should eventually be an flag in d_flags */ +spin_lock (&dentry->d_lock); + cached_with_key = dentry->d_flags &DCACHE_ENCRYPTED_WITH_KEY ; +spin_unlock (&dentry->d_lock); + dir_has_key = (ci !=NULL ); + +/* +* If the dentry was cached without the key, and it is a +* negative dentry, it might be a valid name. We can't check +* if the key has since been made available due to locking +* reasons, so we fail the validation so ext4_lookup() can do +* this check. +* +* We also fail the validation if the dentry was created with +* the key present, but we no longer have the key, or vice versa. +*/ +if ((!cached_with_key &&d_is_negative (dentry)) || + (!cached_with_key && dir_has_key) || + (cached_with_key && !dir_has_key)) +return 0 ; +return 1 ; +} + +const struct dentry_operations fscrypt_d_ops = { + .d_revalidate = fscrypt_d_revalidate, +}; +EXPORT_SYMBOL (fscrypt_d_ops); + +/* * Call fscrypt_decrypt_page on every single page, reusing the encryption * context. */
include/linux/dcache.h +2 -0
@@ -228,6 +228,8 @@ struct dentry_operations {#define DCACHE_FALLTHRU 0x01000000/* Fall through to lower layer */ #define DCACHE_OP_SELECT_INODE 0x02000000/* Unioned entry: dcache op selects inode */ +#define DCACHE_ENCRYPTED_WITH_KEY 0x04000000/* dir is encrypted with a valid key */ +extern seqlock_t rename_lock;/*
include/linux/fscrypto.h +20 -0
@@ -237,6 +237,26 @@ static inline int fscrypt_has_encryption_key(struct inode *inode)#endif } +static inline void fscrypt_set_encrypted_dentry (struct dentry *dentry) +{ +#if IS_ENABLED (CONFIG_FS_ENCRYPTION ) +spin_lock (&dentry->d_lock); + dentry->d_flags |=DCACHE_ENCRYPTED_WITH_KEY ; +spin_unlock (&dentry->d_lock); +#endif +} + +#if IS_ENABLED (CONFIG_FS_ENCRYPTION ) +extern const struct dentry_operations fscrypt_d_ops; +#endif + +static inline void fscrypt_set_d_op (struct dentry *dentry) +{ +#if IS_ENABLED (CONFIG_FS_ENCRYPTION ) +d_set_d_op (dentry, &fscrypt_d_ops); +#endif +} +#if IS_ENABLED (CONFIG_FS_ENCRYPTION )/* crypto.c */ extern struct kmem_cache *fscrypt_info_cachep;
Signature · 1 line
2.6.3
Jaegeuk Kim
maintainerPATCH v3 8/10 f2fs crypto: migrate into vfs's crypto engine
In reply to Jaegeuk KimThis patch removes the most parts of internal crypto codes. And then, it modifies some f2fs-specific crypt codes to use the generic facility.
--- fs/f2fs/Kconfig | 10 +- fs/f2fs/Makefile | 2 - fs/f2fs/crypto.c | 473 ------------------------------------------------ fs/f2fs/crypto_fname.c | 446 --------------------------------------------- fs/f2fs/crypto_key.c | 267 --------------------------- fs/f2fs/crypto_policy.c | 210 --------------------- fs/f2fs/data.c | 31 ++-- fs/f2fs/dir.c | 44 ++--- fs/f2fs/f2fs.h | 172 ++++-------------- fs/f2fs/f2fs_crypto.h | 151 ---------------- fs/f2fs/file.c | 36 ++-- fs/f2fs/inline.c | 4 +- fs/f2fs/inode.c | 5 +- fs/f2fs/namei.c | 56 +++--- fs/f2fs/super.c | 55 ++++-- 15 files changed, 149 insertions(+), 1813 deletions(-) delete mode 100644 fs/f2fs/crypto.c delete mode 100644 fs/f2fs/crypto_fname.c delete mode 100644 fs/f2fs/crypto_key.c delete mode 100644 fs/f2fs/crypto_policy.c delete mode 100644 fs/f2fs/f2fs_crypto.h
fs/f2fs/Kconfig +1 -9
@@ -76,15 +76,7 @@ config F2FS_FS_ENCRYPTION bool "F2FS Encryption" depends on F2FS_FS depends on F2FS_FS_XATTR - select CRYPTO_AES - select CRYPTO_CBC - select CRYPTO_ECB - select CRYPTO_XTS - select CRYPTO_CTS - select CRYPTO_CTR - select CRYPTO_SHA256 - select KEYS - select ENCRYPTED_KEYS + select FS_ENCRYPTION help Enable encryption of f2fs files and directories. This feature is similar to ecryptfs, but it is more memory
fs/f2fs/Makefile +0 -2
@@ -7,5 +7,3 @@ f2fs-$(CONFIG_F2FS_STAT_FS) += debug.o f2fs-$(CONFIG_F2FS_FS_XATTR) += xattr.o f2fs-$(CONFIG_F2FS_FS_POSIX_ACL) += acl.o f2fs-$(CONFIG_F2FS_IO_TRACE) += trace.o -f2fs-$(CONFIG_F2FS_FS_ENCRYPTION) += crypto_policy.o crypto.o \ - crypto_key.o crypto_fname.o
fs/f2fs/crypto.c deleted +0 -473
473 lines not on this page · raw message
fs/f2fs/crypto_fname.c deleted +0 -446
446 lines not on this page · raw message
fs/f2fs/crypto_key.c deleted +0 -267
267 lines not on this page · raw message
fs/f2fs/crypto_policy.c deleted +0 -210
210 lines not on this page · raw message
fs/f2fs/data.c +13 -18
@@ -34,9 +34,9 @@ static void f2fs_read_end_io(struct bio *bio)if (f2fs_bio_encrypted (bio)) {if (bio->bi_error) { -f2fs_release_crypto_ctx (bio->bi_private); +fscrypt_release_ctx (bio->bi_private); }else { -f2fs_end_io_crypto_work (bio->bi_private, bio); +fscrypt_decrypt_bio_pages (bio->bi_private, bio);return ; } }
@@ -64,7 +64,7 @@ static void f2fs_write_end_io(struct bio *bio)bio_for_each_segment_all (bvec, bio, i) {struct page *page = bvec->bv_page; -f2fs_restore_and_release_control_page (&page); +fscrypt_pullback_bio_page (&page, true);if (unlikely (bio->bi_error)) {set_bit (AS_EIO , &page->mapping->flags);
@@ -129,16 +129,10 @@ static bool __has_merged_page(struct f2fs_bio_info *io, struct inode *inode,bio_for_each_segment_all (bvec, io->bio, i) { -if (bvec->bv_page->mapping) { +if (bvec->bv_page->mapping) target = bvec->bv_page; - }else { -struct f2fs_crypto_ctx *ctx; - -/* encrypted page */ - ctx = (struct f2fs_crypto_ctx *)page_private ( - bvec->bv_page); - target = ctx->w.control_page; - } +else + target =fscrypt_control_page (bvec->bv_page);if (inode && inode == target->mapping->host)return true;
@@ -220,7 +214,8 @@ void f2fs_flush_merged_bios(struct f2fs_sb_info *sbi)int f2fs_submit_page_bio (struct f2fs_io_info *fio) {struct bio *bio; -struct page *page = fio->encrypted_page ? fio->encrypted_page : fio->page; +struct page *page = fio->encrypted_page ? + fio->encrypted_page : fio->page;trace_f2fs_submit_page_bio (page, fio);f2fs_trace_ios (fio,0 );
@@ -992,12 +987,12 @@ submit_and_realloc: bio =NULL ; }if (bio ==NULL ) { -struct f2fs_crypto_ctx *ctx =NULL ; +struct fscrypt_ctx *ctx =NULL ;if (f2fs_encrypted_inode (inode) &&S_ISREG (inode->i_mode)) { - ctx =f2fs_get_crypto_ctx (inode); + ctx =fscrypt_get_ctx (inode);if (IS_ERR (ctx)) goto set_error_page;
@@ -1010,7 +1005,7 @@ submit_and_realloc: min_t(int, nr_pages, BIO_MAX_PAGES));if (!bio) {if (ctx) -f2fs_release_crypto_ctx (ctx); +fscrypt_release_ctx (ctx); goto set_error_page; } bio->bi_bdev = bdev;
@@ -1102,7 +1097,7 @@ int do_write_data_page(struct f2fs_io_info *fio)f2fs_wait_on_encrypted_page_writeback (F2FS_I_SB (inode), fio->old_blkaddr); - fio->encrypted_page =f2fs_encrypt (inode, fio->page); + fio->encrypted_page =fscrypt_encrypt_page (inode, fio->page);if (IS_ERR (fio->encrypted_page)) { err =PTR_ERR (fio->encrypted_page); goto out_writepage;
@@ -1608,7 +1603,7 @@ repeat:/* avoid symlink page */ if (f2fs_encrypted_inode (inode) &&S_ISREG (inode->i_mode)) { - err =f2fs_decrypt (page); + err =fscrypt_decrypt_page (page);if (err) goto fail; }
fs/f2fs/dir.c +22 -22
145 lines not on this page · raw message
fs/f2fs/f2fs.h +33 -139
247 lines not on this page · raw message
fs/f2fs/f2fs_crypto.h deleted +0 -151
151 lines not on this page · raw message
fs/f2fs/file.c +14 -22
@@ -421,7 +421,7 @@ static int f2fs_file_mmap(struct file *file, struct vm_area_struct *vma)int err;if (f2fs_encrypted_inode (inode)) { - err =f2fs_get_encryption_info (inode); + err =fscrypt_get_encryption_info (inode);if (err)return 0 ;if (!f2fs_encrypted_inode (inode))
@@ -443,7 +443,7 @@ static int f2fs_file_open(struct inode *inode, struct file *filp)int ret =generic_file_open (inode, filp);if (!ret &&f2fs_encrypted_inode (inode)) { - ret =f2fs_get_encryption_info (inode); + ret =fscrypt_get_encryption_info (inode);if (ret)return -EACCES ;if (!f2fs_encrypted_inode (inode))
@@ -526,7 +526,8 @@ static int truncate_partial_data_page(struct inode *inode, u64 from, truncate_out:f2fs_wait_on_page_writeback (page,DATA , true);zero_user (page, offset,PAGE_CACHE_SIZE - offset); -if (!cache_only || !f2fs_encrypted_inode (inode) || !S_ISREG (inode->i_mode)) +if (!cache_only || !f2fs_encrypted_inode (inode) || + !S_ISREG (inode->i_mode))set_page_dirty (page);f2fs_put_page (page,1 );return 0 ;
@@ -674,7 +675,7 @@ int f2fs_setattr(struct dentry *dentry, struct iattr *attr)if (attr->ia_valid &ATTR_SIZE ) {if (f2fs_encrypted_inode (inode) && -f2fs_get_encryption_info (inode)) +fscrypt_get_encryption_info (inode))return -EACCES ;if (attr->ia_size <=i_size_read (inode)) {
@@ -1529,39 +1530,30 @@ static bool uuid_is_nonzero(__u8 u[16])static int f2fs_ioc_set_encryption_policy (struct file *filp,unsigned long arg) { -#ifdef CONFIG_F2FS_FS_ENCRYPTION -struct f2fs_encryption_policy policy; +struct fscrypt_policy policy;struct inode *inode =file_inode (filp); -if (copy_from_user (&policy, (struct f2fs_encryption_policy __user *)arg, -sizeof (policy))) +if (copy_from_user (&policy, (struct fscrypt_policy __user *)arg, +sizeof (policy)))return -EFAULT ;f2fs_update_time (F2FS_I_SB (inode),REQ_TIME ); -return f2fs_process_policy (&policy, inode); -#else -return -EOPNOTSUPP ; -#endif +return fscrypt_process_policy (inode, &policy); }static int f2fs_ioc_get_encryption_policy (struct file *filp,unsigned long arg) { -#ifdef CONFIG_F2FS_FS_ENCRYPTION -struct f2fs_encryption_policy policy; +struct fscrypt_policy policy;struct inode *inode =file_inode (filp);int err; - err =f2fs_get_policy (inode, &policy); + err =fscrypt_get_policy (inode, &policy);if (err)return err; -if (copy_to_user ((struct f2fs_encryption_policy __user *)arg, &policy, -sizeof (policy))) +if (copy_to_user ((struct fscrypt_policy __user *)arg, &policy,sizeof (policy)))return -EFAULT ;return 0 ; -#else -return -EOPNOTSUPP ; -#endif }static int f2fs_ioc_get_encryption_pwsalt (struct file *filp,unsigned long arg)
@@ -1873,8 +1865,8 @@ static ssize_t f2fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)ssize_t ret;if (f2fs_encrypted_inode (inode) && - !f2fs_has_encryption_key (inode) && -f2fs_get_encryption_info (inode)) + !fscrypt_has_encryption_key (inode) && +fscrypt_get_encryption_info (inode))return -EACCES ;inode_lock (inode);
fs/f2fs/inline.c +2 -2
@@ -277,7 +277,7 @@ process_inline: }struct f2fs_dir_entry *find_in_inline_dir (struct inode *dir, -struct f2fs_filename *fname,struct page **res_page) +struct fscrypt_name *fname,struct page **res_page) {struct f2fs_sb_info *sbi =F2FS_SB (dir->i_sb);struct f2fs_inline_dentry *inline_dentry;
@@ -535,7 +535,7 @@ bool f2fs_empty_inline_dir(struct inode *dir) }int f2fs_read_inline_dir (struct file *file,struct dir_context *ctx, -struct f2fs_str *fstr) +struct fscrypt_str *fstr) {struct inode *inode =file_inode (file);struct f2fs_inline_dentry *inline_dentry =NULL ;
fs/f2fs/inode.c +1 -4
@@ -389,10 +389,7 @@ no_delete: } } out_clear: -#ifdef CONFIG_F2FS_FS_ENCRYPTION -if (fi->i_crypt_info) -f2fs_free_encryption_info (inode, fi->i_crypt_info); -#endif +fscrypt_put_encryption_info (inode,NULL );clear_inode (inode); }
fs/f2fs/namei.c +25 -31
164 lines not on this page · raw message
fs/f2fs/super.c +38 -17
99 lines not on this page · raw message
Signature · 1 line
2.6.3
Jaegeuk Kim
maintainerPATCH v3 9/10 f2fs crypto: sync ext4_lookup and ext4_file_open
In reply to Jaegeuk KimThis patch tries to catch up with lookup and open policies in ext4.
--- fs/f2fs/dir.c | 2 +- fs/f2fs/file.c | 4 ++++ fs/f2fs/namei.c | 23 +++++++++++++++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-)
fs/f2fs/dir.c +1 -1
@@ -855,7 +855,7 @@ static int f2fs_readdir(struct file *file, struct dir_context *ctx)if (f2fs_encrypted_inode (inode)) { err =fscrypt_get_encryption_info (inode); -if (err) +if (err && err != -ENOKEY )return err; err =fscrypt_fname_alloc_buffer (inode,F2FS_NAME_LEN , &fstr);
fs/f2fs/file.c +4 -0
@@ -441,6 +441,7 @@ static int f2fs_file_mmap(struct file *file, struct vm_area_struct *vma)static int f2fs_file_open (struct inode *inode,struct file *filp) {int ret =generic_file_open (inode, filp); +struct inode *dir = filp->f_path.dentry->d_parent->d_inode;if (!ret &&f2fs_encrypted_inode (inode)) { ret =fscrypt_get_encryption_info (inode);
@@ -449,6 +450,9 @@ static int f2fs_file_open(struct inode *inode, struct file *filp)if (!f2fs_encrypted_inode (inode))return -ENOKEY ; } +if (f2fs_encrypted_inode (dir) && + !fscrypt_has_permitted_context (dir, inode)) +return -EPERM ;return ret; }
fs/f2fs/namei.c +23 -0
@@ -262,6 +262,21 @@ static struct dentry *f2fs_lookup(struct inode *dir, struct dentry *dentry,int err =0 ;unsigned int root_ino =F2FS_ROOT_INO (F2FS_I_SB (dir)); +if (f2fs_encrypted_inode (dir)) { +int res =fscrypt_get_encryption_info (dir); + +/* +* DCACHE_ENCRYPTED_WITH_KEY is set if the dentry is +* created while the directory was encrypted and we +* don't have access to the key. +*/ +if (fscrypt_has_encryption_key (dir)) +fscrypt_set_encrypted_dentry (dentry); +fscrypt_set_d_op (dentry); +if (res && res != -ENOKEY ) +return ERR_PTR (res); + } +if (dentry->d_name.len >F2FS_NAME_LEN )return ERR_PTR (-ENAMETOOLONG );
@@ -288,6 +303,14 @@ static struct dentry *f2fs_lookup(struct inode *dir, struct dentry *dentry,if (err) goto err_out; } +if (!IS_ERR (inode) &&f2fs_encrypted_inode (dir) && + (S_ISDIR (inode->i_mode) ||S_ISLNK (inode->i_mode)) && + !fscrypt_has_permitted_context (dir, inode)) { +bool nokey =f2fs_encrypted_inode (inode) && + !fscrypt_has_encryption_key (inode); +iput (inode); +return nokey ?ERR_PTR (-ENOKEY ) :ERR_PTR (-EPERM ); + }return d_splice_alias (inode, dentry); err_out:
Signature · 1 line
2.6.3
Jaegeuk Kim
maintainerPATCH v3 10/10 ext4 crypto: migrate into vfs's crypto engine
In reply to Jaegeuk KimThis patch removes the most parts of internal crypto codes.
And then, it modifies and adds some ext4-specific crypt codes to use the generic facility.
--- fs/ext4/Kconfig | 12 +- fs/ext4/Makefile | 2 - fs/ext4/crypto.c | 525 ------------------------------------------------ fs/ext4/crypto_fname.c | 470 ------------------------------------------- fs/ext4/crypto_key.c | 276 ------------------------- fs/ext4/crypto_policy.c | 229 --------------------- fs/ext4/dir.c | 26 +-- fs/ext4/ext4.h | 195 ++++++------------ fs/ext4/ext4_crypto.h | 159 --------------- fs/ext4/file.c | 10 +- fs/ext4/ialloc.c | 7 +- fs/ext4/inline.c | 14 +- fs/ext4/inode.c | 8 +- fs/ext4/ioctl.c | 20 +- fs/ext4/namei.c | 120 +++++------ fs/ext4/page-io.c | 13 +- fs/ext4/readpage.c | 45 +---- fs/ext4/super.c | 85 +++++++- fs/ext4/symlink.c | 33 ++- 19 files changed, 271 insertions(+), 1978 deletions(-) delete mode 100644 fs/ext4/crypto.c delete mode 100644 fs/ext4/crypto_fname.c delete mode 100644 fs/ext4/crypto_key.c delete mode 100644 fs/ext4/crypto_policy.c delete mode 100644 fs/ext4/ext4_crypto.h
fs/ext4/Kconfig +2 -10
@@ -99,17 +99,9 @@ config EXT4_FS_SECURITY extended attributes for file security labels, say N. config EXT4_ENCRYPTION - tristate "Ext4 Encryption" + bool "Ext4 Encryption" depends on EXT4_FS - select CRYPTO_AES - select CRYPTO_CBC - select CRYPTO_ECB - select CRYPTO_XTS - select CRYPTO_CTS - select CRYPTO_CTR - select CRYPTO_SHA256 - select KEYS - select ENCRYPTED_KEYS + select FS_ENCRYPTION help Enable encryption of ext4 files and directories. This feature is similar to ecryptfs, but it is more memory
fs/ext4/Makefile +0 -2
@@ -12,5 +12,3 @@ ext4-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o page-io.o \ ext4-$(CONFIG_EXT4_FS_POSIX_ACL) += acl.o ext4-$(CONFIG_EXT4_FS_SECURITY) += xattr_security.o -ext4-$(CONFIG_EXT4_FS_ENCRYPTION) += crypto_policy.o crypto.o \ - crypto_key.o crypto_fname.o
fs/ext4/crypto.c deleted +0 -525
525 lines not on this page · raw message
fs/ext4/crypto_fname.c deleted +0 -470
470 lines not on this page · raw message
fs/ext4/crypto_key.c deleted +0 -276
276 lines not on this page · raw message
fs/ext4/crypto_policy.c deleted +0 -229
229 lines not on this page · raw message
fs/ext4/dir.c +14 -12
@@ -109,10 +109,10 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx)struct super_block *sb = inode->i_sb;struct buffer_head *bh =NULL ;int dir_has_error =0 ; -struct ext4_str fname_crypto_str = {.name =NULL , .len =0 }; +struct fscrypt_str fstr =FSTR_INIT (NULL ,0 );if (ext4_encrypted_inode (inode)) { - err =ext4_get_encryption_info (inode); + err =fscrypt_get_encryption_info (inode);if (err && err != -ENOKEY )return err; }
@@ -139,8 +139,7 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx) }if (ext4_encrypted_inode (inode)) { - err =ext4_fname_crypto_alloc_buffer (inode,EXT4_NAME_LEN , - &fname_crypto_str); + err =fscrypt_fname_alloc_buffer (inode,EXT4_NAME_LEN , &fstr);if (err <0 )return err; }
@@ -248,16 +247,19 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx) get_dtype(sb, de->file_type))) goto done; }else { -int save_len = fname_crypto_str.len; +int save_len = fstr.len; +struct fscrypt_str de_name = +FSTR_INIT (de->name, + de->name_len);/* Directory is encrypted */ - err =ext4_fname_disk_to_usr (inode, -NULL , de, &fname_crypto_str); - fname_crypto_str.len = save_len; + err =fscrypt_fname_disk_to_usr (inode, +0 ,0 , &de_name, &fstr); + fstr.len = save_len;if (err <0 ) goto errout;if (!dir_emit (ctx, - fname_crypto_str.name, err, + fstr.name, err,le32_to_cpu (de->inode),get_dtype (sb, de->file_type))) goto done;
@@ -276,7 +278,7 @@ done: err =0 ; errout:#ifdef CONFIG_EXT4_FS_ENCRYPTION -ext4_fname_crypto_free_buffer (&fname_crypto_str); +fscrypt_fname_free_buffer (&fstr);#endif brelse (bh);return err;
@@ -427,7 +429,7 @@ void ext4_htree_free_dir_info(struct dir_private_info *p)int ext4_htree_store_dirent (struct file *dir_file,__u32 hash,__u32 minor_hash,struct ext4_dir_entry_2 *dirent, -struct ext4_str *ent_name) +struct fscrypt_str *ent_name) {struct rb_node **p, *parent =NULL ;struct fname *fname, *new_fn;
@@ -604,7 +606,7 @@ finished:static int ext4_dir_open (struct inode * inode,struct file * filp) {if (ext4_encrypted_inode (inode)) -return ext4_get_encryption_info (inode) ? -EACCES :0 ; +return fscrypt_get_encryption_info (inode) ? -EACCES :0 ;return 0 ; }
fs/ext4/ext4.h +63 -132
279 lines not on this page · raw message
fs/ext4/ext4_crypto.h deleted +0 -159
159 lines not on this page · raw message
fs/ext4/file.c +5 -5
@@ -329,10 +329,10 @@ static int ext4_file_mmap(struct file *file, struct vm_area_struct *vma)struct inode *inode = file->f_mapping->host;if (ext4_encrypted_inode (inode)) { -int err =ext4_get_encryption_info (inode); +int err =fscrypt_get_encryption_info (inode);if (err)return 0 ; -if (ext4_encryption_info (inode) ==NULL ) +if (!fscrypt_has_encryption_key (inode))return -ENOKEY ; }file_accessed (file);
@@ -388,14 +388,14 @@ static int ext4_file_open(struct inode * inode, struct file * filp) } }if (ext4_encrypted_inode (inode)) { - ret =ext4_get_encryption_info (inode); + ret =fscrypt_get_encryption_info (inode);if (ret)return -EACCES ; -if (ext4_encryption_info (inode) ==NULL ) +if (!fscrypt_has_encryption_key (inode))return -ENOKEY ; }if (ext4_encrypted_inode (dir) && - !ext4_is_child_context_consistent_with_parent (dir, inode)) { + !fscrypt_has_permitted_context (dir, inode)) { ext4_warning(inode->i_sb, "Inconsistent encryption contexts: %lu/%lu\n", (unsigned long) dir->i_ino,
fs/ext4/ialloc.c +4 -3
@@ -767,10 +767,10 @@ struct inode *__ext4_new_inode(handle_t *handle, struct inode *dir,if ((ext4_encrypted_inode (dir) ||DUMMY_ENCRYPTION_ENABLED (EXT4_SB (dir->i_sb))) && (S_ISREG (mode) ||S_ISDIR (mode) ||S_ISLNK (mode))) { - err =ext4_get_encryption_info (dir); + err =fscrypt_get_encryption_info (dir);if (err)return ERR_PTR (err); -if (ext4_encryption_info (dir) ==NULL ) +if (!fscrypt_has_encryption_key (dir))return ERR_PTR (-EPERM );if (!handle) nblocks +=EXT4_DATA_TRANS_BLOCKS (dir->i_sb);
@@ -1115,7 +1115,8 @@ got: }if (encrypt) { - err =ext4_inherit_context (dir, inode); +/* give pointer to avoid set_context with journal ops. */ + err =fscrypt_inherit_context (dir, inode, &encrypt, true);if (err) goto fail_free_drop; }
fs/ext4/inline.c +7 -7
@@ -1325,7 +1325,7 @@ int htree_inlinedir_to_tree(struct file *dir_file,struct ext4_iloc iloc;void *dir_buf =NULL ;struct ext4_dir_entry_2 fake; -struct ext4_str tmp_str; +struct fscrypt_str tmp_str; ret =ext4_get_inode_loc (inode, &iloc);if (ret)
@@ -1739,20 +1739,20 @@ ext4_get_inline_entry(struct inode *inode,return (struct ext4_dir_entry_2 *)(inline_pos + offset); } -int empty_inline_dir (struct inode *dir,int *has_inline_data) +bool empty_inline_dir (struct inode *dir,int *has_inline_data) {int err, inline_size;struct ext4_iloc iloc;void *inline_pos;unsigned int offset;struct ext4_dir_entry_2 *de; -int ret =1 ; +bool ret = true; err =ext4_get_inode_loc (dir, &iloc);if (err) {EXT4_ERROR_INODE (dir,"error %d getting inode %lu block" , err, dir->i_ino); -return 1 ; +return true; }down_read (&EXT4_I (dir)->xattr_sem);
@@ -1766,7 +1766,7 @@ int empty_inline_dir(struct inode *dir, int *has_inline_data)ext4_warning (dir->i_sb,"bad inline directory (dir #%lu) - no `..'" , dir->i_ino); - ret =1 ; + ret = true; goto out; }
@@ -1784,11 +1784,11 @@ int empty_inline_dir(struct inode *dir, int *has_inline_data) dir->i_ino,le32_to_cpu (de->inode),le16_to_cpu (de->rec_len), de->name_len, inline_size); - ret =1 ; + ret = true; goto out; }if (le32_to_cpu (de->inode)) { - ret =0 ; + ret = false; goto out; } offset +=ext4_rec_len_from_disk (de->rec_len, inline_size);
fs/ext4/inode.c +4 -4
@@ -389,7 +389,7 @@ int ext4_issue_zeroout(struct inode *inode, ext4_lblk_t lblk, ext4_fsblk_t pblk,int ret;if (ext4_encrypted_inode (inode)) -return ext4_encrypted_zeroout (inode, lblk, pblk, len); +return fscrypt_zeroout_range (inode, lblk, pblk, len); ret =sb_issue_zeroout (inode->i_sb, pblk, len,GFP_NOFS );if (ret >0 )
@@ -1009,7 +1009,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 =ext4_decrypt (page); + err =fscrypt_decrypt_page (page); return err; }#endif
@@ -3544,9 +3544,9 @@ static int __ext4_block_zero_page_range(handle_t *handle,if (S_ISREG (inode->i_mode) &&ext4_encrypted_inode (inode)) {/* We expect the key to be set. */ -BUG_ON (!ext4_has_encryption_key (inode)); +BUG_ON (!fscrypt_has_encryption_key (inode));BUG_ON (blocksize !=PAGE_CACHE_SIZE ); -WARN_ON_ONCE (ext4_decrypt (page)); +WARN_ON_ONCE (fscrypt_decrypt_page (page)); } }if (ext4_should_journal_data (inode)) {
fs/ext4/ioctl.c +7 -13
@@ -767,19 +767,13 @@ resizefs_out:return ext4_ext_precache (inode);case EXT4_IOC_SET_ENCRYPTION_POLICY : {#ifdef CONFIG_EXT4_FS_ENCRYPTION -struct ext4_encryption_policy policy; -int err =0 ; +struct fscrypt_policy policy;if (copy_from_user (&policy, - (struct ext4_encryption_policy __user *)arg, -sizeof (policy))) { - err = -EFAULT ; - goto encryption_policy_out; - } - - err =ext4_process_policy (&policy, inode); -encryption_policy_out: -return err; + (struct fscrypt_policy __user *)arg, +sizeof (policy))) +return -EFAULT ; +return fscrypt_process_policy (inode, &policy);#else return -EOPNOTSUPP ;#endif
@@ -822,12 +816,12 @@ encryption_policy_out: }case EXT4_IOC_GET_ENCRYPTION_POLICY : {#ifdef CONFIG_EXT4_FS_ENCRYPTION -struct ext4_encryption_policy policy; +struct fscrypt_policy policy;int err =0 ;if (!ext4_encrypted_inode (inode))return -ENOENT ; - err =ext4_get_policy (inode, &policy); + err =fscrypt_get_policy (inode, &policy);if (err)return err;if (copy_to_user ((void __user *)arg, &policy,sizeof (policy)))
fs/ext4/namei.c +60 -60
294 lines not on this page · raw message
fs/ext4/page-io.c +6 -7
@@ -23,6 +23,7 @@#include <linux/kernel.h> #include <linux/slab.h> #include <linux/mm.h> +#include <linux/fscrypto.h> #include "ext4_jbd2.h" #include "xattr.h"
@@ -66,7 +67,6 @@ static void ext4_finish_bio(struct bio *bio)struct page *page = bvec->bv_page;#ifdef CONFIG_EXT4_FS_ENCRYPTION struct page *data_page =NULL ; -struct ext4_crypto_ctx *ctx =NULL ;#endif struct buffer_head *bh, *head;unsigned bio_start = bvec->bv_offset;
@@ -81,8 +81,7 @@ static void ext4_finish_bio(struct bio *bio)if (!page->mapping) {/* The bounce data pages are unmapped. */ data_page = page; - ctx = (struct ext4_crypto_ctx *)page_private (data_page); - page = ctx->w.control_page; +fscrypt_pullback_bio_page (&page, false); }#endif
@@ -112,8 +111,8 @@ static void ext4_finish_bio(struct bio *bio)local_irq_restore (flags);if (!under_io) {#ifdef CONFIG_EXT4_FS_ENCRYPTION -if (ctx) -ext4_restore_control_page (data_page); +if (data_page) +fscrypt_restore_control_page (data_page);#endif end_page_writeback (page); }
@@ -484,7 +483,7 @@ int ext4_bio_write_page(struct ext4_io_submit *io,if (ext4_encrypted_inode (inode) &&S_ISREG (inode->i_mode) && nr_to_submit) { - data_page =ext4_encrypt (inode, page); + data_page =fscrypt_encrypt_page (inode, page);if (IS_ERR (data_page)) { ret =PTR_ERR (data_page); data_page =NULL ;
@@ -514,7 +513,7 @@ int ext4_bio_write_page(struct ext4_io_submit *io,if (ret) { out:if (data_page) -ext4_restore_control_page (data_page); +fscrypt_restore_control_page (data_page);printk_ratelimited (KERN_ERR "%s: ret = %d\n" , __func__, ret);redirty_page_for_writepage (wbc, page); do {
fs/ext4/readpage.c +5 -40
74 lines not on this page · raw message
fs/ext4/super.c +79 -6
115 lines not on this page · raw message
fs/ext4/symlink.c +15 -18
@@ -22,23 +22,22 @@#include "ext4.h" #include "xattr.h" -#ifdef CONFIG_EXT4_FS_ENCRYPTION static const char *ext4_encrypted_get_link (struct dentry *dentry,struct inode *inode,struct delayed_call *done) {struct page *cpage =NULL ;char *caddr, *paddr =NULL ; -struct ext4_str cstr, pstr; -struct ext4_encrypted_symlink_data *sd; +struct fscrypt_str cstr, pstr; +struct fscrypt_symlink_data *sd;loff_t size =min_t (loff_t,i_size_read (inode),PAGE_SIZE -1 );int res; -u32 plen, max_size = inode->i_sb->s_blocksize; +u32 max_size = inode->i_sb->s_blocksize;if (!dentry)return ERR_PTR (-ECHILD ); - res =ext4_get_encryption_info (inode); + res =fscrypt_get_encryption_info (inode);if (res)return ERR_PTR (res);
@@ -54,30 +53,29 @@ static const char *ext4_encrypted_get_link(struct dentry *dentry, }/* Symlink is encrypted */ - sd = (struct ext4_encrypted_symlink_data *)caddr; + sd = (struct fscrypt_symlink_data *)caddr; cstr.name = sd->encrypted_path; cstr.len =le16_to_cpu (sd->len);if ((cstr.len + -sizeof (struct ext4_encrypted_symlink_data ) -1 ) > +sizeof (struct fscrypt_symlink_data ) -1 ) > max_size) {/* Symlink data on the disk is corrupted */ res = -EFSCORRUPTED ; goto errout; } - plen = (cstr.len <EXT4_FNAME_CRYPTO_DIGEST_SIZE *2 ) ? -EXT4_FNAME_CRYPTO_DIGEST_SIZE *2 : cstr.len; - paddr =kmalloc (plen +1 ,GFP_NOFS ); -if (!paddr) { - res = -ENOMEM ; + + res =fscrypt_fname_alloc_buffer (inode, cstr.len, &pstr); +if (res) goto errout; - } - pstr.name = paddr; - pstr.len = plen; - res =_ext4_fname_disk_to_usr (inode,NULL , &cstr, &pstr); + + res =fscrypt_fname_disk_to_usr (inode,0 ,0 , &cstr, &pstr);if (res <0 ) goto errout; + + paddr = pstr.name; +/* Null-terminate the name */ -if (res <= plen) +if (res <= pstr.len) paddr[res] ='\0' ;if (cpage)page_cache_release (cpage);
@@ -99,7 +97,6 @@ const struct inode_operations ext4_encrypted_symlink_inode_operations = { .listxattr = ext4_listxattr, .removexattr = generic_removexattr, }; -#endif const struct inode_operations ext4_symlink_inode_operations = { .readlink = generic_readlink,
Signature · 1 line
2.6.3