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>
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
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 -
47 +#ifdef CONFIG_EXT4_FS_ENCRYPTION
48 + /* Check if the directory is encrypted */
49 + ctx = ext4_get_fname_crypto_ctx(dir, EXT4_NAME_LEN);
56 + err = ext4_fname_crypto_alloc_buffer(ctx, EXT4_NAME_LEN,
59 + ext4_put_fname_crypto_ctx(&ctx);
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 */
72 +#ifdef CONFIG_EXT4_FS_ENCRYPTION
73 + err = ext4_fname_disk_to_hash(ctx, de, hinfo);
79 ext4fs_dirhash(de->name, de->name_len, hinfo);
81 if ((hinfo->hash < start_hash) ||
82 ((hinfo->hash == start_hash) &&
83 (hinfo->minor_hash < start_minor_hash)))
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);
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,
99 + /* Directory is encrypted */
100 + err = ext4_fname_disk_to_usr(ctx, de,
101 + &fname_crypto_str);
106 + err = ext4_htree_store_dirent(dir_file,
107 + hinfo->hash, hinfo->minor_hash, de,
108 + &fname_crypto_str);
120 +#ifdef CONFIG_EXT4_FS_ENCRYPTION
121 + ext4_put_fname_crypto_ctx(&ctx);
122 + ext4_fname_crypto_free_buffer(&fname_crypto_str);
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.
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)
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;
144 + ctx = ext4_get_fname_crypto_ctx(dir, EXT4_NAME_LEN);
146 + return PTR_ERR(ctx);
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);
154 + ext4_put_fname_crypto_ctx(&ctx);
158 ext4fs_dirhash(de->name, de->name_len, &h);
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);
167 +#ifdef CONFIG_EXT4_FS_ENCRYPTION
168 + ext4_put_fname_crypto_ctx(&ctx);
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.
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)
190 - return !memcmp(name, de->name, len);
192 +#ifdef CONFIG_EXT4_FS_ENCRYPTION
194 + /* Directory is encrypted */
195 + res = ext4_fname_disk_to_usr(ctx, de, fname_crypto_str);
200 + res = memcmp(name, fname_crypto_str->name, len);
201 + return (res == 0) ? 1 : 0;
204 + if (len != de->name_len)
206 + res = memcmp(name, de->name, len);
207 + return (res == 0) ? 1 : 0;
211 * Returns 0 if not found, -1 on failure, and 1 on success
213 -int search_dir(struct buffer_head *bh,
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;
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};
233 + ctx = ext4_get_fname_crypto_ctx(dir, EXT4_NAME_LEN);
238 + /* Allocate buffer to hold maximum name length */
239 + res = ext4_fname_crypto_alloc_buffer(ctx, EXT4_NAME_LEN,
240 + &fname_crypto_str);
242 + ext4_put_fname_crypto_ctx(&ctx);
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,
257 + goto return_result;
260 + /* found a match - just to be sure, do
262 + if (ext4_check_dir_entry(dir, NULL, de, bh,
264 + bh->b_size, offset)) {
266 + goto return_result;
270 + goto return_result;
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))
282 /* prevent looping on a bad block */
283 de_len = ext4_rec_len_from_disk(de->rec_len,
284 dir->i_sb->s_blocksize);
289 + goto return_result;
292 de = (struct ext4_dir_entry_2 *) ((char *) de + de_len);
298 + ext4_put_fname_crypto_ctx(&ctx);
299 + ext4_fname_crypto_free_buffer(&fname_crypto_str);
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
308 +#ifdef CONFIG_EXT4_FS_ENCRYPTION
311 frame = dx_probe(d_name, dir, &hinfo, frames);
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);
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,
330 de = dx_pack_dirents(data1, blocksize);
331 de->rec_len = ext4_rec_len_to_disk(data1 + (blocksize - csum_size) -
333 @@ -1733,15 +1854,48 @@ int ext4_find_dest_de(struct inode *dir, struct inode *inode,
335 unsigned int offset = 0;
337 + struct ext4_fname_crypto_ctx *ctx = NULL;
338 + struct ext4_str fname_crypto_str = {.name = NULL, .len = 0};
341 + ctx = ext4_get_fname_crypto_ctx(dir, EXT4_NAME_LEN);
346 + /* Calculate record length needed to store the entry */
347 + res = ext4_fname_crypto_namelen_on_disk(ctx, namelen);
349 + ext4_put_fname_crypto_ctx(&ctx);
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);
358 + ext4_put_fname_crypto_ctx(&ctx);
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))
369 - if (ext4_match(namelen, name, de))
371 + buf, buf_size, offset)) {
373 + goto return_result;
375 + /* Provide crypto context and crypto buffer to ext4 match */
376 + res = ext4_match(ctx, &fname_crypto_str, namelen, name, de);
378 + goto return_result;
381 + goto return_result;
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);
390 - if ((char *) de > top)
395 + if ((char *) de > top)
402 + ext4_put_fname_crypto_ctx(&ctx);
403 + ext4_fname_crypto_free_buffer(&fname_crypto_str);
407 int ext4_insert_dentry(struct inode *dir,