Commit 44614711 authored by Michael Halcrow's avatar Michael Halcrow Committed by Theodore Ts'o

ext4 crypto: enable filename encryption

Signed-off-by: default avatarUday Savagaonkar <savagaon@google.com>
Signed-off-by: default avatarIldar Muslukhov <ildarm@google.com>
Signed-off-by: default avatarMichael Halcrow <mhalcrow@google.com>
Signed-off-by: default avatarTheodore Ts'o <tytso@mit.edu>
parent 1f3862b5
...@@ -108,7 +108,10 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx) ...@@ -108,7 +108,10 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx)
int err; int err;
struct inode *inode = file_inode(file); struct inode *inode = file_inode(file);
struct super_block *sb = inode->i_sb; struct super_block *sb = inode->i_sb;
struct buffer_head *bh = NULL;
int dir_has_error = 0; int dir_has_error = 0;
struct ext4_fname_crypto_ctx *enc_ctx = NULL;
struct ext4_str fname_crypto_str = {.name = NULL, .len = 0};
if (is_dx_dir(inode)) { if (is_dx_dir(inode)) {
err = ext4_dx_readdir(file, ctx); err = ext4_dx_readdir(file, ctx);
...@@ -125,17 +128,28 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx) ...@@ -125,17 +128,28 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx)
if (ext4_has_inline_data(inode)) { if (ext4_has_inline_data(inode)) {
int has_inline_data = 1; int has_inline_data = 1;
int ret = ext4_read_inline_dir(file, ctx, err = ext4_read_inline_dir(file, ctx,
&has_inline_data); &has_inline_data);
if (has_inline_data) if (has_inline_data)
return ret; return err;
}
enc_ctx = ext4_get_fname_crypto_ctx(inode, EXT4_NAME_LEN);
if (IS_ERR(enc_ctx))
return PTR_ERR(enc_ctx);
if (enc_ctx) {
err = ext4_fname_crypto_alloc_buffer(enc_ctx, EXT4_NAME_LEN,
&fname_crypto_str);
if (err < 0) {
ext4_put_fname_crypto_ctx(&enc_ctx);
return err;
}
} }
offset = ctx->pos & (sb->s_blocksize - 1); offset = ctx->pos & (sb->s_blocksize - 1);
while (ctx->pos < inode->i_size) { while (ctx->pos < inode->i_size) {
struct ext4_map_blocks map; struct ext4_map_blocks map;
struct buffer_head *bh = NULL;
map.m_lblk = ctx->pos >> EXT4_BLOCK_SIZE_BITS(sb); map.m_lblk = ctx->pos >> EXT4_BLOCK_SIZE_BITS(sb);
map.m_len = 1; map.m_len = 1;
...@@ -178,6 +192,7 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx) ...@@ -178,6 +192,7 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx)
(unsigned long long)ctx->pos); (unsigned long long)ctx->pos);
ctx->pos += sb->s_blocksize - offset; ctx->pos += sb->s_blocksize - offset;
brelse(bh); brelse(bh);
bh = NULL;
continue; continue;
} }
set_buffer_verified(bh); set_buffer_verified(bh);
...@@ -224,25 +239,44 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx) ...@@ -224,25 +239,44 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx)
offset += ext4_rec_len_from_disk(de->rec_len, offset += ext4_rec_len_from_disk(de->rec_len,
sb->s_blocksize); sb->s_blocksize);
if (le32_to_cpu(de->inode)) { if (le32_to_cpu(de->inode)) {
if (!dir_emit(ctx, de->name, if (enc_ctx == NULL) {
de->name_len, /* Directory is not encrypted */
le32_to_cpu(de->inode), if (!dir_emit(ctx, de->name,
get_dtype(sb, de->file_type))) { de->name_len,
brelse(bh); le32_to_cpu(de->inode),
return 0; get_dtype(sb, de->file_type)))
goto done;
} else {
/* Directory is encrypted */
err = ext4_fname_disk_to_usr(enc_ctx,
de, &fname_crypto_str);
if (err < 0)
goto errout;
if (!dir_emit(ctx,
fname_crypto_str.name, err,
le32_to_cpu(de->inode),
get_dtype(sb, de->file_type)))
goto done;
} }
} }
ctx->pos += ext4_rec_len_from_disk(de->rec_len, ctx->pos += ext4_rec_len_from_disk(de->rec_len,
sb->s_blocksize); sb->s_blocksize);
} }
offset = 0; if ((ctx->pos < inode->i_size) && !dir_relax(inode))
goto done;
brelse(bh); brelse(bh);
if (ctx->pos < inode->i_size) { bh = NULL;
if (!dir_relax(inode)) offset = 0;
return 0;
}
} }
return 0; done:
err = 0;
errout:
#ifdef CONFIG_EXT4_FS_ENCRYPTION
ext4_put_fname_crypto_ctx(&enc_ctx);
ext4_fname_crypto_free_buffer(&fname_crypto_str);
#endif
brelse(bh);
return err;
} }
static inline int is_32bit_api(void) static inline int is_32bit_api(void)
......
...@@ -1033,11 +1033,28 @@ struct inode *__ext4_new_inode(handle_t *handle, struct inode *dir, ...@@ -1033,11 +1033,28 @@ struct inode *__ext4_new_inode(handle_t *handle, struct inode *dir,
ext4_set_inode_state(inode, EXT4_STATE_NEW); ext4_set_inode_state(inode, EXT4_STATE_NEW);
ei->i_extra_isize = EXT4_SB(sb)->s_want_extra_isize; ei->i_extra_isize = EXT4_SB(sb)->s_want_extra_isize;
#ifdef CONFIG_EXT4_FS_ENCRYPTION
if ((sbi->s_file_encryption_mode == EXT4_ENCRYPTION_MODE_INVALID) &&
(sbi->s_dir_encryption_mode == EXT4_ENCRYPTION_MODE_INVALID)) {
ei->i_inline_off = 0;
if (EXT4_HAS_INCOMPAT_FEATURE(sb,
EXT4_FEATURE_INCOMPAT_INLINE_DATA))
ext4_set_inode_state(inode,
EXT4_STATE_MAY_INLINE_DATA);
} else {
/* Inline data and encryption are incompatible
* We turn off inline data since encryption is enabled */
ei->i_inline_off = 1;
if (EXT4_HAS_INCOMPAT_FEATURE(sb,
EXT4_FEATURE_INCOMPAT_INLINE_DATA))
ext4_clear_inode_state(inode,
EXT4_STATE_MAY_INLINE_DATA);
}
#else
ei->i_inline_off = 0; ei->i_inline_off = 0;
if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_INLINE_DATA)) if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_INLINE_DATA))
ext4_set_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA); ext4_set_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA);
#endif
ret = inode; ret = inode;
err = dquot_alloc_inode(inode); err = dquot_alloc_inode(inode);
if (err) if (err)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment