mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-30 14:19:16 +00:00
ext4 crypto: insert encrypted filenames into a leaf directory block
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>
This commit is contained in:
parent
2f61830ae3
commit
4bdfc873ba
3 changed files with 79 additions and 13 deletions
|
@ -2151,9 +2151,11 @@ extern int ext4_find_dest_de(struct inode *dir, struct inode *inode,
|
||||||
void *buf, int buf_size,
|
void *buf, int buf_size,
|
||||||
const char *name, int namelen,
|
const char *name, int namelen,
|
||||||
struct ext4_dir_entry_2 **dest_de);
|
struct ext4_dir_entry_2 **dest_de);
|
||||||
void ext4_insert_dentry(struct inode *inode,
|
int ext4_insert_dentry(struct inode *dir,
|
||||||
|
struct inode *inode,
|
||||||
struct ext4_dir_entry_2 *de,
|
struct ext4_dir_entry_2 *de,
|
||||||
int buf_size,
|
int buf_size,
|
||||||
|
const struct qstr *iname,
|
||||||
const char *name, int namelen);
|
const char *name, int namelen);
|
||||||
static inline void ext4_update_dx_flag(struct inode *inode)
|
static inline void ext4_update_dx_flag(struct inode *inode)
|
||||||
{
|
{
|
||||||
|
|
|
@ -11,11 +11,13 @@
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/fiemap.h>
|
||||||
|
|
||||||
#include "ext4_jbd2.h"
|
#include "ext4_jbd2.h"
|
||||||
#include "ext4.h"
|
#include "ext4.h"
|
||||||
#include "xattr.h"
|
#include "xattr.h"
|
||||||
#include "truncate.h"
|
#include "truncate.h"
|
||||||
#include <linux/fiemap.h>
|
|
||||||
|
|
||||||
#define EXT4_XATTR_SYSTEM_DATA "data"
|
#define EXT4_XATTR_SYSTEM_DATA "data"
|
||||||
#define EXT4_MIN_INLINE_DATA_SIZE ((sizeof(__le32) * EXT4_N_BLOCKS))
|
#define EXT4_MIN_INLINE_DATA_SIZE ((sizeof(__le32) * EXT4_N_BLOCKS))
|
||||||
|
@ -1014,7 +1016,8 @@ static int ext4_add_dirent_to_inline(handle_t *handle,
|
||||||
err = ext4_journal_get_write_access(handle, iloc->bh);
|
err = ext4_journal_get_write_access(handle, iloc->bh);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
ext4_insert_dentry(inode, de, inline_size, name, namelen);
|
ext4_insert_dentry(dir, inode, de, inline_size, &dentry->d_name,
|
||||||
|
name, namelen);
|
||||||
|
|
||||||
ext4_show_inline_dir(dir, iloc->bh, inline_start, inline_size);
|
ext4_show_inline_dir(dir, iloc->bh, inline_start, inline_size);
|
||||||
|
|
||||||
|
|
|
@ -1665,19 +1665,49 @@ int ext4_find_dest_de(struct inode *dir, struct inode *inode,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ext4_insert_dentry(struct inode *inode,
|
int ext4_insert_dentry(struct inode *dir,
|
||||||
struct ext4_dir_entry_2 *de,
|
struct inode *inode,
|
||||||
int buf_size,
|
struct ext4_dir_entry_2 *de,
|
||||||
const char *name, int namelen)
|
int buf_size,
|
||||||
|
const struct qstr *iname,
|
||||||
|
const char *name, int namelen)
|
||||||
{
|
{
|
||||||
|
|
||||||
int nlen, rlen;
|
int nlen, rlen;
|
||||||
|
struct ext4_fname_crypto_ctx *ctx = NULL;
|
||||||
|
struct ext4_str fname_crypto_str = {.name = NULL, .len = 0};
|
||||||
|
struct ext4_str tmp_str;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
ctx = ext4_get_fname_crypto_ctx(dir, EXT4_NAME_LEN);
|
||||||
|
if (IS_ERR(ctx))
|
||||||
|
return -EIO;
|
||||||
|
/* By default, the input name would be written to the disk */
|
||||||
|
tmp_str.name = (unsigned char *)name;
|
||||||
|
tmp_str.len = namelen;
|
||||||
|
if (ctx != NULL) {
|
||||||
|
/* Directory is encrypted */
|
||||||
|
res = ext4_fname_crypto_alloc_buffer(ctx, EXT4_NAME_LEN,
|
||||||
|
&fname_crypto_str);
|
||||||
|
if (res < 0) {
|
||||||
|
ext4_put_fname_crypto_ctx(&ctx);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
res = ext4_fname_usr_to_disk(ctx, iname, &fname_crypto_str);
|
||||||
|
if (res < 0) {
|
||||||
|
ext4_put_fname_crypto_ctx(&ctx);
|
||||||
|
ext4_fname_crypto_free_buffer(&fname_crypto_str);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
tmp_str.name = fname_crypto_str.name;
|
||||||
|
tmp_str.len = fname_crypto_str.len;
|
||||||
|
}
|
||||||
|
|
||||||
nlen = EXT4_DIR_REC_LEN(de->name_len);
|
nlen = EXT4_DIR_REC_LEN(de->name_len);
|
||||||
rlen = ext4_rec_len_from_disk(de->rec_len, buf_size);
|
rlen = ext4_rec_len_from_disk(de->rec_len, buf_size);
|
||||||
if (de->inode) {
|
if (de->inode) {
|
||||||
struct ext4_dir_entry_2 *de1 =
|
struct ext4_dir_entry_2 *de1 =
|
||||||
(struct ext4_dir_entry_2 *)((char *)de + nlen);
|
(struct ext4_dir_entry_2 *)((char *)de + nlen);
|
||||||
de1->rec_len = ext4_rec_len_to_disk(rlen - nlen, buf_size);
|
de1->rec_len = ext4_rec_len_to_disk(rlen - nlen, buf_size);
|
||||||
de->rec_len = ext4_rec_len_to_disk(nlen, buf_size);
|
de->rec_len = ext4_rec_len_to_disk(nlen, buf_size);
|
||||||
de = de1;
|
de = de1;
|
||||||
|
@ -1685,9 +1715,14 @@ void ext4_insert_dentry(struct inode *inode,
|
||||||
de->file_type = EXT4_FT_UNKNOWN;
|
de->file_type = EXT4_FT_UNKNOWN;
|
||||||
de->inode = cpu_to_le32(inode->i_ino);
|
de->inode = cpu_to_le32(inode->i_ino);
|
||||||
ext4_set_de_type(inode->i_sb, de, inode->i_mode);
|
ext4_set_de_type(inode->i_sb, de, inode->i_mode);
|
||||||
de->name_len = namelen;
|
de->name_len = tmp_str.len;
|
||||||
memcpy(de->name, name, namelen);
|
|
||||||
|
memcpy(de->name, tmp_str.name, tmp_str.len);
|
||||||
|
ext4_put_fname_crypto_ctx(&ctx);
|
||||||
|
ext4_fname_crypto_free_buffer(&fname_crypto_str);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Add a new entry into a directory (leaf) block. If de is non-NULL,
|
* Add a new entry into a directory (leaf) block. If de is non-NULL,
|
||||||
* it points to a directory entry which is guaranteed to be large
|
* it points to a directory entry which is guaranteed to be large
|
||||||
|
@ -1724,8 +1759,12 @@ static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry,
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* By now the buffer is marked for journaling */
|
/* By now the buffer is marked for journaling. Due to crypto operations,
|
||||||
ext4_insert_dentry(inode, de, blocksize, name, namelen);
|
* the following function call may fail */
|
||||||
|
err = ext4_insert_dentry(dir, inode, de, blocksize, &dentry->d_name,
|
||||||
|
name, namelen);
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* XXX shouldn't update any times until successful
|
* XXX shouldn't update any times until successful
|
||||||
|
@ -1757,8 +1796,13 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry,
|
||||||
struct inode *inode, struct buffer_head *bh)
|
struct inode *inode, struct buffer_head *bh)
|
||||||
{
|
{
|
||||||
struct inode *dir = dentry->d_parent->d_inode;
|
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;
|
const char *name = dentry->d_name.name;
|
||||||
int namelen = dentry->d_name.len;
|
int namelen = dentry->d_name.len;
|
||||||
|
#endif
|
||||||
struct buffer_head *bh2;
|
struct buffer_head *bh2;
|
||||||
struct dx_root *root;
|
struct dx_root *root;
|
||||||
struct dx_frame frames[2], *frame;
|
struct dx_frame frames[2], *frame;
|
||||||
|
@ -1772,7 +1816,13 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry,
|
||||||
struct dx_hash_info hinfo;
|
struct dx_hash_info hinfo;
|
||||||
ext4_lblk_t block;
|
ext4_lblk_t block;
|
||||||
struct fake_dirent *fde;
|
struct fake_dirent *fde;
|
||||||
int csum_size = 0;
|
int csum_size = 0;
|
||||||
|
|
||||||
|
#ifdef CONFIG_EXT4_FS_ENCRYPTION
|
||||||
|
ctx = ext4_get_fname_crypto_ctx(dir, EXT4_NAME_LEN);
|
||||||
|
if (IS_ERR(ctx))
|
||||||
|
return PTR_ERR(ctx);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (ext4_has_metadata_csum(inode->i_sb))
|
if (ext4_has_metadata_csum(inode->i_sb))
|
||||||
csum_size = sizeof(struct ext4_dir_entry_tail);
|
csum_size = sizeof(struct ext4_dir_entry_tail);
|
||||||
|
@ -1839,7 +1889,18 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry,
|
||||||
if (hinfo.hash_version <= DX_HASH_TEA)
|
if (hinfo.hash_version <= DX_HASH_TEA)
|
||||||
hinfo.hash_version += EXT4_SB(dir->i_sb)->s_hash_unsigned;
|
hinfo.hash_version += EXT4_SB(dir->i_sb)->s_hash_unsigned;
|
||||||
hinfo.seed = EXT4_SB(dir->i_sb)->s_hash_seed;
|
hinfo.seed = EXT4_SB(dir->i_sb)->s_hash_seed;
|
||||||
|
#ifdef CONFIG_EXT4_FS_ENCRYPTION
|
||||||
|
res = ext4_fname_usr_to_hash(ctx, &dentry->d_name, &hinfo);
|
||||||
|
if (res < 0) {
|
||||||
|
ext4_put_fname_crypto_ctx(&ctx);
|
||||||
|
ext4_mark_inode_dirty(handle, dir);
|
||||||
|
brelse(bh);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
ext4_put_fname_crypto_ctx(&ctx);
|
||||||
|
#else
|
||||||
ext4fs_dirhash(name, namelen, &hinfo);
|
ext4fs_dirhash(name, namelen, &hinfo);
|
||||||
|
#endif
|
||||||
memset(frames, 0, sizeof(frames));
|
memset(frames, 0, sizeof(frames));
|
||||||
frame = frames;
|
frame = frames;
|
||||||
frame->entries = entries;
|
frame->entries = entries;
|
||||||
|
|
Loading…
Reference in a new issue