Skip to content

Commit cdeb21d

Browse files
committed
fscrypt: add fscrypt_add_test_dummy_key()
Currently, the test_dummy_encryption mount option (which is used for encryption I/O testing with xfstests) uses v1 encryption policies, and it relies on userspace inserting a test key into the session keyring. We need test_dummy_encryption to support v2 encryption policies too. Requiring userspace to add the test key doesn't work well with v2 policies, since v2 policies only support the filesystem keyring (not the session keyring), and keys in the filesystem keyring are lost when the filesystem is unmounted. Hooking all test code that unmounts and re-mounts the filesystem would be difficult. Instead, let's make the filesystem automatically add the test key to its keyring when test_dummy_encryption is enabled. That puts the responsibility for choosing the test key on the kernel. We could just hard-code a key. But out of paranoia, let's first try using a per-boot random key, to prevent this code from being misused. A per-boot key will work as long as no one expects dummy-encrypted files to remain accessible after a reboot. (gce-xfstests doesn't.) Therefore, this patch adds a function fscrypt_add_test_dummy_key() which implements the above. The next patch will use it. Link: https://lore.kernel.org/r/[email protected] Reviewed-by: Theodore Ts'o <[email protected]> Reviewed-by: Jaegeuk Kim <[email protected]> Signed-off-by: Eric Biggers <[email protected]>
1 parent 8b85996 commit cdeb21d

File tree

2 files changed

+77
-43
lines changed

2 files changed

+77
-43
lines changed

fs/crypto/fscrypt_private.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,9 @@ struct key *
437437
fscrypt_find_master_key(struct super_block *sb,
438438
const struct fscrypt_key_specifier *mk_spec);
439439

440+
int fscrypt_add_test_dummy_key(struct super_block *sb,
441+
struct fscrypt_key_specifier *key_spec);
442+
440443
int fscrypt_verify_key_added(struct super_block *sb,
441444
const u8 identifier[FSCRYPT_KEY_IDENTIFIER_SIZE]);
442445

fs/crypto/keyring.c

Lines changed: 74 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
#include <crypto/skcipher.h>
2222
#include <linux/key-type.h>
23+
#include <linux/random.h>
2324
#include <linux/seq_file.h>
2425

2526
#include "fscrypt_private.h"
@@ -424,9 +425,9 @@ static int add_existing_master_key(struct fscrypt_master_key *mk,
424425
return 0;
425426
}
426427

427-
static int add_master_key(struct super_block *sb,
428-
struct fscrypt_master_key_secret *secret,
429-
const struct fscrypt_key_specifier *mk_spec)
428+
static int do_add_master_key(struct super_block *sb,
429+
struct fscrypt_master_key_secret *secret,
430+
const struct fscrypt_key_specifier *mk_spec)
430431
{
431432
static DEFINE_MUTEX(fscrypt_add_key_mutex);
432433
struct key *key;
@@ -465,6 +466,35 @@ static int add_master_key(struct super_block *sb,
465466
return err;
466467
}
467468

469+
static int add_master_key(struct super_block *sb,
470+
struct fscrypt_master_key_secret *secret,
471+
struct fscrypt_key_specifier *key_spec)
472+
{
473+
int err;
474+
475+
if (key_spec->type == FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER) {
476+
err = fscrypt_init_hkdf(&secret->hkdf, secret->raw,
477+
secret->size);
478+
if (err)
479+
return err;
480+
481+
/*
482+
* Now that the HKDF context is initialized, the raw key is no
483+
* longer needed.
484+
*/
485+
memzero_explicit(secret->raw, secret->size);
486+
487+
/* Calculate the key identifier */
488+
err = fscrypt_hkdf_expand(&secret->hkdf,
489+
HKDF_CONTEXT_KEY_IDENTIFIER, NULL, 0,
490+
key_spec->u.identifier,
491+
FSCRYPT_KEY_IDENTIFIER_SIZE);
492+
if (err)
493+
return err;
494+
}
495+
return do_add_master_key(sb, secret, key_spec);
496+
}
497+
468498
static int fscrypt_provisioning_key_preparse(struct key_preparsed_payload *prep)
469499
{
470500
const struct fscrypt_provisioning_key_payload *payload = prep->data;
@@ -609,6 +639,15 @@ int fscrypt_ioctl_add_key(struct file *filp, void __user *_uarg)
609639
if (memchr_inv(arg.__reserved, 0, sizeof(arg.__reserved)))
610640
return -EINVAL;
611641

642+
/*
643+
* Only root can add keys that are identified by an arbitrary descriptor
644+
* rather than by a cryptographic hash --- since otherwise a malicious
645+
* user could add the wrong key.
646+
*/
647+
if (arg.key_spec.type == FSCRYPT_KEY_SPEC_TYPE_DESCRIPTOR &&
648+
!capable(CAP_SYS_ADMIN))
649+
return -EACCES;
650+
612651
memset(&secret, 0, sizeof(secret));
613652
if (arg.key_id) {
614653
if (arg.raw_size != 0)
@@ -626,54 +665,46 @@ int fscrypt_ioctl_add_key(struct file *filp, void __user *_uarg)
626665
goto out_wipe_secret;
627666
}
628667

629-
switch (arg.key_spec.type) {
630-
case FSCRYPT_KEY_SPEC_TYPE_DESCRIPTOR:
631-
/*
632-
* Only root can add keys that are identified by an arbitrary
633-
* descriptor rather than by a cryptographic hash --- since
634-
* otherwise a malicious user could add the wrong key.
635-
*/
636-
err = -EACCES;
637-
if (!capable(CAP_SYS_ADMIN))
638-
goto out_wipe_secret;
639-
break;
640-
case FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER:
641-
err = fscrypt_init_hkdf(&secret.hkdf, secret.raw, secret.size);
642-
if (err)
643-
goto out_wipe_secret;
644-
645-
/*
646-
* Now that the HKDF context is initialized, the raw key is no
647-
* longer needed.
648-
*/
649-
memzero_explicit(secret.raw, secret.size);
650-
651-
/* Calculate the key identifier and return it to userspace. */
652-
err = fscrypt_hkdf_expand(&secret.hkdf,
653-
HKDF_CONTEXT_KEY_IDENTIFIER,
654-
NULL, 0, arg.key_spec.u.identifier,
655-
FSCRYPT_KEY_IDENTIFIER_SIZE);
656-
if (err)
657-
goto out_wipe_secret;
658-
err = -EFAULT;
659-
if (copy_to_user(uarg->key_spec.u.identifier,
660-
arg.key_spec.u.identifier,
661-
FSCRYPT_KEY_IDENTIFIER_SIZE))
662-
goto out_wipe_secret;
663-
break;
664-
default:
665-
WARN_ON(1);
666-
err = -EINVAL;
668+
err = add_master_key(sb, &secret, &arg.key_spec);
669+
if (err)
667670
goto out_wipe_secret;
668-
}
669671

670-
err = add_master_key(sb, &secret, &arg.key_spec);
672+
/* Return the key identifier to userspace, if applicable */
673+
err = -EFAULT;
674+
if (arg.key_spec.type == FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER &&
675+
copy_to_user(uarg->key_spec.u.identifier, arg.key_spec.u.identifier,
676+
FSCRYPT_KEY_IDENTIFIER_SIZE))
677+
goto out_wipe_secret;
678+
err = 0;
671679
out_wipe_secret:
672680
wipe_master_key_secret(&secret);
673681
return err;
674682
}
675683
EXPORT_SYMBOL_GPL(fscrypt_ioctl_add_key);
676684

685+
/*
686+
* Add the key for '-o test_dummy_encryption' to the filesystem keyring.
687+
*
688+
* Use a per-boot random key to prevent people from misusing this option.
689+
*/
690+
int fscrypt_add_test_dummy_key(struct super_block *sb,
691+
struct fscrypt_key_specifier *key_spec)
692+
{
693+
static u8 test_key[FSCRYPT_MAX_KEY_SIZE];
694+
struct fscrypt_master_key_secret secret;
695+
int err;
696+
697+
get_random_once(test_key, FSCRYPT_MAX_KEY_SIZE);
698+
699+
memset(&secret, 0, sizeof(secret));
700+
secret.size = FSCRYPT_MAX_KEY_SIZE;
701+
memcpy(secret.raw, test_key, FSCRYPT_MAX_KEY_SIZE);
702+
703+
err = add_master_key(sb, &secret, key_spec);
704+
wipe_master_key_secret(&secret);
705+
return err;
706+
}
707+
677708
/*
678709
* Verify that the current user has added a master key with the given identifier
679710
* (returns -ENOKEY if not). This is needed to prevent a user from encrypting

0 commit comments

Comments
 (0)