Skip to content

Commit c945f8d

Browse files
a3fintel-lab-lkp
authored andcommitted
fscrypt: support encrypted and trusted keys
For both v1 and v2 key setup mechanisms, userspace supplies the raw key material to the kernel after which it is never again disclosed to userspace. Use of encrypted and trusted keys offers stronger guarantees: The key material is generated within the kernel and is never disclosed to userspace in clear text and, in the case of trusted keys, can be directly rooted to a trust source like a TPM chip. Add support for trusted and encrypted keys by repurposing fscrypt_add_key_arg::raw to hold the key description when the new FSCRYPT_KEY_ARG_TYPE_DESC flag is supplied. The location of the flag was previously reserved and enforced by ioctl code to be zero, so this change won't break backwards compatibility. Corresponding userspace patches are available for fscryptctl: google/fscryptctl#23 Signed-off-by: Ahmad Fatoum <[email protected]>
1 parent 349a2d5 commit c945f8d

File tree

3 files changed

+87
-12
lines changed

3 files changed

+87
-12
lines changed

Documentation/filesystems/fscrypt.rst

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -681,11 +681,15 @@ It can be executed on any file or directory on the target filesystem,
681681
but using the filesystem's root directory is recommended. It takes in
682682
a pointer to struct fscrypt_add_key_arg, defined as follows::
683683

684+
#define FSCRYPT_KEY_ADD_RAW_ASIS 0
685+
#define FSCRYPT_KEY_ADD_RAW_DESC 1
686+
684687
struct fscrypt_add_key_arg {
685688
struct fscrypt_key_specifier key_spec;
686689
__u32 raw_size;
687690
__u32 key_id;
688-
__u32 __reserved[8];
691+
__u32 raw_flags; /* one of FSCRYPT_KEY_ADD_RAW_* */
692+
__u32 __reserved[7];
689693
__u8 raw[];
690694
};
691695

@@ -732,8 +736,11 @@ as follows:
732736
Alternatively, if ``key_id`` is nonzero, this field must be 0, since
733737
in that case the size is implied by the specified Linux keyring key.
734738

735-
- ``key_id`` is 0 if the raw key is given directly in the ``raw``
736-
field. Otherwise ``key_id`` is the ID of a Linux keyring key of
739+
- If ``key_id`` is 0, the raw key is given directly in the ``raw``
740+
field if ``raw_flags == FSCRYPT_KEY_ADD_RAW_ASIS``. With
741+
``raw_flags == FSCRYPT_KEY_ADD_RAW_DESC``, ``raw`` is instead
742+
interpreted as the description of an encrypted or trusted key.
743+
Otherwise ``key_id`` is the ID of a Linux keyring key of
737744
type "fscrypt-provisioning" whose payload is
738745
struct fscrypt_provisioning_key_payload whose ``raw`` field contains
739746
the raw key and whose ``type`` field matches ``key_spec.type``.
@@ -748,8 +755,15 @@ as follows:
748755
without having to store the raw keys in userspace memory.
749756

750757
- ``raw`` is a variable-length field which must contain the actual
751-
key, ``raw_size`` bytes long. Alternatively, if ``key_id`` is
752-
nonzero, then this field is unused.
758+
key when ``raw_flags == FSCRYPT_KEY_ADD_RAW_ASIS``,
759+
``raw_size`` bytes long. Alternatively, if
760+
``raw_flags == FSCRYPT_KEY_ADD_RAW_DESC``, ``raw`` is interpreted
761+
as the key description of an encrypted or trusted key, in that order.
762+
The material of this key will be used as if it were a raw key
763+
supplied by userspace.
764+
765+
In both cases, the buffer is ``raw_size`` bytes long. If ````key_id``
766+
is nonzero, then this field is unused.
753767

754768
For v2 policy keys, the kernel keeps track of which user (identified
755769
by effective user ID) added the key, and only allows the key to be

fs/crypto/keyring.c

Lines changed: 53 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
2020

2121
#include <crypto/skcipher.h>
2222
#include <linux/key-type.h>
23+
#include <linux/key-type.h>
24+
#include <keys/encrypted-type.h>
25+
#include <keys/trusted-type.h>
2326
#include <linux/random.h>
2427
#include <linux/seq_file.h>
2528

@@ -662,13 +665,57 @@ int fscrypt_ioctl_add_key(struct file *filp, void __user *_uarg)
662665
if (err)
663666
goto out_wipe_secret;
664667
} else {
665-
if (arg.raw_size < FSCRYPT_MIN_KEY_SIZE ||
666-
arg.raw_size > FSCRYPT_MAX_KEY_SIZE)
668+
struct key *keyring_key = ERR_PTR(-EINVAL);
669+
const void *key_material;
670+
const char *desc;
671+
672+
switch (arg.raw_flags) {
673+
case FSCRYPT_KEY_ADD_RAW_ASIS:
674+
if (arg.raw_size < FSCRYPT_MIN_KEY_SIZE ||
675+
arg.raw_size > FSCRYPT_MAX_KEY_SIZE)
676+
return -EINVAL;
677+
secret.size = arg.raw_size;
678+
err = -EFAULT;
679+
if (copy_from_user(secret.raw, uarg->raw, secret.size))
680+
goto out_wipe_secret;
681+
break;
682+
case FSCRYPT_KEY_ADD_RAW_DESC:
683+
if (arg.raw_size > 4096)
684+
return -EINVAL;
685+
desc = memdup_user_nul(uarg->raw, arg.raw_size);
686+
if (IS_ERR(desc))
687+
return PTR_ERR(desc);
688+
689+
if (IS_REACHABLE(CONFIG_ENCRYPTED_KEYS))
690+
keyring_key = request_key(&key_type_encrypted, desc, NULL);
691+
if (IS_REACHABLE(CONFIG_TRUSTED_KEYS) && IS_ERR(keyring_key))
692+
keyring_key = request_key(&key_type_trusted, desc, NULL);
693+
694+
kfree(desc);
695+
696+
if (IS_ERR(keyring_key))
697+
return PTR_ERR(keyring_key);
698+
699+
down_read(&keyring_key->sem);
700+
701+
key_material = key_extract_material(keyring_key, &secret.size);
702+
if (!IS_ERR(key_material) && (secret.size < FSCRYPT_MIN_KEY_SIZE ||
703+
secret.size > FSCRYPT_MAX_KEY_SIZE))
704+
key_material = ERR_PTR(-EINVAL);
705+
if (IS_ERR(key_material)) {
706+
up_read(&keyring_key->sem);
707+
key_put(keyring_key);
708+
return PTR_ERR(key_material);
709+
}
710+
711+
memcpy(secret.raw, key_material, secret.size);
712+
713+
up_read(&keyring_key->sem);
714+
key_put(keyring_key);
715+
break;
716+
default:
667717
return -EINVAL;
668-
secret.size = arg.raw_size;
669-
err = -EFAULT;
670-
if (copy_from_user(secret.raw, uarg->raw, secret.size))
671-
goto out_wipe_secret;
718+
}
672719
}
673720

674721
err = add_master_key(sb, &secret, &arg.key_spec);

include/uapi/linux/fscrypt.h

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,12 +119,26 @@ struct fscrypt_provisioning_key_payload {
119119
__u8 raw[];
120120
};
121121

122+
/*
123+
* fscrypt_add_key_arg::raw contains the raw key material directly
124+
* if key_id == 0
125+
*/
126+
#define FSCRYPT_KEY_ADD_RAW_ASIS 0
127+
128+
/*
129+
* fscrypt_add_key_arg::raw is a key descriptor for an already
130+
* existing kernel encrypted or trusted key if key_id == 0.
131+
* The kernel key's material will be used as input for fscrypt.
132+
*/
133+
#define FSCRYPT_KEY_ADD_RAW_DESC 1
134+
122135
/* Struct passed to FS_IOC_ADD_ENCRYPTION_KEY */
123136
struct fscrypt_add_key_arg {
124137
struct fscrypt_key_specifier key_spec;
125138
__u32 raw_size;
126139
__u32 key_id;
127-
__u32 __reserved[8];
140+
__u32 raw_flags; /* one of FSCRYPT_KEY_ADD_RAW_* */
141+
__u32 __reserved[7];
128142
__u8 raw[];
129143
};
130144

0 commit comments

Comments
 (0)