diff options
author | Michael Halcrow <mhalcrow@google.com> | 2015-04-12 01:09:05 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2015-04-12 01:09:05 -0400 |
commit | 4461471107b79bee16c497c9f7f69fa26126ae5b (patch) | |
tree | 08945642d3fe6af854b6bbb459a8670416ef62d0 | |
parent | 1f3862b5575b138e83080232706e37ee24b8093e (diff) |
ext4 crypto: enable filename encryption
Signed-off-by: Uday Savagaonkar <savagaon@google.com>
Signed-off-by: Ildar Muslukhov <ildarm@google.com>
Signed-off-by: Michael Halcrow <mhalcrow@google.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
-rw-r--r-- | fs/ext4/dir.c | 64 | ||||
-rw-r--r-- | fs/ext4/ialloc.c | 21 |
2 files changed, 68 insertions, 17 deletions
diff --git a/fs/ext4/dir.c b/fs/ext4/dir.c index 315f13ad382e..61db51a5ce4c 100644 --- a/fs/ext4/dir.c +++ b/fs/ext4/dir.c | |||
@@ -108,7 +108,10 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx) | |||
108 | int err; | 108 | int err; |
109 | struct inode *inode = file_inode(file); | 109 | struct inode *inode = file_inode(file); |
110 | struct super_block *sb = inode->i_sb; | 110 | struct super_block *sb = inode->i_sb; |
111 | struct buffer_head *bh = NULL; | ||
111 | int dir_has_error = 0; | 112 | int dir_has_error = 0; |
113 | struct ext4_fname_crypto_ctx *enc_ctx = NULL; | ||
114 | struct ext4_str fname_crypto_str = {.name = NULL, .len = 0}; | ||
112 | 115 | ||
113 | if (is_dx_dir(inode)) { | 116 | if (is_dx_dir(inode)) { |
114 | err = ext4_dx_readdir(file, ctx); | 117 | err = ext4_dx_readdir(file, ctx); |
@@ -125,17 +128,28 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx) | |||
125 | 128 | ||
126 | if (ext4_has_inline_data(inode)) { | 129 | if (ext4_has_inline_data(inode)) { |
127 | int has_inline_data = 1; | 130 | int has_inline_data = 1; |
128 | int ret = ext4_read_inline_dir(file, ctx, | 131 | err = ext4_read_inline_dir(file, ctx, |
129 | &has_inline_data); | 132 | &has_inline_data); |
130 | if (has_inline_data) | 133 | if (has_inline_data) |
131 | return ret; | 134 | return err; |
135 | } | ||
136 | |||
137 | enc_ctx = ext4_get_fname_crypto_ctx(inode, EXT4_NAME_LEN); | ||
138 | if (IS_ERR(enc_ctx)) | ||
139 | return PTR_ERR(enc_ctx); | ||
140 | if (enc_ctx) { | ||
141 | err = ext4_fname_crypto_alloc_buffer(enc_ctx, EXT4_NAME_LEN, | ||
142 | &fname_crypto_str); | ||
143 | if (err < 0) { | ||
144 | ext4_put_fname_crypto_ctx(&enc_ctx); | ||
145 | return err; | ||
146 | } | ||
132 | } | 147 | } |
133 | 148 | ||
134 | offset = ctx->pos & (sb->s_blocksize - 1); | 149 | offset = ctx->pos & (sb->s_blocksize - 1); |
135 | 150 | ||
136 | while (ctx->pos < inode->i_size) { | 151 | while (ctx->pos < inode->i_size) { |
137 | struct ext4_map_blocks map; | 152 | struct ext4_map_blocks map; |
138 | struct buffer_head *bh = NULL; | ||
139 | 153 | ||
140 | map.m_lblk = ctx->pos >> EXT4_BLOCK_SIZE_BITS(sb); | 154 | map.m_lblk = ctx->pos >> EXT4_BLOCK_SIZE_BITS(sb); |
141 | map.m_len = 1; | 155 | map.m_len = 1; |
@@ -178,6 +192,7 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx) | |||
178 | (unsigned long long)ctx->pos); | 192 | (unsigned long long)ctx->pos); |
179 | ctx->pos += sb->s_blocksize - offset; | 193 | ctx->pos += sb->s_blocksize - offset; |
180 | brelse(bh); | 194 | brelse(bh); |
195 | bh = NULL; | ||
181 | continue; | 196 | continue; |
182 | } | 197 | } |
183 | set_buffer_verified(bh); | 198 | set_buffer_verified(bh); |
@@ -224,25 +239,44 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx) | |||
224 | offset += ext4_rec_len_from_disk(de->rec_len, | 239 | offset += ext4_rec_len_from_disk(de->rec_len, |
225 | sb->s_blocksize); | 240 | sb->s_blocksize); |
226 | if (le32_to_cpu(de->inode)) { | 241 | if (le32_to_cpu(de->inode)) { |
227 | if (!dir_emit(ctx, de->name, | 242 | if (enc_ctx == NULL) { |
228 | de->name_len, | 243 | /* Directory is not encrypted */ |
229 | le32_to_cpu(de->inode), | 244 | if (!dir_emit(ctx, de->name, |
230 | get_dtype(sb, de->file_type))) { | 245 | de->name_len, |
231 | brelse(bh); | 246 | le32_to_cpu(de->inode), |
232 | return 0; | 247 | get_dtype(sb, de->file_type))) |
248 | goto done; | ||
249 | } else { | ||
250 | /* Directory is encrypted */ | ||
251 | err = ext4_fname_disk_to_usr(enc_ctx, | ||
252 | de, &fname_crypto_str); | ||
253 | if (err < 0) | ||
254 | goto errout; | ||
255 | if (!dir_emit(ctx, | ||
256 | fname_crypto_str.name, err, | ||
257 | le32_to_cpu(de->inode), | ||
258 | get_dtype(sb, de->file_type))) | ||
259 | goto done; | ||
233 | } | 260 | } |
234 | } | 261 | } |
235 | ctx->pos += ext4_rec_len_from_disk(de->rec_len, | 262 | ctx->pos += ext4_rec_len_from_disk(de->rec_len, |
236 | sb->s_blocksize); | 263 | sb->s_blocksize); |
237 | } | 264 | } |
238 | offset = 0; | 265 | if ((ctx->pos < inode->i_size) && !dir_relax(inode)) |
266 | goto done; | ||
239 | brelse(bh); | 267 | brelse(bh); |
240 | if (ctx->pos < inode->i_size) { | 268 | bh = NULL; |
241 | if (!dir_relax(inode)) | 269 | offset = 0; |
242 | return 0; | ||
243 | } | ||
244 | } | 270 | } |
245 | return 0; | 271 | done: |
272 | err = 0; | ||
273 | errout: | ||
274 | #ifdef CONFIG_EXT4_FS_ENCRYPTION | ||
275 | ext4_put_fname_crypto_ctx(&enc_ctx); | ||
276 | ext4_fname_crypto_free_buffer(&fname_crypto_str); | ||
277 | #endif | ||
278 | brelse(bh); | ||
279 | return err; | ||
246 | } | 280 | } |
247 | 281 | ||
248 | static inline int is_32bit_api(void) | 282 | static inline int is_32bit_api(void) |
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index 247737efd725..850267c89407 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c | |||
@@ -1033,11 +1033,28 @@ got: | |||
1033 | ext4_set_inode_state(inode, EXT4_STATE_NEW); | 1033 | ext4_set_inode_state(inode, EXT4_STATE_NEW); |
1034 | 1034 | ||
1035 | ei->i_extra_isize = EXT4_SB(sb)->s_want_extra_isize; | 1035 | ei->i_extra_isize = EXT4_SB(sb)->s_want_extra_isize; |
1036 | 1036 | #ifdef CONFIG_EXT4_FS_ENCRYPTION | |
1037 | if ((sbi->s_file_encryption_mode == EXT4_ENCRYPTION_MODE_INVALID) && | ||
1038 | (sbi->s_dir_encryption_mode == EXT4_ENCRYPTION_MODE_INVALID)) { | ||
1039 | ei->i_inline_off = 0; | ||
1040 | if (EXT4_HAS_INCOMPAT_FEATURE(sb, | ||
1041 | EXT4_FEATURE_INCOMPAT_INLINE_DATA)) | ||
1042 | ext4_set_inode_state(inode, | ||
1043 | EXT4_STATE_MAY_INLINE_DATA); | ||
1044 | } else { | ||
1045 | /* Inline data and encryption are incompatible | ||
1046 | * We turn off inline data since encryption is enabled */ | ||
1047 | ei->i_inline_off = 1; | ||
1048 | if (EXT4_HAS_INCOMPAT_FEATURE(sb, | ||
1049 | EXT4_FEATURE_INCOMPAT_INLINE_DATA)) | ||
1050 | ext4_clear_inode_state(inode, | ||
1051 | EXT4_STATE_MAY_INLINE_DATA); | ||
1052 | } | ||
1053 | #else | ||
1037 | ei->i_inline_off = 0; | 1054 | ei->i_inline_off = 0; |
1038 | if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_INLINE_DATA)) | 1055 | if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_INLINE_DATA)) |
1039 | ext4_set_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA); | 1056 | ext4_set_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA); |
1040 | 1057 | #endif | |
1041 | ret = inode; | 1058 | ret = inode; |
1042 | err = dquot_alloc_inode(inode); | 1059 | err = dquot_alloc_inode(inode); |
1043 | if (err) | 1060 | if (err) |