diff options
Diffstat (limited to 'security')
| -rw-r--r-- | security/pfe/pfk.c | 52 | ||||
| -rw-r--r-- | security/pfe/pfk_ice.c | 40 | ||||
| -rw-r--r-- | security/pfe/pfk_ice.h | 2 | ||||
| -rw-r--r-- | security/pfe/pfk_kc.c | 145 | ||||
| -rw-r--r-- | security/pfe/pfk_kc.h | 5 |
5 files changed, 208 insertions, 36 deletions
diff --git a/security/pfe/pfk.c b/security/pfe/pfk.c index e8d7cb678aed..3c8e2f8fad41 100644 --- a/security/pfe/pfk.c +++ b/security/pfe/pfk.c @@ -65,6 +65,7 @@ static int g_events_handle; /* might be replaced by a table when more than one cipher is supported */ #define PFK_SUPPORTED_CIPHER "aes_xts" #define PFK_SUPPORTED_KEY_SIZE 32 +#define PFK_SUPPORTED_SALT_SIZE 32 static int pfk_inode_alloc_security(struct inode *inode) { @@ -326,12 +327,14 @@ int pfk_load_key(const struct bio *bio, struct ice_crypto_setting *ice_setting) 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; @@ -386,6 +389,20 @@ int pfk_load_key(const struct bio *bio, struct ice_crypto_setting *ice_setting) goto end; } + salt = ecryptfs_get_salt(ecryptfs_data); + if (!salt) { + pr_err("could not parse salt from ecryptfs\n"); + ret = -EINVAL; + goto end; + } + + 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; + } + cipher = ecryptfs_get_cipher(ecryptfs_data); if (!key) { pr_err("could not parse key from ecryptfs\n"); @@ -401,7 +418,7 @@ 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, &key_index); + 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); @@ -503,7 +520,6 @@ bool pfk_allow_merge_bio(struct bio *bio1, struct bio *bio2) goto end; } - /* * at this point both bio's are in the same file which is probably * encrypted, last thing to check is header vs data @@ -587,7 +603,9 @@ static void pfk_open_cb(struct inode *inode, void *ecryptfs_data) static void pfk_release_cb(struct inode *inode) { const unsigned char *key = NULL; - size_t key_size; + const unsigned char *salt = NULL; + size_t key_size = 0; + size_t salt_size = 0; void *data = NULL; if (!pfk_is_ready()) @@ -616,14 +634,26 @@ static void pfk_release_cb(struct inode *inode) return; } - pfk_kc_remove_key(key, key_size); + salt = ecryptfs_get_salt(data); + if (!salt) { + pr_err("could not parse salt from ecryptfs\n"); + return; + } + + salt_size = ecryptfs_get_salt_size(data); + if (!salt_size) { + pr_err("could not parse salt size from ecryptfs\n"); + return; + } + + pfk_kc_remove_key_with_salt(key, key_size, salt, salt_size); mutex_lock(&pfk_lock); pfk_set_ecryptfs_data(inode, NULL); mutex_unlock(&pfk_lock); } -static bool pfk_is_cipher_supported_cb(char *cipher) +static bool pfk_is_cipher_supported_cb(const char *cipher) { if (!pfk_is_ready()) return false; @@ -642,6 +672,17 @@ static bool pfk_is_hw_crypt_cb(void) return true; } +static size_t pfk_get_salt_key_size_cb(const char *cipher) +{ + if (!pfk_is_ready()) + return 0; + + if (!pfk_is_cipher_supported_cb(cipher)) + return 0; + + return PFK_SUPPORTED_SALT_SIZE; +} + static void __exit pfk_exit(void) { @@ -660,6 +701,7 @@ static int __init pfk_init(void) events.release_cb = pfk_release_cb; events.is_cipher_supported_cb = pfk_is_cipher_supported_cb; events.is_hw_crypt_cb = pfk_is_hw_crypt_cb; + events.get_salt_key_size_cb = pfk_get_salt_key_size_cb; g_events_handle = ecryptfs_register_to_events(&events); if (0 == g_events_handle) { diff --git a/security/pfe/pfk_ice.c b/security/pfe/pfk_ice.c index d26dee245cc5..1cb350296159 100644 --- a/security/pfe/pfk_ice.c +++ b/security/pfe/pfk_ice.c @@ -48,46 +48,60 @@ #define TZ_ES_SET_ICE_KEY_PARAM_ID \ - TZ_SYSCALL_CREATE_PARAM_ID_3( \ - TZ_SYSCALL_PARAM_TYPE_VAL, \ - TZ_SYSCALL_PARAM_TYPE_BUF_RW, TZ_SYSCALL_PARAM_TYPE_VAL) + TZ_SYSCALL_CREATE_PARAM_ID_5( \ + TZ_SYSCALL_PARAM_TYPE_VAL, \ + TZ_SYSCALL_PARAM_TYPE_BUF_RW, TZ_SYSCALL_PARAM_TYPE_VAL, \ + TZ_SYSCALL_PARAM_TYPE_BUF_RW, TZ_SYSCALL_PARAM_TYPE_VAL) #define TZ_ES_INVALIDATE_ICE_KEY_PARAM_ID \ TZ_SYSCALL_CREATE_PARAM_ID_1( \ TZ_SYSCALL_PARAM_TYPE_VAL) #define ICE_KEY_SIZE 32 - +#define ICE_SALT_SIZE 32 uint8_t ice_key[ICE_KEY_SIZE]; +uint8_t ice_salt[ICE_KEY_SIZE]; -int qti_pfk_ice_set_key(uint32_t index, uint8_t *key) +int qti_pfk_ice_set_key(uint32_t index, uint8_t *key, uint8_t *salt) { struct scm_desc desc = {0}; int ret; - char *tzbuf = (char *)ice_key; + char *tzbuf_key = (char *)ice_key; + char *tzbuf_salt = (char *)ice_salt; uint32_t smc_id = 0; - u32 tzbuflen = sizeof(ice_key); + u32 tzbuflen_key = sizeof(ice_key); + u32 tzbuflen_salt = sizeof(ice_salt); if (index < MIN_ICE_KEY_INDEX || index > MAX_ICE_KEY_INDEX) return -EINVAL; - if (!tzbuf) + if (!key || !salt) + return -EINVAL; + + if (!tzbuf_key || !tzbuf_salt) return -ENOMEM; - memset(tzbuf, 0, tzbuflen); - memcpy(ice_key, key, ICE_KEY_SIZE); + memset(tzbuf_key, 0, tzbuflen_key); + memset(tzbuf_salt, 0, tzbuflen_salt); - dmac_flush_range(tzbuf, tzbuf + tzbuflen); + memcpy(ice_key, key, tzbuflen_key); + memcpy(ice_salt, salt, tzbuflen_salt); + + dmac_flush_range(tzbuf_key, tzbuf_key + tzbuflen_key); + dmac_flush_range(tzbuf_salt, tzbuf_salt + tzbuflen_salt); smc_id = TZ_ES_SET_ICE_KEY_ID; pr_debug(" %s , smc_id = 0x%x\n", __func__, smc_id); desc.arginfo = TZ_ES_SET_ICE_KEY_PARAM_ID; desc.args[0] = index; - desc.args[1] = virt_to_phys(tzbuf); - desc.args[2] = tzbuflen; + desc.args[1] = virt_to_phys(tzbuf_key); + desc.args[2] = tzbuflen_key; + desc.args[3] = virt_to_phys(tzbuf_salt); + desc.args[4] = tzbuflen_salt; + ret = scm_call2_atomic(smc_id, &desc); pr_debug(" %s , ret = %d\n", __func__, ret); diff --git a/security/pfe/pfk_ice.h b/security/pfe/pfk_ice.h index b1a5c4c807a3..1d6339a575be 100644 --- a/security/pfe/pfk_ice.h +++ b/security/pfe/pfk_ice.h @@ -26,7 +26,7 @@ int pfk_ice_init(void); int pfk_ice_deinit(void); -int qti_pfk_ice_set_key(uint32_t index, uint8_t *key); +int qti_pfk_ice_set_key(uint32_t index, uint8_t *key, uint8_t *salt); int qti_pfk_ice_invalidate_key(uint32_t index); diff --git a/security/pfe/pfk_kc.c b/security/pfe/pfk_kc.c index 687663f5a7ac..eff49d0315b5 100644 --- a/security/pfe/pfk_kc.c +++ b/security/pfe/pfk_kc.c @@ -41,15 +41,17 @@ /** the first available index in ice engine */ #define PFK_KC_STARTING_INDEX 2 -/** currently the only supported key size */ +/** currently the only supported key and salt sizes */ #define PFK_KC_KEY_SIZE 32 +#define PFK_KC_SALT_SIZE 32 /** Table size */ /* TODO replace by some constant from ice.h */ #define PFK_KC_TABLE_SIZE ((32) - (PFK_KC_STARTING_INDEX)) -/** The maximum key size */ +/** The maximum key and salt size */ #define PFK_MAX_KEY_SIZE PFK_KC_KEY_SIZE +#define PFK_MAX_SALT_SIZE PFK_KC_SALT_SIZE static DEFINE_SPINLOCK(kc_lock); static bool kc_ready; @@ -57,11 +59,15 @@ static bool kc_ready; struct kc_entry { unsigned char key[PFK_MAX_KEY_SIZE]; size_t key_size; + + unsigned char salt[PFK_MAX_SALT_SIZE]; + size_t salt_size; + u64 time_stamp; u32 key_index; }; -static struct kc_entry kc_table[PFK_KC_TABLE_SIZE] = {{{0} , 0, 0, 0} }; +static struct kc_entry kc_table[PFK_KC_TABLE_SIZE] = {{{0}, 0, {0}, 0, 0, 0} }; /** * pfk_min_time_entry() - update min time and update min entry @@ -96,31 +102,66 @@ static inline bool kc_is_ready(void) } /** - * kc_find_key() - find kc entry + * kc_find_key_at_index() - find kc entry starting at specific index * @key: key to look for * @key_size: the key size + * @salt: salt to look for + * @salt_size: the salt size + * @sarting_index: index to start search with, if entry found, updated with + * index of that entry * * Return entry or NULL in case of error * Should be invoked under lock */ -static struct kc_entry *kc_find_key(const unsigned char *key, size_t key_size) +static struct kc_entry *kc_find_key_at_index(const unsigned char *key, + size_t key_size, const unsigned char *salt, size_t salt_size, + int *starting_index) { struct kc_entry *entry = NULL; int i = 0; - for (i = 0; i < PFK_KC_TABLE_SIZE; i++) { + for (i = *starting_index; i < PFK_KC_TABLE_SIZE; i++) { entry = &(kc_table[i]); + + if (NULL != salt) { + if (entry->salt_size != salt_size) + continue; + + if (0 != memcmp(entry->salt, salt, salt_size)) + continue; + } + if (entry->key_size != key_size) continue; - if (0 == memcmp(entry->key, key, key_size)) + if (0 == memcmp(entry->key, key, key_size)) { + *starting_index = i; return entry; + } } return NULL; } /** + * kc_find_key() - find kc entry + * @key: key to look for + * @key_size: the key size + * @salt: salt to look for + * @salt_size: the salt size + * + * Return entry or NULL in case of error + * Should be invoked under lock + */ +static struct kc_entry *kc_find_key(const unsigned char *key, size_t key_size, + const unsigned char *salt, size_t salt_size) +{ + int index = 0; + + return kc_find_key_at_index(key, key_size, salt, salt_size, &index); +} + +/** * kc_find_oldest_entry() - finds the entry with minimal timestamp * * Returns entry with minimal timestamp. Empty entries have timestamp @@ -183,6 +224,7 @@ static void kc_clear_entry(struct kc_entry *entry, bool clear_qscee) qti_pfk_ice_invalidate_key(entry->key_index); memset(entry->key, 0, entry->key_size); + memset(entry->salt, 0, entry->salt_size); entry->time_stamp = 0; } @@ -194,13 +236,15 @@ static void kc_clear_entry(struct kc_entry *entry, bool clear_qscee) * @entry: entry to replace key in * @key: key * @key_size: key_size + * @salt: salt + * @salt_size: salt_size * * The previous key is securely released and wiped, the new one is loaded * to ICE. * Should be invoked under lock */ static int kc_replace_entry(struct kc_entry *entry, const unsigned char *key, - size_t key_size) + size_t key_size, const unsigned char *salt, size_t salt_size) { int ret = 0; @@ -209,7 +253,11 @@ static int kc_replace_entry(struct kc_entry *entry, const unsigned char *key, memcpy(entry->key, key, key_size); entry->key_size = key_size; - ret = qti_pfk_ice_set_key(entry->key_index, (uint8_t *) key); + memcpy(entry->salt, salt, salt_size); + entry->salt_size = salt_size; + + ret = qti_pfk_ice_set_key(entry->key_index, (uint8_t *) key, + (uint8_t *) salt); if (ret != 0) { ret = -EINVAL; goto err; @@ -265,7 +313,9 @@ int pfk_kc_deinit(void) * pfk_kc_load_key() - retrieve the key from cache or add it if it's not there * return the ICE hw key index * @key: pointer to the key - * @key_size: the size of the key, assumed to be not bigger than + * @key_size: the size of the key + * @salt: pointer to the salt + * @salt_size: the size of the salt * @key_index: the pointer to key_index where the output will be stored * * If key is present in cache, than the key_index will be retrieved from cache. @@ -275,7 +325,8 @@ int pfk_kc_deinit(void) * * Return 0 in case of success, error otherwise */ -int pfk_kc_load_key(const unsigned char *key, size_t key_size, u32 *key_index) +int pfk_kc_load_key(const unsigned char *key, size_t key_size, + const unsigned char *salt, size_t salt_size, u32 *key_index) { int ret = 0; struct kc_entry *entry = NULL; @@ -283,14 +334,17 @@ int pfk_kc_load_key(const unsigned char *key, size_t key_size, u32 *key_index) if (!kc_is_ready()) return -ENODEV; - if (!key || !key_index) + if (!key || !salt || !key_index) return -EPERM; if (key_size != PFK_KC_KEY_SIZE) return -EPERM; + if (salt_size != PFK_KC_SALT_SIZE) + return -EPERM; + spin_lock(&kc_lock); - entry = kc_find_key(key, key_size); + entry = kc_find_key(key, key_size, salt, salt_size); if (!entry) { entry = kc_find_oldest_entry(); if (!entry) { @@ -302,7 +356,7 @@ int pfk_kc_load_key(const unsigned char *key, size_t key_size, u32 *key_index) pr_debug("didn't found key in cache, replacing entry with index %d\n", entry->key_index); - ret = kc_replace_entry(entry, key, key_size); + ret = kc_replace_entry(entry, key, key_size, salt, salt_size); if (ret) { spin_unlock(&kc_lock); return -EINVAL; @@ -322,7 +376,54 @@ int pfk_kc_load_key(const unsigned char *key, size_t key_size, u32 *key_index) /** * pfk_kc_remove_key() - remove the key from cache and from ICE engine * @key: pointer to the key - * @key_size: the size of the key, assumed to be not bigger than + * @key_size: the size of the key + * @salt: pointer to the key + * @salt_size: the size of the key + * + * Return 0 in case of success, error otherwise (also in case of non + * (existing key) + */ +int pfk_kc_remove_key_with_salt(const unsigned char *key, size_t key_size, + const unsigned char *salt, size_t salt_size) +{ + struct kc_entry *entry = NULL; + + if (!kc_is_ready()) + return -ENODEV; + + if (!key) + return -EPERM; + + if (!salt) + return -EPERM; + + if (key_size != PFK_KC_KEY_SIZE) + return -EPERM; + + if (salt_size != PFK_KC_SALT_SIZE) + return -EPERM; + + spin_lock(&kc_lock); + entry = kc_find_key(key, key_size, salt, salt_size); + if (!entry) { + pr_err("key does not exist\n"); + spin_unlock(&kc_lock); + return -EINVAL; + } + + kc_clear_entry(entry, true); + spin_unlock(&kc_lock); + + return 0; +} + +/** + * pfk_kc_remove_key() - remove the key from cache and from ICE engine + * when no salt is available. Will only search key part, if there are several, + * all will be removed + * + * @key: pointer to the key + * @key_size: the size of the key * * Return 0 in case of success, error otherwise (also in case of non * (existing key) @@ -330,6 +431,7 @@ int pfk_kc_load_key(const unsigned char *key, size_t key_size, u32 *key_index) int pfk_kc_remove_key(const unsigned char *key, size_t key_size) { struct kc_entry *entry = NULL; + int index = 0; if (!kc_is_ready()) return -ENODEV; @@ -341,7 +443,8 @@ int pfk_kc_remove_key(const unsigned char *key, size_t key_size) return -EPERM; spin_lock(&kc_lock); - entry = kc_find_key(key, key_size); + + entry = kc_find_key_at_index(key, key_size, NULL, 0, &index); if (!entry) { pr_err("key does not exist\n"); spin_unlock(&kc_lock); @@ -349,6 +452,16 @@ int pfk_kc_remove_key(const unsigned char *key, size_t key_size) } kc_clear_entry(entry, true); + + /* let's clean additional entries with the same key if there are any */ + do { + entry = kc_find_key_at_index(key, key_size, NULL, 0, &index); + if (!entry) + break; + + kc_clear_entry(entry, true); + } while (true); + spin_unlock(&kc_lock); return 0; diff --git a/security/pfe/pfk_kc.h b/security/pfe/pfk_kc.h index 86cc1b43e4f3..07b7827e8ddc 100644 --- a/security/pfe/pfk_kc.h +++ b/security/pfe/pfk_kc.h @@ -17,7 +17,10 @@ int pfk_kc_init(void); int pfk_kc_deinit(void); -int pfk_kc_load_key(const unsigned char *key, size_t key_size, u32 *key_index); +int pfk_kc_load_key(const unsigned char *key, size_t key_size, + const unsigned char *salt, size_t salt_size, u32 *key_index); +int pfk_kc_remove_key_with_salt(const unsigned char *key, size_t key_size, + const unsigned char *salt, size_t salt_size); int pfk_kc_remove_key(const unsigned char *key, size_t key_size); void pfk_kc_clear(void); |
