Sync ext4 encryption as of commit dffd334e4d7134
[ext4-patch-queue.git] / insert-encrypted-filename-into-directory-leaf-block
blobaaaccbac7f4ada267140e9e1bd846aa51670fea2
1 ext4 crypto: insert encrypted filenames into a leaf directory block
3 From: Michael Halcrow <mhalcrow@google.com>
5 Change-Id: Iea5da045383d41e3912eed7e63292096c24668e4
6 Signed-off-by: Uday Savagaonkar <savagaon@google.com>
7 Signed-off-by: Ildar Muslukhov <ildarm@google.com>
8 Signed-off-by: Michael Halcrow <mhalcrow@google.com>
9 Signed-off-by: Theodore Ts'o <tytso@mit.edu>
10 ---
11  fs/ext4/ext4.h   |  4 +++-
12  fs/ext4/inline.c |  7 +++++--
13  fs/ext4/namei.c  | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------
14  3 files changed, 79 insertions(+), 13 deletions(-)
16 diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
17 index 7229159..08d2930 100644
18 --- a/fs/ext4/ext4.h
19 +++ b/fs/ext4/ext4.h
20 @@ -2136,9 +2136,11 @@ extern int ext4_find_dest_de(struct inode *dir, struct inode *inode,
21                              void *buf, int buf_size,
22                              const char *name, int namelen,
23                              struct ext4_dir_entry_2 **dest_de);
24 -void ext4_insert_dentry(struct inode *inode,
25 +int ext4_insert_dentry(struct inode *dir,
26 +                       struct inode *inode,
27                         struct ext4_dir_entry_2 *de,
28                         int buf_size,
29 +                      const struct qstr *iname,
30                         const char *name, int namelen);
31  static inline void ext4_update_dx_flag(struct inode *inode)
32  {
33 diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c
34 index 056ef06..0dc619b 100644
35 --- a/fs/ext4/inline.c
36 +++ b/fs/ext4/inline.c
37 @@ -11,11 +11,13 @@
38   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
39   * GNU General Public License for more details.
40   */
42 +#include <linux/fiemap.h>
44  #include "ext4_jbd2.h"
45  #include "ext4.h"
46  #include "xattr.h"
47  #include "truncate.h"
48 -#include <linux/fiemap.h>
50  #define EXT4_XATTR_SYSTEM_DATA "data"
51  #define EXT4_MIN_INLINE_DATA_SIZE      ((sizeof(__le32) * EXT4_N_BLOCKS))
52 @@ -1014,7 +1016,8 @@ static int ext4_add_dirent_to_inline(handle_t *handle,
53         err = ext4_journal_get_write_access(handle, iloc->bh);
54         if (err)
55                 return err;
56 -       ext4_insert_dentry(inode, de, inline_size, name, namelen);
57 +       ext4_insert_dentry(dir, inode, de, inline_size, &dentry->d_name,
58 +                          name, namelen);
60         ext4_show_inline_dir(dir, iloc->bh, inline_start, inline_size);
62 diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
63 index 57cae22..f3234d4 100644
64 --- a/fs/ext4/namei.c
65 +++ b/fs/ext4/namei.c
66 @@ -1663,19 +1663,49 @@ int ext4_find_dest_de(struct inode *dir, struct inode *inode,
67         return 0;
68  }
70 -void ext4_insert_dentry(struct inode *inode,
71 -                       struct ext4_dir_entry_2 *de,
72 -                       int buf_size,
73 -                       const char *name, int namelen)
74 +int ext4_insert_dentry(struct inode *dir,
75 +                      struct inode *inode,
76 +                      struct ext4_dir_entry_2 *de,
77 +                      int buf_size,
78 +                      const struct qstr *iname,
79 +                      const char *name, int namelen)
80  {
82         int nlen, rlen;
83 +       struct ext4_fname_crypto_ctx *ctx = NULL;
84 +       struct ext4_str fname_crypto_str = {.name = NULL, .len = 0};
85 +       struct ext4_str tmp_str;
86 +       int res;
88 +       ctx = ext4_get_fname_crypto_ctx(dir, EXT4_NAME_LEN);
89 +       if (IS_ERR(ctx))
90 +               return -EIO;
91 +       /* By default, the input name would be written to the disk */
92 +       tmp_str.name = (unsigned char *)name;
93 +       tmp_str.len = namelen;
94 +       if (ctx != NULL) {
95 +               /* Directory is encrypted */
96 +               res = ext4_fname_crypto_alloc_buffer(ctx, EXT4_NAME_LEN,
97 +                                                    &fname_crypto_str);
98 +               if (res < 0) {
99 +                       ext4_put_fname_crypto_ctx(&ctx);
100 +                       return -ENOMEM;
101 +               }
102 +               res = ext4_fname_usr_to_disk(ctx, iname, &fname_crypto_str);
103 +               if (res < 0) {
104 +                       ext4_put_fname_crypto_ctx(&ctx);
105 +                       ext4_fname_crypto_free_buffer(&fname_crypto_str);
106 +                       return res;
107 +               }
108 +               tmp_str.name = fname_crypto_str.name;
109 +               tmp_str.len = fname_crypto_str.len;
110 +       }
112         nlen = EXT4_DIR_REC_LEN(de->name_len);
113         rlen = ext4_rec_len_from_disk(de->rec_len, buf_size);
114         if (de->inode) {
115                 struct ext4_dir_entry_2 *de1 =
116 -                               (struct ext4_dir_entry_2 *)((char *)de + nlen);
117 +                       (struct ext4_dir_entry_2 *)((char *)de + nlen);
118                 de1->rec_len = ext4_rec_len_to_disk(rlen - nlen, buf_size);
119                 de->rec_len = ext4_rec_len_to_disk(nlen, buf_size);
120                 de = de1;
121 @@ -1683,9 +1713,14 @@ void ext4_insert_dentry(struct inode *inode,
122         de->file_type = EXT4_FT_UNKNOWN;
123         de->inode = cpu_to_le32(inode->i_ino);
124         ext4_set_de_type(inode->i_sb, de, inode->i_mode);
125 -       de->name_len = namelen;
126 -       memcpy(de->name, name, namelen);
127 +       de->name_len = tmp_str.len;
129 +       memcpy(de->name, tmp_str.name, tmp_str.len);
130 +       ext4_put_fname_crypto_ctx(&ctx);
131 +       ext4_fname_crypto_free_buffer(&fname_crypto_str);
132 +       return 0;
135  /*
136   * Add a new entry into a directory (leaf) block.  If de is non-NULL,
137   * it points to a directory entry which is guaranteed to be large
138 @@ -1722,8 +1757,12 @@ static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry,
139                 return err;
140         }
142 -       /* By now the buffer is marked for journaling */
143 -       ext4_insert_dentry(inode, de, blocksize, name, namelen);
144 +       /* By now the buffer is marked for journaling. Due to crypto operations,
145 +        * the following function call may fail */
146 +       err = ext4_insert_dentry(dir, inode, de, blocksize, &dentry->d_name,
147 +                                name, namelen);
148 +       if (err < 0)
149 +               return err;
151         /*
152          * XXX shouldn't update any times until successful
153 @@ -1755,8 +1794,13 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry,
154                             struct inode *inode, struct buffer_head *bh)
156         struct inode    *dir = dentry->d_parent->d_inode;
157 +#ifdef CONFIG_EXT4_FS_ENCRYPTION
158 +       struct ext4_fname_crypto_ctx *ctx = NULL;
159 +       int res;
160 +#else
161         const char      *name = dentry->d_name.name;
162         int             namelen = dentry->d_name.len;
163 +#endif
164         struct buffer_head *bh2;
165         struct dx_root  *root;
166         struct dx_frame frames[2], *frame;
167 @@ -1770,7 +1814,13 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry,
168         struct dx_hash_info hinfo;
169         ext4_lblk_t  block;
170         struct fake_dirent *fde;
171 -       int             csum_size = 0;
172 +       int csum_size = 0;
174 +#ifdef CONFIG_EXT4_FS_ENCRYPTION
175 +       ctx = ext4_get_fname_crypto_ctx(dir, EXT4_NAME_LEN);
176 +       if (IS_ERR(ctx))
177 +               return PTR_ERR(ctx);
178 +#endif
180         if (ext4_has_metadata_csum(inode->i_sb))
181                 csum_size = sizeof(struct ext4_dir_entry_tail);
182 @@ -1837,7 +1887,18 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry,
183         if (hinfo.hash_version <= DX_HASH_TEA)
184                 hinfo.hash_version += EXT4_SB(dir->i_sb)->s_hash_unsigned;
185         hinfo.seed = EXT4_SB(dir->i_sb)->s_hash_seed;
186 +#ifdef CONFIG_EXT4_FS_ENCRYPTION
187 +       res = ext4_fname_usr_to_hash(ctx, &dentry->d_name, &hinfo);
188 +       if (res < 0) {
189 +               ext4_put_fname_crypto_ctx(&ctx);
190 +               ext4_mark_inode_dirty(handle, dir);
191 +               brelse(bh);
192 +               return res;
193 +       }
194 +       ext4_put_fname_crypto_ctx(&ctx);
195 +#else
196         ext4fs_dirhash(name, namelen, &hinfo);
197 +#endif
198         memset(frames, 0, sizeof(frames));
199         frame = frames;
200         frame->entries = entries;