diff options
author | Eric Biggers <ebiggers@google.com> | 2019-08-04 22:35:45 -0400 |
---|---|---|
committer | Eric Biggers <ebiggers@google.com> | 2019-08-12 22:05:51 -0400 |
commit | 3ec4f2a62927c72607db633f55b0489e3d5b8e48 (patch) | |
tree | 3d0db9c40d623b71b43ec7a99ac9e17bd6d592d9 /fs/crypto/keyinfo.c | |
parent | a828daabb2ae917c12f4dc617c04db1185e6221f (diff) |
fscrypt: refactor key setup code in preparation for v2 policies
Do some more refactoring of the key setup code, in preparation for
introducing a filesystem-level keyring and v2 encryption policies:
- Now that ci_inode exists, don't pass around the inode unnecessarily.
- Define a function setup_file_encryption_key() which handles the crypto
key setup given an under-construction fscrypt_info. Don't pass the
fscrypt_context, since everything is in the fscrypt_info.
[This will be extended for v2 policies and the fs-level keyring.]
- Define a function fscrypt_set_derived_key() which sets the per-file
key, without depending on anything specific to v1 policies.
[This will also be used for v2 policies.]
- Define a function fscrypt_setup_v1_file_key() which takes the raw
master key, thus separating finding the key from using it.
[This will also be used if the key is found in the fs-level keyring.]
Reviewed-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Eric Biggers <ebiggers@google.com>
Diffstat (limited to 'fs/crypto/keyinfo.c')
-rw-r--r-- | fs/crypto/keyinfo.c | 247 |
1 files changed, 138 insertions, 109 deletions
diff --git a/fs/crypto/keyinfo.c b/fs/crypto/keyinfo.c index c4650071df27..c6bf44d64111 100644 --- a/fs/crypto/keyinfo.c +++ b/fs/crypto/keyinfo.c | |||
@@ -1,12 +1,11 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | 1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | 2 | /* |
3 | * key management facility for FS encryption support. | 3 | * Key setup facility for FS encryption support. |
4 | * | 4 | * |
5 | * Copyright (C) 2015, Google, Inc. | 5 | * Copyright (C) 2015, Google, Inc. |
6 | * | 6 | * |
7 | * This contains encryption key functions. | 7 | * Originally written by Michael Halcrow, Ildar Muslukhov, and Uday Savagaonkar. |
8 | * | 8 | * Heavily modified since then. |
9 | * Written by Michael Halcrow, Ildar Muslukhov, and Uday Savagaonkar, 2015. | ||
10 | */ | 9 | */ |
11 | 10 | ||
12 | #include <keys/user-type.h> | 11 | #include <keys/user-type.h> |
@@ -25,14 +24,19 @@ static DEFINE_HASHTABLE(fscrypt_direct_keys, 6); /* 6 bits = 64 buckets */ | |||
25 | static DEFINE_SPINLOCK(fscrypt_direct_keys_lock); | 24 | static DEFINE_SPINLOCK(fscrypt_direct_keys_lock); |
26 | 25 | ||
27 | /* | 26 | /* |
28 | * Key derivation function. This generates the derived key by encrypting the | 27 | * v1 key derivation function. This generates the derived key by encrypting the |
29 | * master key with AES-128-ECB using the inode's nonce as the AES key. | 28 | * master key with AES-128-ECB using the nonce as the AES key. This provides a |
29 | * unique derived key with sufficient entropy for each inode. However, it's | ||
30 | * nonstandard, non-extensible, doesn't evenly distribute the entropy from the | ||
31 | * master key, and is trivially reversible: an attacker who compromises a | ||
32 | * derived key can "decrypt" it to get back to the master key, then derive any | ||
33 | * other key. For all new code, use HKDF instead. | ||
30 | * | 34 | * |
31 | * The master key must be at least as long as the derived key. If the master | 35 | * The master key must be at least as long as the derived key. If the master |
32 | * key is longer, then only the first 'derived_keysize' bytes are used. | 36 | * key is longer, then only the first 'derived_keysize' bytes are used. |
33 | */ | 37 | */ |
34 | static int derive_key_aes(const u8 *master_key, | 38 | static int derive_key_aes(const u8 *master_key, |
35 | const struct fscrypt_context *ctx, | 39 | const u8 nonce[FS_KEY_DERIVATION_NONCE_SIZE], |
36 | u8 *derived_key, unsigned int derived_keysize) | 40 | u8 *derived_key, unsigned int derived_keysize) |
37 | { | 41 | { |
38 | int res = 0; | 42 | int res = 0; |
@@ -55,7 +59,7 @@ static int derive_key_aes(const u8 *master_key, | |||
55 | skcipher_request_set_callback(req, | 59 | skcipher_request_set_callback(req, |
56 | CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, | 60 | CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, |
57 | crypto_req_done, &wait); | 61 | crypto_req_done, &wait); |
58 | res = crypto_skcipher_setkey(tfm, ctx->nonce, sizeof(ctx->nonce)); | 62 | res = crypto_skcipher_setkey(tfm, nonce, FS_KEY_DERIVATION_NONCE_SIZE); |
59 | if (res < 0) | 63 | if (res < 0) |
60 | goto out; | 64 | goto out; |
61 | 65 | ||
@@ -183,54 +187,10 @@ select_encryption_mode(const struct fscrypt_info *ci, const struct inode *inode) | |||
183 | return ERR_PTR(-EINVAL); | 187 | return ERR_PTR(-EINVAL); |
184 | } | 188 | } |
185 | 189 | ||
186 | /* Find the master key, then derive the inode's actual encryption key */ | 190 | /* Create a symmetric cipher object for the given encryption mode and key */ |
187 | static int find_and_derive_key(const struct inode *inode, | ||
188 | const struct fscrypt_context *ctx, | ||
189 | u8 *derived_key, const struct fscrypt_mode *mode) | ||
190 | { | ||
191 | struct key *key; | ||
192 | const struct fscrypt_key *payload; | ||
193 | int err; | ||
194 | |||
195 | key = find_and_lock_process_key(FSCRYPT_KEY_DESC_PREFIX, | ||
196 | ctx->master_key_descriptor, | ||
197 | mode->keysize, &payload); | ||
198 | if (key == ERR_PTR(-ENOKEY) && inode->i_sb->s_cop->key_prefix) { | ||
199 | key = find_and_lock_process_key(inode->i_sb->s_cop->key_prefix, | ||
200 | ctx->master_key_descriptor, | ||
201 | mode->keysize, &payload); | ||
202 | } | ||
203 | if (IS_ERR(key)) | ||
204 | return PTR_ERR(key); | ||
205 | |||
206 | if (ctx->flags & FSCRYPT_POLICY_FLAG_DIRECT_KEY) { | ||
207 | if (mode->ivsize < offsetofend(union fscrypt_iv, nonce)) { | ||
208 | fscrypt_warn(inode, | ||
209 | "Direct key mode not allowed with %s", | ||
210 | mode->friendly_name); | ||
211 | err = -EINVAL; | ||
212 | } else if (ctx->contents_encryption_mode != | ||
213 | ctx->filenames_encryption_mode) { | ||
214 | fscrypt_warn(inode, | ||
215 | "Direct key mode not allowed with different contents and filenames modes"); | ||
216 | err = -EINVAL; | ||
217 | } else { | ||
218 | memcpy(derived_key, payload->raw, mode->keysize); | ||
219 | err = 0; | ||
220 | } | ||
221 | } else { | ||
222 | err = derive_key_aes(payload->raw, ctx, derived_key, | ||
223 | mode->keysize); | ||
224 | } | ||
225 | up_read(&key->sem); | ||
226 | key_put(key); | ||
227 | return err; | ||
228 | } | ||
229 | |||
230 | /* Allocate and key a symmetric cipher object for the given encryption mode */ | ||
231 | static struct crypto_skcipher * | 191 | static struct crypto_skcipher * |
232 | allocate_skcipher_for_mode(struct fscrypt_mode *mode, const u8 *raw_key, | 192 | fscrypt_allocate_skcipher(struct fscrypt_mode *mode, const u8 *raw_key, |
233 | const struct inode *inode) | 193 | const struct inode *inode) |
234 | { | 194 | { |
235 | struct crypto_skcipher *tfm; | 195 | struct crypto_skcipher *tfm; |
236 | int err; | 196 | int err; |
@@ -308,8 +268,7 @@ static void put_direct_key(struct fscrypt_direct_key *dk) | |||
308 | */ | 268 | */ |
309 | static struct fscrypt_direct_key * | 269 | static struct fscrypt_direct_key * |
310 | find_or_insert_direct_key(struct fscrypt_direct_key *to_insert, | 270 | find_or_insert_direct_key(struct fscrypt_direct_key *to_insert, |
311 | const u8 *raw_key, const struct fscrypt_mode *mode, | 271 | const u8 *raw_key, const struct fscrypt_info *ci) |
312 | const struct fscrypt_info *ci) | ||
313 | { | 272 | { |
314 | unsigned long hash_key; | 273 | unsigned long hash_key; |
315 | struct fscrypt_direct_key *dk; | 274 | struct fscrypt_direct_key *dk; |
@@ -328,9 +287,9 @@ find_or_insert_direct_key(struct fscrypt_direct_key *to_insert, | |||
328 | if (memcmp(ci->ci_master_key_descriptor, dk->dk_descriptor, | 287 | if (memcmp(ci->ci_master_key_descriptor, dk->dk_descriptor, |
329 | FSCRYPT_KEY_DESCRIPTOR_SIZE) != 0) | 288 | FSCRYPT_KEY_DESCRIPTOR_SIZE) != 0) |
330 | continue; | 289 | continue; |
331 | if (mode != dk->dk_mode) | 290 | if (ci->ci_mode != dk->dk_mode) |
332 | continue; | 291 | continue; |
333 | if (crypto_memneq(raw_key, dk->dk_raw, mode->keysize)) | 292 | if (crypto_memneq(raw_key, dk->dk_raw, ci->ci_mode->keysize)) |
334 | continue; | 293 | continue; |
335 | /* using existing tfm with same (descriptor, mode, raw_key) */ | 294 | /* using existing tfm with same (descriptor, mode, raw_key) */ |
336 | refcount_inc(&dk->dk_refcount); | 295 | refcount_inc(&dk->dk_refcount); |
@@ -346,14 +305,13 @@ find_or_insert_direct_key(struct fscrypt_direct_key *to_insert, | |||
346 | 305 | ||
347 | /* Prepare to encrypt directly using the master key in the given mode */ | 306 | /* Prepare to encrypt directly using the master key in the given mode */ |
348 | static struct fscrypt_direct_key * | 307 | static struct fscrypt_direct_key * |
349 | fscrypt_get_direct_key(const struct fscrypt_info *ci, struct fscrypt_mode *mode, | 308 | fscrypt_get_direct_key(const struct fscrypt_info *ci, const u8 *raw_key) |
350 | const u8 *raw_key, const struct inode *inode) | ||
351 | { | 309 | { |
352 | struct fscrypt_direct_key *dk; | 310 | struct fscrypt_direct_key *dk; |
353 | int err; | 311 | int err; |
354 | 312 | ||
355 | /* Is there already a tfm for this key? */ | 313 | /* Is there already a tfm for this key? */ |
356 | dk = find_or_insert_direct_key(NULL, raw_key, mode, ci); | 314 | dk = find_or_insert_direct_key(NULL, raw_key, ci); |
357 | if (dk) | 315 | if (dk) |
358 | return dk; | 316 | return dk; |
359 | 317 | ||
@@ -362,8 +320,9 @@ fscrypt_get_direct_key(const struct fscrypt_info *ci, struct fscrypt_mode *mode, | |||
362 | if (!dk) | 320 | if (!dk) |
363 | return ERR_PTR(-ENOMEM); | 321 | return ERR_PTR(-ENOMEM); |
364 | refcount_set(&dk->dk_refcount, 1); | 322 | refcount_set(&dk->dk_refcount, 1); |
365 | dk->dk_mode = mode; | 323 | dk->dk_mode = ci->ci_mode; |
366 | dk->dk_ctfm = allocate_skcipher_for_mode(mode, raw_key, inode); | 324 | dk->dk_ctfm = fscrypt_allocate_skcipher(ci->ci_mode, raw_key, |
325 | ci->ci_inode); | ||
367 | if (IS_ERR(dk->dk_ctfm)) { | 326 | if (IS_ERR(dk->dk_ctfm)) { |
368 | err = PTR_ERR(dk->dk_ctfm); | 327 | err = PTR_ERR(dk->dk_ctfm); |
369 | dk->dk_ctfm = NULL; | 328 | dk->dk_ctfm = NULL; |
@@ -371,9 +330,9 @@ fscrypt_get_direct_key(const struct fscrypt_info *ci, struct fscrypt_mode *mode, | |||
371 | } | 330 | } |
372 | memcpy(dk->dk_descriptor, ci->ci_master_key_descriptor, | 331 | memcpy(dk->dk_descriptor, ci->ci_master_key_descriptor, |
373 | FSCRYPT_KEY_DESCRIPTOR_SIZE); | 332 | FSCRYPT_KEY_DESCRIPTOR_SIZE); |
374 | memcpy(dk->dk_raw, raw_key, mode->keysize); | 333 | memcpy(dk->dk_raw, raw_key, ci->ci_mode->keysize); |
375 | 334 | ||
376 | return find_or_insert_direct_key(dk, raw_key, mode, ci); | 335 | return find_or_insert_direct_key(dk, raw_key, ci); |
377 | 336 | ||
378 | err_free_dk: | 337 | err_free_dk: |
379 | free_direct_key(dk); | 338 | free_direct_key(dk); |
@@ -422,6 +381,9 @@ static int init_essiv_generator(struct fscrypt_info *ci, const u8 *raw_key, | |||
422 | struct crypto_cipher *essiv_tfm; | 381 | struct crypto_cipher *essiv_tfm; |
423 | u8 salt[SHA256_DIGEST_SIZE]; | 382 | u8 salt[SHA256_DIGEST_SIZE]; |
424 | 383 | ||
384 | if (WARN_ON(ci->ci_mode->ivsize != AES_BLOCK_SIZE)) | ||
385 | return -EINVAL; | ||
386 | |||
425 | essiv_tfm = crypto_alloc_cipher("aes", 0, 0); | 387 | essiv_tfm = crypto_alloc_cipher("aes", 0, 0); |
426 | if (IS_ERR(essiv_tfm)) | 388 | if (IS_ERR(essiv_tfm)) |
427 | return PTR_ERR(essiv_tfm); | 389 | return PTR_ERR(essiv_tfm); |
@@ -446,41 +408,24 @@ out: | |||
446 | return err; | 408 | return err; |
447 | } | 409 | } |
448 | 410 | ||
449 | /* | 411 | /* Given the per-file key, set up the file's crypto transform object(s) */ |
450 | * Given the encryption mode and key (normally the derived key, but for | 412 | static int fscrypt_set_derived_key(struct fscrypt_info *ci, |
451 | * DIRECT_KEY mode it's the master key), set up the inode's symmetric cipher | 413 | const u8 *derived_key) |
452 | * transform object(s). | ||
453 | */ | ||
454 | static int setup_crypto_transform(struct fscrypt_info *ci, | ||
455 | struct fscrypt_mode *mode, | ||
456 | const u8 *raw_key, const struct inode *inode) | ||
457 | { | 414 | { |
458 | struct fscrypt_direct_key *dk; | 415 | struct fscrypt_mode *mode = ci->ci_mode; |
459 | struct crypto_skcipher *ctfm; | 416 | struct crypto_skcipher *ctfm; |
460 | int err; | 417 | int err; |
461 | 418 | ||
462 | if (ci->ci_flags & FSCRYPT_POLICY_FLAG_DIRECT_KEY) { | 419 | ctfm = fscrypt_allocate_skcipher(mode, derived_key, ci->ci_inode); |
463 | dk = fscrypt_get_direct_key(ci, mode, raw_key, inode); | 420 | if (IS_ERR(ctfm)) |
464 | if (IS_ERR(dk)) | 421 | return PTR_ERR(ctfm); |
465 | return PTR_ERR(dk); | 422 | |
466 | ctfm = dk->dk_ctfm; | ||
467 | } else { | ||
468 | dk = NULL; | ||
469 | ctfm = allocate_skcipher_for_mode(mode, raw_key, inode); | ||
470 | if (IS_ERR(ctfm)) | ||
471 | return PTR_ERR(ctfm); | ||
472 | } | ||
473 | ci->ci_direct_key = dk; | ||
474 | ci->ci_ctfm = ctfm; | 423 | ci->ci_ctfm = ctfm; |
475 | 424 | ||
476 | if (mode->needs_essiv) { | 425 | if (mode->needs_essiv) { |
477 | /* ESSIV implies 16-byte IVs which implies !DIRECT_KEY */ | 426 | err = init_essiv_generator(ci, derived_key, mode->keysize); |
478 | WARN_ON(mode->ivsize != AES_BLOCK_SIZE); | ||
479 | WARN_ON(ci->ci_flags & FSCRYPT_POLICY_FLAG_DIRECT_KEY); | ||
480 | |||
481 | err = init_essiv_generator(ci, raw_key, mode->keysize); | ||
482 | if (err) { | 427 | if (err) { |
483 | fscrypt_warn(inode, | 428 | fscrypt_warn(ci->ci_inode, |
484 | "Error initializing ESSIV generator: %d", | 429 | "Error initializing ESSIV generator: %d", |
485 | err); | 430 | err); |
486 | return err; | 431 | return err; |
@@ -489,6 +434,105 @@ static int setup_crypto_transform(struct fscrypt_info *ci, | |||
489 | return 0; | 434 | return 0; |
490 | } | 435 | } |
491 | 436 | ||
437 | /* v1 policy, DIRECT_KEY: use the master key directly */ | ||
438 | static int setup_v1_file_key_direct(struct fscrypt_info *ci, | ||
439 | const u8 *raw_master_key) | ||
440 | { | ||
441 | const struct fscrypt_mode *mode = ci->ci_mode; | ||
442 | struct fscrypt_direct_key *dk; | ||
443 | |||
444 | if (!fscrypt_mode_supports_direct_key(mode)) { | ||
445 | fscrypt_warn(ci->ci_inode, | ||
446 | "Direct key mode not allowed with %s", | ||
447 | mode->friendly_name); | ||
448 | return -EINVAL; | ||
449 | } | ||
450 | |||
451 | if (ci->ci_data_mode != ci->ci_filename_mode) { | ||
452 | fscrypt_warn(ci->ci_inode, | ||
453 | "Direct key mode not allowed with different contents and filenames modes"); | ||
454 | return -EINVAL; | ||
455 | } | ||
456 | |||
457 | /* ESSIV implies 16-byte IVs which implies !DIRECT_KEY */ | ||
458 | if (WARN_ON(mode->needs_essiv)) | ||
459 | return -EINVAL; | ||
460 | |||
461 | dk = fscrypt_get_direct_key(ci, raw_master_key); | ||
462 | if (IS_ERR(dk)) | ||
463 | return PTR_ERR(dk); | ||
464 | ci->ci_direct_key = dk; | ||
465 | ci->ci_ctfm = dk->dk_ctfm; | ||
466 | return 0; | ||
467 | } | ||
468 | |||
469 | /* v1 policy, !DIRECT_KEY: derive the file's encryption key */ | ||
470 | static int setup_v1_file_key_derived(struct fscrypt_info *ci, | ||
471 | const u8 *raw_master_key) | ||
472 | { | ||
473 | u8 *derived_key; | ||
474 | int err; | ||
475 | |||
476 | /* | ||
477 | * This cannot be a stack buffer because it will be passed to the | ||
478 | * scatterlist crypto API during derive_key_aes(). | ||
479 | */ | ||
480 | derived_key = kmalloc(ci->ci_mode->keysize, GFP_NOFS); | ||
481 | if (!derived_key) | ||
482 | return -ENOMEM; | ||
483 | |||
484 | err = derive_key_aes(raw_master_key, ci->ci_nonce, | ||
485 | derived_key, ci->ci_mode->keysize); | ||
486 | if (err) | ||
487 | goto out; | ||
488 | |||
489 | err = fscrypt_set_derived_key(ci, derived_key); | ||
490 | out: | ||
491 | kzfree(derived_key); | ||
492 | return err; | ||
493 | } | ||
494 | |||
495 | static int fscrypt_setup_v1_file_key(struct fscrypt_info *ci, | ||
496 | const u8 *raw_master_key) | ||
497 | { | ||
498 | if (ci->ci_flags & FSCRYPT_POLICY_FLAG_DIRECT_KEY) | ||
499 | return setup_v1_file_key_direct(ci, raw_master_key); | ||
500 | else | ||
501 | return setup_v1_file_key_derived(ci, raw_master_key); | ||
502 | } | ||
503 | |||
504 | static int fscrypt_setup_v1_file_key_via_subscribed_keyrings( | ||
505 | struct fscrypt_info *ci) | ||
506 | { | ||
507 | struct key *key; | ||
508 | const struct fscrypt_key *payload; | ||
509 | int err; | ||
510 | |||
511 | key = find_and_lock_process_key(FSCRYPT_KEY_DESC_PREFIX, | ||
512 | ci->ci_master_key_descriptor, | ||
513 | ci->ci_mode->keysize, &payload); | ||
514 | if (key == ERR_PTR(-ENOKEY) && ci->ci_inode->i_sb->s_cop->key_prefix) { | ||
515 | key = find_and_lock_process_key(ci->ci_inode->i_sb->s_cop->key_prefix, | ||
516 | ci->ci_master_key_descriptor, | ||
517 | ci->ci_mode->keysize, &payload); | ||
518 | } | ||
519 | if (IS_ERR(key)) | ||
520 | return PTR_ERR(key); | ||
521 | |||
522 | err = fscrypt_setup_v1_file_key(ci, payload->raw); | ||
523 | up_read(&key->sem); | ||
524 | key_put(key); | ||
525 | return err; | ||
526 | } | ||
527 | |||
528 | /* | ||
529 | * Find the master key, then set up the inode's actual encryption key. | ||
530 | */ | ||
531 | static int setup_file_encryption_key(struct fscrypt_info *ci) | ||
532 | { | ||
533 | return fscrypt_setup_v1_file_key_via_subscribed_keyrings(ci); | ||
534 | } | ||
535 | |||
492 | static void put_crypt_info(struct fscrypt_info *ci) | 536 | static void put_crypt_info(struct fscrypt_info *ci) |
493 | { | 537 | { |
494 | if (!ci) | 538 | if (!ci) |
@@ -508,7 +552,6 @@ int fscrypt_get_encryption_info(struct inode *inode) | |||
508 | struct fscrypt_info *crypt_info; | 552 | struct fscrypt_info *crypt_info; |
509 | struct fscrypt_context ctx; | 553 | struct fscrypt_context ctx; |
510 | struct fscrypt_mode *mode; | 554 | struct fscrypt_mode *mode; |
511 | u8 *raw_key = NULL; | ||
512 | int res; | 555 | int res; |
513 | 556 | ||
514 | if (fscrypt_has_encryption_key(inode)) | 557 | if (fscrypt_has_encryption_key(inode)) |
@@ -573,20 +616,7 @@ int fscrypt_get_encryption_info(struct inode *inode) | |||
573 | WARN_ON(mode->ivsize > FSCRYPT_MAX_IV_SIZE); | 616 | WARN_ON(mode->ivsize > FSCRYPT_MAX_IV_SIZE); |
574 | crypt_info->ci_mode = mode; | 617 | crypt_info->ci_mode = mode; |
575 | 618 | ||
576 | /* | 619 | res = setup_file_encryption_key(crypt_info); |
577 | * This cannot be a stack buffer because it may be passed to the | ||
578 | * scatterlist crypto API as part of key derivation. | ||
579 | */ | ||
580 | res = -ENOMEM; | ||
581 | raw_key = kmalloc(mode->keysize, GFP_NOFS); | ||
582 | if (!raw_key) | ||
583 | goto out; | ||
584 | |||
585 | res = find_and_derive_key(inode, &ctx, raw_key, mode); | ||
586 | if (res) | ||
587 | goto out; | ||
588 | |||
589 | res = setup_crypto_transform(crypt_info, mode, raw_key, inode); | ||
590 | if (res) | 620 | if (res) |
591 | goto out; | 621 | goto out; |
592 | 622 | ||
@@ -596,7 +626,6 @@ out: | |||
596 | if (res == -ENOKEY) | 626 | if (res == -ENOKEY) |
597 | res = 0; | 627 | res = 0; |
598 | put_crypt_info(crypt_info); | 628 | put_crypt_info(crypt_info); |
599 | kzfree(raw_key); | ||
600 | return res; | 629 | return res; |
601 | } | 630 | } |
602 | EXPORT_SYMBOL(fscrypt_get_encryption_info); | 631 | EXPORT_SYMBOL(fscrypt_get_encryption_info); |