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) |
