| /* |
| * Copyright (c) 2015 Samsung Electronics Co., Ltd. |
| * |
| * Sensitive Data Protection |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License version 2 as |
| * published by the Free Software Foundation. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License along |
| * with this program; if not, write to the Free Software Foundation, Inc., |
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
| */ |
| |
| #include <linux/fs.h> |
| #include <linux/fcntl.h> |
| #include <linux/module.h> |
| #include <linux/kernel.h> |
| #include <linux/init.h> |
| #include <linux/miscdevice.h> |
| #include <linux/uaccess.h> |
| #include <linux/syscalls.h> |
| #include <linux/time.h> |
| #include <linux/list.h> |
| #include <linux/wait.h> |
| #include <linux/random.h> |
| #include <linux/err.h> |
| #include <sdp/dek_common.h> |
| #include <sdp/dek_ioctl.h> |
| #include <sdp/dek_aes.h> |
| #include <sdp/kek_pack.h> |
| |
| #include "../../fs/ext4/sdp/fscrypto_sdp_cache.h" |
| |
| /* |
| * Need to move this to defconfig |
| */ |
| #define CONFIG_PUB_CRYPTO |
| //#define CONFIG_SDP_IOCTL_PRIV |
| |
| #ifdef CONFIG_PUB_CRYPTO |
| #include <sdp/pub_crypto_emul.h> |
| #endif |
| |
| #define DEK_LOG_COUNT 100 |
| |
| #if defined(CONFIG_SDP) && !defined(CONFIG_EXT4CRYPT_SDP) |
| extern void ecryptfs_mm_drop_cache(int userid, int engineid); |
| #endif |
| |
| /* Log buffer */ |
| struct log_struct |
| { |
| int len; |
| char buf[256]; |
| struct list_head list; |
| spinlock_t list_lock; |
| }; |
| struct log_struct log_buffer; |
| static int log_count = 0; |
| |
| /* Wait queue */ |
| wait_queue_head_t wq; |
| static int flag = 0; |
| |
| int dek_is_sdp_uid(uid_t uid) { |
| int userid = uid / PER_USER_RANGE; |
| |
| return is_kek_pack(userid); |
| } |
| EXPORT_SYMBOL(dek_is_sdp_uid); |
| |
| int is_system_server(void) { |
| uid_t uid = from_kuid(&init_user_ns, current_uid()); |
| |
| switch(uid) { |
| #if 0 |
| case 0: //root |
| DEK_LOGD("allowing root to access SDP device files\n"); |
| #endif |
| case 1000: |
| return 1; |
| default: |
| break; |
| } |
| |
| return 0; |
| } |
| |
| int is_root(void) { |
| uid_t uid = from_kuid(&init_user_ns, current_uid()); |
| |
| switch(uid) { |
| case 0: //root |
| //DEK_LOGD("allowing root to access SDP device files\n"); |
| return 1; |
| default: |
| ; |
| } |
| |
| return 0; |
| } |
| |
| int is_current_adbd(void) { |
| DEK_LOGD("current->comm : %s\n", current->comm); |
| #if 1 |
| if(is_root()) { |
| // epmd/vold are 4 length string |
| if(strlen(current->comm) == 4) |
| if(strcmp(current->comm, "adbd")) |
| return 1; |
| } |
| |
| return 0; |
| #else |
| return 1; |
| #endif |
| } |
| |
| int is_current_epmd(void) { |
| DEK_LOGD("current->comm : %s\n", current->comm); |
| #if 1 |
| if(is_root()) { |
| // epmd/vold are 4 length string |
| if(strlen(current->comm) == 4) |
| if(strcmp(current->comm, "vold") || strcmp(current->comm, "epmd")) |
| return 1; |
| } |
| |
| return 0; |
| #else |
| return 1; |
| #endif |
| } |
| |
| static int zero_out(char *buf, unsigned int len) { |
| char zero = 0; |
| int retry_cnt = 3; |
| int i; |
| |
| retry: |
| if(retry_cnt > 0) { |
| memset((void *)buf, zero, len); |
| for (i = 0; i < len; ++i) { |
| zero |= buf[i]; |
| if (zero) { |
| DEK_LOGE("the memory was not properly zeroed\n"); |
| retry_cnt--; |
| goto retry; |
| } |
| } |
| } else { |
| DEK_LOGE("FATAL : can't zero out!!\n"); |
| return -1; |
| } |
| |
| return 0; |
| } |
| |
| /* Log */ |
| static void dek_add_to_log(int engine_id, char * buffer); |
| |
| |
| static int dek_open_evt(struct inode *inode, struct file *file) |
| { |
| return 0; |
| } |
| |
| static int dek_release_evt(struct inode *ignored, struct file *file) |
| { |
| return 0; |
| } |
| |
| static int dek_open_req(struct inode *inode, struct file *file) |
| { |
| return 0; |
| } |
| |
| static int dek_release_req(struct inode *ignored, struct file *file) |
| { |
| return 0; |
| } |
| |
| #ifdef CONFIG_SDP_ENHANCED |
| #if DEK_DEBUG |
| void hex_key_dump(const char* tag, uint8_t *data, size_t data_len) |
| { |
| static const char *hex = "0123456789ABCDEF"; |
| static const char delimiter = ' '; |
| int i; |
| char *buf; |
| size_t buf_len; |
| |
| if (tag == NULL || data == NULL || data_len <= 0) { |
| return; |
| } |
| |
| buf_len = data_len * 3; |
| buf = (char *)kmalloc(buf_len, GFP_ATOMIC); |
| if (buf == NULL) { |
| return; |
| } |
| for (i= 0 ; i < data_len ; i++) { |
| buf[i*3 + 0] = hex[(data[i] >> 4) & 0x0F]; |
| buf[i*3 + 1] = hex[(data[i]) & 0x0F]; |
| buf[i*3 + 2] = delimiter; |
| } |
| buf[buf_len - 1] = '\0'; |
| printk(KERN_ERR |
| "[%s] %s(len=%d) : %s\n", "DEK_DBG", tag, data_len, buf); |
| kfree(buf); |
| } |
| #endif |
| #endif |
| |
| #ifdef CONFIG_SDP_KEY_DUMP |
| void key_dump(unsigned char *buf, int len) { |
| int i; |
| |
| printk("len=%d: ", len); |
| for(i=0;i<len;++i) { |
| if((i%16) == 0) |
| printk("\n"); |
| printk("%02X ", (unsigned char)buf[i]); |
| } |
| printk("\n"); |
| } |
| |
| static void kek_dump(int engine_id, int kek_type, const char *kek_name) { |
| kek_t *kek; |
| int ret; |
| |
| kek = get_kek(engine_id, kek_type, &ret); |
| if(kek) { |
| printk("dek: %s: ", kek_name); |
| key_dump(kek->buf, kek->len); |
| put_kek(kek); |
| } else { |
| printk("dek: %s: empty\n", kek_name); |
| } |
| } |
| |
| static void dump_all_keys(int engine_id) { |
| kek_dump(engine_id, KEK_TYPE_SYM, "KEK_TYPE_SYM"); |
| kek_dump(engine_id, KEK_TYPE_RSA_PUB, "KEK_TYPE_RSA_PUB"); |
| kek_dump(engine_id, KEK_TYPE_RSA_PRIV, "KEK_TYPE_RSA_PRIV"); |
| kek_dump(engine_id, KEK_TYPE_DH_PUB, "KEK_TYPE_DH_PUB"); |
| kek_dump(engine_id, KEK_TYPE_DH_PRIV, "KEK_TYPE_DH_PRIV"); |
| kek_dump(engine_id, KEK_TYPE_ECDH256_PUB, "KEK_TYPE_ECDH256_PUB"); |
| kek_dump(engine_id, KEK_TYPE_ECDH256_PRIV, "KEK_TYPE_ECDH256_PRIV"); |
| } |
| #endif |
| |
| int dek_is_locked(int engine_id) { |
| if(is_kek(engine_id, KEK_TYPE_SYM)) |
| return 0; |
| |
| return 1; |
| } |
| |
| int dek_generate_dek(int engine_id, dek_t *newDek) { |
| newDek->len = DEK_LEN; |
| get_random_bytes(newDek->buf, newDek->len); |
| |
| if (newDek->len <= 0 || newDek->len > DEK_LEN) { |
| zero_out((char *)newDek, sizeof(dek_t)); |
| return -EFAULT; |
| } |
| #ifdef CONFIG_SDP_KEY_DUMP |
| else { |
| if(get_sdp_sysfs_key_dump()) { |
| DEK_LOGD("DEK: "); |
| key_dump(newDek->buf, newDek->len); |
| } |
| } |
| #endif |
| |
| return 0; |
| } |
| |
| #ifdef CONFIG_SDP_ENHANCED |
| int dek_encrypt_dek_ecdh(dek_t *plainDek, dek_t *encDek, kek_t *drv_key) |
| { |
| int res; |
| int enc_type; |
| unsigned int enc_plen; |
| u8 enc_pbuf[SDP_CRYPTO_GCM_MAX_PLEN]; |
| |
| ss_payload sspay; |
| dek_t in; |
| dek_t out; |
| |
| enc_type = CONV_DLEN_TO_TYPE(plainDek->len); |
| if (unlikely(!enc_type)) |
| return -EINVAL; |
| |
| #if DEK_DEBUG |
| hex_key_dump("enc_ecdh: plainDek", (u8 *)plainDek, sizeof(dek_t)); |
| #endif |
| |
| // Update Dummy DEK into input dek |
| in.type = DEK_TYPE_DUMMY, |
| in.len = 0; |
| |
| // Derive shared secret |
| res = ecdh_deriveSS(&in, &out, drv_key); |
| if (res || out.len != sizeof(ss_payload)) |
| return -EINVAL; |
| |
| // Update ss_payload |
| memcpy(&sspay, out.buf, out.len); |
| res = dek_aes_encrypt_key_raw( |
| sspay.ss.buf, sspay.ss.len, plainDek->buf, plainDek->len, enc_pbuf, &enc_plen); |
| if (res) |
| goto clean; |
| |
| /* |
| * Update encDek which will be stored into file system |
| * |
| * Blob Format : [ DataK.pub | GCM Pack ] |
| * [ dhkt_t | gcm_pack32 ] |
| * or [ dhkt_t | gcm_pack64 ] |
| */ |
| memset(encDek->buf, 0, DEK_MAXLEN); |
| memcpy(encDek->buf, &sspay.dh, sizeof(dhk_t)); |
| memcpy((u8 *)encDek->buf + sizeof(dhk_t), enc_pbuf, enc_plen); |
| encDek->len = sizeof(dhk_t) + enc_plen; |
| encDek->type = DEK_TYPE_ECDH256_ENC; |
| |
| #if DEK_DEBUG |
| hex_key_dump("enc_ecdh: encDek", (u8 *)encDek, sizeof(dek_t)); |
| #endif |
| |
| clean: |
| memset(sspay.ss.buf, 0, sspay.ss.len); |
| memset(out.buf, 0, out.len); |
| |
| return res; |
| } |
| #endif |
| |
| static int dek_encrypt_dek(int engine_id, dek_t *plainDek, dek_t *encDek) { |
| int ret = 0; |
| kek_t *kek; |
| |
| #ifdef CONFIG_SDP_KEY_DUMP |
| if(get_sdp_sysfs_key_dump()) { |
| DEK_LOGD("plainDek from user: "); |
| key_dump(plainDek->buf, plainDek->len); |
| } |
| #endif |
| |
| kek = get_kek(engine_id, KEK_TYPE_SYM, &ret); |
| if (kek) { |
| #ifdef CONFIG_SDP_ENHANCED |
| ret = dek_aes_encrypt_key(kek, plainDek->buf, plainDek->len, encDek->buf, &encDek->len); |
| if (ret) { |
| DEK_LOGE("aes encrypt failed\n"); |
| dek_add_to_log(engine_id, "aes encrypt failed"); |
| } else { |
| encDek->type = DEK_TYPE_AES_ENC; |
| } |
| #else |
| if (dek_aes_encrypt(kek, plainDek->buf, encDek->buf, plainDek->len)) { |
| DEK_LOGE("aes encrypt failed\n"); |
| dek_add_to_log(engine_id, "aes encrypt failed"); |
| encDek->len = 0; |
| } else { |
| encDek->len = plainDek->len; |
| encDek->type = DEK_TYPE_AES_ENC; |
| } |
| #endif |
| put_kek(kek); |
| } else { |
| #ifdef CONFIG_PUB_CRYPTO |
| /* |
| * Do an asymmetric crypto |
| */ |
| switch(get_sdp_sysfs_asym_alg()) { |
| case SDPK_ALGOTYPE_ASYMM_ECDH: |
| kek = get_kek(engine_id, KEK_TYPE_ECDH256_PUB, &ret); |
| if(kek) { |
| #ifdef CONFIG_SDP_ENHANCED |
| ret = dek_encrypt_dek_ecdh(plainDek, encDek, kek); |
| #else |
| ret = ecdh_encryptDEK(plainDek, encDek, kek); |
| #endif |
| put_kek(kek); |
| break; |
| }else{ |
| if(ret == -EACCES) return ret; |
| |
| DEK_LOGE("no KEK_TYPE_ECDH256_PUB : %d\n", engine_id); |
| dek_add_to_log(engine_id, "encrypt failed, no KEK_TYPE_ECDH256_PUB"); |
| } |
| // no ECDH, try DH |
| /* no break */ |
| case SDPK_ALGOTYPE_ASYMM_DH: |
| kek = get_kek(engine_id, KEK_TYPE_DH_PUB, &ret); |
| if(kek) { |
| ret = dh_encryptDEK(plainDek, encDek, kek); |
| put_kek(kek); |
| break; |
| }else{ |
| if(ret == -EACCES) return ret; |
| |
| DEK_LOGE("no KEK_TYPE_DH_PUB : %d\n", engine_id); |
| dek_add_to_log(engine_id, "encrypt failed, no KEK_TYPE_DH_PUB"); |
| } |
| // no DH, try RSA |
| /* no break */ |
| case SDPK_ALGOTYPE_ASYMM_RSA: |
| kek = get_kek(engine_id, KEK_TYPE_RSA_PUB, &ret); |
| if(kek) { |
| ret = rsa_encryptByPub(plainDek, encDek, kek); |
| put_kek(kek); |
| break; |
| }else{ |
| if(ret == -EACCES) return ret; |
| |
| DEK_LOGE("no KEK_TYPE_RSA_PUB : %d\n", engine_id); |
| dek_add_to_log(engine_id, "encrypt failed, no KEK_TYPE_RSA_PUB"); |
| } |
| // no RSA, return error; |
| /* no break */ |
| default: |
| DEK_LOGE("no ASYMM algo registered : %d\n", engine_id); |
| dek_add_to_log(engine_id, "no ASYMM algo supported"); |
| return -EOPNOTSUPP; |
| } |
| #else |
| DEK_LOGE("pub crypto not supported : %d\n", engine_id); |
| dek_add_to_log(engine_id, "encrypt failed, no key"); |
| return -EOPNOTSUPP; |
| #endif |
| } |
| |
| if(ret) return ret; |
| |
| if (encDek->len <= 0 || encDek->len > DEK_MAXLEN) { |
| DEK_LOGE("dek_encrypt_dek, incorrect len=%d\n", encDek->len); |
| zero_out((char *)encDek, sizeof(dek_t)); |
| return -EFAULT; |
| } |
| #ifdef CONFIG_SDP_KEY_DUMP |
| else { |
| if(get_sdp_sysfs_key_dump()) { |
| DEK_LOGD("encDek to user: "); |
| key_dump(encDek->buf, encDek->len); |
| } |
| } |
| #endif |
| |
| return 0; |
| } |
| |
| int dek_encrypt_dek_efs(int engine_id, dek_t *plainDek, dek_t *encDek) { |
| return dek_encrypt_dek(engine_id, plainDek, encDek); |
| } |
| |
| #ifdef CONFIG_SDP_ENHANCED |
| int dek_decrypt_dek_ecdh(dek_t *encDek, dek_t *plainDek, kek_t *drv_key) |
| { |
| int res; |
| int dec_type; |
| unsigned int dec_plen; |
| u8 dec_pbuf[SDP_CRYPTO_GCM_MAX_PLEN]; |
| |
| ssk_t ss; |
| dek_t in; |
| dek_t out; |
| |
| dec_plen = encDek->len - sizeof(dhk_t); |
| dec_type = CONV_PLEN_TO_TYPE(dec_plen); |
| if (unlikely(!dec_type)) |
| return -EINVAL; |
| |
| #if DEK_DEBUG |
| hex_key_dump("dec_ecdh: encDek", (u8 *)encDek, sizeof(dek_t)); |
| #endif |
| |
| // Update DataK.pub into input dek |
| memcpy(in.buf, encDek->buf, sizeof(dhk_t)); |
| in.type = DEK_TYPE_ECDH256_ENC; |
| in.len = sizeof(dhk_t); |
| |
| // Derive shared secret |
| res = ecdh_deriveSS(&in, &out, drv_key); |
| if (res || out.len != sizeof(ssk_t)) |
| return -EINVAL; |
| |
| // Update ss_payload |
| memcpy(&ss, out.buf, out.len); |
| |
| // Update GCM pack buffer |
| memcpy(dec_pbuf, (u8 *)encDek->buf + sizeof(dhk_t), dec_plen); |
| |
| // Clean up plain key buffer |
| memset(plainDek->buf, 0, DEK_MAXLEN); |
| |
| res = dek_aes_decrypt_key_raw( |
| ss.buf, ss.len, dec_pbuf, dec_plen, plainDek->buf, &plainDek->len); |
| if (res) |
| goto clean; |
| |
| plainDek->type = DEK_TYPE_PLAIN; |
| |
| #if DEK_DEBUG |
| hex_key_dump("dec_ecdh: plainDek->buf", plainDek->buf,plainDek->len); |
| #endif |
| |
| clean: |
| memset(ss.buf, 0, ss.len); |
| memset(out.buf, 0, out.len); |
| |
| return res; |
| } |
| #endif |
| |
| static int dek_decrypt_dek(int engine_id, dek_t *encDek, dek_t *plainDek) { |
| int dek_type = encDek->type; |
| kek_t *kek = NULL; |
| int ret = 0; |
| |
| #ifdef CONFIG_SDP_KEY_DUMP |
| if(get_sdp_sysfs_key_dump()) { |
| DEK_LOGD("encDek from user: "); |
| key_dump(encDek->buf, encDek->len); |
| } |
| #endif |
| switch(dek_type) { |
| case DEK_TYPE_AES_ENC: |
| { |
| kek = get_kek(engine_id, KEK_TYPE_SYM, &ret); |
| if (kek) { |
| #ifdef CONFIG_SDP_ENHANCED |
| ret = dek_aes_decrypt_key(kek, encDek->buf, encDek->len, plainDek->buf, &plainDek->len); |
| if (ret) { |
| DEK_LOGE("aes decrypt failed\n"); |
| dek_add_to_log(engine_id, "aes decrypt failed"); |
| } else { |
| plainDek->type = DEK_TYPE_PLAIN; |
| } |
| #else |
| if (dek_aes_decrypt(kek, encDek->buf, plainDek->buf, encDek->len)) { |
| DEK_LOGE("aes decrypt failed\n"); |
| dek_add_to_log(engine_id, "aes decrypt failed"); |
| plainDek->len = 0; |
| } else { |
| plainDek->len = encDek->len; |
| plainDek->type = DEK_TYPE_PLAIN; |
| } |
| #endif |
| put_kek(kek); |
| } else { |
| DEK_LOGE("no KEK_TYPE_SYM for id: %d\n", engine_id); |
| dek_add_to_log(engine_id, "decrypt failed, no KEK_TYPE_SYM"); |
| return -EIO; |
| } |
| #ifdef CONFIG_SDP_ENHANCED |
| return ret; |
| #else |
| return 0; |
| #endif |
| } |
| case DEK_TYPE_RSA_ENC: |
| { |
| #ifdef CONFIG_PUB_CRYPTO |
| kek = get_kek(engine_id, KEK_TYPE_RSA_PRIV, &ret); |
| if(kek) { |
| ret = rsa_decryptByPair(encDek, plainDek, kek); |
| put_kek(kek); |
| }else{ |
| DEK_LOGE("no KEK_TYPE_RSA_PRIV for id: %d\n", engine_id); |
| dek_add_to_log(engine_id, "decrypt failed, no KEK_TYPE_RSA_PRIV"); |
| return -EIO; |
| } |
| #else |
| DEK_LOGE("Not supported key type: %d\n", encDek->type); |
| dek_add_to_log(engine_id, "decrypt failed, DH type not supported"); |
| return -EOPNOTSUPP; |
| #endif |
| return ret; |
| } |
| case DEK_TYPE_DH_ENC: |
| { |
| #ifdef CONFIG_PUB_CRYPTO |
| kek = get_kek(engine_id, KEK_TYPE_DH_PRIV, &ret); |
| if(kek) { |
| ret = dh_decryptEDEK(encDek, plainDek, kek); |
| put_kek(kek); |
| }else{ |
| DEK_LOGE("no KEK_TYPE_DH_PRIV for id: %d\n", engine_id); |
| dek_add_to_log(engine_id, "decrypt failed, no KEK_TYPE_DH_PRIV"); |
| return -EIO; |
| } |
| #else |
| DEK_LOGE("Not supported key type: %d\n", encDek->type); |
| dek_add_to_log(engine_id, "decrypt failed, DH type not supported"); |
| return -EOPNOTSUPP; |
| #endif |
| return ret; |
| } |
| case DEK_TYPE_ECDH256_ENC: |
| { |
| #ifdef CONFIG_PUB_CRYPTO |
| kek = get_kek(engine_id, KEK_TYPE_ECDH256_PRIV, &ret); |
| if(kek) { |
| #ifdef CONFIG_SDP_ENHANCED |
| ret = dek_decrypt_dek_ecdh(encDek, plainDek, kek); |
| #else |
| ret = ecdh_decryptEDEK(encDek, plainDek, kek); |
| #endif |
| put_kek(kek); |
| }else{ |
| DEK_LOGE("no KEK_TYPE_ECDH256_PRIV for id: %d\n", engine_id); |
| dek_add_to_log(engine_id, "decrypt failed, no KEK_TYPE_ECDH256_PRIV"); |
| return -EIO; |
| } |
| #else |
| DEK_LOGE("Not supported key type: %d\n", encDek->type); |
| dek_add_to_log(engine_id, "decrypt failed, ECDH type not supported"); |
| return -EOPNOTSUPP; |
| #endif |
| return ret; |
| } |
| default: |
| { |
| DEK_LOGE("Unsupported edek type: %d\n", encDek->type); |
| dek_add_to_log(engine_id, "decrypt failed, unsupported key type"); |
| return -EFAULT; |
| } |
| } |
| } |
| |
| int dek_decrypt_dek_efs(int engine_id, dek_t *encDek, dek_t *plainDek) { |
| return dek_decrypt_dek(engine_id, encDek, plainDek); |
| } |
| |
| #ifdef CONFIG_SDP_ENHANCED |
| int dek_encrypt_fek(unsigned char *master_key, unsigned int master_key_len, |
| unsigned char *fek, unsigned int fek_len, |
| unsigned char *efek, unsigned int *efek_len) |
| { |
| return dek_aes_encrypt_key_raw(master_key, master_key_len, |
| fek, fek_len, |
| efek, efek_len); |
| } |
| |
| int dek_decrypt_fek(unsigned char *master_key, unsigned int master_key_len, |
| unsigned char *efek, unsigned int efek_len, |
| unsigned char *fek, unsigned int *fek_len) |
| { |
| return dek_aes_decrypt_key_raw(master_key, master_key_len, |
| efek, efek_len, |
| fek, fek_len); |
| } |
| #endif |
| |
| static int dek_on_boot(dek_arg_on_boot *evt) { |
| int ret = 0; |
| int engine_id = evt->engine_id; |
| int user_id = evt->user_id; |
| |
| if((evt->SDPK_Rpub.len > KEK_MAXLEN) || |
| (evt->SDPK_Dpub.len > KEK_MAXLEN) || |
| (evt->SDPK_EDpub.len > KEK_MAXLEN)) { |
| DEK_LOGE("Invalid args\n"); |
| DEK_LOGE("SDPK_Rpub.len : %d\n", evt->SDPK_Rpub.len); |
| DEK_LOGE("SDPK_Dpub.len : %d\n", evt->SDPK_Dpub.len); |
| DEK_LOGE("SDPK_EDpub.len : %d\n", evt->SDPK_EDpub.len); |
| return -EINVAL; |
| } |
| |
| if(!is_kek_pack(engine_id)) { |
| ret = add_kek_pack(engine_id, user_id); |
| if(ret && ret != -EEXIST) { |
| DEK_LOGE("add_kek_pack failed\n"); |
| return ret; |
| } |
| |
| ret = 0; |
| add_kek(engine_id, &evt->SDPK_Rpub); |
| add_kek(engine_id, &evt->SDPK_Dpub); |
| add_kek(engine_id, &evt->SDPK_EDpub); |
| |
| #ifdef CONFIG_SDP_KEY_DUMP |
| if(get_sdp_sysfs_key_dump()) { |
| dump_all_keys(engine_id); |
| } |
| #endif |
| } |
| |
| return ret; |
| } |
| |
| static int dek_on_device_locked(dek_arg_on_device_locked *evt) { |
| #if defined(CONFIG_SDP) && !defined(CONFIG_EXT4CRYPT_SDP) |
| int user_id = evt->user_id; |
| #endif |
| int engine_id = evt->engine_id; |
| |
| del_kek(engine_id, KEK_TYPE_SYM); |
| del_kek(engine_id, KEK_TYPE_RSA_PRIV); |
| del_kek(engine_id, KEK_TYPE_DH_PRIV); |
| del_kek(engine_id, KEK_TYPE_ECDH256_PRIV); |
| |
| #if defined(CONFIG_SDP) && !defined(CONFIG_EXT4CRYPT_SDP) |
| ecryptfs_mm_drop_cache(user_id, engine_id); |
| #elif defined(CONFIG_EXT4CRYPT_SDP) |
| fscrypt_sdp_cache_drop_inode_mappings(engine_id); |
| #endif |
| |
| #ifdef CONFIG_SDP_KEY_DUMP |
| if(get_sdp_sysfs_key_dump()) { |
| dump_all_keys(engine_id); |
| } |
| #endif |
| |
| return 0; |
| } |
| |
| static int dek_on_device_unlocked(dek_arg_on_device_unlocked *evt) { |
| int engine_id = evt->engine_id; |
| |
| if((evt->SDPK_sym.len > KEK_MAXLEN) || |
| (evt->SDPK_Rpri.len > KEK_MAXLEN) || |
| (evt->SDPK_Dpri.len > KEK_MAXLEN) || |
| (evt->SDPK_EDpri.len > KEK_MAXLEN)) { |
| DEK_LOGE("%s Invalid args\n", __func__); |
| DEK_LOGE("SDPK_sym.len : %d\n", evt->SDPK_sym.len); |
| DEK_LOGE("SDPK_Rpri.len : %d\n", evt->SDPK_Rpri.len); |
| DEK_LOGE("SDPK_Dpri.len : %d\n", evt->SDPK_Dpri.len); |
| DEK_LOGE("SDPK_EDpri.len : %d\n", evt->SDPK_EDpri.len); |
| return -EINVAL; |
| } |
| |
| add_kek(engine_id, &evt->SDPK_sym); |
| add_kek(engine_id, &evt->SDPK_Rpri); |
| add_kek(engine_id, &evt->SDPK_Dpri); |
| add_kek(engine_id, &evt->SDPK_EDpri); |
| |
| #ifdef CONFIG_SDP_KEY_DUMP |
| if(get_sdp_sysfs_key_dump()) { |
| dump_all_keys(engine_id); |
| } |
| #endif |
| |
| return 0; |
| } |
| |
| static int dek_on_user_added(dek_arg_on_user_added *evt) { |
| int ret; |
| int engine_id = evt->engine_id; |
| int user_id = evt->user_id; |
| |
| if((evt->SDPK_Rpub.len > KEK_MAXLEN) || |
| (evt->SDPK_Dpub.len > KEK_MAXLEN) || |
| (evt->SDPK_EDpub.len > KEK_MAXLEN)) { |
| DEK_LOGE("Invalid args\n"); |
| DEK_LOGE("SDPK_Rpub.len : %d\n", evt->SDPK_Rpub.len); |
| DEK_LOGE("SDPK_Dpub.len : %d\n", evt->SDPK_Dpub.len); |
| DEK_LOGE("SDPK_EDpub.len : %d\n", evt->SDPK_EDpub.len); |
| return -EINVAL; |
| } |
| |
| ret = add_kek_pack(engine_id, user_id); |
| if(ret && ret != -EEXIST) { |
| DEK_LOGE("add_kek_pack failed\n"); |
| return ret; |
| } |
| |
| ret = 0; |
| add_kek(engine_id, &evt->SDPK_Rpub); |
| add_kek(engine_id, &evt->SDPK_Dpub); |
| add_kek(engine_id, &evt->SDPK_EDpub); |
| |
| #ifdef CONFIG_SDP_KEY_DUMP |
| if(get_sdp_sysfs_key_dump()) { |
| dump_all_keys(engine_id); |
| } |
| #endif |
| |
| return ret; |
| } |
| |
| static int dek_on_user_removed(dek_arg_on_user_removed *evt) { |
| del_kek_pack(evt->engine_id); |
| |
| return 0; |
| } |
| |
| // I'm thinking... if minor id can represent persona id |
| |
| static long dek_do_ioctl_evt(unsigned int minor, unsigned int cmd, |
| unsigned long arg) { |
| long ret = 0; |
| void __user *ubuf = (void __user *)arg; |
| void *cleanup = NULL; |
| unsigned int size = 0; |
| |
| switch (cmd) { |
| /* |
| * Event while booting. |
| * |
| * This event comes per persona, the driver is responsible to |
| * verify things good whether it's compromised. |
| */ |
| case DEK_ON_BOOT: { |
| dek_arg_on_boot *evt = kzalloc(sizeof(dek_arg_on_boot), GFP_KERNEL); |
| |
| DEK_LOGD("DEK_ON_BOOT\n"); |
| |
| if (evt == NULL) { |
| ret = -ENOMEM; |
| goto err; |
| } |
| cleanup = evt; |
| size = sizeof(dek_arg_on_boot); |
| |
| if(copy_from_user(evt, ubuf, size)) { |
| DEK_LOGE("can't copy from user evt\n"); |
| ret = -EFAULT; |
| goto err; |
| } |
| ret = dek_on_boot(evt); |
| if (ret < 0) { |
| dek_add_to_log(evt->engine_id, "Boot failed"); |
| goto err; |
| } |
| dek_add_to_log(evt->engine_id, "Booted"); |
| break; |
| } |
| /* |
| * Event when device is locked. |
| * |
| * Nullify private key which prevents decryption. |
| */ |
| case DEK_ON_DEVICE_LOCKED: { |
| dek_arg_on_device_locked *evt = kzalloc(sizeof(dek_arg_on_device_locked), GFP_KERNEL); |
| |
| DEK_LOGD("DEK_ON_DEVICE_LOCKED\n"); |
| if (evt == NULL) { |
| ret = -ENOMEM; |
| goto err; |
| } |
| cleanup = evt; |
| size = sizeof(dek_arg_on_device_locked); |
| |
| if(copy_from_user(evt, ubuf, size)) { |
| DEK_LOGE("can't copy from user evt\n"); |
| ret = -EFAULT; |
| goto err; |
| } |
| ret = dek_on_device_locked(evt); |
| if (ret < 0) { |
| dek_add_to_log(evt->engine_id, "Lock failed"); |
| goto err; |
| } |
| dek_add_to_log(evt->engine_id, "Locked"); |
| break; |
| } |
| /* |
| * Event when device unlocked. |
| * |
| * Read private key and decrypt with user password. |
| */ |
| case DEK_ON_DEVICE_UNLOCKED: { |
| dek_arg_on_device_unlocked *evt = kzalloc(sizeof(dek_arg_on_device_unlocked), GFP_KERNEL); |
| |
| DEK_LOGD("DEK_ON_DEVICE_UNLOCKED\n"); |
| if (evt == NULL) { |
| ret = -ENOMEM; |
| goto err; |
| } |
| cleanup = evt; |
| size = sizeof(dek_arg_on_device_unlocked); |
| |
| if(copy_from_user(evt, ubuf, size)) { |
| DEK_LOGE("can't copy from user evt\n"); |
| ret = -EFAULT; |
| goto err; |
| } |
| ret = dek_on_device_unlocked(evt); |
| if (ret < 0) { |
| dek_add_to_log(evt->engine_id, "Unlock failed"); |
| goto err; |
| } |
| dek_add_to_log(evt->engine_id, "Unlocked"); |
| break; |
| } |
| /* |
| * Event when new user(persona) added. |
| * |
| * Generate RSA public key and encrypt private key with given |
| * password. Also pub-key and encryped priv-key have to be stored |
| * in a file system. |
| */ |
| case DEK_ON_USER_ADDED: { |
| dek_arg_on_user_added *evt = kzalloc(sizeof(dek_arg_on_user_added), GFP_KERNEL); |
| |
| DEK_LOGD("DEK_ON_USER_ADDED\n"); |
| if (evt == NULL) { |
| ret = -ENOMEM; |
| goto err; |
| } |
| cleanup = evt; |
| size = sizeof(dek_arg_on_user_added); |
| |
| if(copy_from_user(evt, ubuf, size)) { |
| DEK_LOGE("can't copy from user evt\n"); |
| ret = -EFAULT; |
| goto err; |
| } |
| ret = dek_on_user_added(evt); |
| if (ret < 0) { |
| dek_add_to_log(evt->engine_id, "Add user failed"); |
| goto err; |
| } |
| dek_add_to_log(evt->engine_id, "Added user"); |
| break; |
| } |
| /* |
| * Event when user is removed. |
| * |
| * Remove pub-key file & encrypted priv-key file. |
| */ |
| case DEK_ON_USER_REMOVED: { |
| dek_arg_on_user_removed *evt = kzalloc(sizeof(dek_arg_on_user_removed), GFP_KERNEL); |
| |
| DEK_LOGD("DEK_ON_USER_REMOVED\n"); |
| if (evt == NULL) { |
| ret = -ENOMEM; |
| goto err; |
| } |
| cleanup = evt; |
| size = sizeof(dek_arg_on_user_removed); |
| |
| if(copy_from_user(evt, ubuf, size)) { |
| DEK_LOGE("can't copy from user evt\n"); |
| ret = -EFAULT; |
| goto err; |
| } |
| ret = dek_on_user_removed(evt); |
| if (ret < 0) { |
| dek_add_to_log(evt->engine_id, "Remove user failed"); |
| goto err; |
| } |
| dek_add_to_log(evt->engine_id, "Removed user"); |
| break; |
| } |
| /* |
| * Event when password changed. |
| * |
| * Encrypt SDPK_Rpri with new password and store it. |
| */ |
| case DEK_ON_CHANGE_PASSWORD: { |
| DEK_LOGD("DEK_ON_CHANGE_PASSWORD << deprecated. SKIP\n"); |
| ret = 0; |
| dek_add_to_log(0, "Changed password << deprecated"); |
| break; |
| } |
| |
| case DEK_DISK_CACHE_CLEANUP: { |
| dek_arg_disk_cache_cleanup *evt = kzalloc(sizeof(dek_arg_disk_cache_cleanup), GFP_KERNEL); |
| |
| DEK_LOGD("DEK_DISK_CACHE_CLEANUP\n"); |
| if (evt == NULL) { |
| ret = -ENOMEM; |
| goto err; |
| } |
| cleanup = evt; |
| size = sizeof(dek_arg_disk_cache_cleanup); |
| |
| if(copy_from_user(evt, ubuf, size)) { |
| DEK_LOGE("can't copy from user evt\n"); |
| ret = -EFAULT; |
| goto err; |
| } |
| |
| #if defined(CONFIG_SDP) && !defined(CONFIG_EXT4CRYPT_SDP) |
| ecryptfs_mm_drop_cache(evt->user_id, evt->engine_id); |
| #elif defined(CONFIG_EXT4CRYPT_SDP) |
| fscrypt_sdp_cache_drop_inode_mappings(evt->engine_id); |
| #endif |
| ret = 0; |
| dek_add_to_log(evt->engine_id, "Disk cache clean up"); |
| break; |
| } |
| default: |
| DEK_LOGE("%s case default\n", __func__); |
| ret = -EINVAL; |
| break; |
| } |
| |
| err: |
| if (cleanup) { |
| zero_out((char *)cleanup, size); |
| kfree(cleanup); |
| } |
| return ret; |
| } |
| |
| static long dek_do_ioctl_req(unsigned int minor, unsigned int cmd, |
| unsigned long arg) { |
| long ret = 0; |
| void __user *ubuf = (void __user *)arg; |
| |
| switch (cmd) { |
| case DEK_IS_KEK_AVAIL: { |
| dek_arg_is_kek_avail req; |
| |
| DEK_LOGD("DEK_IS_KEK_AVAIL\n"); |
| |
| memset(&req, 0, sizeof(dek_arg_is_kek_avail)); |
| if(copy_from_user(&req, ubuf, sizeof(req))) { |
| DEK_LOGE("can't copy from user\n"); |
| ret = -EFAULT; |
| goto err; |
| } |
| |
| req.ret = is_kek_available(req.engine_id, req.kek_type); |
| if(req.ret < 0) { |
| DEK_LOGE("is_kek_available(id:%d, kek:%d) error\n", |
| req.engine_id, req.kek_type); |
| ret = -ENOENT; |
| goto err; |
| } |
| |
| if(copy_to_user(ubuf, &req, sizeof(req))) { |
| DEK_LOGE("can't copy to user req\n"); |
| zero_out((char *)&req, sizeof(dek_arg_is_kek_avail)); |
| ret = -EFAULT; |
| goto err; |
| } |
| |
| ret = 0; |
| } |
| break; |
| /* |
| * Request to generate DEK. |
| * Generate DEK and return to the user |
| */ |
| case DEK_GENERATE_DEK: { |
| dek_arg_generate_dek req; |
| |
| DEK_LOGD("DEK_GENERATE_DEK\n"); |
| |
| memset(&req, 0, sizeof(dek_arg_generate_dek)); |
| if(copy_from_user(&req, ubuf, sizeof(req))) { |
| DEK_LOGE("can't copy from user req\n"); |
| ret = -EFAULT; |
| goto err; |
| } |
| dek_generate_dek(req.engine_id, &req.dek); |
| if(copy_to_user(ubuf, &req, sizeof(req))) { |
| DEK_LOGE("can't copy to user req\n"); |
| zero_out((char *)&req, sizeof(dek_arg_generate_dek)); |
| ret = -EFAULT; |
| goto err; |
| } |
| zero_out((char *)&req, sizeof(dek_arg_generate_dek)); |
| break; |
| } |
| /* |
| * Request to encrypt given DEK. |
| * |
| * encrypt dek and return to the user |
| */ |
| case DEK_ENCRYPT_DEK: { |
| dek_arg_encrypt_dek req; |
| dek_t *tempPlain_dek, *tempEnc_dek; |
| DEK_LOGD("DEK_ENCRYPT_DEK\n"); |
| |
| memset(&req, 0, sizeof(dek_arg_encrypt_dek)); |
| if(copy_from_user(&req, ubuf, sizeof(req))) { |
| DEK_LOGE("can't copy from user req\n"); |
| zero_out((char *)&req, sizeof(dek_arg_encrypt_dek)); |
| ret = -EFAULT; |
| goto err; |
| } |
| if(req.plain_dek.len <= 0 || req.plain_dek.len > DEK_MAXLEN) { |
| DEK_LOGE("Incorrect dek len\n"); |
| zero_out((char *)&req, sizeof(dek_arg_encrypt_dek)); |
| ret = -EFAULT; |
| goto err; |
| } |
| tempPlain_dek = kmalloc(sizeof(dek_t), GFP_NOFS); |
| if (tempPlain_dek == NULL) { |
| return -ENOMEM; |
| } |
| tempEnc_dek = kmalloc(sizeof(dek_t), GFP_NOFS); |
| if (tempEnc_dek == NULL) { |
| kzfree(tempPlain_dek); |
| return -ENOMEM; |
| } |
| |
| tempPlain_dek->type = req.plain_dek.type; |
| tempPlain_dek->len = req.plain_dek.len; |
| memcpy(tempPlain_dek->buf, req.plain_dek.buf, req.plain_dek.len); |
| |
| ret = dek_encrypt_dek(req.engine_id, |
| tempPlain_dek, tempEnc_dek); |
| |
| memset(tempPlain_dek->buf, 0, DEK_MAXLEN); |
| |
| if (ret < 0) { |
| DEK_LOGE("DEK_ENCRYPT_DEK: failed to encrypt dek! (err:%ld)\n", ret); |
| zero_out((char *)&req, sizeof(dek_arg_encrypt_dek)); |
| kzfree(tempPlain_dek); |
| kzfree(tempEnc_dek); |
| goto err; |
| } |
| |
| req.enc_dek.type = tempEnc_dek->type; |
| req.enc_dek.len = tempEnc_dek->len; |
| memcpy(req.enc_dek.buf, tempEnc_dek->buf, tempEnc_dek->len); |
| |
| if(copy_to_user(ubuf, &req, sizeof(req))) { |
| DEK_LOGE("can't copy to user req\n"); |
| zero_out((char *)&req, sizeof(dek_arg_encrypt_dek)); |
| ret = -EFAULT; |
| kzfree(tempPlain_dek); |
| kzfree(tempEnc_dek); |
| goto err; |
| } |
| zero_out((char *)&req, sizeof(dek_arg_encrypt_dek)); |
| |
| kzfree(tempPlain_dek); |
| kzfree(tempEnc_dek); |
| break; |
| } |
| /* |
| * Request to decrypt given DEK. |
| * |
| * Decrypt dek and return to the user. |
| * When device is locked, private key is not available, so |
| * the driver must return EPERM or some kind of error. |
| */ |
| case DEK_DECRYPT_DEK: { |
| dek_arg_decrypt_dek req; |
| dek_t *tempPlain_dek, *tempEnc_dek; |
| DEK_LOGD("DEK_DECRYPT_DEK\n"); |
| |
| memset(&req, 0, sizeof(dek_arg_decrypt_dek)); |
| if(copy_from_user(&req, ubuf, sizeof(req))) { |
| DEK_LOGE("can't copy from user req\n"); |
| zero_out((char *)&req, sizeof(dek_arg_decrypt_dek)); |
| ret = -EFAULT; |
| goto err; |
| } |
| if(req.enc_dek.len <= 0 || req.enc_dek.len > DEK_MAXLEN) { |
| DEK_LOGE("Incorrect dek len\n"); |
| zero_out((char *)&req, sizeof(dek_arg_decrypt_dek)); |
| ret = -EFAULT; |
| goto err; |
| } |
| tempPlain_dek = kmalloc(sizeof(dek_t), GFP_NOFS); |
| if (tempPlain_dek == NULL) { |
| return -ENOMEM; |
| } |
| tempEnc_dek = kmalloc(sizeof(dek_t), GFP_NOFS); |
| if (tempEnc_dek == NULL) { |
| kzfree(tempPlain_dek); |
| return -ENOMEM; |
| } |
| tempEnc_dek->type = req.enc_dek.type; |
| tempEnc_dek->len = req.enc_dek.len; |
| memcpy(tempEnc_dek->buf, req.enc_dek.buf, req.enc_dek.len); |
| |
| ret = dek_decrypt_dek(req.engine_id, |
| tempEnc_dek, tempPlain_dek); |
| |
| if (ret < 0) { |
| DEK_LOGE("DEK_DECRYPT_DEK: failed to decrypt dek! (err:%ld)\n", ret); |
| zero_out((char *)&req, sizeof(dek_arg_decrypt_dek)); |
| kzfree(tempPlain_dek); |
| kzfree(tempEnc_dek); |
| goto err; |
| } |
| |
| req.plain_dek.type = tempPlain_dek->type; |
| req.plain_dek.len = tempPlain_dek->len; |
| memcpy(req.plain_dek.buf, tempPlain_dek->buf, tempPlain_dek->len); |
| memset(tempPlain_dek->buf, 0, DEK_MAXLEN); |
| |
| if(copy_to_user(ubuf, &req, sizeof(req))) { |
| DEK_LOGE("can't copy to user req\n"); |
| zero_out((char *)&req, sizeof(dek_arg_decrypt_dek)); |
| ret = -EFAULT; |
| kzfree(tempPlain_dek); |
| kzfree(tempEnc_dek); |
| goto err; |
| } |
| zero_out((char *)&req, sizeof(dek_arg_decrypt_dek)); |
| |
| kzfree(tempPlain_dek); |
| kzfree(tempEnc_dek); |
| break; |
| } |
| |
| default: |
| DEK_LOGE("%s case default\n", __func__); |
| ret = -EINVAL; |
| break; |
| } |
| |
| return ret; |
| err: |
| return ret; |
| } |
| |
| int is_kek_available(int engine_id, int kek_type) { |
| return is_kek(engine_id, kek_type); |
| } |
| |
| static long dek_ioctl_evt(struct file *file, |
| unsigned int cmd, unsigned long arg) |
| { |
| unsigned int minor; |
| if(!is_system_server()) { |
| DEK_LOGE("Current process can't access evt device\n"); |
| #if 0 |
| /* TODO: fix build issue first */ |
| DEK_LOGE("Current process info :: " |
| "uid=%u gid=%u euid=%u egid=%u suid=%u sgid=%u " |
| "fsuid=%u fsgid=%u\n", |
| current_uid(), current_gid(), current_euid(), |
| current_egid(), current_suid(), current_sgid(), |
| current_fsuid(), current_fsgid()); |
| #endif |
| dek_add_to_log(000, "Access denied to evt device"); |
| return -EACCES; |
| } |
| |
| minor = iminor(file->f_path.dentry->d_inode); |
| return dek_do_ioctl_evt(minor, cmd, arg); |
| } |
| |
| static long dek_ioctl_req(struct file *file, |
| unsigned int cmd, unsigned long arg) |
| { |
| unsigned int minor; |
| #if 0 |
| if(!is_container_app() && !is_root()) { |
| DEK_LOGE("Current process can't access req device\n"); |
| DEK_LOGE("Current process info :: " |
| "uid=%u gid=%u euid=%u egid=%u suid=%u sgid=%u " |
| "fsuid=%u fsgid=%u\n", |
| current_uid(), current_gid(), current_euid(), |
| current_egid(), current_suid(), current_sgid(), |
| current_fsuid(), current_fsgid()); |
| dek_add_to_log(000, "Access denied to req device"); |
| return -EACCES; |
| } |
| #endif |
| |
| minor = iminor(file->f_path.dentry->d_inode); |
| return dek_do_ioctl_req(minor, cmd, arg); |
| } |
| |
| /* |
| * DAR engine log |
| */ |
| |
| static int dek_open_log(struct inode *inode, struct file *file) |
| { |
| DEK_LOGD("dek_open_log\n"); |
| return 0; |
| } |
| |
| static int dek_release_log(struct inode *ignored, struct file *file) |
| { |
| DEK_LOGD("dek_release_log\n"); |
| return 0; |
| } |
| |
| static ssize_t dek_read_log(struct file *file, char __user *buffer, size_t len, loff_t *off) |
| { |
| int ret = 0; |
| struct log_struct *tmp = NULL; |
| char log_buf[256]; |
| int log_buf_len; |
| |
| if (list_empty(&log_buffer.list)) { |
| DEK_LOGD("process %i (%s) going to sleep\n", |
| current->pid, current->comm); |
| flag = 0; |
| wait_event_interruptible(wq, flag != 0); |
| |
| } |
| flag = 0; |
| |
| spin_lock(&log_buffer.list_lock); |
| if (!list_empty(&log_buffer.list)) { |
| tmp = list_first_entry(&log_buffer.list, struct log_struct, list); |
| memcpy(&log_buf, tmp->buf, tmp->len); |
| log_buf_len = tmp->len; |
| list_del(&tmp->list); |
| kfree(tmp); |
| log_count--; |
| spin_unlock(&log_buffer.list_lock); |
| |
| ret = copy_to_user(buffer, log_buf, log_buf_len); |
| if (ret) { |
| DEK_LOGE("dek_read_log, copy_to_user fail, ret=%d, len=%d\n", |
| ret, log_buf_len); |
| return -EFAULT; |
| } |
| len = log_buf_len; |
| *off = log_buf_len; |
| } else { |
| spin_unlock(&log_buffer.list_lock); |
| DEK_LOGD("dek_read_log, list empty\n"); |
| len = 0; |
| } |
| |
| return len; |
| } |
| |
| static void dek_add_to_log(int engine_id, char * buffer) { |
| struct timespec ts; |
| struct log_struct *tmp = (struct log_struct*)kmalloc(sizeof(struct log_struct), GFP_KERNEL); |
| |
| if (tmp) { |
| INIT_LIST_HEAD(&tmp->list); |
| |
| getnstimeofday(&ts); |
| tmp->len = sprintf(tmp->buf, "%ld.%.3ld|%d|%s|%d|%s\n", |
| (long)ts.tv_sec, |
| (long)ts.tv_nsec / 1000000, |
| current->pid, |
| current->comm, |
| engine_id, |
| buffer); |
| |
| spin_lock(&log_buffer.list_lock); |
| list_add_tail(&(tmp->list), &(log_buffer.list)); |
| log_count++; |
| if (log_count > DEK_LOG_COUNT) { |
| DEK_LOGD("dek_add_to_log - exceeded DEK_LOG_COUNT\n"); |
| tmp = list_first_entry(&log_buffer.list, struct log_struct, list); |
| list_del(&tmp->list); |
| kfree(tmp); |
| log_count--; |
| } |
| spin_unlock(&log_buffer.list_lock); |
| |
| DEK_LOGD("process %i (%s) awakening the readers, log_count=%d\n", |
| current->pid, current->comm, log_count); |
| flag = 1; |
| wake_up_interruptible(&wq); |
| } else { |
| DEK_LOGE("dek_add_to_log - failed to allocate buffer\n"); |
| } |
| } |
| |
| const struct file_operations dek_fops_evt = { |
| .owner = THIS_MODULE, |
| .open = dek_open_evt, |
| .release = dek_release_evt, |
| .unlocked_ioctl = dek_ioctl_evt, |
| .compat_ioctl = dek_ioctl_evt, |
| }; |
| |
| static struct miscdevice dek_misc_evt = { |
| .minor = MISC_DYNAMIC_MINOR, |
| .name = "dek_evt", |
| .fops = &dek_fops_evt, |
| }; |
| |
| const struct file_operations dek_fops_req = { |
| .owner = THIS_MODULE, |
| .open = dek_open_req, |
| .release = dek_release_req, |
| .unlocked_ioctl = dek_ioctl_req, |
| .compat_ioctl = dek_ioctl_req, |
| }; |
| |
| static struct miscdevice dek_misc_req = { |
| .minor = MISC_DYNAMIC_MINOR, |
| .name = "dek_req", |
| .fops = &dek_fops_req, |
| }; |
| |
| const struct file_operations dek_fops_log = { |
| .owner = THIS_MODULE, |
| .open = dek_open_log, |
| .release = dek_release_log, |
| .read = dek_read_log, |
| }; |
| |
| static struct miscdevice dek_misc_log = { |
| .minor = MISC_DYNAMIC_MINOR, |
| .name = "dek_log", |
| .fops = &dek_fops_log, |
| }; |
| |
| static int __init dek_init(void) { |
| int ret; |
| |
| ret = misc_register(&dek_misc_evt); |
| if (unlikely(ret)) { |
| DEK_LOGE("failed to register misc_evt device!\n"); |
| return ret; |
| } |
| ret = misc_register(&dek_misc_req); |
| if (unlikely(ret)) { |
| DEK_LOGE("failed to register misc_req device!\n"); |
| return ret; |
| } |
| |
| ret = dek_create_sysfs_asym_alg(dek_misc_req.this_device); |
| if (unlikely(ret)) { |
| DEK_LOGE("failed to create sysfs_asym_alg device!\n"); |
| return ret; |
| } |
| |
| ret = misc_register(&dek_misc_log); |
| if (unlikely(ret)) { |
| DEK_LOGE("failed to register misc_log device!\n"); |
| return ret; |
| } |
| |
| ret = dek_create_sysfs_key_dump(dek_misc_log.this_device); |
| if (unlikely(ret)) { |
| DEK_LOGE("failed to create sysfs_key_dump device!\n"); |
| return ret; |
| } |
| |
| INIT_LIST_HEAD(&log_buffer.list); |
| spin_lock_init(&log_buffer.list_lock); |
| init_waitqueue_head(&wq); |
| |
| init_kek_pack(); |
| |
| printk("dek: initialized\n"); |
| dek_add_to_log(000, "Initialized"); |
| |
| #ifdef CONFIG_EXT4CRYPT_SDP |
| fscrypt_sdp_cache_init(); |
| #endif |
| |
| return 0; |
| } |
| |
| static void __exit dek_exit(void) |
| { |
| printk("dek: unloaded\n"); |
| } |
| |
| module_init(dek_init) |
| module_exit(dek_exit) |
| |
| MODULE_LICENSE("GPL"); |
| MODULE_DESCRIPTION("SDP DEK"); |