ANDROID: pfk: allow encryption key to be specified in bio
Introduce the ability for an encryption key to be passed through 'struct bio' to the "PFK" module for use by inline encryption with Qualcomm ICE. This will be used to specify a default key for metadata encryption. Instead of referencing the keyring key (struct key) directly as we did in the marlin kernel, require users to provide a structure directly containing the key material. Referencing a keyring key from struct bio is incorrect because userspace can call keyctl_revoke() at any time, causing the key's payload to be freed; so unless the key semaphore is held, there's no guarantee the payload will live until the bio is done. For now, leave in place most of the PFK code, including the "get the bio's inode and call back into ext4 to get the key" hack. This is necessary for now, though really this should be implemented by having ext4 set the key in its bios, and refactoring the "PFK" module's functionality into more appropriate places in block/ and drivers/. But in any case, keys specified by ext4 will override the "default" key, as intended. Signed-off-by: Eric Biggers <ebiggers@google.com> Change-Id: I4295abaeecf6f7ab8c9854eb80d928f40500fde2
This commit is contained in:
committed by
Nick Desaulniers
parent
52c1cf611e
commit
7abc033ea9
11
block/bio.c
11
block/bio.c
@@ -562,6 +562,13 @@ inline int bio_phys_segments(struct request_queue *q, struct bio *bio)
|
||||
}
|
||||
EXPORT_SYMBOL(bio_phys_segments);
|
||||
|
||||
static inline void bio_clone_crypt_key(struct bio *dst, const struct bio *src)
|
||||
{
|
||||
#ifdef CONFIG_PFK
|
||||
dst->bi_crypt_key = src->bi_crypt_key;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* __bio_clone_fast - clone a bio that shares the original bio's biovec
|
||||
* @bio: destination bio
|
||||
@@ -588,6 +595,8 @@ void __bio_clone_fast(struct bio *bio, struct bio *bio_src)
|
||||
bio->bi_io_vec = bio_src->bi_io_vec;
|
||||
bio->bi_dio_inode = bio_src->bi_dio_inode;
|
||||
|
||||
bio_clone_crypt_key(bio, bio_src);
|
||||
|
||||
bio_clone_blkcg_association(bio, bio_src);
|
||||
}
|
||||
EXPORT_SYMBOL(__bio_clone_fast);
|
||||
@@ -694,6 +703,8 @@ integrity_clone:
|
||||
}
|
||||
}
|
||||
|
||||
bio_clone_crypt_key(bio, bio_src);
|
||||
|
||||
bio_clone_blkcg_association(bio, bio_src);
|
||||
|
||||
return bio;
|
||||
|
||||
@@ -98,6 +98,11 @@ struct bio {
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PFK
|
||||
/* Encryption key to use (NULL if none) */
|
||||
const struct blk_encryption_key *bi_crypt_key;
|
||||
#endif
|
||||
|
||||
unsigned short bi_vcnt; /* how many bio_vec's */
|
||||
|
||||
/*
|
||||
|
||||
@@ -17,6 +17,19 @@
|
||||
|
||||
struct ice_crypto_setting;
|
||||
|
||||
/*
|
||||
* Default key for inline encryption.
|
||||
*
|
||||
* For now only AES-256-XTS is supported, so this is a fixed length. But if
|
||||
* ever needed, this should be made variable-length with a 'mode' and 'size'.
|
||||
* (Remember to update pfk_allow_merge_bio() when doing so!)
|
||||
*/
|
||||
#define BLK_ENCRYPTION_KEY_SIZE_AES_256_XTS 64
|
||||
|
||||
struct blk_encryption_key {
|
||||
u8 raw[BLK_ENCRYPTION_KEY_SIZE_AES_256_XTS];
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PFK
|
||||
|
||||
int pfk_load_key_start(const struct bio *bio,
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
#include <linux/printk.h>
|
||||
#include <linux/bio.h>
|
||||
#include <linux/security.h>
|
||||
#include <crypto/algapi.h>
|
||||
#include <crypto/ice.h>
|
||||
|
||||
#include <linux/pfk.h>
|
||||
@@ -151,28 +152,6 @@ static enum pfe_type pfk_get_pfe_type(const struct inode *inode)
|
||||
return INVALID_PFE;
|
||||
}
|
||||
|
||||
/**
|
||||
* inode_to_filename() - get the filename from inode pointer.
|
||||
* @inode: inode pointer
|
||||
*
|
||||
* it is used for debug prints.
|
||||
*
|
||||
* Return: filename string or "unknown".
|
||||
*/
|
||||
char *inode_to_filename(const struct inode *inode)
|
||||
{
|
||||
struct dentry *dentry = NULL;
|
||||
char *filename = NULL;
|
||||
|
||||
if (hlist_empty(&inode->i_dentry))
|
||||
return "unknown";
|
||||
|
||||
dentry = hlist_entry(inode->i_dentry.first, struct dentry, d_u.d_alias);
|
||||
filename = dentry->d_iname;
|
||||
|
||||
return filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* pfk_is_ready() - driver is initialized and ready.
|
||||
*
|
||||
@@ -271,6 +250,59 @@ bool pfe_is_inode_filesystem_type(const struct inode *inode,
|
||||
return (strcmp(inode->i_sb->s_type->name, fs_type) == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* pfk_get_key_for_bio() - get the encryption key to be used for a bio
|
||||
*
|
||||
* @bio: pointer to the BIO
|
||||
* @key_info: pointer to the key information which will be filled in
|
||||
* @algo_mode: optional pointer to the algorithm identifier which will be set
|
||||
* @is_pfe: will be set to false if the BIO should be left unencrypted
|
||||
*
|
||||
* Return: 0 if a key is being used, otherwise a -errno value
|
||||
*/
|
||||
static int pfk_get_key_for_bio(const struct bio *bio,
|
||||
struct pfk_key_info *key_info,
|
||||
enum ice_cryto_algo_mode *algo_mode,
|
||||
bool *is_pfe)
|
||||
{
|
||||
const struct inode *inode;
|
||||
enum pfe_type which_pfe;
|
||||
const struct blk_encryption_key *key;
|
||||
|
||||
inode = pfk_bio_get_inode(bio);
|
||||
which_pfe = pfk_get_pfe_type(inode);
|
||||
|
||||
if (which_pfe != INVALID_PFE) {
|
||||
/* Encrypted file; override ->bi_crypt_key */
|
||||
pr_debug("parsing inode %lu with PFE type %d\n",
|
||||
inode->i_ino, which_pfe);
|
||||
return (*(pfk_parse_inode_ftable[which_pfe]))
|
||||
(bio, inode, key_info, algo_mode, is_pfe);
|
||||
}
|
||||
|
||||
/*
|
||||
* bio is not for an encrypted file. Use ->bi_crypt_key if it was set.
|
||||
* Otherwise, don't encrypt/decrypt the bio.
|
||||
*/
|
||||
|
||||
key = bio->bi_crypt_key;
|
||||
if (!key) {
|
||||
*is_pfe = false;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Note: the "salt" is really just the second half of the XTS key. */
|
||||
BUILD_BUG_ON(sizeof(key->raw) !=
|
||||
PFK_SUPPORTED_KEY_SIZE + PFK_SUPPORTED_SALT_SIZE);
|
||||
key_info->key = &key->raw[0];
|
||||
key_info->key_size = PFK_SUPPORTED_KEY_SIZE;
|
||||
key_info->salt = &key->raw[PFK_SUPPORTED_KEY_SIZE];
|
||||
key_info->salt_size = PFK_SUPPORTED_SALT_SIZE;
|
||||
if (algo_mode)
|
||||
*algo_mode = ICE_CRYPTO_ALGO_MODE_AES_XTS;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* pfk_load_key_start() - loads PFE encryption key to the ICE
|
||||
@@ -300,8 +332,6 @@ int pfk_load_key_start(const struct bio *bio,
|
||||
enum ice_cryto_algo_mode algo_mode = ICE_CRYPTO_ALGO_MODE_AES_XTS;
|
||||
enum ice_crpto_key_size key_size_type = 0;
|
||||
u32 key_index = 0;
|
||||
struct inode *inode = NULL;
|
||||
enum pfe_type which_pfe = INVALID_PFE;
|
||||
|
||||
if (!is_pfe) {
|
||||
pr_err("is_pfe is NULL\n");
|
||||
@@ -323,23 +353,7 @@ int pfk_load_key_start(const struct bio *bio,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
inode = pfk_bio_get_inode(bio);
|
||||
if (!inode) {
|
||||
*is_pfe = false;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
which_pfe = pfk_get_pfe_type(inode);
|
||||
if (which_pfe == INVALID_PFE) {
|
||||
*is_pfe = false;
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
pr_debug("parsing file %s with PFE %d\n",
|
||||
inode_to_filename(inode), which_pfe);
|
||||
|
||||
ret = (*(pfk_parse_inode_ftable[which_pfe]))
|
||||
(bio, inode, &key_info, &algo_mode, is_pfe);
|
||||
ret = pfk_get_key_for_bio(bio, &key_info, &algo_mode, is_pfe);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
@@ -363,9 +377,6 @@ int pfk_load_key_start(const struct bio *bio,
|
||||
ice_setting->key_mode = ICE_CRYPTO_USE_LUT_SW_KEY;
|
||||
ice_setting->key_index = key_index;
|
||||
|
||||
pr_debug("loaded key for file %s key_index %d\n",
|
||||
inode_to_filename(inode), key_index);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -384,8 +395,6 @@ int pfk_load_key_end(const struct bio *bio, bool *is_pfe)
|
||||
{
|
||||
int ret = 0;
|
||||
struct pfk_key_info key_info = {0};
|
||||
enum pfe_type which_pfe = INVALID_PFE;
|
||||
struct inode *inode = NULL;
|
||||
|
||||
if (!is_pfe) {
|
||||
pr_err("is_pfe is NULL\n");
|
||||
@@ -401,29 +410,13 @@ int pfk_load_key_end(const struct bio *bio, bool *is_pfe)
|
||||
if (!pfk_is_ready())
|
||||
return -ENODEV;
|
||||
|
||||
inode = pfk_bio_get_inode(bio);
|
||||
if (!inode) {
|
||||
*is_pfe = false;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
which_pfe = pfk_get_pfe_type(inode);
|
||||
if (which_pfe == INVALID_PFE) {
|
||||
*is_pfe = false;
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
ret = (*(pfk_parse_inode_ftable[which_pfe]))
|
||||
(bio, inode, &key_info, NULL, is_pfe);
|
||||
ret = pfk_get_key_for_bio(bio, &key_info, NULL, is_pfe);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
pfk_kc_load_key_end(key_info.key, key_info.key_size,
|
||||
key_info.salt, key_info.salt_size);
|
||||
|
||||
pr_debug("finished using key for file %s\n",
|
||||
inode_to_filename(inode));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -444,10 +437,12 @@ int pfk_load_key_end(const struct bio *bio, bool *is_pfe)
|
||||
*/
|
||||
bool pfk_allow_merge_bio(const struct bio *bio1, const struct bio *bio2)
|
||||
{
|
||||
struct inode *inode1 = NULL;
|
||||
struct inode *inode2 = NULL;
|
||||
enum pfe_type which_pfe1 = INVALID_PFE;
|
||||
enum pfe_type which_pfe2 = INVALID_PFE;
|
||||
const struct blk_encryption_key *key1 = bio1->bi_crypt_key;
|
||||
const struct blk_encryption_key *key2 = bio2->bi_crypt_key;
|
||||
const struct inode *inode1;
|
||||
const struct inode *inode2;
|
||||
enum pfe_type which_pfe1;
|
||||
enum pfe_type which_pfe2;
|
||||
|
||||
if (!pfk_is_ready())
|
||||
return false;
|
||||
@@ -465,17 +460,29 @@ bool pfk_allow_merge_bio(const struct bio *bio1, const struct bio *bio2)
|
||||
which_pfe1 = pfk_get_pfe_type(inode1);
|
||||
which_pfe2 = pfk_get_pfe_type(inode2);
|
||||
|
||||
/* nodes with different encryption, do not merge */
|
||||
/*
|
||||
* If one bio is for an encrypted file and the other is for a different
|
||||
* type of encrypted file or for blocks that are not part of an
|
||||
* encrypted file, do not merge.
|
||||
*/
|
||||
if (which_pfe1 != which_pfe2)
|
||||
return false;
|
||||
|
||||
/* both nodes do not have encryption, allow merge */
|
||||
if (which_pfe1 == INVALID_PFE)
|
||||
return true;
|
||||
if (which_pfe1 != INVALID_PFE) {
|
||||
/* Both bios are for the same type of encrypted file. */
|
||||
return (*(pfk_allow_merge_bio_ftable[which_pfe1]))(bio1, bio2,
|
||||
inode1, inode2);
|
||||
}
|
||||
|
||||
return (*(pfk_allow_merge_bio_ftable[which_pfe1]))(bio1, bio2,
|
||||
inode1, inode2);
|
||||
/*
|
||||
* Neither bio is for an encrypted file. Merge only if the default keys
|
||||
* are the same (or both are NULL).
|
||||
*/
|
||||
return key1 == key2 ||
|
||||
(key1 && key2 &&
|
||||
!crypto_memneq(key1->raw, key2->raw, sizeof(key1->raw)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush key table on storage core reset. During core reset key configuration
|
||||
* is lost in ICE. We need to flash the cache, so that the keys will be
|
||||
|
||||
@@ -29,6 +29,4 @@ int pfk_key_size_to_key_type(size_t key_size,
|
||||
bool pfe_is_inode_filesystem_type(const struct inode *inode,
|
||||
const char *fs_type);
|
||||
|
||||
char *inode_to_filename(const struct inode *inode);
|
||||
|
||||
#endif /* _PFK_INTERNAL_H_ */
|
||||
|
||||
Reference in New Issue
Block a user