fscrypt: rename keyinfo.c to keysetup.c
authorEric Biggers <ebiggers@google.com>
Mon, 5 Aug 2019 02:35:45 +0000 (19:35 -0700)
committerEric Biggers <ebiggers@google.com>
Tue, 13 Aug 2019 02:06:06 +0000 (19:06 -0700)
Rename keyinfo.c to keysetup.c since this better describes what the file
does (sets up the key), and it matches the new file keysetup_v1.c.

Reviewed-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Eric Biggers <ebiggers@google.com>
fs/crypto/Makefile
fs/crypto/fscrypt_private.h
fs/crypto/keyinfo.c [deleted file]
fs/crypto/keysetup.c [new file with mode: 0644]
include/linux/fscrypt.h

index 1fba255c34ca5675b73e4b86cb38f4257a012ecf..ad14d4c29784a67aeab7e34e8299a72deda06fef 100644 (file)
@@ -4,7 +4,7 @@ obj-$(CONFIG_FS_ENCRYPTION)     += fscrypto.o
 fscrypto-y := crypto.o \
              fname.o \
              hooks.o \
-             keyinfo.o \
+             keysetup.o \
              keysetup_v1.o \
              policy.o
 
index 387b44b255f6ab41ad3980a831198e3a3431bc36..794dcba25ca826a0ea98443ee2425ad324317ef1 100644 (file)
@@ -156,7 +156,7 @@ extern bool fscrypt_fname_encrypted_size(const struct inode *inode,
                                         u32 orig_len, u32 max_len,
                                         u32 *encrypted_len_ret);
 
-/* keyinfo.c */
+/* keysetup.c */
 
 struct fscrypt_mode {
        const char *friendly_name;
diff --git a/fs/crypto/keyinfo.c b/fs/crypto/keyinfo.c
deleted file mode 100644 (file)
index f4a4744..0000000
+++ /dev/null
@@ -1,345 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Key setup facility for FS encryption support.
- *
- * Copyright (C) 2015, Google, Inc.
- *
- * Originally written by Michael Halcrow, Ildar Muslukhov, and Uday Savagaonkar.
- * Heavily modified since then.
- */
-
-#include <crypto/aes.h>
-#include <crypto/sha.h>
-#include <crypto/skcipher.h>
-#include <linux/key.h>
-
-#include "fscrypt_private.h"
-
-static struct crypto_shash *essiv_hash_tfm;
-
-static struct fscrypt_mode available_modes[] = {
-       [FSCRYPT_MODE_AES_256_XTS] = {
-               .friendly_name = "AES-256-XTS",
-               .cipher_str = "xts(aes)",
-               .keysize = 64,
-               .ivsize = 16,
-       },
-       [FSCRYPT_MODE_AES_256_CTS] = {
-               .friendly_name = "AES-256-CTS-CBC",
-               .cipher_str = "cts(cbc(aes))",
-               .keysize = 32,
-               .ivsize = 16,
-       },
-       [FSCRYPT_MODE_AES_128_CBC] = {
-               .friendly_name = "AES-128-CBC",
-               .cipher_str = "cbc(aes)",
-               .keysize = 16,
-               .ivsize = 16,
-               .needs_essiv = true,
-       },
-       [FSCRYPT_MODE_AES_128_CTS] = {
-               .friendly_name = "AES-128-CTS-CBC",
-               .cipher_str = "cts(cbc(aes))",
-               .keysize = 16,
-               .ivsize = 16,
-       },
-       [FSCRYPT_MODE_ADIANTUM] = {
-               .friendly_name = "Adiantum",
-               .cipher_str = "adiantum(xchacha12,aes)",
-               .keysize = 32,
-               .ivsize = 32,
-       },
-};
-
-static struct fscrypt_mode *
-select_encryption_mode(const struct fscrypt_info *ci, const struct inode *inode)
-{
-       if (!fscrypt_valid_enc_modes(ci->ci_data_mode, ci->ci_filename_mode)) {
-               fscrypt_warn(inode,
-                            "Unsupported encryption modes (contents mode %d, filenames mode %d)",
-                            ci->ci_data_mode, ci->ci_filename_mode);
-               return ERR_PTR(-EINVAL);
-       }
-
-       if (S_ISREG(inode->i_mode))
-               return &available_modes[ci->ci_data_mode];
-
-       if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))
-               return &available_modes[ci->ci_filename_mode];
-
-       WARN_ONCE(1, "fscrypt: filesystem tried to load encryption info for inode %lu, which is not encryptable (file type %d)\n",
-                 inode->i_ino, (inode->i_mode & S_IFMT));
-       return ERR_PTR(-EINVAL);
-}
-
-/* Create a symmetric cipher object for the given encryption mode and key */
-struct crypto_skcipher *fscrypt_allocate_skcipher(struct fscrypt_mode *mode,
-                                                 const u8 *raw_key,
-                                                 const struct inode *inode)
-{
-       struct crypto_skcipher *tfm;
-       int err;
-
-       tfm = crypto_alloc_skcipher(mode->cipher_str, 0, 0);
-       if (IS_ERR(tfm)) {
-               if (PTR_ERR(tfm) == -ENOENT) {
-                       fscrypt_warn(inode,
-                                    "Missing crypto API support for %s (API name: \"%s\")",
-                                    mode->friendly_name, mode->cipher_str);
-                       return ERR_PTR(-ENOPKG);
-               }
-               fscrypt_err(inode, "Error allocating '%s' transform: %ld",
-                           mode->cipher_str, PTR_ERR(tfm));
-               return tfm;
-       }
-       if (unlikely(!mode->logged_impl_name)) {
-               /*
-                * fscrypt performance can vary greatly depending on which
-                * crypto algorithm implementation is used.  Help people debug
-                * performance problems by logging the ->cra_driver_name the
-                * first time a mode is used.  Note that multiple threads can
-                * race here, but it doesn't really matter.
-                */
-               mode->logged_impl_name = true;
-               pr_info("fscrypt: %s using implementation \"%s\"\n",
-                       mode->friendly_name,
-                       crypto_skcipher_alg(tfm)->base.cra_driver_name);
-       }
-       crypto_skcipher_set_flags(tfm, CRYPTO_TFM_REQ_FORBID_WEAK_KEYS);
-       err = crypto_skcipher_setkey(tfm, raw_key, mode->keysize);
-       if (err)
-               goto err_free_tfm;
-
-       return tfm;
-
-err_free_tfm:
-       crypto_free_skcipher(tfm);
-       return ERR_PTR(err);
-}
-
-static int derive_essiv_salt(const u8 *key, int keysize, u8 *salt)
-{
-       struct crypto_shash *tfm = READ_ONCE(essiv_hash_tfm);
-
-       /* init hash transform on demand */
-       if (unlikely(!tfm)) {
-               struct crypto_shash *prev_tfm;
-
-               tfm = crypto_alloc_shash("sha256", 0, 0);
-               if (IS_ERR(tfm)) {
-                       if (PTR_ERR(tfm) == -ENOENT) {
-                               fscrypt_warn(NULL,
-                                            "Missing crypto API support for SHA-256");
-                               return -ENOPKG;
-                       }
-                       fscrypt_err(NULL,
-                                   "Error allocating SHA-256 transform: %ld",
-                                   PTR_ERR(tfm));
-                       return PTR_ERR(tfm);
-               }
-               prev_tfm = cmpxchg(&essiv_hash_tfm, NULL, tfm);
-               if (prev_tfm) {
-                       crypto_free_shash(tfm);
-                       tfm = prev_tfm;
-               }
-       }
-
-       {
-               SHASH_DESC_ON_STACK(desc, tfm);
-               desc->tfm = tfm;
-
-               return crypto_shash_digest(desc, key, keysize, salt);
-       }
-}
-
-static int init_essiv_generator(struct fscrypt_info *ci, const u8 *raw_key,
-                               int keysize)
-{
-       int err;
-       struct crypto_cipher *essiv_tfm;
-       u8 salt[SHA256_DIGEST_SIZE];
-
-       if (WARN_ON(ci->ci_mode->ivsize != AES_BLOCK_SIZE))
-               return -EINVAL;
-
-       essiv_tfm = crypto_alloc_cipher("aes", 0, 0);
-       if (IS_ERR(essiv_tfm))
-               return PTR_ERR(essiv_tfm);
-
-       ci->ci_essiv_tfm = essiv_tfm;
-
-       err = derive_essiv_salt(raw_key, keysize, salt);
-       if (err)
-               goto out;
-
-       /*
-        * Using SHA256 to derive the salt/key will result in AES-256 being
-        * used for IV generation. File contents encryption will still use the
-        * configured keysize (AES-128) nevertheless.
-        */
-       err = crypto_cipher_setkey(essiv_tfm, salt, sizeof(salt));
-       if (err)
-               goto out;
-
-out:
-       memzero_explicit(salt, sizeof(salt));
-       return err;
-}
-
-/* Given the per-file key, set up the file's crypto transform object(s) */
-int fscrypt_set_derived_key(struct fscrypt_info *ci, const u8 *derived_key)
-{
-       struct fscrypt_mode *mode = ci->ci_mode;
-       struct crypto_skcipher *ctfm;
-       int err;
-
-       ctfm = fscrypt_allocate_skcipher(mode, derived_key, ci->ci_inode);
-       if (IS_ERR(ctfm))
-               return PTR_ERR(ctfm);
-
-       ci->ci_ctfm = ctfm;
-
-       if (mode->needs_essiv) {
-               err = init_essiv_generator(ci, derived_key, mode->keysize);
-               if (err) {
-                       fscrypt_warn(ci->ci_inode,
-                                    "Error initializing ESSIV generator: %d",
-                                    err);
-                       return err;
-               }
-       }
-       return 0;
-}
-
-/*
- * Find the master key, then set up the inode's actual encryption key.
- */
-static int setup_file_encryption_key(struct fscrypt_info *ci)
-{
-       return fscrypt_setup_v1_file_key_via_subscribed_keyrings(ci);
-}
-
-static void put_crypt_info(struct fscrypt_info *ci)
-{
-       if (!ci)
-               return;
-
-       if (ci->ci_direct_key) {
-               fscrypt_put_direct_key(ci->ci_direct_key);
-       } else {
-               crypto_free_skcipher(ci->ci_ctfm);
-               crypto_free_cipher(ci->ci_essiv_tfm);
-       }
-       kmem_cache_free(fscrypt_info_cachep, ci);
-}
-
-int fscrypt_get_encryption_info(struct inode *inode)
-{
-       struct fscrypt_info *crypt_info;
-       struct fscrypt_context ctx;
-       struct fscrypt_mode *mode;
-       int res;
-
-       if (fscrypt_has_encryption_key(inode))
-               return 0;
-
-       res = fscrypt_initialize(inode->i_sb->s_cop->flags);
-       if (res)
-               return res;
-
-       res = inode->i_sb->s_cop->get_context(inode, &ctx, sizeof(ctx));
-       if (res < 0) {
-               if (!fscrypt_dummy_context_enabled(inode) ||
-                   IS_ENCRYPTED(inode)) {
-                       fscrypt_warn(inode,
-                                    "Error %d getting encryption context",
-                                    res);
-                       return res;
-               }
-               /* Fake up a context for an unencrypted directory */
-               memset(&ctx, 0, sizeof(ctx));
-               ctx.format = FS_ENCRYPTION_CONTEXT_FORMAT_V1;
-               ctx.contents_encryption_mode = FSCRYPT_MODE_AES_256_XTS;
-               ctx.filenames_encryption_mode = FSCRYPT_MODE_AES_256_CTS;
-               memset(ctx.master_key_descriptor, 0x42,
-                      FSCRYPT_KEY_DESCRIPTOR_SIZE);
-       } else if (res != sizeof(ctx)) {
-               fscrypt_warn(inode,
-                            "Unknown encryption context size (%d bytes)", res);
-               return -EINVAL;
-       }
-
-       if (ctx.format != FS_ENCRYPTION_CONTEXT_FORMAT_V1) {
-               fscrypt_warn(inode, "Unknown encryption context version (%d)",
-                            ctx.format);
-               return -EINVAL;
-       }
-
-       if (ctx.flags & ~FSCRYPT_POLICY_FLAGS_VALID) {
-               fscrypt_warn(inode, "Unknown encryption context flags (0x%02x)",
-                            ctx.flags);
-               return -EINVAL;
-       }
-
-       crypt_info = kmem_cache_zalloc(fscrypt_info_cachep, GFP_NOFS);
-       if (!crypt_info)
-               return -ENOMEM;
-
-       crypt_info->ci_inode = inode;
-
-       crypt_info->ci_flags = ctx.flags;
-       crypt_info->ci_data_mode = ctx.contents_encryption_mode;
-       crypt_info->ci_filename_mode = ctx.filenames_encryption_mode;
-       memcpy(crypt_info->ci_master_key_descriptor, ctx.master_key_descriptor,
-              FSCRYPT_KEY_DESCRIPTOR_SIZE);
-       memcpy(crypt_info->ci_nonce, ctx.nonce, FS_KEY_DERIVATION_NONCE_SIZE);
-
-       mode = select_encryption_mode(crypt_info, inode);
-       if (IS_ERR(mode)) {
-               res = PTR_ERR(mode);
-               goto out;
-       }
-       WARN_ON(mode->ivsize > FSCRYPT_MAX_IV_SIZE);
-       crypt_info->ci_mode = mode;
-
-       res = setup_file_encryption_key(crypt_info);
-       if (res)
-               goto out;
-
-       if (cmpxchg_release(&inode->i_crypt_info, NULL, crypt_info) == NULL)
-               crypt_info = NULL;
-out:
-       if (res == -ENOKEY)
-               res = 0;
-       put_crypt_info(crypt_info);
-       return res;
-}
-EXPORT_SYMBOL(fscrypt_get_encryption_info);
-
-/**
- * fscrypt_put_encryption_info - free most of an inode's fscrypt data
- *
- * Free the inode's fscrypt_info.  Filesystems must call this when the inode is
- * being evicted.  An RCU grace period need not have elapsed yet.
- */
-void fscrypt_put_encryption_info(struct inode *inode)
-{
-       put_crypt_info(inode->i_crypt_info);
-       inode->i_crypt_info = NULL;
-}
-EXPORT_SYMBOL(fscrypt_put_encryption_info);
-
-/**
- * fscrypt_free_inode - free an inode's fscrypt data requiring RCU delay
- *
- * Free the inode's cached decrypted symlink target, if any.  Filesystems must
- * call this after an RCU grace period, just before they free the inode.
- */
-void fscrypt_free_inode(struct inode *inode)
-{
-       if (IS_ENCRYPTED(inode) && S_ISLNK(inode->i_mode)) {
-               kfree(inode->i_link);
-               inode->i_link = NULL;
-       }
-}
-EXPORT_SYMBOL(fscrypt_free_inode);
diff --git a/fs/crypto/keysetup.c b/fs/crypto/keysetup.c
new file mode 100644 (file)
index 0000000..f4a4744
--- /dev/null
@@ -0,0 +1,345 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Key setup facility for FS encryption support.
+ *
+ * Copyright (C) 2015, Google, Inc.
+ *
+ * Originally written by Michael Halcrow, Ildar Muslukhov, and Uday Savagaonkar.
+ * Heavily modified since then.
+ */
+
+#include <crypto/aes.h>
+#include <crypto/sha.h>
+#include <crypto/skcipher.h>
+#include <linux/key.h>
+
+#include "fscrypt_private.h"
+
+static struct crypto_shash *essiv_hash_tfm;
+
+static struct fscrypt_mode available_modes[] = {
+       [FSCRYPT_MODE_AES_256_XTS] = {
+               .friendly_name = "AES-256-XTS",
+               .cipher_str = "xts(aes)",
+               .keysize = 64,
+               .ivsize = 16,
+       },
+       [FSCRYPT_MODE_AES_256_CTS] = {
+               .friendly_name = "AES-256-CTS-CBC",
+               .cipher_str = "cts(cbc(aes))",
+               .keysize = 32,
+               .ivsize = 16,
+       },
+       [FSCRYPT_MODE_AES_128_CBC] = {
+               .friendly_name = "AES-128-CBC",
+               .cipher_str = "cbc(aes)",
+               .keysize = 16,
+               .ivsize = 16,
+               .needs_essiv = true,
+       },
+       [FSCRYPT_MODE_AES_128_CTS] = {
+               .friendly_name = "AES-128-CTS-CBC",
+               .cipher_str = "cts(cbc(aes))",
+               .keysize = 16,
+               .ivsize = 16,
+       },
+       [FSCRYPT_MODE_ADIANTUM] = {
+               .friendly_name = "Adiantum",
+               .cipher_str = "adiantum(xchacha12,aes)",
+               .keysize = 32,
+               .ivsize = 32,
+       },
+};
+
+static struct fscrypt_mode *
+select_encryption_mode(const struct fscrypt_info *ci, const struct inode *inode)
+{
+       if (!fscrypt_valid_enc_modes(ci->ci_data_mode, ci->ci_filename_mode)) {
+               fscrypt_warn(inode,
+                            "Unsupported encryption modes (contents mode %d, filenames mode %d)",
+                            ci->ci_data_mode, ci->ci_filename_mode);
+               return ERR_PTR(-EINVAL);
+       }
+
+       if (S_ISREG(inode->i_mode))
+               return &available_modes[ci->ci_data_mode];
+
+       if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))
+               return &available_modes[ci->ci_filename_mode];
+
+       WARN_ONCE(1, "fscrypt: filesystem tried to load encryption info for inode %lu, which is not encryptable (file type %d)\n",
+                 inode->i_ino, (inode->i_mode & S_IFMT));
+       return ERR_PTR(-EINVAL);
+}
+
+/* Create a symmetric cipher object for the given encryption mode and key */
+struct crypto_skcipher *fscrypt_allocate_skcipher(struct fscrypt_mode *mode,
+                                                 const u8 *raw_key,
+                                                 const struct inode *inode)
+{
+       struct crypto_skcipher *tfm;
+       int err;
+
+       tfm = crypto_alloc_skcipher(mode->cipher_str, 0, 0);
+       if (IS_ERR(tfm)) {
+               if (PTR_ERR(tfm) == -ENOENT) {
+                       fscrypt_warn(inode,
+                                    "Missing crypto API support for %s (API name: \"%s\")",
+                                    mode->friendly_name, mode->cipher_str);
+                       return ERR_PTR(-ENOPKG);
+               }
+               fscrypt_err(inode, "Error allocating '%s' transform: %ld",
+                           mode->cipher_str, PTR_ERR(tfm));
+               return tfm;
+       }
+       if (unlikely(!mode->logged_impl_name)) {
+               /*
+                * fscrypt performance can vary greatly depending on which
+                * crypto algorithm implementation is used.  Help people debug
+                * performance problems by logging the ->cra_driver_name the
+                * first time a mode is used.  Note that multiple threads can
+                * race here, but it doesn't really matter.
+                */
+               mode->logged_impl_name = true;
+               pr_info("fscrypt: %s using implementation \"%s\"\n",
+                       mode->friendly_name,
+                       crypto_skcipher_alg(tfm)->base.cra_driver_name);
+       }
+       crypto_skcipher_set_flags(tfm, CRYPTO_TFM_REQ_FORBID_WEAK_KEYS);
+       err = crypto_skcipher_setkey(tfm, raw_key, mode->keysize);
+       if (err)
+               goto err_free_tfm;
+
+       return tfm;
+
+err_free_tfm:
+       crypto_free_skcipher(tfm);
+       return ERR_PTR(err);
+}
+
+static int derive_essiv_salt(const u8 *key, int keysize, u8 *salt)
+{
+       struct crypto_shash *tfm = READ_ONCE(essiv_hash_tfm);
+
+       /* init hash transform on demand */
+       if (unlikely(!tfm)) {
+               struct crypto_shash *prev_tfm;
+
+               tfm = crypto_alloc_shash("sha256", 0, 0);
+               if (IS_ERR(tfm)) {
+                       if (PTR_ERR(tfm) == -ENOENT) {
+                               fscrypt_warn(NULL,
+                                            "Missing crypto API support for SHA-256");
+                               return -ENOPKG;
+                       }
+                       fscrypt_err(NULL,
+                                   "Error allocating SHA-256 transform: %ld",
+                                   PTR_ERR(tfm));
+                       return PTR_ERR(tfm);
+               }
+               prev_tfm = cmpxchg(&essiv_hash_tfm, NULL, tfm);
+               if (prev_tfm) {
+                       crypto_free_shash(tfm);
+                       tfm = prev_tfm;
+               }
+       }
+
+       {
+               SHASH_DESC_ON_STACK(desc, tfm);
+               desc->tfm = tfm;
+
+               return crypto_shash_digest(desc, key, keysize, salt);
+       }
+}
+
+static int init_essiv_generator(struct fscrypt_info *ci, const u8 *raw_key,
+                               int keysize)
+{
+       int err;
+       struct crypto_cipher *essiv_tfm;
+       u8 salt[SHA256_DIGEST_SIZE];
+
+       if (WARN_ON(ci->ci_mode->ivsize != AES_BLOCK_SIZE))
+               return -EINVAL;
+
+       essiv_tfm = crypto_alloc_cipher("aes", 0, 0);
+       if (IS_ERR(essiv_tfm))
+               return PTR_ERR(essiv_tfm);
+
+       ci->ci_essiv_tfm = essiv_tfm;
+
+       err = derive_essiv_salt(raw_key, keysize, salt);
+       if (err)
+               goto out;
+
+       /*
+        * Using SHA256 to derive the salt/key will result in AES-256 being
+        * used for IV generation. File contents encryption will still use the
+        * configured keysize (AES-128) nevertheless.
+        */
+       err = crypto_cipher_setkey(essiv_tfm, salt, sizeof(salt));
+       if (err)
+               goto out;
+
+out:
+       memzero_explicit(salt, sizeof(salt));
+       return err;
+}
+
+/* Given the per-file key, set up the file's crypto transform object(s) */
+int fscrypt_set_derived_key(struct fscrypt_info *ci, const u8 *derived_key)
+{
+       struct fscrypt_mode *mode = ci->ci_mode;
+       struct crypto_skcipher *ctfm;
+       int err;
+
+       ctfm = fscrypt_allocate_skcipher(mode, derived_key, ci->ci_inode);
+       if (IS_ERR(ctfm))
+               return PTR_ERR(ctfm);
+
+       ci->ci_ctfm = ctfm;
+
+       if (mode->needs_essiv) {
+               err = init_essiv_generator(ci, derived_key, mode->keysize);
+               if (err) {
+                       fscrypt_warn(ci->ci_inode,
+                                    "Error initializing ESSIV generator: %d",
+                                    err);
+                       return err;
+               }
+       }
+       return 0;
+}
+
+/*
+ * Find the master key, then set up the inode's actual encryption key.
+ */
+static int setup_file_encryption_key(struct fscrypt_info *ci)
+{
+       return fscrypt_setup_v1_file_key_via_subscribed_keyrings(ci);
+}
+
+static void put_crypt_info(struct fscrypt_info *ci)
+{
+       if (!ci)
+               return;
+
+       if (ci->ci_direct_key) {
+               fscrypt_put_direct_key(ci->ci_direct_key);
+       } else {
+               crypto_free_skcipher(ci->ci_ctfm);
+               crypto_free_cipher(ci->ci_essiv_tfm);
+       }
+       kmem_cache_free(fscrypt_info_cachep, ci);
+}
+
+int fscrypt_get_encryption_info(struct inode *inode)
+{
+       struct fscrypt_info *crypt_info;
+       struct fscrypt_context ctx;
+       struct fscrypt_mode *mode;
+       int res;
+
+       if (fscrypt_has_encryption_key(inode))
+               return 0;
+
+       res = fscrypt_initialize(inode->i_sb->s_cop->flags);
+       if (res)
+               return res;
+
+       res = inode->i_sb->s_cop->get_context(inode, &ctx, sizeof(ctx));
+       if (res < 0) {
+               if (!fscrypt_dummy_context_enabled(inode) ||
+                   IS_ENCRYPTED(inode)) {
+                       fscrypt_warn(inode,
+                                    "Error %d getting encryption context",
+                                    res);
+                       return res;
+               }
+               /* Fake up a context for an unencrypted directory */
+               memset(&ctx, 0, sizeof(ctx));
+               ctx.format = FS_ENCRYPTION_CONTEXT_FORMAT_V1;
+               ctx.contents_encryption_mode = FSCRYPT_MODE_AES_256_XTS;
+               ctx.filenames_encryption_mode = FSCRYPT_MODE_AES_256_CTS;
+               memset(ctx.master_key_descriptor, 0x42,
+                      FSCRYPT_KEY_DESCRIPTOR_SIZE);
+       } else if (res != sizeof(ctx)) {
+               fscrypt_warn(inode,
+                            "Unknown encryption context size (%d bytes)", res);
+               return -EINVAL;
+       }
+
+       if (ctx.format != FS_ENCRYPTION_CONTEXT_FORMAT_V1) {
+               fscrypt_warn(inode, "Unknown encryption context version (%d)",
+                            ctx.format);
+               return -EINVAL;
+       }
+
+       if (ctx.flags & ~FSCRYPT_POLICY_FLAGS_VALID) {
+               fscrypt_warn(inode, "Unknown encryption context flags (0x%02x)",
+                            ctx.flags);
+               return -EINVAL;
+       }
+
+       crypt_info = kmem_cache_zalloc(fscrypt_info_cachep, GFP_NOFS);
+       if (!crypt_info)
+               return -ENOMEM;
+
+       crypt_info->ci_inode = inode;
+
+       crypt_info->ci_flags = ctx.flags;
+       crypt_info->ci_data_mode = ctx.contents_encryption_mode;
+       crypt_info->ci_filename_mode = ctx.filenames_encryption_mode;
+       memcpy(crypt_info->ci_master_key_descriptor, ctx.master_key_descriptor,
+              FSCRYPT_KEY_DESCRIPTOR_SIZE);
+       memcpy(crypt_info->ci_nonce, ctx.nonce, FS_KEY_DERIVATION_NONCE_SIZE);
+
+       mode = select_encryption_mode(crypt_info, inode);
+       if (IS_ERR(mode)) {
+               res = PTR_ERR(mode);
+               goto out;
+       }
+       WARN_ON(mode->ivsize > FSCRYPT_MAX_IV_SIZE);
+       crypt_info->ci_mode = mode;
+
+       res = setup_file_encryption_key(crypt_info);
+       if (res)
+               goto out;
+
+       if (cmpxchg_release(&inode->i_crypt_info, NULL, crypt_info) == NULL)
+               crypt_info = NULL;
+out:
+       if (res == -ENOKEY)
+               res = 0;
+       put_crypt_info(crypt_info);
+       return res;
+}
+EXPORT_SYMBOL(fscrypt_get_encryption_info);
+
+/**
+ * fscrypt_put_encryption_info - free most of an inode's fscrypt data
+ *
+ * Free the inode's fscrypt_info.  Filesystems must call this when the inode is
+ * being evicted.  An RCU grace period need not have elapsed yet.
+ */
+void fscrypt_put_encryption_info(struct inode *inode)
+{
+       put_crypt_info(inode->i_crypt_info);
+       inode->i_crypt_info = NULL;
+}
+EXPORT_SYMBOL(fscrypt_put_encryption_info);
+
+/**
+ * fscrypt_free_inode - free an inode's fscrypt data requiring RCU delay
+ *
+ * Free the inode's cached decrypted symlink target, if any.  Filesystems must
+ * call this after an RCU grace period, just before they free the inode.
+ */
+void fscrypt_free_inode(struct inode *inode)
+{
+       if (IS_ENCRYPTED(inode) && S_ISLNK(inode->i_mode)) {
+               kfree(inode->i_link);
+               inode->i_link = NULL;
+       }
+}
+EXPORT_SYMBOL(fscrypt_free_inode);
index 81c0c754f8b21b7e35eead6703e88cffa9d79c71..583802cb2e35d0fffc5f73782b18962b87129362 100644 (file)
@@ -138,7 +138,7 @@ extern int fscrypt_ioctl_get_policy(struct file *, void __user *);
 extern int fscrypt_has_permitted_context(struct inode *, struct inode *);
 extern int fscrypt_inherit_context(struct inode *, struct inode *,
                                        void *, bool);
-/* keyinfo.c */
+/* keysetup.c */
 extern int fscrypt_get_encryption_info(struct inode *);
 extern void fscrypt_put_encryption_info(struct inode *);
 extern void fscrypt_free_inode(struct inode *);
@@ -367,7 +367,7 @@ static inline int fscrypt_inherit_context(struct inode *parent,
        return -EOPNOTSUPP;
 }
 
-/* keyinfo.c */
+/* keysetup.c */
 static inline int fscrypt_get_encryption_info(struct inode *inode)
 {
        return -EOPNOTSUPP;