]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - fs/crypto/crypto.c
Merge tag 'y2038-vfs' of git://git.kernel.org/pub/scm/linux/kernel/git/arnd/playground
[linux.git] / fs / crypto / crypto.c
index 335a362ee4468986a6a9483f6230881bd53ddc74..32a7ad0098cc28b7739d225e52d4898d812f939b 100644 (file)
@@ -59,23 +59,16 @@ void fscrypt_enqueue_decrypt_work(struct work_struct *work)
 EXPORT_SYMBOL(fscrypt_enqueue_decrypt_work);
 
 /**
- * fscrypt_release_ctx() - Releases an encryption context
- * @ctx: The encryption context to release.
+ * fscrypt_release_ctx() - Release a decryption context
+ * @ctx: The decryption 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.
+ * If the decryption context was allocated from the pre-allocated pool, return
+ * it to that pool.  Else, free it.
  */
 void fscrypt_release_ctx(struct fscrypt_ctx *ctx)
 {
        unsigned long flags;
 
-       if (ctx->flags & FS_CTX_HAS_BOUNCE_BUFFER_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 {
@@ -87,12 +80,12 @@ void fscrypt_release_ctx(struct fscrypt_ctx *ctx)
 EXPORT_SYMBOL(fscrypt_release_ctx);
 
 /**
- * fscrypt_get_ctx() - Gets an encryption context
+ * fscrypt_get_ctx() - Get a decryption context
  * @gfp_flags:   The gfp flag for memory allocation
  *
- * Allocates and initializes an encryption context.
+ * Allocate and initialize a decryption context.
  *
- * Return: A new encryption context on success; an ERR_PTR() otherwise.
+ * Return: A new decryption context on success; an ERR_PTR() otherwise.
  */
 struct fscrypt_ctx *fscrypt_get_ctx(gfp_t gfp_flags)
 {
@@ -100,14 +93,8 @@ struct fscrypt_ctx *fscrypt_get_ctx(gfp_t gfp_flags)
        unsigned long flags;
 
        /*
-        * 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.
+        * First try getting a ctx from the free list so that we don't have to
+        * call into the slab allocator.
         */
        spin_lock_irqsave(&fscrypt_ctx_lock, flags);
        ctx = list_first_entry_or_null(&fscrypt_free_ctxs,
@@ -123,28 +110,49 @@ struct fscrypt_ctx *fscrypt_get_ctx(gfp_t gfp_flags)
        } else {
                ctx->flags &= ~FS_CTX_REQUIRES_FREE_ENCRYPT_FL;
        }
-       ctx->flags &= ~FS_CTX_HAS_BOUNCE_BUFFER_FL;
        return ctx;
 }
 EXPORT_SYMBOL(fscrypt_get_ctx);
 
+struct page *fscrypt_alloc_bounce_page(gfp_t gfp_flags)
+{
+       return mempool_alloc(fscrypt_bounce_page_pool, gfp_flags);
+}
+
+/**
+ * fscrypt_free_bounce_page() - free a ciphertext bounce page
+ *
+ * Free a bounce page that was allocated by fscrypt_encrypt_pagecache_blocks(),
+ * or by fscrypt_alloc_bounce_page() directly.
+ */
+void fscrypt_free_bounce_page(struct page *bounce_page)
+{
+       if (!bounce_page)
+               return;
+       set_page_private(bounce_page, (unsigned long)NULL);
+       ClearPagePrivate(bounce_page);
+       mempool_free(bounce_page, fscrypt_bounce_page_pool);
+}
+EXPORT_SYMBOL(fscrypt_free_bounce_page);
+
 void fscrypt_generate_iv(union fscrypt_iv *iv, u64 lblk_num,
                         const struct fscrypt_info *ci)
 {
        memset(iv, 0, ci->ci_mode->ivsize);
        iv->lblk_num = cpu_to_le64(lblk_num);
 
-       if (ci->ci_flags & FS_POLICY_FLAG_DIRECT_KEY)
+       if (fscrypt_is_direct_key_policy(&ci->ci_policy))
                memcpy(iv->nonce, ci->ci_nonce, FS_KEY_DERIVATION_NONCE_SIZE);
 
        if (ci->ci_essiv_tfm != NULL)
                crypto_cipher_encrypt_one(ci->ci_essiv_tfm, iv->raw, iv->raw);
 }
 
-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)
+/* Encrypt or decrypt a single filesystem block of file contents */
+int fscrypt_crypt_block(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)
 {
        union fscrypt_iv iv;
        struct skcipher_request *req = NULL;
@@ -154,7 +162,10 @@ int fscrypt_do_page_crypto(const struct inode *inode, fscrypt_direction_t rw,
        struct crypto_skcipher *tfm = ci->ci_ctfm;
        int res = 0;
 
-       BUG_ON(len == 0);
+       if (WARN_ON_ONCE(len <= 0))
+               return -EINVAL;
+       if (WARN_ON_ONCE(len % FS_CRYPTO_BLOCK_SIZE != 0))
+               return -EINVAL;
 
        fscrypt_generate_iv(&iv, lblk_num, ci);
 
@@ -177,135 +188,165 @@ int fscrypt_do_page_crypto(const struct inode *inode, fscrypt_direction_t rw,
                res = crypto_wait_req(crypto_skcipher_encrypt(req), &wait);
        skcipher_request_free(req);
        if (res) {
-               fscrypt_err(inode->i_sb,
-                           "%scryption failed for inode %lu, block %llu: %d",
-                           (rw == FS_DECRYPT ? "de" : "en"),
-                           inode->i_ino, lblk_num, res);
+               fscrypt_err(inode, "%scryption failed for block %llu: %d",
+                           (rw == FS_DECRYPT ? "De" : "En"), lblk_num, res);
                return res;
        }
        return 0;
 }
 
-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)
-               return ERR_PTR(-ENOMEM);
-       ctx->flags |= FS_CTX_HAS_BOUNCE_BUFFER_FL;
-       return ctx->w.bounce_page;
-}
-
 /**
- * fscypt_encrypt_page() - Encrypts a page
- * @inode:     The inode for which the encryption should take place
- * @page:      The page to encrypt. Must be locked for bounce-page
- *             encryption.
- * @len:       Length of data to encrypt in @page and encrypted
- *             data in returned page.
- * @offs:      Offset of data within @page and returned
- *             page holding encrypted data.
- * @lblk_num:  Logical block number. This must be unique for multiple
- *             calls with same inode, except when overwriting
- *             previously written data.
- * @gfp_flags: The gfp flag for memory allocation
- *
- * Encrypts @page using the ctx encryption context. Performs encryption
- * either in-place or into a newly allocated bounce page.
- * Called on the page write path.
+ * fscrypt_encrypt_pagecache_blocks() - Encrypt filesystem blocks from a pagecache page
+ * @page:      The locked pagecache page containing the block(s) to encrypt
+ * @len:       Total size of the block(s) to encrypt.  Must be a nonzero
+ *             multiple of the filesystem's block size.
+ * @offs:      Byte offset within @page of the first block to encrypt.  Must be
+ *             a multiple of the filesystem's block size.
+ * @gfp_flags: Memory allocation flags
  *
- * Bounce page allocation is the default.
- * In this case, the contents of @page are encrypted and stored in an
- * allocated bounce page. @page has to be locked and the caller must call
- * fscrypt_restore_control_page() on the returned ciphertext page to
- * release the bounce buffer and the encryption context.
+ * A new bounce page is allocated, and the specified block(s) are encrypted into
+ * it.  In the bounce page, the ciphertext block(s) will be located at the same
+ * offsets at which the plaintext block(s) were located in the source page; any
+ * other parts of the bounce page will be left uninitialized.  However, normally
+ * blocksize == PAGE_SIZE and the whole page is encrypted at once.
  *
- * In-place encryption is used by setting the FS_CFLG_OWN_PAGES flag in
- * fscrypt_operations. Here, the input-page is returned with its content
- * encrypted.
+ * This is for use by the filesystem's ->writepages() method.
  *
- * Return: A page with the encrypted content on success. Else, an
- * error value or NULL.
+ * Return: the new encrypted bounce page on success; an ERR_PTR() on failure
  */
-struct page *fscrypt_encrypt_page(const struct inode *inode,
-                               struct page *page,
-                               unsigned int len,
-                               unsigned int offs,
-                               u64 lblk_num, gfp_t gfp_flags)
+struct page *fscrypt_encrypt_pagecache_blocks(struct page *page,
+                                             unsigned int len,
+                                             unsigned int offs,
+                                             gfp_t gfp_flags)
 
 {
-       struct fscrypt_ctx *ctx;
-       struct page *ciphertext_page = page;
+       const struct inode *inode = page->mapping->host;
+       const unsigned int blockbits = inode->i_blkbits;
+       const unsigned int blocksize = 1 << blockbits;
+       struct page *ciphertext_page;
+       u64 lblk_num = ((u64)page->index << (PAGE_SHIFT - blockbits)) +
+                      (offs >> blockbits);
+       unsigned int i;
        int err;
 
-       BUG_ON(len % FS_CRYPTO_BLOCK_SIZE != 0);
-
-       if (inode->i_sb->s_cop->flags & FS_CFLG_OWN_PAGES) {
-               /* with inplace-encryption we just encrypt the page */
-               err = fscrypt_do_page_crypto(inode, FS_ENCRYPT, lblk_num, page,
-                                            ciphertext_page, len, offs,
-                                            gfp_flags);
-               if (err)
-                       return ERR_PTR(err);
-
-               return ciphertext_page;
-       }
-
-       BUG_ON(!PageLocked(page));
+       if (WARN_ON_ONCE(!PageLocked(page)))
+               return ERR_PTR(-EINVAL);
 
-       ctx = fscrypt_get_ctx(gfp_flags);
-       if (IS_ERR(ctx))
-               return ERR_CAST(ctx);
+       if (WARN_ON_ONCE(len <= 0 || !IS_ALIGNED(len | offs, blocksize)))
+               return ERR_PTR(-EINVAL);
 
-       /* The encryption operation will require a bounce page. */
-       ciphertext_page = fscrypt_alloc_bounce_page(ctx, gfp_flags);
-       if (IS_ERR(ciphertext_page))
-               goto errout;
+       ciphertext_page = fscrypt_alloc_bounce_page(gfp_flags);
+       if (!ciphertext_page)
+               return ERR_PTR(-ENOMEM);
 
-       ctx->w.control_page = page;
-       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;
+       for (i = offs; i < offs + len; i += blocksize, lblk_num++) {
+               err = fscrypt_crypt_block(inode, FS_ENCRYPT, lblk_num,
+                                         page, ciphertext_page,
+                                         blocksize, i, gfp_flags);
+               if (err) {
+                       fscrypt_free_bounce_page(ciphertext_page);
+                       return ERR_PTR(err);
+               }
        }
        SetPagePrivate(ciphertext_page);
-       set_page_private(ciphertext_page, (unsigned long)ctx);
-       lock_page(ciphertext_page);
+       set_page_private(ciphertext_page, (unsigned long)page);
        return ciphertext_page;
+}
+EXPORT_SYMBOL(fscrypt_encrypt_pagecache_blocks);
 
-errout:
-       fscrypt_release_ctx(ctx);
-       return ciphertext_page;
+/**
+ * fscrypt_encrypt_block_inplace() - Encrypt a filesystem block in-place
+ * @inode:     The inode to which this block belongs
+ * @page:      The page containing the block to encrypt
+ * @len:       Size of block to encrypt.  Doesn't need to be a multiple of the
+ *             fs block size, but must be a multiple of FS_CRYPTO_BLOCK_SIZE.
+ * @offs:      Byte offset within @page at which the block to encrypt begins
+ * @lblk_num:  Filesystem logical block number of the block, i.e. the 0-based
+ *             number of the block within the file
+ * @gfp_flags: Memory allocation flags
+ *
+ * Encrypt a possibly-compressed filesystem block that is located in an
+ * arbitrary page, not necessarily in the original pagecache page.  The @inode
+ * and @lblk_num must be specified, as they can't be determined from @page.
+ *
+ * Return: 0 on success; -errno on failure
+ */
+int fscrypt_encrypt_block_inplace(const struct inode *inode, struct page *page,
+                                 unsigned int len, unsigned int offs,
+                                 u64 lblk_num, gfp_t gfp_flags)
+{
+       return fscrypt_crypt_block(inode, FS_ENCRYPT, lblk_num, page, page,
+                                  len, offs, gfp_flags);
 }
-EXPORT_SYMBOL(fscrypt_encrypt_page);
+EXPORT_SYMBOL(fscrypt_encrypt_block_inplace);
 
 /**
- * fscrypt_decrypt_page() - Decrypts a page in-place
- * @inode:     The corresponding inode for the page to decrypt.
- * @page:      The page to decrypt. Must be locked in case
- *             it is a writeback page (FS_CFLG_OWN_PAGES unset).
- * @len:       Number of bytes in @page to be decrypted.
- * @offs:      Start of data in @page.
- * @lblk_num:  Logical block number.
+ * fscrypt_decrypt_pagecache_blocks() - Decrypt filesystem blocks in a pagecache page
+ * @page:      The locked pagecache page containing the block(s) to decrypt
+ * @len:       Total size of the block(s) to decrypt.  Must be a nonzero
+ *             multiple of the filesystem's block size.
+ * @offs:      Byte offset within @page of the first block to decrypt.  Must be
+ *             a multiple of the filesystem's block size.
  *
- * Decrypts page in-place using the ctx encryption context.
+ * The specified block(s) are decrypted in-place within the pagecache page,
+ * which must still be locked and not uptodate.  Normally, blocksize ==
+ * PAGE_SIZE and the whole page is decrypted at once.
  *
- * Called from the read completion callback.
+ * This is for use by the filesystem's ->readpages() method.
  *
- * Return: Zero on success, non-zero otherwise.
+ * Return: 0 on success; -errno on failure
  */
-int fscrypt_decrypt_page(const struct inode *inode, struct page *page,
-                       unsigned int len, unsigned int offs, u64 lblk_num)
+int fscrypt_decrypt_pagecache_blocks(struct page *page, unsigned int len,
+                                    unsigned int offs)
 {
-       if (!(inode->i_sb->s_cop->flags & FS_CFLG_OWN_PAGES))
-               BUG_ON(!PageLocked(page));
+       const struct inode *inode = page->mapping->host;
+       const unsigned int blockbits = inode->i_blkbits;
+       const unsigned int blocksize = 1 << blockbits;
+       u64 lblk_num = ((u64)page->index << (PAGE_SHIFT - blockbits)) +
+                      (offs >> blockbits);
+       unsigned int i;
+       int err;
+
+       if (WARN_ON_ONCE(!PageLocked(page)))
+               return -EINVAL;
 
-       return fscrypt_do_page_crypto(inode, FS_DECRYPT, lblk_num, page, page,
-                                     len, offs, GFP_NOFS);
+       if (WARN_ON_ONCE(len <= 0 || !IS_ALIGNED(len | offs, blocksize)))
+               return -EINVAL;
+
+       for (i = offs; i < offs + len; i += blocksize, lblk_num++) {
+               err = fscrypt_crypt_block(inode, FS_DECRYPT, lblk_num, page,
+                                         page, blocksize, i, GFP_NOFS);
+               if (err)
+                       return err;
+       }
+       return 0;
 }
-EXPORT_SYMBOL(fscrypt_decrypt_page);
+EXPORT_SYMBOL(fscrypt_decrypt_pagecache_blocks);
+
+/**
+ * fscrypt_decrypt_block_inplace() - Decrypt a filesystem block in-place
+ * @inode:     The inode to which this block belongs
+ * @page:      The page containing the block to decrypt
+ * @len:       Size of block to decrypt.  Doesn't need to be a multiple of the
+ *             fs block size, but must be a multiple of FS_CRYPTO_BLOCK_SIZE.
+ * @offs:      Byte offset within @page at which the block to decrypt begins
+ * @lblk_num:  Filesystem logical block number of the block, i.e. the 0-based
+ *             number of the block within the file
+ *
+ * Decrypt a possibly-compressed filesystem block that is located in an
+ * arbitrary page, not necessarily in the original pagecache page.  The @inode
+ * and @lblk_num must be specified, as they can't be determined from @page.
+ *
+ * Return: 0 on success; -errno on failure
+ */
+int fscrypt_decrypt_block_inplace(const struct inode *inode, struct page *page,
+                                 unsigned int len, unsigned int offs,
+                                 u64 lblk_num)
+{
+       return fscrypt_crypt_block(inode, FS_DECRYPT, lblk_num, page, page,
+                                  len, offs, GFP_NOFS);
+}
+EXPORT_SYMBOL(fscrypt_decrypt_block_inplace);
 
 /*
  * Validate dentries in encrypted directories to make sure we aren't potentially
@@ -355,18 +396,6 @@ const struct dentry_operations fscrypt_d_ops = {
        .d_revalidate = fscrypt_d_revalidate,
 };
 
-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;
@@ -422,7 +451,7 @@ int fscrypt_initialize(unsigned int cop_flags)
        return res;
 }
 
-void fscrypt_msg(struct super_block *sb, const char *level,
+void fscrypt_msg(const struct inode *inode, const char *level,
                 const char *fmt, ...)
 {
        static DEFINE_RATELIMIT_STATE(rs, DEFAULT_RATELIMIT_INTERVAL,
@@ -436,8 +465,9 @@ void fscrypt_msg(struct super_block *sb, const char *level,
        va_start(args, fmt);
        vaf.fmt = fmt;
        vaf.va = &args;
-       if (sb)
-               printk("%sfscrypt (%s): %pV\n", level, sb->s_id, &vaf);
+       if (inode)
+               printk("%sfscrypt (%s, inode %lu): %pV\n",
+                      level, inode->i_sb->s_id, inode->i_ino, &vaf);
        else
                printk("%sfscrypt: %pV\n", level, &vaf);
        va_end(args);
@@ -448,6 +478,8 @@ void fscrypt_msg(struct super_block *sb, const char *level,
  */
 static int __init fscrypt_init(void)
 {
+       int err = -ENOMEM;
+
        /*
         * Use an unbound workqueue to allow bios to be decrypted in parallel
         * even when they happen to complete on the same CPU.  This sacrifices
@@ -470,31 +502,19 @@ static int __init fscrypt_init(void)
        if (!fscrypt_info_cachep)
                goto fail_free_ctx;
 
+       err = fscrypt_init_keyring();
+       if (err)
+               goto fail_free_info;
+
        return 0;
 
+fail_free_info:
+       kmem_cache_destroy(fscrypt_info_cachep);
 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
- */
-static 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);
-
-       fscrypt_essiv_cleanup();
+       return err;
 }
-module_exit(fscrypt_exit);
-
-MODULE_LICENSE("GPL");
+late_initcall(fscrypt_init)