From 5c34f02d301e1469473fb03e84dbc07bc16e5bcc Mon Sep 17 00:00:00 2001 From: Michael Halcrow Date: Wed, 8 Apr 2015 00:20:20 -0400 Subject: [PATCH] ext4 crypto: partial update to namei.c for fname crypto Modifies dx_show_leaf and dx_probe to support fname encryption. Filename encryption not yet enabled. Change-Id: I2058ea5cf6c3920a05c75e42acb2baab631fa1e8 Signed-off-by: Uday Savagaonkar Signed-off-by: Ildar Muslukhov Signed-off-by: Michael Halcrow Signed-off-by: Theodore Ts'o --- fs/ext4/namei.c | 156 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 117 insertions(+), 39 deletions(-) diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index e00600fad7a6..7c796ee96d63 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -587,8 +587,10 @@ struct stats unsigned bcount; }; -static struct stats dx_show_leaf(struct dx_hash_info *hinfo, struct ext4_dir_entry_2 *de, - int size, int show_names) +static struct stats dx_show_leaf(struct inode *dir, + struct dx_hash_info *hinfo, + struct ext4_dir_entry_2 *de, + int size, int show_names) { unsigned names = 0, space = 0; char *base = (char *) de; @@ -601,12 +603,85 @@ static struct stats dx_show_leaf(struct dx_hash_info *hinfo, struct ext4_dir_ent { if (show_names) { +#ifdef CONFIG_EXT4_FS_ENCRYPTION + int len; + char *name; + struct ext4_str fname_crypto_str + = {.name = NULL, .len = 0}; + struct ext4_fname_crypto_ctx *ctx = NULL; + int res; + + name = de->name; + len = de->name_len; + ctx = ext4_get_fname_crypto_ctx(dir, + EXT4_NAME_LEN); + if (IS_ERR(ctx)) { + printk(KERN_WARNING "Error acquiring" + " crypto ctxt--skipping crypto\n"); + ctx = NULL; + } + if (ctx == NULL) { + /* Directory is not encrypted */ + while (len--) + printk("%c", *name++); + ext4fs_dirhash(de->name, + de->name_len, &h); + printk(":(U)%x.%u ", h.hash, + (unsigned) ((char *) de + - base)); + } else { + /* Directory is encrypted */ + res = ext4_fname_crypto_alloc_buffer( + ctx, &fname_crypto_str.name, + &fname_crypto_str.len, + de->name_len); + if (res < 0) { + printk(KERN_WARNING "Error " + "allocating crypto " + "buffer--skipping " + "crypto\n"); + ext4_put_fname_crypto_ctx(&ctx); + ctx = NULL; + } + res = ext4_fname_disk_to_usr(ctx, de, + &fname_crypto_str); + if (res < 0) { + printk(KERN_WARNING "Error " + "converting filename " + "from disk to usr" + "\n"); + name = "??"; + len = 2; + } else { + name = fname_crypto_str.name; + len = fname_crypto_str.len; + } + while (len--) + printk("%c", *name++); + res = ext4_fname_disk_to_hash(ctx, de, + &h); + if (res < 0) { + printk(KERN_WARNING "Error " + "converting filename " + "from disk to htree" + "\n"); + h.hash = 0xDEADBEEF; + } + printk(":(E)%x.%u ", h.hash, + (unsigned) ((char *) de + - base)); + ext4_put_fname_crypto_ctx(&ctx); + ext4_fname_crypto_free_buffer( + (void **)&fname_crypto_str.name); + } +#else int len = de->name_len; char *name = de->name; while (len--) printk("%c", *name++); ext4fs_dirhash(de->name, de->name_len, &h); printk(":%x.%u ", h.hash, (unsigned) ((char *) de - base)); +#endif } space += EXT4_DIR_REC_LEN(de->name_len); names++; @@ -638,7 +713,8 @@ struct stats dx_show_entries(struct dx_hash_info *hinfo, struct inode *dir, continue; stats = levels? dx_show_entries(hinfo, dir, ((struct dx_node *) bh->b_data)->entries, levels - 1): - dx_show_leaf(hinfo, (struct ext4_dir_entry_2 *) bh->b_data, blocksize, 0); + dx_show_leaf(dir, hinfo, (struct ext4_dir_entry_2 *) + bh->b_data, blocksize, 0); names += stats.names; space += stats.space; bcount += stats.bcount; @@ -688,8 +764,28 @@ dx_probe(const struct qstr *d_name, struct inode *dir, if (hinfo->hash_version <= DX_HASH_TEA) hinfo->hash_version += EXT4_SB(dir->i_sb)->s_hash_unsigned; hinfo->seed = EXT4_SB(dir->i_sb)->s_hash_seed; +#ifdef CONFIG_EXT4_FS_ENCRYPTION + if (d_name) { + struct ext4_fname_crypto_ctx *ctx = NULL; + int res; + + /* Check if the directory is encrypted */ + ctx = ext4_get_fname_crypto_ctx(dir, EXT4_NAME_LEN); + if (IS_ERR(ctx)) { + ret_err = ERR_PTR(PTR_ERR(ctx)); + goto fail; + } + res = ext4_fname_usr_to_hash(ctx, d_name, hinfo); + if (res < 0) { + ret_err = ERR_PTR(res); + goto fail; + } + ext4_put_fname_crypto_ctx(&ctx); + } +#else if (d_name) ext4fs_dirhash(d_name->name, d_name->len, hinfo); +#endif hash = hinfo->hash; if (root->info.unused_flags & 1) { @@ -774,6 +870,7 @@ fail: brelse(frame->bh); frame--; } + if (ret_err == ERR_PTR(ERR_BAD_DX_DIR)) ext4_warning(dir->i_sb, "Corrupt dir inode %lu, running e2fsck is " @@ -1601,8 +1698,10 @@ static struct ext4_dir_entry_2 *do_split(handle_t *handle, struct inode *dir, initialize_dirent_tail(t, blocksize); } - dxtrace(dx_show_leaf (hinfo, (struct ext4_dir_entry_2 *) data1, blocksize, 1)); - dxtrace(dx_show_leaf (hinfo, (struct ext4_dir_entry_2 *) data2, blocksize, 1)); + dxtrace(dx_show_leaf(dir, hinfo, (struct ext4_dir_entry_2 *) data1, + blocksize, 1)); + dxtrace(dx_show_leaf(dir, hinfo, (struct ext4_dir_entry_2 *) data2, + blocksize, 1)); /* Which block gets the new entry? */ if (hinfo->hash >= hash2) { @@ -1795,8 +1894,13 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry, struct inode *inode, struct buffer_head *bh) { struct inode *dir = dentry->d_parent->d_inode; +#ifdef CONFIG_EXT4_FS_ENCRYPTION + struct ext4_fname_crypto_ctx *ctx = NULL; + int res; +#else const char *name = dentry->d_name.name; int namelen = dentry->d_name.len; +#endif struct buffer_head *bh2; struct dx_root *root; struct dx_frame frames[2], *frame; @@ -1811,24 +1915,11 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry, ext4_lblk_t block; struct fake_dirent *fde; int csum_size = 0; -#ifdef CONFIG_EXT4_FS_ENCRYPTION - struct ext4_fname_crypto_ctx *ctx = NULL; - struct ext4_str fname_crypto_str = {.name = NULL, .len = 0}; - int res; +#ifdef CONFIG_EXT4_FS_ENCRYPTION ctx = ext4_get_fname_crypto_ctx(dir, EXT4_NAME_LEN); if (IS_ERR(ctx)) - return -1; - if (ctx != NULL) { - /* Allocate buffer to hold maximum name length */ - res = ext4_fname_crypto_alloc_buffer(ctx, - &fname_crypto_str.name, &fname_crypto_str.len, - EXT4_NAME_LEN); - if (res < 0) { - ext4_put_fname_crypto_ctx(&ctx); - return -1; - } - } + return PTR_ERR(ctx); #endif if (ext4_has_metadata_csum(inode->i_sb)) @@ -1897,27 +1988,14 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry, hinfo.hash_version += EXT4_SB(dir->i_sb)->s_hash_unsigned; hinfo.seed = EXT4_SB(dir->i_sb)->s_hash_seed; #ifdef CONFIG_EXT4_FS_ENCRYPTION - if (ctx == NULL) { - /* Directory is not encrypted */ - ext4fs_dirhash(name, namelen, &hinfo); - } else { - /* Directory is encrypted */ - res = ext4_fname_usr_to_htree(ctx, &dentry->d_name, - &fname_crypto_str); - if (res < 0) { - ext4_put_fname_crypto_ctx(&ctx); - ext4_fname_crypto_free_buffer( - (void **)&fname_crypto_str.name); - ext4_mark_inode_dirty(handle, dir); - brelse(bh); - return res; - } - ext4fs_dirhash(fname_crypto_str.name, - fname_crypto_str.len, - &hinfo); + res = ext4_fname_usr_to_hash(ctx, &dentry->d_name, &hinfo); + if (res < 0) { ext4_put_fname_crypto_ctx(&ctx); - ext4_fname_crypto_free_buffer((void **)&fname_crypto_str.name); + ext4_mark_inode_dirty(handle, dir); + brelse(bh); + return res; } + ext4_put_fname_crypto_ctx(&ctx); #else ext4fs_dirhash(name, namelen, &hinfo); #endif -- 2.39.5