ext4 crypto: enable encryption feature flag
Also add the test dummy encryption mode flag so we can more easily test the encryption patches using xfstests. Signed-off-by: Michael Halcrow <mhalcrow@google.com> Signed-off-by: Theodore Ts'o <tytso@mit.edu>
This commit is contained in:
parent
f348c25232
commit
6ddb244784
@ -98,6 +98,7 @@ int ext4_generate_encryption_key(struct inode *inode)
|
||||
struct ext4_encryption_key *master_key;
|
||||
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));
|
||||
@ -109,6 +110,20 @@ int ext4_generate_encryption_key(struct inode *inode)
|
||||
}
|
||||
res = 0;
|
||||
|
||||
if (S_ISREG(inode->i_mode))
|
||||
crypt_key->mode = ctx.contents_encryption_mode;
|
||||
else if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))
|
||||
crypt_key->mode = ctx.filenames_encryption_mode;
|
||||
else {
|
||||
printk(KERN_ERR "ext4 crypto: Unsupported inode type.\n");
|
||||
BUG();
|
||||
}
|
||||
crypt_key->size = ext4_encryption_key_size(crypt_key->mode);
|
||||
BUG_ON(!crypt_key->size);
|
||||
if (DUMMY_ENCRYPTION_ENABLED(sbi)) {
|
||||
memset(crypt_key->raw, 0x42, EXT4_AES_256_XTS_KEY_SIZE);
|
||||
goto out;
|
||||
}
|
||||
memcpy(full_key_descriptor, EXT4_KEY_DESC_PREFIX,
|
||||
EXT4_KEY_DESC_PREFIX_SIZE);
|
||||
sprintf(full_key_descriptor + EXT4_KEY_DESC_PREFIX_SIZE,
|
||||
@ -129,21 +144,9 @@ int ext4_generate_encryption_key(struct inode *inode)
|
||||
goto out;
|
||||
}
|
||||
master_key = (struct ext4_encryption_key *)ukp->data;
|
||||
|
||||
if (S_ISREG(inode->i_mode))
|
||||
crypt_key->mode = ctx.contents_encryption_mode;
|
||||
else if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))
|
||||
crypt_key->mode = ctx.filenames_encryption_mode;
|
||||
else {
|
||||
printk(KERN_ERR "ext4 crypto: Unsupported inode type.\n");
|
||||
BUG();
|
||||
}
|
||||
crypt_key->size = ext4_encryption_key_size(crypt_key->mode);
|
||||
BUG_ON(!crypt_key->size);
|
||||
BUILD_BUG_ON(EXT4_AES_128_ECB_KEY_SIZE !=
|
||||
EXT4_KEY_DERIVATION_NONCE_SIZE);
|
||||
BUG_ON(master_key->size != EXT4_AES_256_XTS_KEY_SIZE);
|
||||
BUG_ON(crypt_key->size < EXT4_AES_256_CBC_KEY_SIZE);
|
||||
res = ext4_derive_key_aes(ctx.nonce, master_key->raw, crypt_key->raw);
|
||||
out:
|
||||
if (keyring_key)
|
||||
|
@ -169,13 +169,25 @@ int ext4_inherit_context(struct inode *parent, struct inode *child)
|
||||
EXT4_XATTR_NAME_ENCRYPTION_CONTEXT,
|
||||
&ctx, sizeof(ctx));
|
||||
|
||||
if (res != sizeof(ctx))
|
||||
return -ENOENT;
|
||||
|
||||
if (res != sizeof(ctx)) {
|
||||
if (DUMMY_ENCRYPTION_ENABLED(EXT4_SB(parent->i_sb))) {
|
||||
ctx.format = EXT4_ENCRYPTION_CONTEXT_FORMAT_V1;
|
||||
ctx.contents_encryption_mode =
|
||||
EXT4_ENCRYPTION_MODE_AES_256_XTS;
|
||||
ctx.filenames_encryption_mode =
|
||||
EXT4_ENCRYPTION_MODE_AES_256_CTS;
|
||||
memset(ctx.master_key_descriptor, 0x42,
|
||||
EXT4_KEY_DESCRIPTOR_SIZE);
|
||||
res = 0;
|
||||
} else {
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
get_random_bytes(ctx.nonce, EXT4_KEY_DERIVATION_NONCE_SIZE);
|
||||
res = ext4_xattr_set(child, EXT4_XATTR_INDEX_ENCRYPTION,
|
||||
EXT4_XATTR_NAME_ENCRYPTION_CONTEXT, &ctx,
|
||||
sizeof(ctx), 0);
|
||||
out:
|
||||
if (!res)
|
||||
ext4_set_inode_flag(child, EXT4_INODE_ENCRYPT);
|
||||
return res;
|
||||
|
@ -1200,8 +1200,16 @@ struct ext4_super_block {
|
||||
/*
|
||||
* run-time mount flags
|
||||
*/
|
||||
#define EXT4_MF_MNTDIR_SAMPLED 0x0001
|
||||
#define EXT4_MF_FS_ABORTED 0x0002 /* Fatal error detected */
|
||||
#define EXT4_MF_MNTDIR_SAMPLED 0x0001
|
||||
#define EXT4_MF_FS_ABORTED 0x0002 /* Fatal error detected */
|
||||
#define EXT4_MF_TEST_DUMMY_ENCRYPTION 0x0004
|
||||
|
||||
#ifdef CONFIG_EXT4_FS_ENCRYPTION
|
||||
#define DUMMY_ENCRYPTION_ENABLED(sbi) (unlikely((sbi)->s_mount_flags & \
|
||||
EXT4_MF_TEST_DUMMY_ENCRYPTION))
|
||||
#else
|
||||
#define DUMMY_ENCRYPTION_ENABLED(sbi) (0)
|
||||
#endif
|
||||
|
||||
/* Number of quota types we support */
|
||||
#define EXT4_MAXQUOTAS 2
|
||||
@ -1613,8 +1621,9 @@ static inline int ext4_encrypted_inode(struct inode *inode)
|
||||
EXT4_FEATURE_INCOMPAT_EXTENTS| \
|
||||
EXT4_FEATURE_INCOMPAT_64BIT| \
|
||||
EXT4_FEATURE_INCOMPAT_FLEX_BG| \
|
||||
EXT4_FEATURE_INCOMPAT_MMP | \
|
||||
EXT4_FEATURE_INCOMPAT_INLINE_DATA)
|
||||
EXT4_FEATURE_INCOMPAT_MMP | \
|
||||
EXT4_FEATURE_INCOMPAT_INLINE_DATA | \
|
||||
EXT4_FEATURE_INCOMPAT_ENCRYPT)
|
||||
#define EXT4_FEATURE_RO_COMPAT_SUPP (EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER| \
|
||||
EXT4_FEATURE_RO_COMPAT_LARGE_FILE| \
|
||||
EXT4_FEATURE_RO_COMPAT_GDT_CSUM| \
|
||||
|
@ -998,7 +998,8 @@ got:
|
||||
|
||||
/* If the directory encrypted, then we should encrypt the inode. */
|
||||
if ((S_ISDIR(mode) || S_ISREG(mode) || S_ISLNK(mode)) &&
|
||||
ext4_encrypted_inode(dir))
|
||||
(ext4_encrypted_inode(dir) ||
|
||||
DUMMY_ENCRYPTION_ENABLED(sbi)))
|
||||
ext4_set_inode_flag(inode, EXT4_INODE_ENCRYPT);
|
||||
|
||||
ext4_set_inode_flags(inode);
|
||||
|
@ -2582,7 +2582,8 @@ retry:
|
||||
ext4_set_aops(inode);
|
||||
err = 0;
|
||||
#ifdef CONFIG_EXT4_FS_ENCRYPTION
|
||||
if (!err && ext4_encrypted_inode(dir)) {
|
||||
if (!err && (ext4_encrypted_inode(dir) ||
|
||||
DUMMY_ENCRYPTION_ENABLED(EXT4_SB(dir->i_sb)))) {
|
||||
err = ext4_inherit_context(dir, inode);
|
||||
if (err) {
|
||||
clear_nlink(inode);
|
||||
@ -2777,7 +2778,8 @@ retry:
|
||||
if (err)
|
||||
goto out_clear_inode;
|
||||
#ifdef CONFIG_EXT4_FS_ENCRYPTION
|
||||
if (ext4_encrypted_inode(dir)) {
|
||||
if (ext4_encrypted_inode(dir) ||
|
||||
DUMMY_ENCRYPTION_ENABLED(EXT4_SB(dir->i_sb))) {
|
||||
err = ext4_inherit_context(dir, inode);
|
||||
if (err)
|
||||
goto out_clear_inode;
|
||||
@ -3202,7 +3204,8 @@ static int ext4_symlink(struct inode *dir,
|
||||
disk_link.len = len + 1;
|
||||
disk_link.name = (char *) symname;
|
||||
|
||||
encryption_required = ext4_encrypted_inode(dir);
|
||||
encryption_required = (ext4_encrypted_inode(dir) ||
|
||||
DUMMY_ENCRYPTION_ENABLED(EXT4_SB(dir->i_sb)));
|
||||
if (encryption_required)
|
||||
disk_link.len = encrypted_symlink_data_len(len) + 1;
|
||||
if (disk_link.len > dir->i_sb->s_blocksize)
|
||||
|
@ -1106,7 +1106,7 @@ enum {
|
||||
Opt_commit, Opt_min_batch_time, Opt_max_batch_time, Opt_journal_dev,
|
||||
Opt_journal_path, Opt_journal_checksum, Opt_journal_async_commit,
|
||||
Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback,
|
||||
Opt_data_err_abort, Opt_data_err_ignore,
|
||||
Opt_data_err_abort, Opt_data_err_ignore, Opt_test_dummy_encryption,
|
||||
Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota,
|
||||
Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_jqfmt_vfsv1, Opt_quota,
|
||||
Opt_noquota, Opt_barrier, Opt_nobarrier, Opt_err,
|
||||
@ -1197,6 +1197,7 @@ static const match_table_t tokens = {
|
||||
{Opt_init_itable, "init_itable"},
|
||||
{Opt_noinit_itable, "noinit_itable"},
|
||||
{Opt_max_dir_size_kb, "max_dir_size_kb=%u"},
|
||||
{Opt_test_dummy_encryption, "test_dummy_encryption"},
|
||||
{Opt_removed, "check=none"}, /* mount option from ext2/3 */
|
||||
{Opt_removed, "nocheck"}, /* mount option from ext2/3 */
|
||||
{Opt_removed, "reservation"}, /* mount option from ext2/3 */
|
||||
@ -1398,6 +1399,7 @@ static const struct mount_opts {
|
||||
{Opt_jqfmt_vfsv0, QFMT_VFS_V0, MOPT_QFMT},
|
||||
{Opt_jqfmt_vfsv1, QFMT_VFS_V1, MOPT_QFMT},
|
||||
{Opt_max_dir_size_kb, 0, MOPT_GTE0},
|
||||
{Opt_test_dummy_encryption, 0, MOPT_GTE0},
|
||||
{Opt_err, 0, 0}
|
||||
};
|
||||
|
||||
@ -1574,6 +1576,15 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token,
|
||||
}
|
||||
*journal_ioprio =
|
||||
IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, arg);
|
||||
} else if (token == Opt_test_dummy_encryption) {
|
||||
#ifdef CONFIG_EXT4_FS_ENCRYPTION
|
||||
sbi->s_mount_flags |= EXT4_MF_TEST_DUMMY_ENCRYPTION;
|
||||
ext4_msg(sb, KERN_WARNING,
|
||||
"Test dummy encryption mode enabled");
|
||||
#else
|
||||
ext4_msg(sb, KERN_WARNING,
|
||||
"Test dummy encryption mount option ignored");
|
||||
#endif
|
||||
} else if (m->flags & MOPT_DATAJ) {
|
||||
if (is_remount) {
|
||||
if (!sbi->s_journal)
|
||||
@ -2671,11 +2682,13 @@ static struct attribute *ext4_attrs[] = {
|
||||
EXT4_INFO_ATTR(lazy_itable_init);
|
||||
EXT4_INFO_ATTR(batched_discard);
|
||||
EXT4_INFO_ATTR(meta_bg_resize);
|
||||
EXT4_INFO_ATTR(encryption);
|
||||
|
||||
static struct attribute *ext4_feat_attrs[] = {
|
||||
ATTR_LIST(lazy_itable_init),
|
||||
ATTR_LIST(batched_discard),
|
||||
ATTR_LIST(meta_bg_resize),
|
||||
ATTR_LIST(encryption),
|
||||
NULL,
|
||||
};
|
||||
|
||||
@ -3683,6 +3696,13 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
|
||||
}
|
||||
}
|
||||
|
||||
if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_ENCRYPT) &&
|
||||
es->s_encryption_level) {
|
||||
ext4_msg(sb, KERN_ERR, "Unsupported encryption level %d",
|
||||
es->s_encryption_level);
|
||||
goto failed_mount;
|
||||
}
|
||||
|
||||
if (sb->s_blocksize != blocksize) {
|
||||
/* Validate the filesystem blocksize */
|
||||
if (!sb_set_blocksize(sb, blocksize)) {
|
||||
@ -4045,6 +4065,13 @@ no_journal:
|
||||
}
|
||||
}
|
||||
|
||||
if (unlikely(sbi->s_mount_flags & EXT4_MF_TEST_DUMMY_ENCRYPTION) &&
|
||||
!(sb->s_flags & MS_RDONLY) &&
|
||||
!EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_ENCRYPT)) {
|
||||
EXT4_SET_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_ENCRYPT);
|
||||
ext4_commit_super(sb, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the # of file system overhead blocks from the
|
||||
* superblock if present.
|
||||
|
Loading…
Reference in New Issue
Block a user