diff options
author | Theodore Ts'o <tytso@mit.edu> | 2015-04-16 01:56:00 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2015-04-16 01:56:00 -0400 |
commit | 6ddb2447846a8ece111e316a2863c2355023682d (patch) | |
tree | e56b2d3100baf35e7d99d79ff411c28bf8c5f4c2 /fs | |
parent | f348c252320b98e11176074fe04223f22bddaf0d (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.c | 27 | ||||
-rw-r--r-- | fs/ext4/crypto_policy.c | 18 | ||||
-rw-r--r-- | fs/ext4/ext4.h | 17 | ||||
-rw-r--r-- | fs/ext4/ialloc.c | 3 | ||||
-rw-r--r-- | fs/ext4/namei.c | 9 | ||||
-rw-r--r-- | fs/ext4/super.c | 29 |
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); |
148 | out: | 151 | out: |
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); |
190 | out: | ||
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[] = { | |||
2671 | EXT4_INFO_ATTR(lazy_itable_init); | 2682 | EXT4_INFO_ATTR(lazy_itable_init); |
2672 | EXT4_INFO_ATTR(batched_discard); | 2683 | EXT4_INFO_ATTR(batched_discard); |
2673 | EXT4_INFO_ATTR(meta_bg_resize); | 2684 | EXT4_INFO_ATTR(meta_bg_resize); |
2685 | EXT4_INFO_ATTR(encryption); | ||
2674 | 2686 | ||
2675 | static struct attribute *ext4_feat_attrs[] = { | 2687 | static 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. |