summaryrefslogtreecommitdiff
path: root/fs/ext4/crypto_key.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/ext4/crypto_key.c')
-rw-r--r--fs/ext4/crypto_key.c74
1 files changed, 57 insertions, 17 deletions
diff --git a/fs/ext4/crypto_key.c b/fs/ext4/crypto_key.c
index ec6635dc50f9..0075e43ffea6 100644
--- a/fs/ext4/crypto_key.c
+++ b/fs/ext4/crypto_key.c
@@ -84,14 +84,26 @@ out:
return res;
}
-/**
- * ext4_generate_encryption_key() - generates an encryption key
- * @inode: The inode to generate the encryption key for.
- */
-int ext4_generate_encryption_key(struct inode *inode)
+void ext4_free_encryption_info(struct inode *inode)
+{
+ struct ext4_inode_info *ei = EXT4_I(inode);
+ struct ext4_crypt_info *ci = ei->i_crypt_info;
+
+ if (!ci)
+ return;
+
+ if (ci->ci_keyring_key)
+ key_put(ci->ci_keyring_key);
+ crypto_free_ablkcipher(ci->ci_ctfm);
+ memzero_explicit(&ci->ci_raw, sizeof(ci->ci_raw));
+ kfree(ci);
+ ei->i_crypt_info = NULL;
+}
+
+int _ext4_get_encryption_info(struct inode *inode)
{
struct ext4_inode_info *ei = EXT4_I(inode);
- struct ext4_crypt_info *crypt_info = &ei->i_crypt_info;
+ struct ext4_crypt_info *crypt_info;
char full_key_descriptor[EXT4_KEY_DESC_PREFIX_SIZE +
(EXT4_KEY_DESCRIPTOR_SIZE * 2) + 1];
struct key *keyring_key = NULL;
@@ -99,18 +111,40 @@ int ext4_generate_encryption_key(struct inode *inode)
struct ext4_encryption_context ctx;
struct user_key_payload *ukp;
struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
- int res = ext4_xattr_get(inode, EXT4_XATTR_INDEX_ENCRYPTION,
- EXT4_XATTR_NAME_ENCRYPTION_CONTEXT,
- &ctx, sizeof(ctx));
+ int res;
- if (res != sizeof(ctx)) {
- if (res > 0)
- res = -EINVAL;
- goto out;
+ if (ei->i_crypt_info) {
+ if (!ei->i_crypt_info->ci_keyring_key ||
+ key_validate(ei->i_crypt_info->ci_keyring_key) == 0)
+ return 0;
+ ext4_free_encryption_info(inode);
}
+
+ res = ext4_xattr_get(inode, EXT4_XATTR_INDEX_ENCRYPTION,
+ EXT4_XATTR_NAME_ENCRYPTION_CONTEXT,
+ &ctx, sizeof(ctx));
+ if (res < 0) {
+ if (!DUMMY_ENCRYPTION_ENABLED(sbi))
+ return res;
+ ctx.contents_encryption_mode = EXT4_ENCRYPTION_MODE_AES_256_XTS;
+ ctx.filenames_encryption_mode =
+ EXT4_ENCRYPTION_MODE_AES_256_CTS;
+ ctx.flags = 0;
+ } else if (res != sizeof(ctx))
+ return -EINVAL;
res = 0;
+ crypt_info = kmalloc(sizeof(struct ext4_crypt_info), GFP_KERNEL);
+ if (!crypt_info)
+ return -ENOMEM;
+
ei->i_crypt_policy_flags = ctx.flags;
+ 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;
+ memcpy(crypt_info->ci_master_key, ctx.master_key_descriptor,
+ sizeof(crypt_info->ci_master_key));
if (S_ISREG(inode->i_mode))
crypt_info->ci_mode = ctx.contents_encryption_mode;
else if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))
@@ -151,17 +185,23 @@ int ext4_generate_encryption_key(struct inode *inode)
res = ext4_derive_key_aes(ctx.nonce, master_key->raw,
crypt_info->ci_raw);
out:
+ if (res < 0) {
+ if (res == -ENOKEY)
+ res = 0;
+ kfree(crypt_info);
+ } else {
+ ei->i_crypt_info = crypt_info;
+ crypt_info->ci_keyring_key = keyring_key;
+ keyring_key = NULL;
+ }
if (keyring_key)
key_put(keyring_key);
- if (res < 0)
- crypt_info->ci_mode = EXT4_ENCRYPTION_MODE_INVALID;
return res;
}
int ext4_has_encryption_key(struct inode *inode)
{
struct ext4_inode_info *ei = EXT4_I(inode);
- struct ext4_crypt_info *crypt_info = &ei->i_crypt_info;
- return (crypt_info->ci_mode != EXT4_ENCRYPTION_MODE_INVALID);
+ return (ei->i_crypt_info != NULL);
}