aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorTheodore Ts'o <tytso@mit.edu>2015-04-16 01:56:00 -0400
committerTheodore Ts'o <tytso@mit.edu>2015-04-16 01:56:00 -0400
commit6ddb2447846a8ece111e316a2863c2355023682d (patch)
treee56b2d3100baf35e7d99d79ff411c28bf8c5f4c2 /fs
parentf348c252320b98e11176074fe04223f22bddaf0d (diff)
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>
Diffstat (limited to 'fs')
-rw-r--r--fs/ext4/crypto_key.c27
-rw-r--r--fs/ext4/crypto_policy.c18
-rw-r--r--fs/ext4/ext4.h17
-rw-r--r--fs/ext4/ialloc.c3
-rw-r--r--fs/ext4/namei.c9
-rw-r--r--fs/ext4/super.c29
6 files changed, 79 insertions, 24 deletions
diff --git a/fs/ext4/crypto_key.c b/fs/ext4/crypto_key.c
index 572bd97f58dd..c8392af8abbb 100644
--- a/fs/ext4/crypto_key.c
+++ b/fs/ext4/crypto_key.c
@@ -98,6 +98,7 @@ int ext4_generate_encryption_key(struct inode *inode)
98 struct ext4_encryption_key *master_key; 98 struct ext4_encryption_key *master_key;
99 struct ext4_encryption_context ctx; 99 struct ext4_encryption_context ctx;
100 struct user_key_payload *ukp; 100 struct user_key_payload *ukp;
101 struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
101 int res = ext4_xattr_get(inode, EXT4_XATTR_INDEX_ENCRYPTION, 102 int res = ext4_xattr_get(inode, EXT4_XATTR_INDEX_ENCRYPTION,
102 EXT4_XATTR_NAME_ENCRYPTION_CONTEXT, 103 EXT4_XATTR_NAME_ENCRYPTION_CONTEXT,
103 &ctx, sizeof(ctx)); 104 &ctx, sizeof(ctx));
@@ -109,6 +110,20 @@ int ext4_generate_encryption_key(struct inode *inode)
109 } 110 }
110 res = 0; 111 res = 0;
111 112
113 if (S_ISREG(inode->i_mode))
114 crypt_key->mode = ctx.contents_encryption_mode;
115 else if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))
116 crypt_key->mode = ctx.filenames_encryption_mode;
117 else {
118 printk(KERN_ERR "ext4 crypto: Unsupported inode type.\n");
119 BUG();
120 }
121 crypt_key->size = ext4_encryption_key_size(crypt_key->mode);
122 BUG_ON(!crypt_key->size);
123 if (DUMMY_ENCRYPTION_ENABLED(sbi)) {
124 memset(crypt_key->raw, 0x42, EXT4_AES_256_XTS_KEY_SIZE);
125 goto out;
126 }
112 memcpy(full_key_descriptor, EXT4_KEY_DESC_PREFIX, 127 memcpy(full_key_descriptor, EXT4_KEY_DESC_PREFIX,
113 EXT4_KEY_DESC_PREFIX_SIZE); 128 EXT4_KEY_DESC_PREFIX_SIZE);
114 sprintf(full_key_descriptor + EXT4_KEY_DESC_PREFIX_SIZE, 129 sprintf(full_key_descriptor + EXT4_KEY_DESC_PREFIX_SIZE,
@@ -129,21 +144,9 @@ int ext4_generate_encryption_key(struct inode *inode)
129 goto out; 144 goto out;
130 } 145 }
131 master_key = (struct ext4_encryption_key *)ukp->data; 146 master_key = (struct ext4_encryption_key *)ukp->data;
132
133 if (S_ISREG(inode->i_mode))
134 crypt_key->mode = ctx.contents_encryption_mode;
135 else if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))
136 crypt_key->mode = ctx.filenames_encryption_mode;
137 else {
138 printk(KERN_ERR "ext4 crypto: Unsupported inode type.\n");
139 BUG();
140 }
141 crypt_key->size = ext4_encryption_key_size(crypt_key->mode);
142 BUG_ON(!crypt_key->size);
143 BUILD_BUG_ON(EXT4_AES_128_ECB_KEY_SIZE != 147 BUILD_BUG_ON(EXT4_AES_128_ECB_KEY_SIZE !=
144 EXT4_KEY_DERIVATION_NONCE_SIZE); 148 EXT4_KEY_DERIVATION_NONCE_SIZE);
145 BUG_ON(master_key->size != EXT4_AES_256_XTS_KEY_SIZE); 149 BUG_ON(master_key->size != EXT4_AES_256_XTS_KEY_SIZE);
146 BUG_ON(crypt_key->size < EXT4_AES_256_CBC_KEY_SIZE);
147 res = ext4_derive_key_aes(ctx.nonce, master_key->raw, crypt_key->raw); 150 res = ext4_derive_key_aes(ctx.nonce, master_key->raw, crypt_key->raw);
148out: 151out:
149 if (keyring_key) 152 if (keyring_key)
diff --git a/fs/ext4/crypto_policy.c b/fs/ext4/crypto_policy.c
index 749ed6e91e50..30eaf9e9864a 100644
--- a/fs/ext4/crypto_policy.c
+++ b/fs/ext4/crypto_policy.c
@@ -169,13 +169,25 @@ int ext4_inherit_context(struct inode *parent, struct inode *child)
169 EXT4_XATTR_NAME_ENCRYPTION_CONTEXT, 169 EXT4_XATTR_NAME_ENCRYPTION_CONTEXT,
170 &ctx, sizeof(ctx)); 170 &ctx, sizeof(ctx));
171 171
172 if (res != sizeof(ctx)) 172 if (res != sizeof(ctx)) {
173 return -ENOENT; 173 if (DUMMY_ENCRYPTION_ENABLED(EXT4_SB(parent->i_sb))) {
174 174 ctx.format = EXT4_ENCRYPTION_CONTEXT_FORMAT_V1;
175 ctx.contents_encryption_mode =
176 EXT4_ENCRYPTION_MODE_AES_256_XTS;
177 ctx.filenames_encryption_mode =
178 EXT4_ENCRYPTION_MODE_AES_256_CTS;
179 memset(ctx.master_key_descriptor, 0x42,
180 EXT4_KEY_DESCRIPTOR_SIZE);
181 res = 0;
182 } else {
183 goto out;
184 }
185 }
175 get_random_bytes(ctx.nonce, EXT4_KEY_DERIVATION_NONCE_SIZE); 186 get_random_bytes(ctx.nonce, EXT4_KEY_DERIVATION_NONCE_SIZE);
176 res = ext4_xattr_set(child, EXT4_XATTR_INDEX_ENCRYPTION, 187 res = ext4_xattr_set(child, EXT4_XATTR_INDEX_ENCRYPTION,
177 EXT4_XATTR_NAME_ENCRYPTION_CONTEXT, &ctx, 188 EXT4_XATTR_NAME_ENCRYPTION_CONTEXT, &ctx,
178 sizeof(ctx), 0); 189 sizeof(ctx), 0);
190out:
179 if (!res) 191 if (!res)
180 ext4_set_inode_flag(child, EXT4_INODE_ENCRYPT); 192 ext4_set_inode_flag(child, EXT4_INODE_ENCRYPT);
181 return res; 193 return res;
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 86d15706d27a..0179654faf79 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -1200,8 +1200,16 @@ struct ext4_super_block {
1200/* 1200/*
1201 * run-time mount flags 1201 * run-time mount flags
1202 */ 1202 */
1203#define EXT4_MF_MNTDIR_SAMPLED 0x0001 1203#define EXT4_MF_MNTDIR_SAMPLED 0x0001
1204#define EXT4_MF_FS_ABORTED 0x0002 /* Fatal error detected */ 1204#define EXT4_MF_FS_ABORTED 0x0002 /* Fatal error detected */
1205#define EXT4_MF_TEST_DUMMY_ENCRYPTION 0x0004
1206
1207#ifdef CONFIG_EXT4_FS_ENCRYPTION
1208#define DUMMY_ENCRYPTION_ENABLED(sbi) (unlikely((sbi)->s_mount_flags & \
1209 EXT4_MF_TEST_DUMMY_ENCRYPTION))
1210#else
1211#define DUMMY_ENCRYPTION_ENABLED(sbi) (0)
1212#endif
1205 1213
1206/* Number of quota types we support */ 1214/* Number of quota types we support */
1207#define EXT4_MAXQUOTAS 2 1215#define EXT4_MAXQUOTAS 2
@@ -1613,8 +1621,9 @@ static inline int ext4_encrypted_inode(struct inode *inode)
1613 EXT4_FEATURE_INCOMPAT_EXTENTS| \ 1621 EXT4_FEATURE_INCOMPAT_EXTENTS| \
1614 EXT4_FEATURE_INCOMPAT_64BIT| \ 1622 EXT4_FEATURE_INCOMPAT_64BIT| \
1615 EXT4_FEATURE_INCOMPAT_FLEX_BG| \ 1623 EXT4_FEATURE_INCOMPAT_FLEX_BG| \
1616 EXT4_FEATURE_INCOMPAT_MMP | \ 1624 EXT4_FEATURE_INCOMPAT_MMP | \
1617 EXT4_FEATURE_INCOMPAT_INLINE_DATA) 1625 EXT4_FEATURE_INCOMPAT_INLINE_DATA | \
1626 EXT4_FEATURE_INCOMPAT_ENCRYPT)
1618#define EXT4_FEATURE_RO_COMPAT_SUPP (EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER| \ 1627#define EXT4_FEATURE_RO_COMPAT_SUPP (EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER| \
1619 EXT4_FEATURE_RO_COMPAT_LARGE_FILE| \ 1628 EXT4_FEATURE_RO_COMPAT_LARGE_FILE| \
1620 EXT4_FEATURE_RO_COMPAT_GDT_CSUM| \ 1629 EXT4_FEATURE_RO_COMPAT_GDT_CSUM| \
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c
index 850267c89407..2cf18a2d5c72 100644
--- a/fs/ext4/ialloc.c
+++ b/fs/ext4/ialloc.c
@@ -998,7 +998,8 @@ got:
998 998
999 /* If the directory encrypted, then we should encrypt the inode. */ 999 /* If the directory encrypted, then we should encrypt the inode. */
1000 if ((S_ISDIR(mode) || S_ISREG(mode) || S_ISLNK(mode)) && 1000 if ((S_ISDIR(mode) || S_ISREG(mode) || S_ISLNK(mode)) &&
1001 ext4_encrypted_inode(dir)) 1001 (ext4_encrypted_inode(dir) ||
1002 DUMMY_ENCRYPTION_ENABLED(sbi)))
1002 ext4_set_inode_flag(inode, EXT4_INODE_ENCRYPT); 1003 ext4_set_inode_flag(inode, EXT4_INODE_ENCRYPT);
1003 1004
1004 ext4_set_inode_flags(inode); 1005 ext4_set_inode_flags(inode);
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index d201426b8d39..4f87127f781f 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -2582,7 +2582,8 @@ retry:
2582 ext4_set_aops(inode); 2582 ext4_set_aops(inode);
2583 err = 0; 2583 err = 0;
2584#ifdef CONFIG_EXT4_FS_ENCRYPTION 2584#ifdef CONFIG_EXT4_FS_ENCRYPTION
2585 if (!err && ext4_encrypted_inode(dir)) { 2585 if (!err && (ext4_encrypted_inode(dir) ||
2586 DUMMY_ENCRYPTION_ENABLED(EXT4_SB(dir->i_sb)))) {
2586 err = ext4_inherit_context(dir, inode); 2587 err = ext4_inherit_context(dir, inode);
2587 if (err) { 2588 if (err) {
2588 clear_nlink(inode); 2589 clear_nlink(inode);
@@ -2777,7 +2778,8 @@ retry:
2777 if (err) 2778 if (err)
2778 goto out_clear_inode; 2779 goto out_clear_inode;
2779#ifdef CONFIG_EXT4_FS_ENCRYPTION 2780#ifdef CONFIG_EXT4_FS_ENCRYPTION
2780 if (ext4_encrypted_inode(dir)) { 2781 if (ext4_encrypted_inode(dir) ||
2782 DUMMY_ENCRYPTION_ENABLED(EXT4_SB(dir->i_sb))) {
2781 err = ext4_inherit_context(dir, inode); 2783 err = ext4_inherit_context(dir, inode);
2782 if (err) 2784 if (err)
2783 goto out_clear_inode; 2785 goto out_clear_inode;
@@ -3202,7 +3204,8 @@ static int ext4_symlink(struct inode *dir,
3202 disk_link.len = len + 1; 3204 disk_link.len = len + 1;
3203 disk_link.name = (char *) symname; 3205 disk_link.name = (char *) symname;
3204 3206
3205 encryption_required = ext4_encrypted_inode(dir); 3207 encryption_required = (ext4_encrypted_inode(dir) ||
3208 DUMMY_ENCRYPTION_ENABLED(EXT4_SB(dir->i_sb)));
3206 if (encryption_required) 3209 if (encryption_required)
3207 disk_link.len = encrypted_symlink_data_len(len) + 1; 3210 disk_link.len = encrypted_symlink_data_len(len) + 1;
3208 if (disk_link.len > dir->i_sb->s_blocksize) 3211 if (disk_link.len > dir->i_sb->s_blocksize)
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 1008ca258de4..f9ebd58f40dd 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -1106,7 +1106,7 @@ enum {
1106 Opt_commit, Opt_min_batch_time, Opt_max_batch_time, Opt_journal_dev, 1106 Opt_commit, Opt_min_batch_time, Opt_max_batch_time, Opt_journal_dev,
1107 Opt_journal_path, Opt_journal_checksum, Opt_journal_async_commit, 1107 Opt_journal_path, Opt_journal_checksum, Opt_journal_async_commit,
1108 Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback, 1108 Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback,
1109 Opt_data_err_abort, Opt_data_err_ignore, 1109 Opt_data_err_abort, Opt_data_err_ignore, Opt_test_dummy_encryption,
1110 Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota, 1110 Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota,
1111 Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_jqfmt_vfsv1, Opt_quota, 1111 Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_jqfmt_vfsv1, Opt_quota,
1112 Opt_noquota, Opt_barrier, Opt_nobarrier, Opt_err, 1112 Opt_noquota, Opt_barrier, Opt_nobarrier, Opt_err,
@@ -1197,6 +1197,7 @@ static const match_table_t tokens = {
1197 {Opt_init_itable, "init_itable"}, 1197 {Opt_init_itable, "init_itable"},
1198 {Opt_noinit_itable, "noinit_itable"}, 1198 {Opt_noinit_itable, "noinit_itable"},
1199 {Opt_max_dir_size_kb, "max_dir_size_kb=%u"}, 1199 {Opt_max_dir_size_kb, "max_dir_size_kb=%u"},
1200 {Opt_test_dummy_encryption, "test_dummy_encryption"},
1200 {Opt_removed, "check=none"}, /* mount option from ext2/3 */ 1201 {Opt_removed, "check=none"}, /* mount option from ext2/3 */
1201 {Opt_removed, "nocheck"}, /* mount option from ext2/3 */ 1202 {Opt_removed, "nocheck"}, /* mount option from ext2/3 */
1202 {Opt_removed, "reservation"}, /* mount option from ext2/3 */ 1203 {Opt_removed, "reservation"}, /* mount option from ext2/3 */
@@ -1398,6 +1399,7 @@ static const struct mount_opts {
1398 {Opt_jqfmt_vfsv0, QFMT_VFS_V0, MOPT_QFMT}, 1399 {Opt_jqfmt_vfsv0, QFMT_VFS_V0, MOPT_QFMT},
1399 {Opt_jqfmt_vfsv1, QFMT_VFS_V1, MOPT_QFMT}, 1400 {Opt_jqfmt_vfsv1, QFMT_VFS_V1, MOPT_QFMT},
1400 {Opt_max_dir_size_kb, 0, MOPT_GTE0}, 1401 {Opt_max_dir_size_kb, 0, MOPT_GTE0},
1402 {Opt_test_dummy_encryption, 0, MOPT_GTE0},
1401 {Opt_err, 0, 0} 1403 {Opt_err, 0, 0}
1402}; 1404};
1403 1405
@@ -1574,6 +1576,15 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token,
1574 } 1576 }
1575 *journal_ioprio = 1577 *journal_ioprio =
1576 IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, arg); 1578 IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, arg);
1579 } else if (token == Opt_test_dummy_encryption) {
1580#ifdef CONFIG_EXT4_FS_ENCRYPTION
1581 sbi->s_mount_flags |= EXT4_MF_TEST_DUMMY_ENCRYPTION;
1582 ext4_msg(sb, KERN_WARNING,
1583 "Test dummy encryption mode enabled");
1584#else
1585 ext4_msg(sb, KERN_WARNING,
1586 "Test dummy encryption mount option ignored");
1587#endif
1577 } else if (m->flags & MOPT_DATAJ) { 1588 } else if (m->flags & MOPT_DATAJ) {
1578 if (is_remount) { 1589 if (is_remount) {
1579 if (!sbi->s_journal) 1590 if (!sbi->s_journal)
@@ -2671,11 +2682,13 @@ static struct attribute *ext4_attrs[] = {
2671EXT4_INFO_ATTR(lazy_itable_init); 2682EXT4_INFO_ATTR(lazy_itable_init);
2672EXT4_INFO_ATTR(batched_discard); 2683EXT4_INFO_ATTR(batched_discard);
2673EXT4_INFO_ATTR(meta_bg_resize); 2684EXT4_INFO_ATTR(meta_bg_resize);
2685EXT4_INFO_ATTR(encryption);
2674 2686
2675static struct attribute *ext4_feat_attrs[] = { 2687static struct attribute *ext4_feat_attrs[] = {
2676 ATTR_LIST(lazy_itable_init), 2688 ATTR_LIST(lazy_itable_init),
2677 ATTR_LIST(batched_discard), 2689 ATTR_LIST(batched_discard),
2678 ATTR_LIST(meta_bg_resize), 2690 ATTR_LIST(meta_bg_resize),
2691 ATTR_LIST(encryption),
2679 NULL, 2692 NULL,
2680}; 2693};
2681 2694
@@ -3683,6 +3696,13 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
3683 } 3696 }
3684 } 3697 }
3685 3698
3699 if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_ENCRYPT) &&
3700 es->s_encryption_level) {
3701 ext4_msg(sb, KERN_ERR, "Unsupported encryption level %d",
3702 es->s_encryption_level);
3703 goto failed_mount;
3704 }
3705
3686 if (sb->s_blocksize != blocksize) { 3706 if (sb->s_blocksize != blocksize) {
3687 /* Validate the filesystem blocksize */ 3707 /* Validate the filesystem blocksize */
3688 if (!sb_set_blocksize(sb, blocksize)) { 3708 if (!sb_set_blocksize(sb, blocksize)) {
@@ -4045,6 +4065,13 @@ no_journal:
4045 } 4065 }
4046 } 4066 }
4047 4067
4068 if (unlikely(sbi->s_mount_flags & EXT4_MF_TEST_DUMMY_ENCRYPTION) &&
4069 !(sb->s_flags & MS_RDONLY) &&
4070 !EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_ENCRYPT)) {
4071 EXT4_SET_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_ENCRYPT);
4072 ext4_commit_super(sb, 1);
4073 }
4074
4048 /* 4075 /*
4049 * Get the # of file system overhead blocks from the 4076 * Get the # of file system overhead blocks from the
4050 * superblock if present. 4077 * superblock if present.