Sync ext4 encryption as of commit dffd334e4d7134
[ext4-patch-queue.git] / enable-encryption-feature
blob805a957520e484f45a97a4ac1e0920bcba9d8282
1 ext4 crypto: enable encryption feature flag
3 Also add the test dummy encryption mode flag so we can more easily
4 test the encryption patches using xfstests.
6 Change-Id: I63a7f5b969738eed81b2f12715cfff161a988d84
7 Signed-off-by: Michael Halcrow <mhalcrow@google.com>
8 Signed-off-by: Theodore Ts'o <tytso@mit.edu>
9 ---
10  fs/ext4/crypto_key.c    | 27 +++++++++++++++------------
11  fs/ext4/crypto_policy.c | 18 +++++++++++++++---
12  fs/ext4/ext4.h          | 17 +++++++++++++----
13  fs/ext4/ialloc.c        |  3 ++-
14  fs/ext4/namei.c         |  9 ++++++---
15  fs/ext4/super.c         | 29 ++++++++++++++++++++++++++++-
16  6 files changed, 79 insertions(+), 24 deletions(-)
18 diff --git a/fs/ext4/crypto_key.c b/fs/ext4/crypto_key.c
19 index 572bd97..c8392af 100644
20 --- a/fs/ext4/crypto_key.c
21 +++ b/fs/ext4/crypto_key.c
22 @@ -98,6 +98,7 @@ int ext4_generate_encryption_key(struct inode *inode)
23         struct ext4_encryption_key *master_key;
24         struct ext4_encryption_context ctx;
25         struct user_key_payload *ukp;
26 +       struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
27         int res = ext4_xattr_get(inode, EXT4_XATTR_INDEX_ENCRYPTION,
28                                  EXT4_XATTR_NAME_ENCRYPTION_CONTEXT,
29                                  &ctx, sizeof(ctx));
30 @@ -109,6 +110,20 @@ int ext4_generate_encryption_key(struct inode *inode)
31         }
32         res = 0;
34 +       if (S_ISREG(inode->i_mode))
35 +               crypt_key->mode = ctx.contents_encryption_mode;
36 +       else if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))
37 +               crypt_key->mode = ctx.filenames_encryption_mode;
38 +       else {
39 +               printk(KERN_ERR "ext4 crypto: Unsupported inode type.\n");
40 +               BUG();
41 +       }
42 +       crypt_key->size = ext4_encryption_key_size(crypt_key->mode);
43 +       BUG_ON(!crypt_key->size);
44 +       if (DUMMY_ENCRYPTION_ENABLED(sbi)) {
45 +               memset(crypt_key->raw, 0x42, EXT4_AES_256_XTS_KEY_SIZE);
46 +               goto out;
47 +       }
48         memcpy(full_key_descriptor, EXT4_KEY_DESC_PREFIX,
49                EXT4_KEY_DESC_PREFIX_SIZE);
50         sprintf(full_key_descriptor + EXT4_KEY_DESC_PREFIX_SIZE,
51 @@ -129,21 +144,9 @@ int ext4_generate_encryption_key(struct inode *inode)
52                 goto out;
53         }
54         master_key = (struct ext4_encryption_key *)ukp->data;
56 -       if (S_ISREG(inode->i_mode))
57 -               crypt_key->mode = ctx.contents_encryption_mode;
58 -       else if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))
59 -               crypt_key->mode = ctx.filenames_encryption_mode;
60 -       else {
61 -               printk(KERN_ERR "ext4 crypto: Unsupported inode type.\n");
62 -               BUG();
63 -       }
64 -       crypt_key->size = ext4_encryption_key_size(crypt_key->mode);
65 -       BUG_ON(!crypt_key->size);
66         BUILD_BUG_ON(EXT4_AES_128_ECB_KEY_SIZE !=
67                      EXT4_KEY_DERIVATION_NONCE_SIZE);
68         BUG_ON(master_key->size != EXT4_AES_256_XTS_KEY_SIZE);
69 -       BUG_ON(crypt_key->size < EXT4_AES_256_CBC_KEY_SIZE);
70         res = ext4_derive_key_aes(ctx.nonce, master_key->raw, crypt_key->raw);
71  out:
72         if (keyring_key)
73 diff --git a/fs/ext4/crypto_policy.c b/fs/ext4/crypto_policy.c
74 index 5b4fbb3..89024ec 100644
75 --- a/fs/ext4/crypto_policy.c
76 +++ b/fs/ext4/crypto_policy.c
77 @@ -158,13 +158,25 @@ int ext4_inherit_context(struct inode *parent, struct inode *child)
78                                  EXT4_XATTR_NAME_ENCRYPTION_CONTEXT,
79                                  &ctx, sizeof(ctx));
81 -       if (res != sizeof(ctx))
82 -               return -ENOENT;
84 +       if (res != sizeof(ctx)) {
85 +               if (DUMMY_ENCRYPTION_ENABLED(EXT4_SB(parent->i_sb))) {
86 +                       ctx.format = EXT4_ENCRYPTION_CONTEXT_FORMAT_V1;
87 +                       ctx.contents_encryption_mode =
88 +                               EXT4_ENCRYPTION_MODE_AES_256_XTS;
89 +                       ctx.filenames_encryption_mode =
90 +                               EXT4_ENCRYPTION_MODE_AES_256_CTS;
91 +                       memset(ctx.master_key_descriptor, 0x42,
92 +                              EXT4_KEY_DESCRIPTOR_SIZE);
93 +                       res = 0;
94 +               } else {
95 +                       goto out;
96 +               }
97 +       }
98         get_random_bytes(ctx.nonce, EXT4_KEY_DERIVATION_NONCE_SIZE);
99         res = ext4_xattr_set(child, EXT4_XATTR_INDEX_ENCRYPTION,
100                              EXT4_XATTR_NAME_ENCRYPTION_CONTEXT, &ctx,
101                              sizeof(ctx), 0);
102 +out:
103         if (!res)
104                 ext4_set_inode_flag(child, EXT4_INODE_ENCRYPT);
105         return res;
106 diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
107 index 7ae0454..c4e2a2e 100644
108 --- a/fs/ext4/ext4.h
109 +++ b/fs/ext4/ext4.h
110 @@ -1189,8 +1189,16 @@ struct ext4_super_block {
111  /*
112   * run-time mount flags
113   */
114 -#define EXT4_MF_MNTDIR_SAMPLED 0x0001
115 -#define EXT4_MF_FS_ABORTED     0x0002  /* Fatal error detected */
116 +#define EXT4_MF_MNTDIR_SAMPLED         0x0001
117 +#define EXT4_MF_FS_ABORTED             0x0002  /* Fatal error detected */
118 +#define EXT4_MF_TEST_DUMMY_ENCRYPTION  0x0004
120 +#ifdef CONFIG_EXT4_FS_ENCRYPTION
121 +#define DUMMY_ENCRYPTION_ENABLED(sbi) (unlikely((sbi)->s_mount_flags & \
122 +                                               EXT4_MF_TEST_DUMMY_ENCRYPTION))
123 +#else
124 +#define DUMMY_ENCRYPTION_ENABLED(sbi) (0)
125 +#endif
127  /* Number of quota types we support */
128  #define EXT4_MAXQUOTAS 2
129 @@ -1601,8 +1609,9 @@ static inline int ext4_encrypted_inode(struct inode *inode)
130                                          EXT4_FEATURE_INCOMPAT_EXTENTS| \
131                                          EXT4_FEATURE_INCOMPAT_64BIT| \
132                                          EXT4_FEATURE_INCOMPAT_FLEX_BG| \
133 -                                        EXT4_FEATURE_INCOMPAT_MMP |    \
134 -                                        EXT4_FEATURE_INCOMPAT_INLINE_DATA)
135 +                                        EXT4_FEATURE_INCOMPAT_MMP | \
136 +                                        EXT4_FEATURE_INCOMPAT_INLINE_DATA | \
137 +                                        EXT4_FEATURE_INCOMPAT_ENCRYPT)
138  #define EXT4_FEATURE_RO_COMPAT_SUPP    (EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER| \
139                                          EXT4_FEATURE_RO_COMPAT_LARGE_FILE| \
140                                          EXT4_FEATURE_RO_COMPAT_GDT_CSUM| \
141 diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c
142 index 8f37c9e..12571b4 100644
143 --- a/fs/ext4/ialloc.c
144 +++ b/fs/ext4/ialloc.c
145 @@ -999,7 +999,8 @@ got:
147         /* If the directory encrypted, then we should encrypt the inode. */
148         if ((S_ISDIR(mode) || S_ISREG(mode) || S_ISLNK(mode)) &&
149 -           ext4_encrypted_inode(dir))
150 +           (ext4_encrypted_inode(dir) ||
151 +            DUMMY_ENCRYPTION_ENABLED(sbi)))
152                 ext4_set_inode_flag(inode, EXT4_INODE_ENCRYPT);
154         ext4_set_inode_flags(inode);
155 diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
156 index 09b2f89..07e2ad1 100644
157 --- a/fs/ext4/namei.c
158 +++ b/fs/ext4/namei.c
159 @@ -2577,7 +2577,8 @@ retry:
160                 if (!err && IS_DIRSYNC(dir))
161                         ext4_handle_sync(handle);
162  #ifdef CONFIG_EXT4_FS_ENCRYPTION
163 -               if (!err && ext4_encrypted_inode(dir)) {
164 +               if (!err && (ext4_encrypted_inode(dir) ||
165 +                            DUMMY_ENCRYPTION_ENABLED(EXT4_SB(dir->i_sb)))) {
166                         err = ext4_inherit_context(dir, inode);
167                         if (err)
168                                 ext4_unlink(dir, dentry);
169 @@ -2782,7 +2783,8 @@ out_clear_inode:
170         if (IS_DIRSYNC(dir))
171                 ext4_handle_sync(handle);
172  #ifdef CONFIG_EXT4_FS_ENCRYPTION
173 -       if (ext4_encrypted_inode(dir)) {
174 +       if (ext4_encrypted_inode(dir) ||
175 +           DUMMY_ENCRYPTION_ENABLED(EXT4_SB(dir->i_sb))) {
176                 err = ext4_inherit_context(dir, inode);
177                 if (err)
178                         ext4_unlink(dir, dentry);
179 @@ -3187,7 +3189,8 @@ static int ext4_symlink(struct inode *dir,
180         disk_link.len = len + 1;
181         disk_link.name = (char *) symname;
183 -       encryption_required = ext4_encrypted_inode(dir);
184 +       encryption_required = (ext4_encrypted_inode(dir) ||
185 +                              DUMMY_ENCRYPTION_ENABLED(EXT4_SB(dir->i_sb)));
186         if (encryption_required)
187                 disk_link.len = encrypted_symlink_data_len(len) + 1;
188         if (disk_link.len > dir->i_sb->s_blocksize)
189 diff --git a/fs/ext4/super.c b/fs/ext4/super.c
190 index 1a44e74..31a8574 100644
191 --- a/fs/ext4/super.c
192 +++ b/fs/ext4/super.c
193 @@ -1136,7 +1136,7 @@ enum {
194         Opt_commit, Opt_min_batch_time, Opt_max_batch_time, Opt_journal_dev,
195         Opt_journal_path, Opt_journal_checksum, Opt_journal_async_commit,
196         Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback,
197 -       Opt_data_err_abort, Opt_data_err_ignore,
198 +       Opt_data_err_abort, Opt_data_err_ignore, Opt_test_dummy_encryption,
199         Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota,
200         Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_jqfmt_vfsv1, Opt_quota,
201         Opt_noquota, Opt_barrier, Opt_nobarrier, Opt_err,
202 @@ -1223,6 +1223,7 @@ static const match_table_t tokens = {
203         {Opt_init_itable, "init_itable"},
204         {Opt_noinit_itable, "noinit_itable"},
205         {Opt_max_dir_size_kb, "max_dir_size_kb=%u"},
206 +       {Opt_test_dummy_encryption, "test_dummy_encryption"},
207         {Opt_removed, "check=none"},    /* mount option from ext2/3 */
208         {Opt_removed, "nocheck"},       /* mount option from ext2/3 */
209         {Opt_removed, "reservation"},   /* mount option from ext2/3 */
210 @@ -1423,6 +1424,7 @@ static const struct mount_opts {
211         {Opt_jqfmt_vfsv0, QFMT_VFS_V0, MOPT_QFMT},
212         {Opt_jqfmt_vfsv1, QFMT_VFS_V1, MOPT_QFMT},
213         {Opt_max_dir_size_kb, 0, MOPT_GTE0},
214 +       {Opt_test_dummy_encryption, 0, MOPT_GTE0},
215         {Opt_err, 0, 0}
216  };
218 @@ -1593,6 +1595,15 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token,
219                 }
220                 *journal_ioprio =
221                         IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, arg);
222 +       } else if (token == Opt_test_dummy_encryption) {
223 +#ifdef CONFIG_EXT4_FS_ENCRYPTION
224 +               sbi->s_mount_flags |= EXT4_MF_TEST_DUMMY_ENCRYPTION;
225 +               ext4_msg(sb, KERN_WARNING,
226 +                        "Test dummy encryption mode enabled");
227 +#else
228 +               ext4_msg(sb, KERN_WARNING,
229 +                        "Test dummy encryption mount option ignored");
230 +#endif
231         } else if (m->flags & MOPT_DATAJ) {
232                 if (is_remount) {
233                         if (!sbi->s_journal)
234 @@ -2685,11 +2696,13 @@ static struct attribute *ext4_attrs[] = {
235  EXT4_INFO_ATTR(lazy_itable_init);
236  EXT4_INFO_ATTR(batched_discard);
237  EXT4_INFO_ATTR(meta_bg_resize);
238 +EXT4_INFO_ATTR(encryption);
240  static struct attribute *ext4_feat_attrs[] = {
241         ATTR_LIST(lazy_itable_init),
242         ATTR_LIST(batched_discard),
243         ATTR_LIST(meta_bg_resize),
244 +       ATTR_LIST(encryption),
245         NULL,
246  };
248 @@ -3673,6 +3686,13 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
249                 goto failed_mount;
250         }
252 +       if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_ENCRYPT) &&
253 +           es->s_encryption_level) {
254 +               ext4_msg(sb, KERN_ERR, "Unsupported encryption level %d",
255 +                        es->s_encryption_level);
256 +               goto failed_mount;
257 +       }
259         if (sb->s_blocksize != blocksize) {
260                 /* Validate the filesystem blocksize */
261                 if (!sb_set_blocksize(sb, blocksize)) {
262 @@ -4036,6 +4056,13 @@ no_journal:
263                 }
264         }
266 +       if (unlikely(sbi->s_mount_flags & EXT4_MF_TEST_DUMMY_ENCRYPTION) &&
267 +           !(sb->s_flags & MS_RDONLY) &&
268 +           !EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_ENCRYPT)) {
269 +               EXT4_SET_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_ENCRYPT);
270 +               ext4_commit_super(sb, 1);
271 +       }
273         /*
274          * Get the # of file system overhead blocks from the
275          * superblock if present.