ext4 crypto: teach ext4_htree_store_dirent() to store decrypted filenames
authorTheodore Ts'o <tytso@mit.edu>
Sun, 12 Apr 2015 04:56:26 +0000 (00:56 -0400)
committerTheodore Ts'o <tytso@mit.edu>
Sun, 12 Apr 2015 04:56:26 +0000 (00:56 -0400)
For encrypted directories, we need to pass in a separate parameter for
the decrypted filename, since the directory entry contains the
encrypted filename.

Signed-off-by: Theodore Ts'o <tytso@mit.edu>
fs/ext4/dir.c
fs/ext4/ext4.h
fs/ext4/inline.c
fs/ext4/namei.c

index 9e1e9e7869cbd2b7611a32b5b8042641ec7996b4..315f13ad382e7963ddc07ed8dc6c79769d8a8141 100644 (file)
@@ -382,10 +382,15 @@ void ext4_htree_free_dir_info(struct dir_private_info *p)
 
 /*
  * Given a directory entry, enter it into the fname rb tree.
+ *
+ * When filename encryption is enabled, the dirent will hold the
+ * encrypted filename, while the htree will hold decrypted filename.
+ * The decrypted filename is passed in via ent_name.  parameter.
  */
 int ext4_htree_store_dirent(struct file *dir_file, __u32 hash,
                             __u32 minor_hash,
-                            struct ext4_dir_entry_2 *dirent)
+                           struct ext4_dir_entry_2 *dirent,
+                           struct ext4_str *ent_name)
 {
        struct rb_node **p, *parent = NULL;
        struct fname *fname, *new_fn;
@@ -396,17 +401,17 @@ int ext4_htree_store_dirent(struct file *dir_file, __u32 hash,
        p = &info->root.rb_node;
 
        /* Create and allocate the fname structure */
-       len = sizeof(struct fname) + dirent->name_len + 1;
+       len = sizeof(struct fname) + ent_name->len + 1;
        new_fn = kzalloc(len, GFP_KERNEL);
        if (!new_fn)
                return -ENOMEM;
        new_fn->hash = hash;
        new_fn->minor_hash = minor_hash;
        new_fn->inode = le32_to_cpu(dirent->inode);
-       new_fn->name_len = dirent->name_len;
+       new_fn->name_len = ent_name->len;
        new_fn->file_type = dirent->file_type;
-       memcpy(new_fn->name, dirent->name, dirent->name_len);
-       new_fn->name[dirent->name_len] = 0;
+       memcpy(new_fn->name, ent_name->name, ent_name->len);
+       new_fn->name[ent_name->len] = 0;
 
        while (*p) {
                parent = *p;
index 3462532b227fd57df56cbccc6c29b0d3deeea76e..ba75838f35888edf90ef4d9ee4b6d3924feb765b 100644 (file)
@@ -2142,8 +2142,9 @@ extern int __ext4_check_dir_entry(const char *, unsigned int, struct inode *,
        unlikely(__ext4_check_dir_entry(__func__, __LINE__, (dir), (filp), \
                                        (de), (bh), (buf), (size), (offset)))
 extern int ext4_htree_store_dirent(struct file *dir_file, __u32 hash,
-                                   __u32 minor_hash,
-                                   struct ext4_dir_entry_2 *dirent);
+                               __u32 minor_hash,
+                               struct ext4_dir_entry_2 *dirent,
+                               struct ext4_str *ent_name);
 extern void ext4_htree_free_dir_info(struct dir_private_info *p);
 extern int ext4_find_dest_de(struct inode *dir, struct inode *inode,
                             struct buffer_head *bh,
index 8b64d715e476091b103a1df8d037d0cea761ff24..661f0b8dcfe01f77f6fb28e9e0474041c113bc41 100644 (file)
@@ -1327,6 +1327,7 @@ int htree_inlinedir_to_tree(struct file *dir_file,
        struct ext4_iloc iloc;
        void *dir_buf = NULL;
        struct ext4_dir_entry_2 fake;
+       struct ext4_str tmp_str;
 
        ret = ext4_get_inode_loc(inode, &iloc);
        if (ret)
@@ -1398,8 +1399,10 @@ int htree_inlinedir_to_tree(struct file *dir_file,
                        continue;
                if (de->inode == 0)
                        continue;
-               err = ext4_htree_store_dirent(dir_file,
-                                  hinfo->hash, hinfo->minor_hash, de);
+               tmp_str.name = de->name;
+               tmp_str.len = de->name_len;
+               err = ext4_htree_store_dirent(dir_file, hinfo->hash,
+                                             hinfo->minor_hash, de, &tmp_str);
                if (err) {
                        count = err;
                        goto out;
index 77a63ff4aeb98d18094c0986121f980159d8e898..8cef115ee64a344549ecd45f4b43b92267316fc1 100644 (file)
@@ -877,6 +877,7 @@ static int htree_dirblock_to_tree(struct file *dir_file,
        struct buffer_head *bh;
        struct ext4_dir_entry_2 *de, *top;
        int err = 0, count = 0;
+       struct ext4_str tmp_str;
 
        dxtrace(printk(KERN_INFO "In htree dirblock_to_tree: block %lu\n",
                                                        (unsigned long)block));
@@ -903,8 +904,11 @@ static int htree_dirblock_to_tree(struct file *dir_file,
                        continue;
                if (de->inode == 0)
                        continue;
-               if ((err = ext4_htree_store_dirent(dir_file,
-                                  hinfo->hash, hinfo->minor_hash, de)) != 0) {
+               tmp_str.name = de->name;
+               tmp_str.len = de->name_len;
+               err = ext4_htree_store_dirent(dir_file,
+                          hinfo->hash, hinfo->minor_hash, de, &tmp_str);
+               if (err != 0) {
                        brelse(bh);
                        return err;
                }
@@ -934,6 +938,7 @@ int ext4_htree_fill_tree(struct file *dir_file, __u32 start_hash,
        int count = 0;
        int ret, err;
        __u32 hashval;
+       struct ext4_str tmp_str;
 
        dxtrace(printk(KERN_DEBUG "In htree_fill_tree, start hash: %x:%x\n",
                       start_hash, start_minor_hash));
@@ -969,14 +974,22 @@ int ext4_htree_fill_tree(struct file *dir_file, __u32 start_hash,
        /* Add '.' and '..' from the htree header */
        if (!start_hash && !start_minor_hash) {
                de = (struct ext4_dir_entry_2 *) frames[0].bh->b_data;
-               if ((err = ext4_htree_store_dirent(dir_file, 0, 0, de)) != 0)
+               tmp_str.name = de->name;
+               tmp_str.len = de->name_len;
+               err = ext4_htree_store_dirent(dir_file, 0, 0,
+                                             de, &tmp_str);
+               if (err != 0)
                        goto errout;
                count++;
        }
        if (start_hash < 2 || (start_hash ==2 && start_minor_hash==0)) {
                de = (struct ext4_dir_entry_2 *) frames[0].bh->b_data;
                de = ext4_next_entry(de, dir->i_sb->s_blocksize);
-               if ((err = ext4_htree_store_dirent(dir_file, 2, 0, de)) != 0)
+               tmp_str.name = de->name;
+               tmp_str.len = de->name_len;
+               err = ext4_htree_store_dirent(dir_file, 2, 0,
+                                             de, &tmp_str);
+               if (err != 0)
                        goto errout;
                count++;
        }