Clean up whitespace and fixed a bug in the context inheritance error path
[ext4-patch-queue.git] / filename-encryption-modifications-1
blobab99d262c05533ffbb458966663153f283ea47a7
1 ext4 crypto: filename encryption modifications
3 From: Michael Halcrow <mhalcrow@google.com>
5 Modifies htree_dirblock_to_tree, dx_make_map, ext4_match search_dir,
6 and ext4_find_dest_de to support fname crypto.  Filename encryption
7 feature is not yet enabled at this patch.
9 Signed-off-by: Uday Savagaonkar <savagaon@google.com>
10 Signed-off-by: Ildar Muslukhov <ildarm@google.com>
11 Signed-off-by: Michael Halcrow <mhalcrow@google.com>
12 Signed-off-by: Theodore Ts'o <tytso@mit.edu>
13 ---
14  fs/ext4/namei.c | 248 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------
15  1 file changed, 204 insertions(+), 44 deletions(-)
17 diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
18 index 8fcda60..671f878 100644
19 --- a/fs/ext4/namei.c
20 +++ b/fs/ext4/namei.c
21 @@ -256,8 +256,9 @@ static struct dx_frame *dx_probe(const struct qstr *d_name,
22                                  struct dx_hash_info *hinfo,
23                                  struct dx_frame *frame);
24  static void dx_release(struct dx_frame *frames);
25 -static int dx_make_map(struct ext4_dir_entry_2 *de, unsigned blocksize,
26 -                      struct dx_hash_info *hinfo, struct dx_map_entry map[]);
27 +static int dx_make_map(struct inode *dir, struct ext4_dir_entry_2 *de,
28 +                      unsigned blocksize, struct dx_hash_info *hinfo,
29 +                      struct dx_map_entry map[]);
30  static void dx_sort_map(struct dx_map_entry *map, unsigned count);
31  static struct ext4_dir_entry_2 *dx_move_dirents(char *from, char *to,
32                 struct dx_map_entry *offsets, int count, unsigned blocksize);
33 @@ -971,7 +972,8 @@ static int htree_dirblock_to_tree(struct file *dir_file,
34         struct buffer_head *bh;
35         struct ext4_dir_entry_2 *de, *top;
36         int err = 0, count = 0;
37 -       struct ext4_str tmp_str;
38 +       struct ext4_fname_crypto_ctx *ctx = NULL;
39 +       struct ext4_str fname_crypto_str = {.name = NULL, .len = 0}, tmp_str;
41         dxtrace(printk(KERN_INFO "In htree dirblock_to_tree: block %lu\n",
42                                                         (unsigned long)block));
43 @@ -983,6 +985,24 @@ static int htree_dirblock_to_tree(struct file *dir_file,
44         top = (struct ext4_dir_entry_2 *) ((char *) de +
45                                            dir->i_sb->s_blocksize -
46                                            EXT4_DIR_REC_LEN(0));
47 +#ifdef CONFIG_EXT4_FS_ENCRYPTION
48 +       /* Check if the directory is encrypted */
49 +       ctx = ext4_get_fname_crypto_ctx(dir, EXT4_NAME_LEN);
50 +       if (IS_ERR(ctx)) {
51 +               err = PTR_ERR(ctx);
52 +               brelse(bh);
53 +               return err;
54 +       }
55 +       if (ctx != NULL) {
56 +               err = ext4_fname_crypto_alloc_buffer(ctx, EXT4_NAME_LEN,
57 +                                                    &fname_crypto_str);
58 +               if (err < 0) {
59 +                       ext4_put_fname_crypto_ctx(&ctx);
60 +                       brelse(bh);
61 +                       return err;
62 +               }
63 +       }
64 +#endif
65         for (; de < top; de = ext4_next_entry(de, dir->i_sb->s_blocksize)) {
66                 if (ext4_check_dir_entry(dir, NULL, de, bh,
67                                 bh->b_data, bh->b_size,
68 @@ -991,24 +1011,52 @@ static int htree_dirblock_to_tree(struct file *dir_file,
69                         /* silently ignore the rest of the block */
70                         break;
71                 }
72 +#ifdef CONFIG_EXT4_FS_ENCRYPTION
73 +               err = ext4_fname_disk_to_hash(ctx, de, hinfo);
74 +               if (err < 0) {
75 +                       count = err;
76 +                       goto errout;
77 +               }
78 +#else
79                 ext4fs_dirhash(de->name, de->name_len, hinfo);
80 +#endif
81                 if ((hinfo->hash < start_hash) ||
82                     ((hinfo->hash == start_hash) &&
83                      (hinfo->minor_hash < start_minor_hash)))
84                         continue;
85                 if (de->inode == 0)
86                         continue;
87 -               tmp_str.name = de->name;
88 -               tmp_str.len = de->name_len;
89 -               err = ext4_htree_store_dirent(dir_file,
90 -                          hinfo->hash, hinfo->minor_hash, de, &tmp_str);
91 +               if (ctx == NULL) {
92 +                       /* Directory is not encrypted */
93 +                       tmp_str.name = de->name;
94 +                       tmp_str.len = de->name_len;
95 +                       err = ext4_htree_store_dirent(dir_file,
96 +                                  hinfo->hash, hinfo->minor_hash, de,
97 +                                  &tmp_str);
98 +               } else {
99 +                       /* Directory is encrypted */
100 +                       err = ext4_fname_disk_to_usr(ctx, de,
101 +                                                    &fname_crypto_str);
102 +                       if (err < 0) {
103 +                               count = err;
104 +                               goto errout;
105 +                       }
106 +                       err = ext4_htree_store_dirent(dir_file,
107 +                                  hinfo->hash, hinfo->minor_hash, de,
108 +                                       &fname_crypto_str);
109 +               }
110                 if (err != 0) {
111 -                       brelse(bh);
112 -                       return err;
113 +                       count = err;
114 +                       goto errout;
115                 }
116                 count++;
117         }
118 +errout:
119         brelse(bh);
120 +#ifdef CONFIG_EXT4_FS_ENCRYPTION
121 +       ext4_put_fname_crypto_ctx(&ctx);
122 +       ext4_fname_crypto_free_buffer(&fname_crypto_str);
123 +#endif
124         return count;
127 @@ -1141,17 +1189,33 @@ static inline int search_dirblock(struct buffer_head *bh,
128   * Create map of hash values, offsets, and sizes, stored at end of block.
129   * Returns number of entries mapped.
130   */
131 -static int dx_make_map(struct ext4_dir_entry_2 *de, unsigned blocksize,
132 -                      struct dx_hash_info *hinfo,
133 +static int dx_make_map(struct inode *dir, struct ext4_dir_entry_2 *de,
134 +                      unsigned blocksize, struct dx_hash_info *hinfo,
135                        struct dx_map_entry *map_tail)
137         int count = 0;
138         char *base = (char *) de;
139         struct dx_hash_info h = *hinfo;
140 +#ifdef CONFIG_EXT4_FS_ENCRYPTION
141 +       struct ext4_fname_crypto_ctx *ctx = NULL;
142 +       int err;
144 +       ctx = ext4_get_fname_crypto_ctx(dir, EXT4_NAME_LEN);
145 +       if (IS_ERR(ctx))
146 +               return PTR_ERR(ctx);
147 +#endif
149         while ((char *) de < base + blocksize) {
150                 if (de->name_len && de->inode) {
151 +#ifdef CONFIG_EXT4_FS_ENCRYPTION
152 +                       err = ext4_fname_disk_to_hash(ctx, de, &h);
153 +                       if (err < 0) {
154 +                               ext4_put_fname_crypto_ctx(&ctx);
155 +                               return err;
156 +                       }
157 +#else
158                         ext4fs_dirhash(de->name, de->name_len, &h);
159 +#endif
160                         map_tail--;
161                         map_tail->hash = h.hash;
162                         map_tail->offs = ((char *) de - base)>>2;
163 @@ -1162,6 +1226,9 @@ static int dx_make_map(struct ext4_dir_entry_2 *de, unsigned blocksize,
164                 /* XXX: do we need to check rec_len == 0 case? -Chris */
165                 de = ext4_next_entry(de, blocksize);
166         }
167 +#ifdef CONFIG_EXT4_FS_ENCRYPTION
168 +       ext4_put_fname_crypto_ctx(&ctx);
169 +#endif
170         return count;
173 @@ -1212,57 +1279,107 @@ static void dx_insert_block(struct dx_frame *frame, u32 hash, ext4_lblk_t block)
174   * `len <= EXT4_NAME_LEN' is guaranteed by caller.
175   * `de != NULL' is guaranteed by caller.
176   */
177 -static inline int ext4_match (int len, const char * const name,
178 -                             struct ext4_dir_entry_2 * de)
179 +static inline int ext4_match(struct ext4_fname_crypto_ctx *ctx,
180 +                            struct ext4_str *fname_crypto_str,
181 +                            int len, const char * const name,
182 +                            struct ext4_dir_entry_2 *de)
184 -       if (len != de->name_len)
185 -               return 0;
186 +       int res;
188         if (!de->inode)
189                 return 0;
190 -       return !memcmp(name, de->name, len);
192 +#ifdef CONFIG_EXT4_FS_ENCRYPTION
193 +       if (ctx) {
194 +               /* Directory is encrypted */
195 +               res = ext4_fname_disk_to_usr(ctx, de, fname_crypto_str);
196 +               if (res < 0)
197 +                       return res;
198 +               if (len != res)
199 +                       return 0;
200 +               res = memcmp(name, fname_crypto_str->name, len);
201 +               return (res == 0) ? 1 : 0;
202 +       }
203 +#endif
204 +       if (len != de->name_len)
205 +               return 0;
206 +       res = memcmp(name, de->name, len);
207 +       return (res == 0) ? 1 : 0;
210  /*
211   * Returns 0 if not found, -1 on failure, and 1 on success
212   */
213 -int search_dir(struct buffer_head *bh,
214 -              char *search_buf,
215 -              int buf_size,
216 -              struct inode *dir,
217 -              const struct qstr *d_name,
218 -              unsigned int offset,
219 -              struct ext4_dir_entry_2 **res_dir)
220 +int search_dir(struct buffer_head *bh, char *search_buf, int buf_size,
221 +              struct inode *dir, const struct qstr *d_name,
222 +              unsigned int offset, struct ext4_dir_entry_2 **res_dir)
224         struct ext4_dir_entry_2 * de;
225         char * dlimit;
226         int de_len;
227         const char *name = d_name->name;
228         int namelen = d_name->len;
229 +       struct ext4_fname_crypto_ctx *ctx = NULL;
230 +       struct ext4_str fname_crypto_str = {.name = NULL, .len = 0};
231 +       int res;
233 +       ctx = ext4_get_fname_crypto_ctx(dir, EXT4_NAME_LEN);
234 +       if (IS_ERR(ctx))
235 +               return -1;
237 +       if (ctx != NULL) {
238 +               /* Allocate buffer to hold maximum name length */
239 +               res = ext4_fname_crypto_alloc_buffer(ctx, EXT4_NAME_LEN,
240 +                                                    &fname_crypto_str);
241 +               if (res < 0) {
242 +                       ext4_put_fname_crypto_ctx(&ctx);
243 +                       return -1;
244 +               }
245 +       }
247         de = (struct ext4_dir_entry_2 *)search_buf;
248         dlimit = search_buf + buf_size;
249         while ((char *) de < dlimit) {
250                 /* this code is executed quadratically often */
251                 /* do minimal checking `by hand' */
252 +               if ((char *) de + de->name_len <= dlimit) {
253 +                       res = ext4_match(ctx, &fname_crypto_str, namelen,
254 +                                        name, de);
255 +                       if (res < 0) {
256 +                               res = -1;
257 +                               goto return_result;
258 +                       }
259 +                       if (res > 0) {
260 +                               /* found a match - just to be sure, do
261 +                                * a full check */
262 +                               if (ext4_check_dir_entry(dir, NULL, de, bh,
263 +                                               bh->b_data,
264 +                                                bh->b_size, offset)) {
265 +                                       res = -1;
266 +                                       goto return_result;
267 +                               }
268 +                               *res_dir = de;
269 +                               res = 1;
270 +                               goto return_result;
271 +                       }
273 -               if ((char *) de + namelen <= dlimit &&
274 -                   ext4_match (namelen, name, de)) {
275 -                       /* found a match - just to be sure, do a full check */
276 -                       if (ext4_check_dir_entry(dir, NULL, de, bh, bh->b_data,
277 -                                                bh->b_size, offset))
278 -                               return -1;
279 -                       *res_dir = de;
280 -                       return 1;
281                 }
282                 /* prevent looping on a bad block */
283                 de_len = ext4_rec_len_from_disk(de->rec_len,
284                                                 dir->i_sb->s_blocksize);
285 -               if (de_len <= 0)
286 -                       return -1;
287 +               if (de_len <= 0) {
288 +                       res = -1;
289 +                       goto return_result;
290 +               }
291                 offset += de_len;
292                 de = (struct ext4_dir_entry_2 *) ((char *) de + de_len);
293         }
294 -       return 0;
296 +       res = 0;
297 +return_result:
298 +       ext4_put_fname_crypto_ctx(&ctx);
299 +       ext4_fname_crypto_free_buffer(&fname_crypto_str);
300 +       return res;
303  static int is_dx_internal_node(struct inode *dir, ext4_lblk_t block,
304 @@ -1451,6 +1568,9 @@ static struct buffer_head * ext4_dx_find_entry(struct inode *dir, const struct q
305         ext4_lblk_t block;
306         int retval;
308 +#ifdef CONFIG_EXT4_FS_ENCRYPTION
309 +       *res_dir = NULL;
310 +#endif
311         frame = dx_probe(d_name, dir, &hinfo, frames);
312         if (IS_ERR(frame))
313                 return (struct buffer_head *) frame;
314 @@ -1654,7 +1774,7 @@ static struct ext4_dir_entry_2 *do_split(handle_t *handle, struct inode *dir,
316         /* create map in the end of data2 block */
317         map = (struct dx_map_entry *) (data2 + blocksize);
318 -       count = dx_make_map((struct ext4_dir_entry_2 *) data1,
319 +       count = dx_make_map(dir, (struct ext4_dir_entry_2 *) data1,
320                              blocksize, hinfo, map);
321         map -= count;
322         dx_sort_map(map, count);
323 @@ -1677,7 +1797,8 @@ static struct ext4_dir_entry_2 *do_split(handle_t *handle, struct inode *dir,
324                                         hash2, split, count-split));
326         /* Fancy dance to stay within two buffers */
327 -       de2 = dx_move_dirents(data1, data2, map + split, count - split, blocksize);
328 +       de2 = dx_move_dirents(data1, data2, map + split, count - split,
329 +                             blocksize);
330         de = dx_pack_dirents(data1, blocksize);
331         de->rec_len = ext4_rec_len_to_disk(data1 + (blocksize - csum_size) -
332                                            (char *) de,
333 @@ -1733,15 +1854,48 @@ int ext4_find_dest_de(struct inode *dir, struct inode *inode,
334         int nlen, rlen;
335         unsigned int offset = 0;
336         char *top;
337 +       struct ext4_fname_crypto_ctx *ctx = NULL;
338 +       struct ext4_str fname_crypto_str = {.name = NULL, .len = 0};
339 +       int res;
341 +       ctx = ext4_get_fname_crypto_ctx(dir, EXT4_NAME_LEN);
342 +       if (IS_ERR(ctx))
343 +               return -1;
345 +       if (ctx != NULL) {
346 +               /* Calculate record length needed to store the entry */
347 +               res = ext4_fname_crypto_namelen_on_disk(ctx, namelen);
348 +               if (res < 0) {
349 +                       ext4_put_fname_crypto_ctx(&ctx);
350 +                       return res;
351 +               }
352 +               reclen = EXT4_DIR_REC_LEN(res);
354 +               /* Allocate buffer to hold maximum name length */
355 +               res = ext4_fname_crypto_alloc_buffer(ctx, EXT4_NAME_LEN,
356 +                                                    &fname_crypto_str);
357 +               if (res < 0) {
358 +                       ext4_put_fname_crypto_ctx(&ctx);
359 +                       return -1;
360 +               }
361 +       }
363         de = (struct ext4_dir_entry_2 *)buf;
364         top = buf + buf_size - reclen;
365         while ((char *) de <= top) {
366                 if (ext4_check_dir_entry(dir, NULL, de, bh,
367 -                                        buf, buf_size, offset))
368 -                       return -EIO;
369 -               if (ext4_match(namelen, name, de))
370 -                       return -EEXIST;
371 +                                        buf, buf_size, offset)) {
372 +                       res = -EIO;
373 +                       goto return_result;
374 +               }
375 +               /* Provide crypto context and crypto buffer to ext4 match */
376 +               res = ext4_match(ctx, &fname_crypto_str, namelen, name, de);
377 +               if (res < 0)
378 +                       goto return_result;
379 +               if (res > 0) {
380 +                       res = -EEXIST;
381 +                       goto return_result;
382 +               }
383                 nlen = EXT4_DIR_REC_LEN(de->name_len);
384                 rlen = ext4_rec_len_from_disk(de->rec_len, buf_size);
385                 if ((de->inode ? rlen - nlen : rlen) >= reclen)
386 @@ -1749,11 +1903,17 @@ int ext4_find_dest_de(struct inode *dir, struct inode *inode,
387                 de = (struct ext4_dir_entry_2 *)((char *)de + rlen);
388                 offset += rlen;
389         }
390 -       if ((char *) de > top)
391 -               return -ENOSPC;
393 -       *dest_de = de;
394 -       return 0;
395 +       if ((char *) de > top)
396 +               res = -ENOSPC;
397 +       else {
398 +               *dest_de = de;
399 +               res = 0;
400 +       }
401 +return_result:
402 +       ext4_put_fname_crypto_ctx(&ctx);
403 +       ext4_fname_crypto_free_buffer(&fname_crypto_str);
404 +       return res;
407  int ext4_insert_dentry(struct inode *dir,