]>
Commit | Line | Data |
---|---|---|
d5d0e8c7 MH |
1 | /* |
2 | * linux/fs/ext4/crypto_fname.c | |
3 | * | |
4 | * Copyright (C) 2015, Google, Inc. | |
5 | * | |
6 | * This contains functions for filename crypto management in ext4 | |
7 | * | |
8 | * Written by Uday Savagaonkar, 2014. | |
9 | * | |
10 | * This has not yet undergone a rigorous security audit. | |
11 | * | |
12 | */ | |
13 | ||
14 | #include <crypto/hash.h> | |
15 | #include <crypto/sha.h> | |
16 | #include <keys/encrypted-type.h> | |
17 | #include <keys/user-type.h> | |
18 | #include <linux/crypto.h> | |
19 | #include <linux/gfp.h> | |
20 | #include <linux/kernel.h> | |
21 | #include <linux/key.h> | |
22 | #include <linux/key.h> | |
23 | #include <linux/list.h> | |
24 | #include <linux/mempool.h> | |
25 | #include <linux/random.h> | |
26 | #include <linux/scatterlist.h> | |
27 | #include <linux/spinlock_types.h> | |
28 | ||
29 | #include "ext4.h" | |
30 | #include "ext4_crypto.h" | |
31 | #include "xattr.h" | |
32 | ||
33 | /** | |
34 | * ext4_dir_crypt_complete() - | |
35 | */ | |
36 | static void ext4_dir_crypt_complete(struct crypto_async_request *req, int res) | |
37 | { | |
38 | struct ext4_completion_result *ecr = req->data; | |
39 | ||
40 | if (res == -EINPROGRESS) | |
41 | return; | |
42 | ecr->res = res; | |
43 | complete(&ecr->completion); | |
44 | } | |
45 | ||
46 | bool ext4_valid_filenames_enc_mode(uint32_t mode) | |
47 | { | |
48 | return (mode == EXT4_ENCRYPTION_MODE_AES_256_CTS); | |
49 | } | |
50 | ||
51 | /** | |
52 | * ext4_fname_encrypt() - | |
53 | * | |
54 | * This function encrypts the input filename, and returns the length of the | |
55 | * ciphertext. Errors are returned as negative numbers. We trust the caller to | |
56 | * allocate sufficient memory to oname string. | |
57 | */ | |
58 | static int ext4_fname_encrypt(struct ext4_fname_crypto_ctx *ctx, | |
59 | const struct qstr *iname, | |
60 | struct ext4_str *oname) | |
61 | { | |
62 | u32 ciphertext_len; | |
63 | struct ablkcipher_request *req = NULL; | |
64 | DECLARE_EXT4_COMPLETION_RESULT(ecr); | |
65 | struct crypto_ablkcipher *tfm = ctx->ctfm; | |
66 | int res = 0; | |
67 | char iv[EXT4_CRYPTO_BLOCK_SIZE]; | |
68 | struct scatterlist sg[1]; | |
69 | char *workbuf; | |
70 | ||
71 | if (iname->len <= 0 || iname->len > ctx->lim) | |
72 | return -EIO; | |
73 | ||
74 | ciphertext_len = (iname->len < EXT4_CRYPTO_BLOCK_SIZE) ? | |
75 | EXT4_CRYPTO_BLOCK_SIZE : iname->len; | |
76 | ciphertext_len = (ciphertext_len > ctx->lim) | |
77 | ? ctx->lim : ciphertext_len; | |
78 | ||
79 | /* Allocate request */ | |
80 | req = ablkcipher_request_alloc(tfm, GFP_NOFS); | |
81 | if (!req) { | |
82 | printk_ratelimited( | |
83 | KERN_ERR "%s: crypto_request_alloc() failed\n", __func__); | |
84 | return -ENOMEM; | |
85 | } | |
86 | ablkcipher_request_set_callback(req, | |
87 | CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, | |
88 | ext4_dir_crypt_complete, &ecr); | |
89 | ||
90 | /* Map the workpage */ | |
91 | workbuf = kmap(ctx->workpage); | |
92 | ||
93 | /* Copy the input */ | |
94 | memcpy(workbuf, iname->name, iname->len); | |
95 | if (iname->len < ciphertext_len) | |
96 | memset(workbuf + iname->len, 0, ciphertext_len - iname->len); | |
97 | ||
98 | /* Initialize IV */ | |
99 | memset(iv, 0, EXT4_CRYPTO_BLOCK_SIZE); | |
100 | ||
101 | /* Create encryption request */ | |
102 | sg_init_table(sg, 1); | |
103 | sg_set_page(sg, ctx->workpage, PAGE_SIZE, 0); | |
104 | ablkcipher_request_set_crypt(req, sg, sg, iname->len, iv); | |
105 | res = crypto_ablkcipher_encrypt(req); | |
106 | if (res == -EINPROGRESS || res == -EBUSY) { | |
107 | BUG_ON(req->base.data != &ecr); | |
108 | wait_for_completion(&ecr.completion); | |
109 | res = ecr.res; | |
110 | } | |
111 | if (res >= 0) { | |
112 | /* Copy the result to output */ | |
113 | memcpy(oname->name, workbuf, ciphertext_len); | |
114 | res = ciphertext_len; | |
115 | } | |
116 | kunmap(ctx->workpage); | |
117 | ablkcipher_request_free(req); | |
118 | if (res < 0) { | |
119 | printk_ratelimited( | |
120 | KERN_ERR "%s: Error (error code %d)\n", __func__, res); | |
121 | } | |
122 | oname->len = ciphertext_len; | |
123 | return res; | |
124 | } | |
125 | ||
126 | /* | |
127 | * ext4_fname_decrypt() | |
128 | * This function decrypts the input filename, and returns | |
129 | * the length of the plaintext. | |
130 | * Errors are returned as negative numbers. | |
131 | * We trust the caller to allocate sufficient memory to oname string. | |
132 | */ | |
133 | static int ext4_fname_decrypt(struct ext4_fname_crypto_ctx *ctx, | |
134 | const struct ext4_str *iname, | |
135 | struct ext4_str *oname) | |
136 | { | |
137 | struct ext4_str tmp_in[2], tmp_out[1]; | |
138 | struct ablkcipher_request *req = NULL; | |
139 | DECLARE_EXT4_COMPLETION_RESULT(ecr); | |
140 | struct scatterlist sg[1]; | |
141 | struct crypto_ablkcipher *tfm = ctx->ctfm; | |
142 | int res = 0; | |
143 | char iv[EXT4_CRYPTO_BLOCK_SIZE]; | |
144 | char *workbuf; | |
145 | ||
146 | if (iname->len <= 0 || iname->len > ctx->lim) | |
147 | return -EIO; | |
148 | ||
149 | tmp_in[0].name = iname->name; | |
150 | tmp_in[0].len = iname->len; | |
151 | tmp_out[0].name = oname->name; | |
152 | ||
153 | /* Allocate request */ | |
154 | req = ablkcipher_request_alloc(tfm, GFP_NOFS); | |
155 | if (!req) { | |
156 | printk_ratelimited( | |
157 | KERN_ERR "%s: crypto_request_alloc() failed\n", __func__); | |
158 | return -ENOMEM; | |
159 | } | |
160 | ablkcipher_request_set_callback(req, | |
161 | CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, | |
162 | ext4_dir_crypt_complete, &ecr); | |
163 | ||
164 | /* Map the workpage */ | |
165 | workbuf = kmap(ctx->workpage); | |
166 | ||
167 | /* Copy the input */ | |
168 | memcpy(workbuf, iname->name, iname->len); | |
169 | ||
170 | /* Initialize IV */ | |
171 | memset(iv, 0, EXT4_CRYPTO_BLOCK_SIZE); | |
172 | ||
173 | /* Create encryption request */ | |
174 | sg_init_table(sg, 1); | |
175 | sg_set_page(sg, ctx->workpage, PAGE_SIZE, 0); | |
176 | ablkcipher_request_set_crypt(req, sg, sg, iname->len, iv); | |
177 | res = crypto_ablkcipher_decrypt(req); | |
178 | if (res == -EINPROGRESS || res == -EBUSY) { | |
179 | BUG_ON(req->base.data != &ecr); | |
180 | wait_for_completion(&ecr.completion); | |
181 | res = ecr.res; | |
182 | } | |
183 | if (res >= 0) { | |
184 | /* Copy the result to output */ | |
185 | memcpy(oname->name, workbuf, iname->len); | |
186 | res = iname->len; | |
187 | } | |
188 | kunmap(ctx->workpage); | |
189 | ablkcipher_request_free(req); | |
190 | if (res < 0) { | |
191 | printk_ratelimited( | |
192 | KERN_ERR "%s: Error in ext4_fname_encrypt (error code %d)\n", | |
193 | __func__, res); | |
194 | return res; | |
195 | } | |
196 | ||
197 | oname->len = strnlen(oname->name, iname->len); | |
198 | return oname->len; | |
199 | } | |
200 | ||
201 | /** | |
202 | * ext4_fname_encode_digest() - | |
203 | * | |
204 | * Encodes the input digest using characters from the set [a-zA-Z0-9_+]. | |
205 | * The encoded string is roughly 4/3 times the size of the input string. | |
206 | */ | |
207 | int ext4_fname_encode_digest(char *dst, char *src, u32 len) | |
208 | { | |
209 | static const char *lookup_table = | |
210 | "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_+"; | |
211 | u32 current_chunk, num_chunks, i; | |
212 | char tmp_buf[3]; | |
213 | u32 c0, c1, c2, c3; | |
214 | ||
215 | current_chunk = 0; | |
216 | num_chunks = len/3; | |
217 | for (i = 0; i < num_chunks; i++) { | |
218 | c0 = src[3*i] & 0x3f; | |
219 | c1 = (((src[3*i]>>6)&0x3) | ((src[3*i+1] & 0xf)<<2)) & 0x3f; | |
220 | c2 = (((src[3*i+1]>>4)&0xf) | ((src[3*i+2] & 0x3)<<4)) & 0x3f; | |
221 | c3 = (src[3*i+2]>>2) & 0x3f; | |
222 | dst[4*i] = lookup_table[c0]; | |
223 | dst[4*i+1] = lookup_table[c1]; | |
224 | dst[4*i+2] = lookup_table[c2]; | |
225 | dst[4*i+3] = lookup_table[c3]; | |
226 | } | |
227 | if (i*3 < len) { | |
228 | memset(tmp_buf, 0, 3); | |
229 | memcpy(tmp_buf, &src[3*i], len-3*i); | |
230 | c0 = tmp_buf[0] & 0x3f; | |
231 | c1 = (((tmp_buf[0]>>6)&0x3) | ((tmp_buf[1] & 0xf)<<2)) & 0x3f; | |
232 | c2 = (((tmp_buf[1]>>4)&0xf) | ((tmp_buf[2] & 0x3)<<4)) & 0x3f; | |
233 | c3 = (tmp_buf[2]>>2) & 0x3f; | |
234 | dst[4*i] = lookup_table[c0]; | |
235 | dst[4*i+1] = lookup_table[c1]; | |
236 | dst[4*i+2] = lookup_table[c2]; | |
237 | dst[4*i+3] = lookup_table[c3]; | |
238 | i++; | |
239 | } | |
240 | return (i * 4); | |
241 | } | |
242 | ||
243 | /** | |
244 | * ext4_fname_hash() - | |
245 | * | |
246 | * This function computes the hash of the input filename, and sets the output | |
247 | * buffer to the *encoded* digest. It returns the length of the digest as its | |
248 | * return value. Errors are returned as negative numbers. We trust the caller | |
249 | * to allocate sufficient memory to oname string. | |
250 | */ | |
251 | static int ext4_fname_hash(struct ext4_fname_crypto_ctx *ctx, | |
252 | const struct ext4_str *iname, | |
253 | struct ext4_str *oname) | |
254 | { | |
255 | struct scatterlist sg; | |
256 | struct hash_desc desc = { | |
257 | .tfm = (struct crypto_hash *)ctx->htfm, | |
258 | .flags = CRYPTO_TFM_REQ_MAY_SLEEP | |
259 | }; | |
260 | int res = 0; | |
261 | ||
262 | if (iname->len <= EXT4_FNAME_CRYPTO_DIGEST_SIZE) { | |
263 | res = ext4_fname_encode_digest(oname->name, iname->name, | |
264 | iname->len); | |
265 | oname->len = res; | |
266 | return res; | |
267 | } | |
268 | ||
269 | sg_init_one(&sg, iname->name, iname->len); | |
270 | res = crypto_hash_init(&desc); | |
271 | if (res) { | |
272 | printk(KERN_ERR | |
273 | "%s: Error initializing crypto hash; res = [%d]\n", | |
274 | __func__, res); | |
275 | goto out; | |
276 | } | |
277 | res = crypto_hash_update(&desc, &sg, iname->len); | |
278 | if (res) { | |
279 | printk(KERN_ERR | |
280 | "%s: Error updating crypto hash; res = [%d]\n", | |
281 | __func__, res); | |
282 | goto out; | |
283 | } | |
284 | res = crypto_hash_final(&desc, | |
285 | &oname->name[EXT4_FNAME_CRYPTO_DIGEST_SIZE]); | |
286 | if (res) { | |
287 | printk(KERN_ERR | |
288 | "%s: Error finalizing crypto hash; res = [%d]\n", | |
289 | __func__, res); | |
290 | goto out; | |
291 | } | |
292 | /* Encode the digest as a printable string--this will increase the | |
293 | * size of the digest */ | |
294 | oname->name[0] = 'I'; | |
295 | res = ext4_fname_encode_digest(oname->name+1, | |
296 | &oname->name[EXT4_FNAME_CRYPTO_DIGEST_SIZE], | |
297 | EXT4_FNAME_CRYPTO_DIGEST_SIZE) + 1; | |
298 | oname->len = res; | |
299 | out: | |
300 | return res; | |
301 | } | |
302 | ||
303 | /** | |
304 | * ext4_free_fname_crypto_ctx() - | |
305 | * | |
306 | * Frees up a crypto context. | |
307 | */ | |
308 | void ext4_free_fname_crypto_ctx(struct ext4_fname_crypto_ctx *ctx) | |
309 | { | |
310 | if (ctx == NULL || IS_ERR(ctx)) | |
311 | return; | |
312 | ||
313 | if (ctx->ctfm && !IS_ERR(ctx->ctfm)) | |
314 | crypto_free_ablkcipher(ctx->ctfm); | |
315 | if (ctx->htfm && !IS_ERR(ctx->htfm)) | |
316 | crypto_free_hash(ctx->htfm); | |
317 | if (ctx->workpage && !IS_ERR(ctx->workpage)) | |
318 | __free_page(ctx->workpage); | |
319 | kfree(ctx); | |
320 | } | |
321 | ||
322 | /** | |
323 | * ext4_put_fname_crypto_ctx() - | |
324 | * | |
325 | * Return: The crypto context onto free list. If the free list is above a | |
326 | * threshold, completely frees up the context, and returns the memory. | |
327 | * | |
328 | * TODO: Currently we directly free the crypto context. Eventually we should | |
329 | * add code it to return to free list. Such an approach will increase | |
330 | * efficiency of directory lookup. | |
331 | */ | |
332 | void ext4_put_fname_crypto_ctx(struct ext4_fname_crypto_ctx **ctx) | |
333 | { | |
334 | if (*ctx == NULL || IS_ERR(*ctx)) | |
335 | return; | |
336 | ext4_free_fname_crypto_ctx(*ctx); | |
337 | *ctx = NULL; | |
338 | } | |
339 | ||
340 | /** | |
341 | * ext4_search_fname_crypto_ctx() - | |
342 | */ | |
343 | static struct ext4_fname_crypto_ctx *ext4_search_fname_crypto_ctx( | |
344 | const struct ext4_encryption_key *key) | |
345 | { | |
346 | return NULL; | |
347 | } | |
348 | ||
349 | /** | |
350 | * ext4_alloc_fname_crypto_ctx() - | |
351 | */ | |
352 | struct ext4_fname_crypto_ctx *ext4_alloc_fname_crypto_ctx( | |
353 | const struct ext4_encryption_key *key) | |
354 | { | |
355 | struct ext4_fname_crypto_ctx *ctx; | |
356 | ||
357 | ctx = kmalloc(sizeof(struct ext4_fname_crypto_ctx), GFP_NOFS); | |
358 | if (ctx == NULL) | |
359 | return ERR_PTR(-ENOMEM); | |
360 | if (key->mode == EXT4_ENCRYPTION_MODE_INVALID) { | |
361 | /* This will automatically set key mode to invalid | |
362 | * As enum for ENCRYPTION_MODE_INVALID is zero */ | |
363 | memset(&ctx->key, 0, sizeof(ctx->key)); | |
364 | } else { | |
365 | memcpy(&ctx->key, key, sizeof(struct ext4_encryption_key)); | |
366 | } | |
367 | ctx->has_valid_key = (EXT4_ENCRYPTION_MODE_INVALID == key->mode) | |
368 | ? 0 : 1; | |
369 | ctx->ctfm_key_is_ready = 0; | |
370 | ctx->ctfm = NULL; | |
371 | ctx->htfm = NULL; | |
372 | ctx->workpage = NULL; | |
373 | return ctx; | |
374 | } | |
375 | ||
376 | /** | |
377 | * ext4_get_fname_crypto_ctx() - | |
378 | * | |
379 | * Allocates a free crypto context and initializes it to hold | |
380 | * the crypto material for the inode. | |
381 | * | |
382 | * Return: NULL if not encrypted. Error value on error. Valid pointer otherwise. | |
383 | */ | |
384 | struct ext4_fname_crypto_ctx *ext4_get_fname_crypto_ctx( | |
385 | struct inode *inode, u32 max_ciphertext_len) | |
386 | { | |
387 | struct ext4_fname_crypto_ctx *ctx; | |
388 | struct ext4_inode_info *ei = EXT4_I(inode); | |
389 | int res; | |
390 | ||
391 | /* Check if the crypto policy is set on the inode */ | |
392 | res = ext4_encrypted_inode(inode); | |
393 | if (res == 0) | |
394 | return NULL; | |
395 | ||
396 | if (!ext4_has_encryption_key(inode)) | |
397 | ext4_generate_encryption_key(inode); | |
398 | ||
399 | /* Get a crypto context based on the key. | |
400 | * A new context is allocated if no context matches the requested key. | |
401 | */ | |
402 | ctx = ext4_search_fname_crypto_ctx(&(ei->i_encryption_key)); | |
403 | if (ctx == NULL) | |
404 | ctx = ext4_alloc_fname_crypto_ctx(&(ei->i_encryption_key)); | |
405 | if (IS_ERR(ctx)) | |
406 | return ctx; | |
407 | ||
408 | if (ctx->has_valid_key) { | |
409 | if (ctx->key.mode != EXT4_ENCRYPTION_MODE_AES_256_CTS) { | |
410 | printk_once(KERN_WARNING | |
411 | "ext4: unsupported key mode %d\n", | |
412 | ctx->key.mode); | |
413 | return ERR_PTR(-ENOKEY); | |
414 | } | |
415 | ||
416 | /* As a first cut, we will allocate new tfm in every call. | |
417 | * later, we will keep the tfm around, in case the key gets | |
418 | * re-used */ | |
419 | if (ctx->ctfm == NULL) { | |
420 | ctx->ctfm = crypto_alloc_ablkcipher("cts(cbc(aes))", | |
421 | 0, 0); | |
422 | } | |
423 | if (IS_ERR(ctx->ctfm)) { | |
424 | res = PTR_ERR(ctx->ctfm); | |
425 | printk( | |
426 | KERN_DEBUG "%s: error (%d) allocating crypto tfm\n", | |
427 | __func__, res); | |
428 | ctx->ctfm = NULL; | |
429 | ext4_put_fname_crypto_ctx(&ctx); | |
430 | return ERR_PTR(res); | |
431 | } | |
432 | if (ctx->ctfm == NULL) { | |
433 | printk( | |
434 | KERN_DEBUG "%s: could not allocate crypto tfm\n", | |
435 | __func__); | |
436 | ext4_put_fname_crypto_ctx(&ctx); | |
437 | return ERR_PTR(-ENOMEM); | |
438 | } | |
439 | if (ctx->workpage == NULL) | |
440 | ctx->workpage = alloc_page(GFP_NOFS); | |
441 | if (IS_ERR(ctx->workpage)) { | |
442 | res = PTR_ERR(ctx->workpage); | |
443 | printk( | |
444 | KERN_DEBUG "%s: error (%d) allocating work page\n", | |
445 | __func__, res); | |
446 | ctx->workpage = NULL; | |
447 | ext4_put_fname_crypto_ctx(&ctx); | |
448 | return ERR_PTR(res); | |
449 | } | |
450 | if (ctx->workpage == NULL) { | |
451 | printk( | |
452 | KERN_DEBUG "%s: could not allocate work page\n", | |
453 | __func__); | |
454 | ext4_put_fname_crypto_ctx(&ctx); | |
455 | return ERR_PTR(-ENOMEM); | |
456 | } | |
457 | ctx->lim = max_ciphertext_len; | |
458 | crypto_ablkcipher_clear_flags(ctx->ctfm, ~0); | |
459 | crypto_tfm_set_flags(crypto_ablkcipher_tfm(ctx->ctfm), | |
460 | CRYPTO_TFM_REQ_WEAK_KEY); | |
461 | ||
462 | /* If we are lucky, we will get a context that is already | |
463 | * set up with the right key. Else, we will have to | |
464 | * set the key */ | |
465 | if (!ctx->ctfm_key_is_ready) { | |
466 | /* Since our crypto objectives for filename encryption | |
467 | * are pretty weak, | |
468 | * we directly use the inode master key */ | |
469 | res = crypto_ablkcipher_setkey(ctx->ctfm, | |
470 | ctx->key.raw, ctx->key.size); | |
471 | if (res) { | |
472 | ext4_put_fname_crypto_ctx(&ctx); | |
473 | return ERR_PTR(-EIO); | |
474 | } | |
475 | ctx->ctfm_key_is_ready = 1; | |
476 | } else { | |
477 | /* In the current implementation, key should never be | |
478 | * marked "ready" for a context that has just been | |
479 | * allocated. So we should never reach here */ | |
480 | BUG(); | |
481 | } | |
482 | } | |
483 | if (ctx->htfm == NULL) | |
484 | ctx->htfm = crypto_alloc_hash("sha256", 0, CRYPTO_ALG_ASYNC); | |
485 | if (IS_ERR(ctx->htfm)) { | |
486 | res = PTR_ERR(ctx->htfm); | |
487 | printk(KERN_DEBUG "%s: error (%d) allocating hash tfm\n", | |
488 | __func__, res); | |
489 | ctx->htfm = NULL; | |
490 | ext4_put_fname_crypto_ctx(&ctx); | |
491 | return ERR_PTR(res); | |
492 | } | |
493 | if (ctx->htfm == NULL) { | |
494 | printk(KERN_DEBUG "%s: could not allocate hash tfm\n", | |
495 | __func__); | |
496 | ext4_put_fname_crypto_ctx(&ctx); | |
497 | return ERR_PTR(-ENOMEM); | |
498 | } | |
499 | ||
500 | return ctx; | |
501 | } | |
502 | ||
503 | /** | |
504 | * ext4_fname_crypto_round_up() - | |
505 | * | |
506 | * Return: The next multiple of block size | |
507 | */ | |
508 | u32 ext4_fname_crypto_round_up(u32 size, u32 blksize) | |
509 | { | |
510 | return ((size+blksize-1)/blksize)*blksize; | |
511 | } | |
512 | ||
513 | /** | |
514 | * ext4_fname_crypto_namelen_on_disk() - | |
515 | */ | |
516 | int ext4_fname_crypto_namelen_on_disk(struct ext4_fname_crypto_ctx *ctx, | |
517 | u32 namelen) | |
518 | { | |
519 | u32 ciphertext_len; | |
520 | ||
521 | if (ctx == NULL) | |
522 | return -EIO; | |
523 | if (!(ctx->has_valid_key)) | |
524 | return -EACCES; | |
525 | ciphertext_len = (namelen < EXT4_CRYPTO_BLOCK_SIZE) ? | |
526 | EXT4_CRYPTO_BLOCK_SIZE : namelen; | |
527 | ciphertext_len = (ciphertext_len > ctx->lim) | |
528 | ? ctx->lim : ciphertext_len; | |
529 | return (int) ciphertext_len; | |
530 | } | |
531 | ||
532 | /** | |
533 | * ext4_fname_crypto_alloc_obuff() - | |
534 | * | |
535 | * Allocates an output buffer that is sufficient for the crypto operation | |
536 | * specified by the context and the direction. | |
537 | */ | |
538 | int ext4_fname_crypto_alloc_buffer(struct ext4_fname_crypto_ctx *ctx, | |
539 | u32 ilen, struct ext4_str *crypto_str) | |
540 | { | |
541 | unsigned int olen; | |
542 | ||
543 | if (!ctx) | |
544 | return -EIO; | |
545 | olen = ext4_fname_crypto_round_up(ilen, EXT4_CRYPTO_BLOCK_SIZE); | |
546 | crypto_str->len = olen; | |
547 | if (olen < EXT4_FNAME_CRYPTO_DIGEST_SIZE*2) | |
548 | olen = EXT4_FNAME_CRYPTO_DIGEST_SIZE*2; | |
549 | /* Allocated buffer can hold one more character to null-terminate the | |
550 | * string */ | |
551 | crypto_str->name = kmalloc(olen+1, GFP_NOFS); | |
552 | if (!(crypto_str->name)) | |
553 | return -ENOMEM; | |
554 | return 0; | |
555 | } | |
556 | ||
557 | /** | |
558 | * ext4_fname_crypto_free_buffer() - | |
559 | * | |
560 | * Frees the buffer allocated for crypto operation. | |
561 | */ | |
562 | void ext4_fname_crypto_free_buffer(struct ext4_str *crypto_str) | |
563 | { | |
564 | if (!crypto_str) | |
565 | return; | |
566 | kfree(crypto_str->name); | |
567 | crypto_str->name = NULL; | |
568 | } | |
569 | ||
570 | /** | |
571 | * ext4_fname_disk_to_usr() - converts a filename from disk space to user space | |
572 | */ | |
573 | int _ext4_fname_disk_to_usr(struct ext4_fname_crypto_ctx *ctx, | |
574 | const struct ext4_str *iname, | |
575 | struct ext4_str *oname) | |
576 | { | |
577 | if (ctx == NULL) | |
578 | return -EIO; | |
579 | if (iname->len < 3) { | |
580 | /*Check for . and .. */ | |
581 | if (iname->name[0] == '.' && iname->name[iname->len-1] == '.') { | |
582 | oname->name[0] = '.'; | |
583 | oname->name[iname->len-1] = '.'; | |
584 | oname->len = iname->len; | |
585 | return oname->len; | |
586 | } | |
587 | } | |
588 | if (ctx->has_valid_key) | |
589 | return ext4_fname_decrypt(ctx, iname, oname); | |
590 | else | |
591 | return ext4_fname_hash(ctx, iname, oname); | |
592 | } | |
593 | ||
594 | int ext4_fname_disk_to_usr(struct ext4_fname_crypto_ctx *ctx, | |
595 | const struct ext4_dir_entry_2 *de, | |
596 | struct ext4_str *oname) | |
597 | { | |
598 | struct ext4_str iname = {.name = (unsigned char *) de->name, | |
599 | .len = de->name_len }; | |
600 | ||
601 | return _ext4_fname_disk_to_usr(ctx, &iname, oname); | |
602 | } | |
603 | ||
604 | ||
605 | /** | |
606 | * ext4_fname_usr_to_disk() - converts a filename from user space to disk space | |
607 | */ | |
608 | int ext4_fname_usr_to_disk(struct ext4_fname_crypto_ctx *ctx, | |
609 | const struct qstr *iname, | |
610 | struct ext4_str *oname) | |
611 | { | |
612 | int res; | |
613 | ||
614 | if (ctx == NULL) | |
615 | return -EIO; | |
616 | if (iname->len < 3) { | |
617 | /*Check for . and .. */ | |
618 | if (iname->name[0] == '.' && | |
619 | iname->name[iname->len-1] == '.') { | |
620 | oname->name[0] = '.'; | |
621 | oname->name[iname->len-1] = '.'; | |
622 | oname->len = iname->len; | |
623 | return oname->len; | |
624 | } | |
625 | } | |
626 | if (ctx->has_valid_key) { | |
627 | res = ext4_fname_encrypt(ctx, iname, oname); | |
628 | return res; | |
629 | } | |
630 | /* Without a proper key, a user is not allowed to modify the filenames | |
631 | * in a directory. Consequently, a user space name cannot be mapped to | |
632 | * a disk-space name */ | |
633 | return -EACCES; | |
634 | } | |
635 | ||
636 | /* | |
637 | * Calculate the htree hash from a filename from user space | |
638 | */ | |
639 | int ext4_fname_usr_to_hash(struct ext4_fname_crypto_ctx *ctx, | |
640 | const struct qstr *iname, | |
641 | struct dx_hash_info *hinfo) | |
642 | { | |
643 | struct ext4_str tmp, tmp2; | |
644 | int ret = 0; | |
645 | ||
646 | if (!ctx || !ctx->has_valid_key || | |
647 | ((iname->name[0] == '.') && | |
648 | ((iname->len == 1) || | |
649 | ((iname->name[1] == '.') && (iname->len == 2))))) { | |
650 | ext4fs_dirhash(iname->name, iname->len, hinfo); | |
651 | return 0; | |
652 | } | |
653 | ||
654 | /* First encrypt the plaintext name */ | |
655 | ret = ext4_fname_crypto_alloc_buffer(ctx, iname->len, &tmp); | |
656 | if (ret < 0) | |
657 | return ret; | |
658 | ||
659 | ret = ext4_fname_encrypt(ctx, iname, &tmp); | |
660 | if (ret < 0) | |
661 | goto out; | |
662 | ||
663 | tmp2.len = (4 * ((EXT4_FNAME_CRYPTO_DIGEST_SIZE + 2) / 3)) + 1; | |
664 | tmp2.name = kmalloc(tmp2.len + 1, GFP_KERNEL); | |
665 | if (tmp2.name == NULL) { | |
666 | ret = -ENOMEM; | |
667 | goto out; | |
668 | } | |
669 | ||
670 | ret = ext4_fname_hash(ctx, &tmp, &tmp2); | |
671 | if (ret > 0) | |
672 | ext4fs_dirhash(tmp2.name, tmp2.len, hinfo); | |
673 | ext4_fname_crypto_free_buffer(&tmp2); | |
674 | out: | |
675 | ext4_fname_crypto_free_buffer(&tmp); | |
676 | return ret; | |
677 | } | |
678 | ||
679 | /** | |
680 | * ext4_fname_disk_to_htree() - converts a filename from disk space to htree-access string | |
681 | */ | |
682 | int ext4_fname_disk_to_hash(struct ext4_fname_crypto_ctx *ctx, | |
683 | const struct ext4_dir_entry_2 *de, | |
684 | struct dx_hash_info *hinfo) | |
685 | { | |
686 | struct ext4_str iname = {.name = (unsigned char *) de->name, | |
687 | .len = de->name_len}; | |
688 | struct ext4_str tmp; | |
689 | int ret; | |
690 | ||
691 | if (!ctx || | |
692 | ((iname.name[0] == '.') && | |
693 | ((iname.len == 1) || | |
694 | ((iname.name[1] == '.') && (iname.len == 2))))) { | |
695 | ext4fs_dirhash(iname.name, iname.len, hinfo); | |
696 | return 0; | |
697 | } | |
698 | ||
699 | tmp.len = (4 * ((EXT4_FNAME_CRYPTO_DIGEST_SIZE + 2) / 3)) + 1; | |
700 | tmp.name = kmalloc(tmp.len + 1, GFP_KERNEL); | |
701 | if (tmp.name == NULL) | |
702 | return -ENOMEM; | |
703 | ||
704 | ret = ext4_fname_hash(ctx, &iname, &tmp); | |
705 | if (ret > 0) | |
706 | ext4fs_dirhash(tmp.name, tmp.len, hinfo); | |
707 | ext4_fname_crypto_free_buffer(&tmp); | |
708 | return ret; | |
709 | } |