summaryrefslogtreecommitdiff
path: root/security
diff options
context:
space:
mode:
Diffstat (limited to 'security')
-rw-r--r--security/pfe/pfk.c52
-rw-r--r--security/pfe/pfk_ice.c40
-rw-r--r--security/pfe/pfk_ice.h2
-rw-r--r--security/pfe/pfk_kc.c145
-rw-r--r--security/pfe/pfk_kc.h5
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);