diff options
Diffstat (limited to 'security/pfe/pfk.c')
-rw-r--r-- | security/pfe/pfk.c | 225 |
1 files changed, 162 insertions, 63 deletions
diff --git a/security/pfe/pfk.c b/security/pfe/pfk.c index 23ea0b9d01b1..05afa19c792b 100644 --- a/security/pfe/pfk.c +++ b/security/pfe/pfk.c @@ -164,7 +164,7 @@ static inline bool pfk_is_ready(void) static int pfk_get_page_index(const struct bio *bio, pgoff_t *page_index) { if (!bio || !page_index) - return -EPERM; + return -EINVAL; /* check bio bi_size > 0 before using the bio->bi_io_vec[] array */ if (!(bio->bi_iter).bi_size) @@ -260,7 +260,7 @@ static int pfk_set_ecryptfs_data(struct inode *inode, void *ecryptfs_data) struct inode_security_struct *isec = NULL; if (!inode) - return -EPERM; + return -EINVAL; isec = inode->i_security; @@ -333,54 +333,40 @@ static int pfk_key_size_to_key_type(size_t key_size, return 0; } -/** - * pfk_load_key() - loads the encryption key to the ICE - * @bio: Pointer to the BIO structure - * @ice_setting: Pointer to ice setting structure that will be filled with - * ice configuration values, including the index to which the key was loaded - * - * Via bio gets access to ecryptfs key stored in auxiliary structure inside - * inode and loads it to encryption hw. - * Returns the index where the key is stored in encryption hw and additional - * information that will be used later for configuration of the encryption hw. - * - */ -int pfk_load_key(const struct bio *bio, struct ice_crypto_setting *ice_setting) +static int pfk_bio_to_key(const struct bio *bio, unsigned char const **key, + size_t *key_size, unsigned char const **salt, size_t *salt_size, + bool *is_pfe) { struct inode *inode = NULL; int ret = 0; - const unsigned char *key = NULL; - const unsigned char *salt = NULL; - const unsigned char *cipher = NULL; void *ecryptfs_data = NULL; - u32 key_index = 0; - enum ice_cryto_algo_mode algo_mode = 0; - enum ice_crpto_key_size key_size_type = 0; - size_t key_size = 0; - size_t salt_size = 0; pgoff_t offset; bool is_metadata = false; - if (!pfk_is_ready()) - return -ENODEV; + /* + * only a few errors below can indicate that + * this function was not invoked within PFE context, + * otherwise we will consider it PFE + */ + *is_pfe = true; + if (!bio) - return -EPERM; + return -EINVAL; - if (!ice_setting) { - pr_err("ice setting is NULL\n"); - return -EPERM; - } + if (!key || !salt || !key_size || !salt_size) + return -EINVAL; inode = pfk_bio_get_inode(bio); - if (!inode) + if (!inode) { + *is_pfe = false; return -EINVAL; + } ecryptfs_data = pfk_get_ecryptfs_data(inode); - if (!ecryptfs_data) { - ret = -EINVAL; - goto end; + *is_pfe = false; + return -EPERM; } pr_debug("loading key for file %s\n", inode_to_filename(inode)); @@ -388,49 +374,118 @@ int pfk_load_key(const struct bio *bio, struct ice_crypto_setting *ice_setting) ret = pfk_get_page_index(bio, &offset); if (ret != 0) { pr_err("could not get page index from bio, probably bug %d\n", - ret); - ret = -EINVAL; - goto end; + ret); + return -EINVAL; } is_metadata = ecryptfs_is_page_in_metadata(ecryptfs_data, offset); if (is_metadata == true) { pr_debug("ecryptfs metadata, bypassing ICE\n"); - ret = -ESPIPE; - goto end; + *is_pfe = false; + return -EPERM; } - key = ecryptfs_get_key(ecryptfs_data); + *key = ecryptfs_get_key(ecryptfs_data); if (!key) { pr_err("could not parse key from ecryptfs\n"); - ret = -EINVAL; - goto end; + return -EINVAL; } - key_size = ecryptfs_get_key_size(ecryptfs_data); - if (!key_size) { + *key_size = ecryptfs_get_key_size(ecryptfs_data); + if (!(*key_size)) { pr_err("could not parse key size from ecryptfs\n"); - ret = -EINVAL; - goto end; + return -EINVAL; } - salt = ecryptfs_get_salt(ecryptfs_data); + *salt = ecryptfs_get_salt(ecryptfs_data); if (!salt) { pr_err("could not parse salt from ecryptfs\n"); - ret = -EINVAL; - goto end; + return -EINVAL; } - salt_size = ecryptfs_get_salt_size(ecryptfs_data); - if (!salt_size) { + *salt_size = ecryptfs_get_salt_size(ecryptfs_data); + if (!(*salt_size)) { pr_err("could not parse salt size from ecryptfs\n"); - ret = -EINVAL; - goto end; + return -EINVAL; } - ret = pfk_parse_cipher(cipher, &algo_mode); + return 0; +} + +/** + * pfk_load_key_start() - loads PFE encryption key to the ICE + * Can also be invoked from non + * PFE context, than it is not + * relevant and is_pfe flag is + * set to true + * @bio: Pointer to the BIO structure + * @ice_setting: Pointer to ice setting structure that will be filled with + * ice configuration values, including the index to which the key was loaded + * @is_pfe: Pointer to is_pfe flag, which will be true if function was invoked + * from PFE context + * + * Via bio gets access to ecryptfs key stored in auxiliary structure inside + * inode and loads it to encryption hw. + * Returns the index where the key is stored in encryption hw and additional + * information that will be used later for configuration of the encryption hw. + * + * Must be followed by pfk_load_key_end when key is no longer used by ice + * + */ +int pfk_load_key_start(const struct bio *bio, + struct ice_crypto_setting *ice_setting, bool *is_pfe, + bool async) +{ + int ret = 0; + const unsigned char *key = NULL; + const unsigned char *salt = NULL; + size_t key_size = 0; + size_t salt_size = 0; + enum ice_cryto_algo_mode algo_mode = 0; + enum ice_crpto_key_size key_size_type = 0; + void *ecryptfs_data = NULL; + u32 key_index = 0; + struct inode *inode = NULL; + + if (!is_pfe) { + pr_err("is_pfe is NULL\n"); + return -EINVAL; + } + + /* + * only a few errors below can indicate that + * this function was not invoked within PFE context, + * otherwise we will consider it PFE + */ + *is_pfe = true; + + if (!pfk_is_ready()) + return -ENODEV; + + if (!ice_setting) { + pr_err("ice setting is NULL\n"); + return -EINVAL; + } + + ret = pfk_bio_to_key(bio, &key, &key_size, &salt, &salt_size, is_pfe); + if (ret != 0) + return ret; + + inode = pfk_bio_get_inode(bio); + if (!inode) { + *is_pfe = false; + return -EINVAL; + } + + ecryptfs_data = pfk_get_ecryptfs_data(inode); + if (!ecryptfs_data) { + *is_pfe = false; + return -EPERM; + } + + ret = pfk_parse_cipher(ecryptfs_data, &algo_mode); if (ret != 0) { - pr_debug("not supported cipher\n"); + pr_err("not supported cipher\n"); return ret; } @@ -438,11 +493,14 @@ int pfk_load_key(const struct bio *bio, struct ice_crypto_setting *ice_setting) if (ret != 0) return ret; - ret = pfk_kc_load_key(key, key_size, salt, salt_size, &key_index); - if (ret != 0) { - pr_err("could not load key into pfk key cache, error %d\n", - ret); - return -EINVAL; + ret = pfk_kc_load_key_start(key, key_size, salt, salt_size, &key_index, + async); + if (ret) { + if (ret != -EBUSY && ret != -EAGAIN) + pr_err("start: could not load key into pfk key cache, error %d\n", + ret); + + return ret; } ice_setting->key_size = key_size_type; @@ -452,10 +510,51 @@ int pfk_load_key(const struct bio *bio, struct ice_crypto_setting *ice_setting) ice_setting->key_index = key_index; return 0; +} -end: +/** + * pfk_load_key_end() - marks the PFE key as no longer used by ICE + * Can also be invoked from non + * PFE context, than it is not + * relevant and is_pfe flag is + * set to true + * @bio: Pointer to the BIO structure + * @is_pfe: Pointer to is_pfe flag, which will be true if function was invoked + * from PFE context + * + * Via bio gets access to ecryptfs key stored in auxiliary structure inside + * inode and loads it to encryption hw. + * + */ +int pfk_load_key_end(const struct bio *bio, bool *is_pfe) +{ + int ret = 0; + const unsigned char *key = NULL; + const unsigned char *salt = NULL; + size_t key_size = 0; + size_t salt_size = 0; - return ret; + if (!is_pfe) { + pr_err("is_pfe is NULL\n"); + return -EINVAL; + } + + /* only a few errors below can indicate that + * this function was not invoked within PFE context, + * otherwise we will consider it PFE + */ + *is_pfe = true; + + if (!pfk_is_ready()) + return -ENODEV; + + ret = pfk_bio_to_key(bio, &key, &key_size, &salt, &salt_size, is_pfe); + if (ret != 0) + return ret; + + pfk_kc_load_key_end(key, key_size, salt, salt_size); + + return 0; } /** @@ -477,7 +576,7 @@ int pfk_remove_key(const unsigned char *key, size_t key_size) return -ENODEV; if (!key) - return -EPERM; + return -EINVAL; ret = pfk_kc_remove_key(key, key_size); |