1 ext4 crypto: enable filename encryption
3 From: Michael Halcrow <mhalcrow@google.com>
5 Signed-off-by: Uday Savagaonkar <savagaon@google.com>
6 Signed-off-by: Ildar Muslukhov <ildarm@google.com>
7 Signed-off-by: Michael Halcrow <mhalcrow@google.com>
8 Signed-off-by: Theodore Ts'o <tytso@mit.edu>
10 fs/ext4/dir.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++---------------
11 fs/ext4/ialloc.c | 21 +++++++++++++++++++--
12 2 files changed, 68 insertions(+), 17 deletions(-)
14 diff --git a/fs/ext4/dir.c b/fs/ext4/dir.c
15 index f67f955..2b6e0c8 100644
18 @@ -110,7 +110,10 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx)
20 struct inode *inode = file_inode(file);
21 struct super_block *sb = inode->i_sb;
22 + struct buffer_head *bh = NULL;
23 int dir_has_error = 0;
24 + struct ext4_fname_crypto_ctx *enc_ctx = NULL;
25 + struct ext4_str fname_crypto_str = {.name = NULL, .len = 0};
27 if (is_dx_dir(inode)) {
28 err = ext4_dx_readdir(file, ctx);
29 @@ -127,17 +130,28 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx)
31 if (ext4_has_inline_data(inode)) {
32 int has_inline_data = 1;
33 - int ret = ext4_read_inline_dir(file, ctx,
34 + err = ext4_read_inline_dir(file, ctx,
41 + enc_ctx = ext4_get_fname_crypto_ctx(inode, EXT4_NAME_LEN);
42 + if (IS_ERR(enc_ctx))
43 + return PTR_ERR(enc_ctx);
45 + err = ext4_fname_crypto_alloc_buffer(enc_ctx, EXT4_NAME_LEN,
48 + ext4_put_fname_crypto_ctx(&enc_ctx);
53 offset = ctx->pos & (sb->s_blocksize - 1);
55 while (ctx->pos < inode->i_size) {
56 struct ext4_map_blocks map;
57 - struct buffer_head *bh = NULL;
59 map.m_lblk = ctx->pos >> EXT4_BLOCK_SIZE_BITS(sb);
61 @@ -180,6 +194,7 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx)
62 (unsigned long long)ctx->pos);
63 ctx->pos += sb->s_blocksize - offset;
68 set_buffer_verified(bh);
69 @@ -226,25 +241,44 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx)
70 offset += ext4_rec_len_from_disk(de->rec_len,
72 if (le32_to_cpu(de->inode)) {
73 - if (!dir_emit(ctx, de->name,
75 - le32_to_cpu(de->inode),
76 - get_dtype(sb, de->file_type))) {
79 + if (enc_ctx == NULL) {
80 + /* Directory is not encrypted */
81 + if (!dir_emit(ctx, de->name,
83 + le32_to_cpu(de->inode),
84 + get_dtype(sb, de->file_type)))
87 + /* Directory is encrypted */
88 + err = ext4_fname_disk_to_usr(enc_ctx,
89 + de, &fname_crypto_str);
93 + fname_crypto_str.name, err,
94 + le32_to_cpu(de->inode),
95 + get_dtype(sb, de->file_type)))
99 ctx->pos += ext4_rec_len_from_disk(de->rec_len,
103 + if ((ctx->pos < inode->i_size) && !dir_relax(inode))
106 - if (ctx->pos < inode->i_size) {
107 - if (!dir_relax(inode))
117 +#ifdef CONFIG_EXT4_FS_ENCRYPTION
118 + ext4_put_fname_crypto_ctx(&enc_ctx);
119 + ext4_fname_crypto_free_buffer(&fname_crypto_str);
125 static inline int is_32bit_api(void)
126 diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c
127 index e554ca3..8f37c9e 100644
128 --- a/fs/ext4/ialloc.c
129 +++ b/fs/ext4/ialloc.c
130 @@ -1034,11 +1034,28 @@ got:
131 ext4_set_inode_state(inode, EXT4_STATE_NEW);
133 ei->i_extra_isize = EXT4_SB(sb)->s_want_extra_isize;
135 +#ifdef CONFIG_EXT4_FS_ENCRYPTION
136 + if ((sbi->s_file_encryption_mode == EXT4_ENCRYPTION_MODE_INVALID) &&
137 + (sbi->s_dir_encryption_mode == EXT4_ENCRYPTION_MODE_INVALID)) {
138 + ei->i_inline_off = 0;
139 + if (EXT4_HAS_INCOMPAT_FEATURE(sb,
140 + EXT4_FEATURE_INCOMPAT_INLINE_DATA))
141 + ext4_set_inode_state(inode,
142 + EXT4_STATE_MAY_INLINE_DATA);
144 + /* Inline data and encryption are incompatible
145 + * We turn off inline data since encryption is enabled */
146 + ei->i_inline_off = 1;
147 + if (EXT4_HAS_INCOMPAT_FEATURE(sb,
148 + EXT4_FEATURE_INCOMPAT_INLINE_DATA))
149 + ext4_clear_inode_state(inode,
150 + EXT4_STATE_MAY_INLINE_DATA);
153 ei->i_inline_off = 0;
154 if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_INLINE_DATA))
155 ext4_set_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA);
159 err = dquot_alloc_inode(inode);