Fixed MTP to work with TWRP

This commit is contained in:
awab228 2018-06-19 23:16:04 +02:00
commit f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions

7
security/sdp/Makefile Normal file
View file

@ -0,0 +1,7 @@
#
# Makefile for DEK and DLP modules
#
obj-$(CONFIG_SDP) += dek.o dek_aes.o sdp_mm.o pub_crypto_emul.o dek_sysfs.o cache_cleanup.o kek_pack.o fs_handler.o
obj-$(CONFIG_DLP) += sdp_dlp.o

70
security/sdp/cache_cleanup.c Executable file
View file

@ -0,0 +1,70 @@
/*
* 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 <sdp/common.h>
#include <sdp/cache_cleanup.h>
#if SDP_CACHE_CLEANUP_DEBUG
static void sdp_page_dump(unsigned char *buf, int len, const char* str)
{
unsigned int i;
char s[512];
s[0] = 0;
for(i=0;i<len && i<32;++i) {
char tmp[8];
sprintf(tmp, " %02x", buf[i]);
strcat(s, tmp);
}
if (len > 32) {
char tmp[8];
sprintf(tmp, " ...");
strcat(s, tmp);
}
printk("%s [%s len=%d]\n", s, str, len);
}
#else
static void sdp_page_dump(unsigned char *buf, int len, const char* str) {
return;
}
#endif
void sdp_page_cleanup(struct page *page)
{
if(page && page->mapping) {
if(mapping_sensitive(page->mapping)) {
void *d;
#if SDP_CACHE_CLEANUP_DEBUG
printk("%s : deleting [%s] sensitive page.\n",
__func__, page->mapping->host->i_sb->s_type->name);
//dump_stack();
#endif
d = kmap_atomic(page);
if(d) {
sdp_page_dump((unsigned char *)d, PAGE_SIZE, "freeing");
clear_page(d);
sdp_page_dump((unsigned char *)d, PAGE_SIZE, "freed");
kunmap_atomic(d);
}
}
}
}

1182
security/sdp/dek.c Normal file

File diff suppressed because it is too large Load diff

107
security/sdp/dek_aes.c Normal file
View file

@ -0,0 +1,107 @@
/*
* 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/err.h>
#include <sdp/dek_common.h>
#include <sdp/dek_aes.h>
static struct crypto_blkcipher *dek_aes_key_setup(kek_t *kek)
{
struct crypto_blkcipher *tfm = NULL;
tfm = crypto_alloc_blkcipher("cbc(aes)", 0, CRYPTO_ALG_ASYNC);
if (!IS_ERR(tfm)) {
crypto_blkcipher_setkey(tfm, kek->buf, kek->len);
} else {
printk("dek: failed to alloc blkcipher\n");
}
return tfm;
}
static void dek_aes_key_free(struct crypto_blkcipher *tfm)
{
crypto_free_blkcipher(tfm);
}
static int __dek_aes_encrypt(struct crypto_blkcipher *tfm, char *src, char *dst, int len) {
struct blkcipher_desc desc;
struct scatterlist src_sg, dst_sg;
int bsize = crypto_blkcipher_ivsize(tfm);
u8 iv[bsize];
memset(&iv, 0, sizeof(iv));
desc.tfm = tfm;
desc.info = iv;
desc.flags = 0;
sg_init_one(&src_sg, src, len);
sg_init_one(&dst_sg, dst, len);
return crypto_blkcipher_encrypt_iv(&desc, &dst_sg, &src_sg, len);
}
static int __dek_aes_decrypt(struct crypto_blkcipher *tfm, char *src, char *dst, int len) {
struct blkcipher_desc desc;
struct scatterlist src_sg, dst_sg;
int bsize = crypto_blkcipher_ivsize(tfm);
u8 iv[bsize];
memset(&iv, 0, sizeof(iv));
desc.tfm = tfm;
desc.info = iv;
desc.flags = 0;
sg_init_one(&src_sg, src, len);
sg_init_one(&dst_sg, dst, len);
return crypto_blkcipher_decrypt_iv(&desc, &dst_sg, &src_sg, len);
}
int dek_aes_encrypt(kek_t *kek, char *src, char *dst, int len) {
int rc;
struct crypto_blkcipher *tfm;
if(kek == NULL) return -EINVAL;
tfm = dek_aes_key_setup(kek);
if(tfm) {
rc = __dek_aes_encrypt(tfm, src, dst, len);
dek_aes_key_free(tfm);
return rc;
} else
return -ENOMEM;
}
int dek_aes_decrypt(kek_t *kek, char *src, char *dst, int len) {
int rc;
struct crypto_blkcipher *tfm;
if(kek == NULL) return -EINVAL;
tfm = dek_aes_key_setup(kek);
if(tfm) {
rc = __dek_aes_decrypt(tfm, src, dst, len);
dek_aes_key_free(tfm);
return rc;
} else
return -ENOMEM;
}

129
security/sdp/dek_sysfs.c Normal file
View file

@ -0,0 +1,129 @@
/*
* 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/kernel.h>
#include <linux/stat.h>
#include <linux/string.h>
#include <sdp/dek_common.h>
static int g_asym_alg = SDPK_DEFAULT_ALGOTYPE;
#define ALG_NAME_RSA_NAME "RSA"
#define ALG_NAME_DH_NAME "DH"
#define ALG_NAME_ECDH_NAME "ECDH"
static ssize_t dek_show_asym_alg(struct device *dev,
struct device_attribute *attr, char *buf) {
switch(g_asym_alg) {
case SDPK_ALGOTYPE_ASYMM_RSA:
return sprintf(buf, "%s\n", ALG_NAME_RSA_NAME);
case SDPK_ALGOTYPE_ASYMM_DH:
return sprintf(buf, "%s\n", ALG_NAME_DH_NAME);
case SDPK_ALGOTYPE_ASYMM_ECDH:
return sprintf(buf, "%s\n", ALG_NAME_ECDH_NAME);
default:
return sprintf(buf, "unknown\n");
}
return 0;
}
static ssize_t dek_set_asym_alg(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count) {
if(!strncmp(ALG_NAME_RSA_NAME, buf, strlen(ALG_NAME_RSA_NAME))) {
g_asym_alg = SDPK_ALGOTYPE_ASYMM_RSA;
return strlen(ALG_NAME_RSA_NAME);
}
if(!strncmp(ALG_NAME_DH_NAME, buf, strlen(ALG_NAME_DH_NAME))) {
g_asym_alg = SDPK_ALGOTYPE_ASYMM_DH;
return strlen(ALG_NAME_DH_NAME);
}
if(!strncmp(ALG_NAME_ECDH_NAME, buf, strlen(ALG_NAME_ECDH_NAME))) {
g_asym_alg = SDPK_ALGOTYPE_ASYMM_ECDH;
return strlen(ALG_NAME_ECDH_NAME);
}
return -1;
}
static DEVICE_ATTR(asym_alg, S_IRUSR | S_IWUSR, dek_show_asym_alg, dek_set_asym_alg);
int dek_create_sysfs_asym_alg(struct device *d) {
int error;
if((error = device_create_file(d, &dev_attr_asym_alg)))
return error;
return 0;
}
int get_sdp_sysfs_asym_alg(void) {
return g_asym_alg;
}
#ifdef CONFIG_SDP_KEY_DUMP
static int kek_dump = 0;
static ssize_t dek_show_key_dump(struct device *dev,
struct device_attribute *attr, char *buf) {
return sprintf(buf, "%d\n", kek_dump);
}
static ssize_t dek_set_key_dump(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count) {
int flag = simple_strtoul(buf, NULL, 10);
kek_dump = flag;
return strlen(buf);
}
static DEVICE_ATTR(key_dump, S_IRUGO | S_IWUGO, dek_show_key_dump, dek_set_key_dump);
int dek_create_sysfs_key_dump(struct device *d) {
int error;
if((error = device_create_file(d, &dev_attr_key_dump)))
return error;
return 0;
}
int get_sdp_sysfs_key_dump(void) {
return kek_dump;
}
#else
int dek_create_sysfs_key_dump(struct device *d) {
printk("key_dump feature not available");
return 0;
}
int get_sdp_sysfs_key_dump(void) {
printk("key_dump feature not available");
return 0;
}
#endif

352
security/sdp/fs_handler.c Executable file
View file

@ -0,0 +1,352 @@
/*
* 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 <crypto/internal/hash.h>
#include <crypto/scatterwalk.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/interrupt.h>
#include <linux/wakelock.h>
#include <linux/sched.h>
#include <linux/netlink.h>
#include <linux/net.h>
#include <net/netlink.h>
#include <net/sock.h>
#include <net/net_namespace.h>
#include <linux/types.h>
#include <linux/wait.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/audit.h>
#include <linux/jiffies.h>
#include <linux/version.h>
#include <sdp/fs_handler.h>
#include <sdp/fs_request.h>
#define RESULT_ARRAY_MAX_LEN 100
#define CRYPTO_MAX_TIMEOUT HZ/5
#define SDP_FS_HANDLER_REQ_TIMEOUT 3000
sdp_fs_handler_control_t g_sdp_fs_handler_control;
DEFINE_MUTEX(g_send_mutex);
static int g_user_pid = 0;
static struct sock* g_sock = NULL;
static int to_netlink_msg(sdp_fs_handler_request_t *req, char **msg);
static void request_send(sdp_fs_handler_control_t *con,
sdp_fs_handler_request_t *req);
static sdp_fs_handler_request_t *request_find(sdp_fs_handler_control_t *con,
u32 request_id);
static sdp_fs_handler_request_t *request_alloc(u32 opcode);
static void request_free(sdp_fs_handler_request_t *req);
static void req_dump(sdp_fs_handler_request_t *req, const char *msg);
/* Debug */
#define SDP_FS_HANDLER_DEBUG 0
#if SDP_FS_HANDLER_DEBUG
#define SDP_FS_HANDLER_LOGD(FMT, ...) printk("SDP_FS_HANDLER[%d] : %s " FMT , current->pid, __func__, ##__VA_ARGS__)
#else
#define SDP_FS_HANDLER_LOGD(FMT, ...)
#endif /* SDP_FS_HANDLER_DEBUG */
#define SDP_FS_HANDLER_LOGE(FMT, ...) printk("SDP_FS_HANDLER[%d] : %s " FMT , current->pid, __func__, ##__VA_ARGS__)
static int __handle_request(sdp_fs_handler_request_t *req, char *ret) {
int rc = 0;
struct sk_buff *skb_in = NULL;
struct sk_buff *skb_out = NULL;
struct nlmsghdr *nlh = NULL;
char *nl_msg = NULL;
int nl_msg_size = 0;
SDP_FS_HANDLER_LOGD("====================== \t entred\n");
if(req == NULL) {
SDP_FS_HANDLER_LOGE("invalid request\n");
return -1;
}
request_send(&g_sdp_fs_handler_control, req);
nl_msg_size = to_netlink_msg(req, &nl_msg);
if(nl_msg_size <= 0) {
SDP_FS_HANDLER_LOGE("invalid opcode %d\n", req->opcode);
return -1;
}
// sending netlink message
skb_in = nlmsg_new(nl_msg_size, 0);
if (!skb_in) {
SDP_FS_HANDLER_LOGE("Failed to allocate new skb: \n");
return -1;
}
nlh = nlmsg_put(skb_in, 0, 0, NLMSG_DONE, nl_msg_size, 0);
NETLINK_CB(skb_in).dst_group = 0;
memcpy(nlmsg_data(nlh), nl_msg, nl_msg_size);
mutex_lock(&g_send_mutex);
rc = nlmsg_unicast(g_sock, skb_in, g_user_pid);
mutex_unlock(&g_send_mutex);
skb_out = skb_dequeue(&g_sock->sk_receive_queue);
if(skb_out) {
kfree_skb(skb_out);
}
return 0;
}
int sdp_fs_request(sdp_fs_command_t *cmd, fs_request_cb_t callback){
sdp_fs_handler_request_t *req = request_alloc(cmd->opcode);
int ret = -1;
req_dump(req, "request allocated");
if(req) {
memcpy(&req->command, cmd, sizeof(sdp_fs_command_t));
req->command.req_id = req->id;
req_dump(req, "__handle_reqeust start");
ret = __handle_request(req, NULL);
req_dump(req, "__handle_reqeust end");
if(ret != 0) {
SDP_FS_HANDLER_LOGE("opcode[%d] failed\n", cmd->opcode);
goto error;
}
} else {
SDP_FS_HANDLER_LOGE("request allocation failed\n");
return -ENOMEM;
}
return 0;
error:
request_free(req);
return -1;
}
static int __recver(struct sk_buff *skb, struct nlmsghdr *nlh)
{
void *data;
u16 msg_type = nlh->nlmsg_type;
u32 err = 0;
struct audit_status *status_get = NULL;
u16 len = 0;
data = NLMSG_DATA(nlh);
len = ntohs(*(uint16_t*) (data+1));
switch (msg_type) {
case SDP_FS_HANDLER_PID_SET:
status_get = (struct audit_status *)data;
g_user_pid = status_get->pid;
break;
case SDP_FS_HANDLER_RESULT:
{
result_t *result = (result_t *)data;
sdp_fs_handler_request_t *req = NULL;
printk("result : req_id[%d], opcode[%d] ret[%d]\n",
result->request_id, result->opcode, result->ret);
spin_lock(&g_sdp_fs_handler_control.lock);
req = request_find(&g_sdp_fs_handler_control, result->request_id);
spin_unlock(&g_sdp_fs_handler_control.lock);
if(req == NULL) {
SDP_FS_HANDLER_LOGE("crypto result :: error! can't find request %d\n",
result->request_id);
} else {
memcpy(&req->result, result, sizeof(result_t));
req->state = SDP_FS_HANDLER_REQ_FINISHED;
if(req->callback)
req->callback(req->opcode, req->result.ret, req->command.ino);
memset(result, 0, sizeof(result_t));
request_free(req);
}
break;
}
default:
SDP_FS_HANDLER_LOGE("unknown message type : %d\n", msg_type);
break;
}
return err;
}
/* Receive messages from netlink socket. */
static void recver(struct sk_buff *skb)
{
struct nlmsghdr *nlh;
int len;
int err;
nlh = nlmsg_hdr(skb);
len = skb->len;
err = __recver(skb, nlh);
}
static int to_netlink_msg(sdp_fs_handler_request_t *req, char **msg)
{
*msg = (char *)&req->command;
return sizeof(sdp_fs_command_t);
}
static u32 get_unique_id(sdp_fs_handler_control_t *control)
{
SDP_FS_HANDLER_LOGD("locked\n");
spin_lock(&control->lock);
control->reqctr++;
/* zero is special */
if (control->reqctr == 0)
control->reqctr = 1;
spin_unlock(&control->lock);
SDP_FS_HANDLER_LOGD("unlocked\n");
return control->reqctr;
}
static void req_dump(sdp_fs_handler_request_t *req, const char *msg) {
#if SDP_FS_HANDLER_DEBUG
SDP_FS_HANDLER_LOGD("DUMP REQUEST [%s] ID[%d] opcode[%d] state[%d]\n", msg, req->id, req->opcode, req->state);
#endif
}
static void request_send(sdp_fs_handler_control_t *con,
sdp_fs_handler_request_t *req) {
spin_lock(&con->lock);
SDP_FS_HANDLER_LOGD("entered, control lock\n");
list_add_tail(&req->list, &con->pending_list);
req->state = SDP_FS_HANDLER_REQ_PENDING;
SDP_FS_HANDLER_LOGD("exit, control unlock\n");
spin_unlock(&con->lock);
}
static sdp_fs_handler_request_t *request_find(sdp_fs_handler_control_t *con,
u32 request_id) {
struct list_head *entry;
list_for_each(entry, &con->pending_list) {
sdp_fs_handler_request_t *req;
req = list_entry(entry, sdp_fs_handler_request_t, list);
if (req->id == request_id)
return req;
}
return NULL;
}
static struct kmem_cache *req_cachep;
static void request_init(sdp_fs_handler_request_t *req, u32 opcode) {
memset(req, 0, sizeof(sdp_fs_handler_request_t));
req->state = SDP_FS_HANDLER_REQ_INIT;
req->id = get_unique_id(&g_sdp_fs_handler_control);
INIT_LIST_HEAD(&req->list);
atomic_set(&req->count, 1);
req->aborted = 0;
req->opcode = opcode;
req->callback = NULL;
}
static sdp_fs_handler_request_t *request_alloc(u32 opcode) {
sdp_fs_handler_request_t *req = kmem_cache_alloc(req_cachep, GFP_KERNEL);
if(req)
request_init(req, opcode);
return req;
}
static void request_free(sdp_fs_handler_request_t *req)
{
if(req) {
req_dump(req, "request freed");
/*
* TODO : lock needed here?
*/
list_del(&req->list);
memset(req, 0, sizeof(sdp_fs_handler_request_t));
kmem_cache_free(req_cachep, req);
} else {
SDP_FS_HANDLER_LOGE("req is NULL, skip free\n");
}
}
static void control_init(sdp_fs_handler_control_t *con) {
SDP_FS_HANDLER_LOGD("sdp_fs_handler_control_init");
spin_lock_init(&con->lock);
INIT_LIST_HEAD(&con->pending_list);
con->reqctr = 0;
}
static int __init sdp_fs_handler_mod_init(void) {
#if (LINUX_VERSION_CODE > KERNEL_VERSION(3,4,0))
struct netlink_kernel_cfg cfg = {
.input = recver,
};
g_sock = netlink_kernel_create(&init_net, SDP_FS_HANDLER_NETLINK, &cfg);
#else
g_sock = netlink_kernel_create(&init_net, SDP_FS_HANDLER_NETLINK, 0, recver, NULL, THIS_MODULE);
#endif
if (!g_sock) {
SDP_FS_HANDLER_LOGE("Failed to create Crypto Netlink Socket .. Exiting \n");
return -ENOMEM;
}
SDP_FS_HANDLER_LOGE("netlink socket is created successfully! \n");
control_init(&g_sdp_fs_handler_control);
req_cachep = kmem_cache_create("sdp_fs_handler_requst",
sizeof(sdp_fs_handler_request_t),
0, 0, NULL);
if (!req_cachep) {
netlink_kernel_release(g_sock);
SDP_FS_HANDLER_LOGE("Failed to create sdp_fs_handler_requst cache mem.. Exiting \n");
return -ENOMEM;
}
return 0;
}
static void __exit sdp_fs_handler_mod_exit(void) {
netlink_kernel_release(g_sock);
kmem_cache_destroy(req_cachep);
}
module_init(sdp_fs_handler_mod_init);
module_exit(sdp_fs_handler_mod_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("SDP FS netlink");

306
security/sdp/kek_pack.c Normal file
View file

@ -0,0 +1,306 @@
/*
* 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/kernel.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/list.h>
#include <sdp/dek_common.h>
typedef struct __kek_pack {
int engine_id;
int user_id;
struct list_head list;
struct list_head kek_list_head;
spinlock_t kek_list_lock;
}kek_pack_t;
typedef struct __kek_item {
struct list_head list;
int kek_type;
kek_t kek;
}kek_item_t;
#define KEK_PACK_DEBUG 0
#if KEK_PACK_DEBUG
#define KEK_PACK_LOGD(FMT, ...) printk("KEK_PACK[%d] %s :: " FMT , current->pid, __func__, ##__VA_ARGS__)
#else
#define KEK_PACK_LOGD(FMT, ...)
#endif /* PUB_CRYPTO_DEBUG */
#define KEK_PACK_LOGE(FMT, ...) printk("KEK_PACK[%d] %s :: " FMT , current->pid, __func__, ##__VA_ARGS__)
struct list_head kek_pack_list_head;
spinlock_t kek_pack_list_lock;
void init_kek_pack(void) {
spin_lock_init(&kek_pack_list_lock);
INIT_LIST_HEAD(&kek_pack_list_head);
}
static kek_pack_t *find_kek_pack(int engine_id) {
struct list_head *entry;
spin_lock(&kek_pack_list_lock);
list_for_each(entry, &kek_pack_list_head) {
kek_pack_t *pack = list_entry(entry, kek_pack_t, list);
if(pack->engine_id == engine_id) {
KEK_PACK_LOGD("Found kek-pack : %d\n", engine_id);
spin_unlock(&kek_pack_list_lock);
return pack;
}
}
spin_unlock(&kek_pack_list_lock);
KEK_PACK_LOGE("Can't find kek-pack : %d\n", engine_id);
return NULL;
}
static int __add_kek(kek_pack_t *pack, kek_t *kek) {
kek_item_t *item;
if(kek == NULL) return -EINVAL;
if(pack == NULL) return -EINVAL;
item = kmalloc(sizeof(kek_item_t), GFP_KERNEL);
if(item == NULL) return -ENOMEM;
INIT_LIST_HEAD(&item->list);
item->kek_type = kek->type;
memcpy(&item->kek, kek, sizeof(kek_t));
spin_lock(&pack->kek_list_lock);
list_add_tail(&item->list, &pack->kek_list_head);
spin_unlock(&pack->kek_list_lock);
KEK_PACK_LOGD("item %p\n", item);
return 0;
}
static kek_item_t *find_kek_item(kek_pack_t *pack, int kek_type) {
struct list_head *entry;
if(pack == NULL) return NULL;
spin_lock(&pack->kek_list_lock);
list_for_each(entry, &pack->kek_list_head) {
kek_item_t *item = list_entry(entry, kek_item_t, list);
if(item->kek_type == kek_type) {
KEK_PACK_LOGD("Found kek-item : %d\n", kek_type);
spin_unlock(&pack->kek_list_lock);
return item;
}
}
spin_unlock(&pack->kek_list_lock);
KEK_PACK_LOGD("Can't find kek %d : %d\n", kek_type, pack->engine_id);
return NULL;
}
static void del_kek_item(kek_item_t *item) {
KEK_PACK_LOGD("entered\n");
if(item) {
list_del(&item->list);
kzfree(item);
} else {
KEK_PACK_LOGD("given item is NULL\n");
}
}
int add_kek_pack(int engine_id, int user_id) {
kek_pack_t *new_kek_pack;
KEK_PACK_LOGD("entered\n");
if(find_kek_pack(engine_id)) {
KEK_PACK_LOGE("kek-pack for %d already exists\n", engine_id);
return -EEXIST;
}
new_kek_pack = kmalloc(sizeof(kek_pack_t), GFP_KERNEL);
if(new_kek_pack == NULL) {
KEK_PACK_LOGE("can't alloc memory for kek_pack_t\n");
return -EINVAL;
}
new_kek_pack->engine_id = engine_id;
new_kek_pack->user_id = user_id;
spin_lock_init(&new_kek_pack->kek_list_lock);
INIT_LIST_HEAD(&new_kek_pack->kek_list_head);
spin_lock(&kek_pack_list_lock);
list_add_tail(&new_kek_pack->list, &kek_pack_list_head);
spin_unlock(&kek_pack_list_lock);
return 0;
}
void del_kek_pack(int engine_id) {
struct list_head *entry, *q;
kek_pack_t *pack;
KEK_PACK_LOGD("entered\n");
pack = find_kek_pack(engine_id);
if(pack == NULL) return;
spin_lock(&pack->kek_list_lock);
list_for_each_safe(entry, q, &pack->kek_list_head) {
kek_item_t *item = list_entry(entry, kek_item_t, list);
KEK_PACK_LOGD("entry %p item %p\n", entry, item);
del_kek_item(item);
}
spin_unlock(&pack->kek_list_lock);
list_del(&pack->list);
kzfree(pack);
}
int add_kek(int engine_id, kek_t *kek) {
int rc;
kek_pack_t *pack;
KEK_PACK_LOGD("entered\n");
pack = find_kek_pack(engine_id);
if(pack == NULL) return -ENOENT;
if(find_kek_item(pack, kek->type)) return -EEXIST;
rc = __add_kek(pack, kek);
if(rc) KEK_PACK_LOGE("%s failed. rc = %d", __func__, rc);
return rc;
}
int del_kek(int engine_id, int kek_type) {
kek_pack_t *pack;
kek_item_t *item;
KEK_PACK_LOGD("entered\n");
pack = find_kek_pack(engine_id);
if(pack == NULL) return -ENOENT;
item = find_kek_item(pack, kek_type);
if(item == NULL) return -ENOENT;
spin_lock(&pack->kek_list_lock);
del_kek_item(item);
spin_unlock(&pack->kek_list_lock);
return 0;
}
/*
* I wanted to have some ref-count for kek_item_t that doesn't disturb
* ongoing dek process. But the returned kek won't be zero-freed if the process
* never returns.
*
* So allocate new memory and let the user call put accordingly
*/
kek_t *get_kek(int engine_id, int kek_type, int *rc) {
kek_pack_t *pack;
kek_item_t *item;
int userid = from_kuid(&init_user_ns, current_uid()) / PER_USER_RANGE;
KEK_PACK_LOGD("entered [%d]\n", from_kuid(&init_user_ns, current_uid()));
pack = find_kek_pack(engine_id);
if(pack == NULL) {
*rc = -ENOENT;
return NULL;
}
// Across user engine access denied for Knox containers.
if(!is_root() &&
(pack->user_id >= 100 && pack->user_id < 200) &&
(pack->user_id != userid)) {
KEK_PACK_LOGE("Permission denied to get kek\n");
KEK_PACK_LOGE("pack->user_id[%d] != userid[%d]\n",
pack->user_id, userid);
*rc = -EACCES;
return NULL;
}
item = find_kek_item(pack, kek_type);
if(item) {
kek_t *kek = kmalloc(sizeof(kek_t), GFP_KERNEL);
if(kek == NULL){
*rc = -ENOMEM;
return NULL;
}
*rc = 0;
memcpy(kek, &item->kek, sizeof(kek_t));
return kek;
}
*rc = -ENOENT;
return NULL;
}
void put_kek(kek_t *kek) {
KEK_PACK_LOGD("entered\n");
if(kek) kzfree(kek);
}
int is_kek_pack(int engine_id) {
kek_pack_t *pack;
KEK_PACK_LOGD("entered\n");
pack = find_kek_pack(engine_id);
if(pack) return 1;
return 0;
}
int is_kek(int engine_id, int kek_type) {
kek_pack_t *pack;
kek_item_t *item;
KEK_PACK_LOGD("entered\n");
pack = find_kek_pack(engine_id);
if(pack == NULL) return 0;
item = find_kek_item(pack, kek_type);
if(item) {
return 1;
}
return 0;
}

519
security/sdp/pub_crypto_emul.c Executable file
View file

@ -0,0 +1,519 @@
/*
* 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 <crypto/internal/hash.h>
#include <crypto/scatterwalk.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/interrupt.h>
#include <linux/wakelock.h>
#include <linux/sched.h>
#include <linux/netlink.h>
#include <linux/net.h>
#include <net/netlink.h>
#include <net/sock.h>
#include <net/net_namespace.h>
#include <linux/types.h>
#include <linux/wait.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/audit.h>
#include <linux/jiffies.h>
#include <linux/version.h>
#include <sdp/pub_crypto_emul.h>
#define NETLINK_FIPS_CRYPTO 29
#define PUB_CRYPTO_PID_SET 3001
#define PUB_CRYPTO_RESULT 3002
#define RESULT_ARRAY_MAX_LEN 100
#define CRYPTO_MAX_TIMEOUT HZ/5
#define PUB_CRYPTO_REQ_TIMEOUT 3000
pub_crypto_control_t g_pub_crypto_control;
DEFINE_MUTEX(crypto_send_mutex);
static int user_fipscryptod_pid = 0;
static struct sock* crypto_sock = NULL;
static int pub_crypto_request_get_msg(pub_crypto_request_t *req, char **msg);
static void request_send(pub_crypto_control_t *con,
pub_crypto_request_t *req);
static void request_wait_answer(pub_crypto_control_t *con,
pub_crypto_request_t *req);
static pub_crypto_request_t *request_find(pub_crypto_control_t *con,
u32 request_id);
static pub_crypto_request_t *request_alloc(u32 opcode);
static void request_free(pub_crypto_control_t *con, pub_crypto_request_t *req);
static void req_dump(pub_crypto_request_t *req, const char *msg);
static void dump(unsigned char *buf, int len, const char *msg);
/* Debug */
#define PUB_CRYPTO_DEBUG 0
#if PUB_CRYPTO_DEBUG
#define PUB_CRYPTO_LOGD(FMT, ...) printk("SDP_PUB_CRYPTO[%d] : %s " FMT , current->pid, __func__, ##__VA_ARGS__)
#else
#define PUB_CRYPTO_LOGD(FMT, ...)
#endif /* PUB_CRYPTO_DEBUG */
#define PUB_CRYPTO_LOGE(FMT, ...) printk("SDP_PUB_CRYPTO[%d] : %s " FMT , current->pid, __func__, ##__VA_ARGS__)
#define PUB_CRYPTO_LOGI(FMT, ...) printk("SDP_PUB_CRYPTO[%d] : %s " FMT , current->pid, __func__, ##__VA_ARGS__)
//static char* process_crypto_request(u8 opcode, char* send_msg,
// int send_msg_size, int* result_len, int* ret) {
static int __do_dek_crypt(pub_crypto_request_t *req, char *ret) {
int rc = 0;
struct sk_buff *skb_in = NULL;
struct sk_buff *skb_out = NULL;
struct nlmsghdr *nlh = NULL;
char *nl_msg = NULL;
int nl_msg_size = 0;
PUB_CRYPTO_LOGD("====================== \t entred\n");
if(req == NULL) {
PUB_CRYPTO_LOGE("invalid request\n");
return -1;
}
request_send(&g_pub_crypto_control, req);
nl_msg_size = pub_crypto_request_get_msg(req, &nl_msg);
if(nl_msg_size <= 0) {
PUB_CRYPTO_LOGE("invalid opcode %d\n", req->opcode);
return -1;
}
// sending netlink message
skb_in = nlmsg_new(nl_msg_size, 0);
if (!skb_in) {
PUB_CRYPTO_LOGE("Failed to allocate new skb: \n");
return -1;
}
nlh = nlmsg_put(skb_in, 0, 0, NLMSG_DONE, nl_msg_size, 0);
NETLINK_CB(skb_in).dst_group = 0;
memcpy(nlmsg_data(nlh), nl_msg, nl_msg_size);
mutex_lock(&crypto_send_mutex);
rc = nlmsg_unicast(crypto_sock, skb_in, user_fipscryptod_pid);
mutex_unlock(&crypto_send_mutex);
if (rc < 0) {
PUB_CRYPTO_LOGE("Error while sending bak to user, err id: %d\n", rc);
return -1;
}
/*
* In a very rare case, response comes before request gets into pending list.
*/
if(req->state != PUB_CRYPTO_REQ_FINISHED)
request_wait_answer(&g_pub_crypto_control, req);
else
PUB_CRYPTO_LOGE("request already finished, skip waiting\n");
skb_out = skb_dequeue(&crypto_sock->sk_receive_queue);
if(req->state != PUB_CRYPTO_REQ_FINISHED) {
PUB_CRYPTO_LOGE("FIPS_CRYPTO_ERROR!!!\n");
/*
* TODO :
* Request not finished by an interrupt or abort.
*/
rc = -EINTR;
goto out;
}
if(req->aborted) {
PUB_CRYPTO_LOGE("Request aborted!!!\n");
rc = -ETIMEDOUT;
goto out;
}
if(req->result.ret < 0) {
PUB_CRYPTO_LOGE("failed to opcode(%d)!!!\n", req->opcode);
rc = req->result.ret;
goto out;
}
switch(req->opcode) {
case OP_DH_ENC:
case OP_DH_DEC:
case OP_ECDH_ENC:
case OP_ECDH_DEC:
dump(req->result.dek.buf, req->result.dek.len, "req->result.dek");
memcpy(ret, &(req->result.dek), sizeof(dek_t));
//dump(req->result.dek.buf, req->result.dek.len, "req->result.dek");
rc = 0;
break;
case OP_RSA_ENC:
case OP_RSA_DEC:
memcpy(ret, &(req->result.dek), sizeof(dek_t));
rc = 0;
break;
default:
PUB_CRYPTO_LOGE("Not supported opcode(%d)!!!\n", req->opcode);
rc = -EOPNOTSUPP;
break;
}
out:
if(skb_out) {
kfree_skb(skb_out);
}
if(rc != 0)
req_dump(req, "failed");
return rc;
}
static int pub_crypto_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
{
void *data;
u16 msg_type = nlh->nlmsg_type;
u32 err = 0;
struct audit_status *status_get = NULL;
u16 len = 0;
data = NLMSG_DATA(nlh);
len = ntohs(*(uint16_t*) (data+1));
switch (msg_type) {
case PUB_CRYPTO_PID_SET:
status_get = (struct audit_status *)data;
user_fipscryptod_pid = status_get->pid;
PUB_CRYPTO_LOGE("crypto_receive_msg: pid = %d\n", user_fipscryptod_pid);
break;
case PUB_CRYPTO_RESULT:
{
result_t *result = (result_t *)data;
pub_crypto_request_t *req = NULL;
req = request_find(&g_pub_crypto_control, result->request_id);
if(req) {
memcpy(&req->result, result, sizeof(result_t));
req->state = PUB_CRYPTO_REQ_FINISHED;
wake_up(&req->waitq);
memset(result, 0, sizeof(result_t));
}
break;
}
default:
PUB_CRYPTO_LOGE("unknown message type : %d\n", msg_type);
break;
}
return err;
}
/* Receive messages from netlink socket. */
static void crypto_recver(struct sk_buff *skb)
{
struct nlmsghdr *nlh;
int len;
int err;
nlh = nlmsg_hdr(skb);
len = skb->len;
err = pub_crypto_recv_msg(skb, nlh);
}
static void dump(unsigned char *buf, int len, const char *msg) {
#if PUB_CRYPTO_DEBUG
int i;
printk("%s len=%d: ", msg, len);
for(i=0;i<len;++i) {
printk("%02x ", (unsigned char)buf[i]);
}
printk("\n");
#else
printk("%s len=%d: ", msg, len);
printk("\n");
#endif
}
int do_dek_crypt(int opcode, dek_t *in, dek_t *out, kek_t *key){
pub_crypto_request_t *req = request_alloc(opcode);
int ret = -1;
if(req) {
switch(req->opcode) {
case OP_RSA_ENC:
case OP_RSA_DEC:
case OP_DH_ENC:
case OP_DH_DEC:
case OP_ECDH_ENC:
case OP_ECDH_DEC:
req->cipher_param.request_id = req->id;
req->cipher_param.opcode = req->opcode;
memcpy(&req->cipher_param.in, (void *) in, sizeof(dek_t));
memcpy(&req->cipher_param.key, (void *) key, sizeof(kek_t));
break;
default:
PUB_CRYPTO_LOGE("opcode[%d] failed, not supported\n", opcode);
goto error;
break;
}
ret = __do_dek_crypt(req, (char *)out);
if(ret != 0) {
PUB_CRYPTO_LOGE("opcode[%d] failed\n", opcode);
goto error;
}
} else {
PUB_CRYPTO_LOGE("request allocation failed\n");
return -ENOMEM;
}
request_free(&g_pub_crypto_control, req);
return 0;
error:
request_free(&g_pub_crypto_control, req);
return -1;
}
int rsa_encryptByPub(dek_t *dek, dek_t *edek, kek_t *key){
return do_dek_crypt(OP_RSA_ENC, dek, edek, key);
}
int rsa_decryptByPair(dek_t *edek, dek_t *dek, kek_t *key){
return do_dek_crypt(OP_RSA_DEC, edek, dek, key);
}
int dh_encryptDEK(dek_t *dek, dek_t *edek, kek_t *key){
return do_dek_crypt(OP_DH_ENC, dek, edek, key);
}
int dh_decryptEDEK(dek_t *edek, dek_t *dek, kek_t *key){
return do_dek_crypt(OP_DH_DEC, edek, dek, key);
}
int ecdh_encryptDEK(dek_t *dek, dek_t *edek, kek_t *key){
return do_dek_crypt(OP_ECDH_ENC, dek, edek, key);
}
int ecdh_decryptEDEK(dek_t *edek, dek_t *dek, kek_t *key){
return do_dek_crypt(OP_ECDH_DEC, edek, dek, key);
}
static int pub_crypto_request_get_msg(pub_crypto_request_t *req, char **msg)
{
int msg_len = -1;
switch(req->opcode) {
case OP_RSA_ENC:
case OP_RSA_DEC:
case OP_DH_DEC:
case OP_DH_ENC:
case OP_ECDH_DEC:
case OP_ECDH_ENC:
*msg = (char *)&req->cipher_param;
msg_len = sizeof(cipher_param_t);
break;
default:
*msg = NULL;
msg_len = -1;
break;
}
return msg_len;
}
static u32 pub_crypto_get_unique_id(pub_crypto_control_t *control)
{
spin_lock(&control->lock);
control->reqctr++;
/* zero is special */
if (control->reqctr == 0)
control->reqctr = 1;
spin_unlock(&control->lock);
return control->reqctr;
}
static void req_dump(pub_crypto_request_t *req, const char *msg) {
PUB_CRYPTO_LOGI("req %s {id:%d op:%d state:%d}\n", msg, req->id, req->opcode, req->state);
}
static void request_send(pub_crypto_control_t *con,
pub_crypto_request_t *req) {
spin_lock(&con->lock);
list_add_tail(&req->list, &con->pending_list);
req->state = PUB_CRYPTO_REQ_PENDING;
req_dump(req, "added");
spin_unlock(&con->lock);
}
static void request_wait_answer(pub_crypto_control_t *con,
pub_crypto_request_t *req) {
int intr;
while (req->state != PUB_CRYPTO_REQ_FINISHED) {
/*
* TODO : can anyone answer what happens when current process gets killed here?
*/
intr = wait_event_interruptible_timeout(req->waitq,
req->state == PUB_CRYPTO_REQ_FINISHED,
msecs_to_jiffies(PUB_CRYPTO_REQ_TIMEOUT));
if(req->state == PUB_CRYPTO_REQ_FINISHED)
break;
if(intr == 0) {
PUB_CRYPTO_LOGE("timeout! %d [ID:%d] \n", intr, req->id);
req->state = PUB_CRYPTO_REQ_FINISHED;
req->aborted = 1;
break;
}
if(intr == -ERESTARTSYS) {
PUB_CRYPTO_LOGE("wait interrupted : intr %d(-ERESTARTSYS) \n", intr);
break;
}
}
}
static pub_crypto_request_t *request_find(pub_crypto_control_t *con,
u32 request_id) {
struct list_head *entry;
spin_lock(&con->lock);
list_for_each(entry, &con->pending_list) {
pub_crypto_request_t *req;
req = list_entry(entry, pub_crypto_request_t, list);
if (req->id == request_id) {
req_dump(req, "found");
spin_unlock(&con->lock);
return req;
}
}
spin_unlock(&con->lock);
PUB_CRYPTO_LOGE("Can't find request %d\n", request_id);
return NULL;
}
static struct kmem_cache *pub_crypto_req_cachep;
static void pub_crypto_request_init(pub_crypto_request_t *req, u32 opcode) {
memset(req, 0, sizeof(pub_crypto_request_t));
req->state = PUB_CRYPTO_REQ_INIT;
req->id = pub_crypto_get_unique_id(&g_pub_crypto_control);
INIT_LIST_HEAD(&req->list);
init_waitqueue_head(&req->waitq);
atomic_set(&req->count, 1);
req->aborted = 0;
req->opcode = opcode;
}
static pub_crypto_request_t *request_alloc(u32 opcode) {
pub_crypto_request_t *req = kmem_cache_alloc(pub_crypto_req_cachep, GFP_KERNEL);
if(req)
pub_crypto_request_init(req, opcode);
return req;
}
static void request_free(pub_crypto_control_t *con, pub_crypto_request_t *req) {
if(req) {
req_dump(req, "freed");
spin_lock(&con->lock);
list_del(&req->list);
memset(req, 0, sizeof(pub_crypto_request_t));
kmem_cache_free(pub_crypto_req_cachep, req);
spin_unlock(&con->lock);
} else {
PUB_CRYPTO_LOGE("req is NULL, skip free\n");
}
}
void pub_crypto_control_init(pub_crypto_control_t *con) {
PUB_CRYPTO_LOGD("pub_crypto_control_init");
spin_lock_init(&con->lock);
INIT_LIST_HEAD(&con->pending_list);
con->reqctr = 0;
}
static int __init pub_crypto_mod_init(void) {
#if (LINUX_VERSION_CODE > KERNEL_VERSION(3,4,0))
struct netlink_kernel_cfg cfg = {
.input = crypto_recver,
};
crypto_sock = netlink_kernel_create(&init_net, NETLINK_FIPS_CRYPTO, &cfg);
#else
crypto_sock = netlink_kernel_create(&init_net, NETLINK_FIPS_CRYPTO, 0, crypto_recver, NULL, THIS_MODULE);
#endif
if (!crypto_sock) {
PUB_CRYPTO_LOGE("Failed to create Crypto Netlink Socket .. Exiting \n");
return -ENOMEM;
}
PUB_CRYPTO_LOGE("netlink socket is created successfully! \n");
pub_crypto_control_init(&g_pub_crypto_control);
pub_crypto_req_cachep = kmem_cache_create("pub_crypto_requst",
sizeof(pub_crypto_request_t),
0, 0, NULL);
if (!pub_crypto_req_cachep) {
netlink_kernel_release(crypto_sock);
PUB_CRYPTO_LOGE("Failed to create pub_crypto_requst cache mem.. Exiting \n");
return -ENOMEM;
}
return 0;
}
static void __exit pub_crypto_mod_exit(void) {
/*
if (crypto_sock && crypto_sock->sk_socket) {
sock_release(crypto_sock->sk_socket);
}
*/
netlink_kernel_release(crypto_sock);
kmem_cache_destroy(pub_crypto_req_cachep);
}
module_init(pub_crypto_mod_init);
module_exit(pub_crypto_mod_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("SDP pub crypto");

310
security/sdp/sdp_dlp.c Normal file
View file

@ -0,0 +1,310 @@
/*
* 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/debugfs.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/uaccess.h>
#include <linux/miscdevice.h>
#include <linux/slab.h>
#include <linux/ctype.h>
#include <sdp/dlp_ioctl.h>
#include <sdp/sdp_dlp.h>
#define DLP_DUMP_LIST 1 //TODO
static char *DLP_FILE_EXTENSIONS[] = {"xls", "xlsx", "doc", "docx", "ppt", "pptx", "pdf", "jpg", "jpeg", "zip", "mp4", "txt", "asd", "xlam", "htm", "html", "mht", "eml", "msg", "hwp", "gul", "rtf", "mysingle", "png", "gif"};
struct dlp_struct {
int user_id;
long time;
bool lock;
char* extensions;
struct list_head list;
spinlock_t list_lock;
};
struct dlp_struct dlp_info;
#if DLP_DUMP_LIST
static void dlp_dump_list(void) {
struct list_head *entry;
struct dlp_struct *tmp;
printk("============ debug ============\n");
spin_lock(&dlp_info.list_lock);
list_for_each(entry, &dlp_info.list) {
tmp = list_entry(entry, struct dlp_struct, list);
printk("DLP : user_id : %d\n", tmp->user_id);
printk("DLP : lock : %s\n", tmp->lock ? "true" : "false");
if (tmp->extensions) {
printk("DLP : extensions : %s\n", tmp->extensions);
} else {
printk("DLP : extensions : (empty)\n");
}
}
spin_unlock(&dlp_info.list_lock);
}
#endif
static struct dlp_struct *dlp_find_list(int user_id) {
struct list_head *entry;
struct dlp_struct *tmp;
spin_lock(&dlp_info.list_lock);
printk("DLP: user_id %d\n", user_id);
list_for_each(entry, &dlp_info.list) {
tmp = list_entry(entry, struct dlp_struct, list);
printk("DLP: tmp->user_id %d\n", tmp->user_id);
if(tmp->user_id == user_id) {
printk("DLP: found user_id %d\n", user_id); // TODO : deleted
spin_unlock(&dlp_info.list_lock);
return tmp;
}
}
spin_unlock(&dlp_info.list_lock);
return NULL;
}
bool dlp_is_locked(int user_id) {
struct dlp_struct *tmp;
tmp = dlp_find_list(user_id);
if(tmp){
return tmp->lock;
}
else {
return false;
}
}
static struct dlp_struct *dlp_add_info(int user_id){
struct dlp_struct *new_item;
new_item = kmalloc(sizeof(struct dlp_struct), GFP_KERNEL);
if(new_item == NULL) {
printk("DLP: can't alloc memory for dlp_info\n");
return NULL;
}
new_item->user_id = user_id;
new_item->lock = false;
new_item->extensions = NULL;
spin_lock_init(&new_item->list_lock);
INIT_LIST_HEAD(&new_item->list);
spin_lock(&dlp_info.list_lock);
list_add_tail(&new_item->list, &dlp_info.list);
spin_unlock(&dlp_info.list_lock);
return new_item;
}
static int dlp_lock_setting(void __user *argp, bool lock) {
int ret = 0;
struct dlp_struct *tmp = NULL;
struct _dlp_lock_set dlp_lock_set;
ret = copy_from_user(&dlp_lock_set, (void __user *)argp, sizeof(dlp_lock_set));
if(ret) {
printk("DLP : fail to copy_from_user : dlp_lock_setting\n");
return -EFAULT;
}
tmp = dlp_find_list(dlp_lock_set.user_id);
if(tmp == NULL){
tmp = dlp_add_info(dlp_lock_set.user_id);
if(tmp == NULL){
return -EFAULT;
}
}
spin_lock(&dlp_info.list_lock);
tmp->lock = lock;
spin_unlock(&dlp_info.list_lock);
return 0;
};
static int dlp_extension_setting(void __user *argp) {
int ret = 0;
struct dlp_struct *tmp = NULL;
struct _dlp_extension_set dlp_ext_set;
ret = copy_from_user(&dlp_ext_set, (void __user *)argp, sizeof(dlp_ext_set));
if(ret) {
printk("DLP : fail to copy_from_user : dlp_extension_setting\n");
return -EFAULT;
}
printk("DLP: dlp_extension_setting called with user_id %d\n", dlp_ext_set.user_id);
tmp = dlp_find_list(dlp_ext_set.user_id);
if(tmp == NULL){
tmp = dlp_add_info(dlp_ext_set.user_id);
if(tmp == NULL){
return -EFAULT;
}
}
/* Delete old extensions and create new */
spin_lock(&dlp_info.list_lock);
if(tmp->extensions) {
kfree(tmp->extensions);
tmp->extensions = NULL;
}
if(strlen(dlp_ext_set.extensions)) {
tmp->extensions = kmalloc(strlen(dlp_ext_set.extensions)+1, GFP_KERNEL);
if (!tmp->extensions) {
spin_unlock(&dlp_info.list_lock);
return -EFAULT;
}
} else {
spin_unlock(&dlp_info.list_lock);
return 0;
}
strcpy(tmp->extensions, dlp_ext_set.extensions);
spin_unlock(&dlp_info.list_lock);
return 0;
}
static long dlp_ioctl(struct file *file, unsigned cmd,
unsigned long arg) {
int ret = 0;
void __user *argp = (void __user *) arg;
switch (cmd) {
case DLP_LOCK_ENABLE: {
printk("DLP: DLP_LOCK_ENABLE\n");
ret = dlp_lock_setting(argp, true);
break;
}
case DLP_LOCK_DISABLE: {
printk("DLP: DLP_LOCK_DISABLE\n");
ret = dlp_lock_setting(argp, false);
break;
}
case DLP_EXTENSION_SET: {
printk("DLP: DLP_EXTENSION_SET\n");
ret = dlp_extension_setting(argp);
break;
}
default:
pr_err("DLP : Invalid IOCTL: %d\n", cmd);
return -EINVAL;
}
#if DLP_DUMP_LIST
dlp_dump_list();
#endif
return ret;
}
int dlp_isInterestedFile(int user_id, const char *filename){
int i, j;
char *ext, *ret;
char lower[256];
struct dlp_struct *item = NULL;
ext = strrchr(filename, '.');
printk("DLP: dlp_isInterestedFile : %s\n", filename);
if(ext == NULL){
printk("DLP: Ext not found\n");
return -1;
}else{
ext++;
strncpy(lower, ext, sizeof(lower)-1);
lower[sizeof(lower)-1] = '\0';
for (j=0; j < strlen(lower); j++) {
lower[j] = tolower(lower[j]);
}
printk("DLP: extension : %s\n", lower);
}
item = dlp_find_list(user_id);
if(item == NULL || item->extensions == NULL){
//extensions for DLP is not set ...
// check if the extension is matching with default extensions
printk("DLP: extension set for DLP is not set\n");
for(i=(sizeof(DLP_FILE_EXTENSIONS)/sizeof(char*) -1); i>=0; i--){
if(strcmp(DLP_FILE_EXTENSIONS[i], lower)==0){
return 0;
}
}
printk("DLP: extension not matching with default return -1\n");
return -1;
}
printk("DLP: extension = %s\n", item->extensions);
strcat(lower, ","); // add comma, so that we compare each ext fully (doc vs. docx)
spin_lock(&dlp_info.list_lock);
ret = strstr(item->extensions, lower);
spin_unlock(&dlp_info.list_lock);
if (ret) {
return 0;
} else {
return -1;
}
}
const struct file_operations dlp_fops_evt = {
.owner = THIS_MODULE,
.unlocked_ioctl = dlp_ioctl,
.compat_ioctl = dlp_ioctl,
};
static struct miscdevice dlp_misc_dev = {
.minor = MISC_DYNAMIC_MINOR,
.name = "sdp_dlp",
.fops = &dlp_fops_evt,
};
static int __init dlp_ioctl_init(void) {
int ret;
ret = misc_register(&dlp_misc_dev);
if (unlikely(ret)) {
printk("DLP: failed to register sdp_dlp device!\n");
return ret;
}
INIT_LIST_HEAD(&dlp_info.list);
spin_lock_init(&dlp_info.list_lock);
printk("DLP: dlp_ioctl initialized\n");
return 0;
}
static void __exit dlp_ioctl_exit(void) {
misc_deregister(&dlp_misc_dev);
printk("DLP: dlp_ioctl mics_deregister\n");
}
module_init(dlp_ioctl_init);
module_exit(dlp_ioctl_exit);

301
security/sdp/sdp_mm.c Normal file
View file

@ -0,0 +1,301 @@
/*
* 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.
*/
#define pr_fmt(fmt) "SDP_MM: %s: " fmt, __func__
#include <asm/current.h>
#include <linux/cdev.h>
#include <linux/debugfs.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/mm_types.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/types.h>
#include <linux/uaccess.h>
#include <sdp/sdp_mm.h>
#define SDP_MM_DEV "sdp_mm"
#define SENSITIVE 1
#define PER_USER_RANGE 100000
extern int dek_is_sdp_uid(uid_t uid);
static struct class *driver_class;
static dev_t sdp_mm_device_no;
struct sdp_mm_control {
struct list_head sdp_proc_list_head;
spinlock_t sdp_proc_list_lock;
struct cdev cdev;
unsigned int sensitive_proc_list_len;
unsigned int proc_id[MAX_SENSITIVE_PROC];
};
static struct sdp_mm_control sdp_mm;
static int32_t sdp_mm_query_proc_loaded(void __user *argp)
{
int32_t ret = 0;
struct task_struct *p = NULL;
unsigned long flags = 0;
struct sdp_mm_sensitive_proc_list_resp sdp_resp = {0};
/* foreach process check if 'sensitive' flag is set in task/mm_struct */
/* Copy the relevant information needed for loading the image */
spin_lock_irqsave(&sdp_mm.sdp_proc_list_lock, flags);
for_each_process(p) {
if (p->sensitive == SENSITIVE) {
sdp_resp.sensitive_proc_list[sdp_resp.sensitive_proc_list_len] = p->pid;
sdp_resp.sensitive_proc_list_len++;
}
}
spin_unlock_irqrestore(&sdp_mm.sdp_proc_list_lock, flags);
if (copy_to_user(argp, &sdp_resp, sizeof(sdp_resp))) {
pr_err("SDP_MM: copy_to_user_failed\n");
ret = -EFAULT;
}
return ret;
}
int32_t sdp_mm_set_process_sensitive(unsigned int proc_id)
{
int32_t ret = 0;
struct task_struct *task = NULL;
uid_t uid;
/* current.task.sensitive = 1 */
task = pid_task(find_vpid(proc_id), PIDTYPE_PID);
if (task) {
uid = from_kuid(&init_user_ns, task_uid(task));
if (((uid/PER_USER_RANGE) <= 199) && ((uid/PER_USER_RANGE) >= 100)) {
if (dek_is_sdp_uid(uid)) {
task->sensitive = SENSITIVE;
printk("SDP_MM: set the process as sensitive\n");
} else {
printk("SDP_MM: not a SDP process, failed to mark sensitive\n");
ret = -EINVAL;
goto task_err;
}
}
} else {
printk("SDP_MM; task not present\n");
ret = -EINVAL;
goto task_err;
}
task_err:
return ret;
}
EXPORT_SYMBOL(sdp_mm_set_process_sensitive);
static int32_t sdp_mm_set_proc_sensitive(void __user *argp)
{
unsigned int proc_id = 0;
if (copy_from_user(&proc_id, (void __user *)argp,
sizeof(unsigned int))) {
pr_err("SDP_MM: copy_from_user failed\n");
return -EFAULT;
}
printk("SDP_MM: sensitive process id is %d\n", proc_id);
if (sdp_mm.sensitive_proc_list_len < MAX_SENSITIVE_PROC) {
sdp_mm.proc_id[sdp_mm.sensitive_proc_list_len] = proc_id;
sdp_mm.sensitive_proc_list_len++;
}
return sdp_mm_set_process_sensitive(proc_id);
}
static long sdp_mm_ioctl(struct file *file, unsigned cmd,
unsigned long arg)
{
int ret = 0;
void __user *argp = (void __user *) arg;
printk("SDP_MM: Entering ioctl\n");
switch (cmd) {
case SDP_MM_IOCTL_PROC_SENSITIVE_QUERY_REQ: {
printk("SDP_MM: SENSITIVE_PROC_QUERY\n");
ret = sdp_mm_query_proc_loaded(argp);
break;
}
case SDP_MM_IOCTL_SET_SENSITIVE_PROC_REQ: {
printk("SDP_MM: SET_PROC_SENSITIVE\n");
ret = sdp_mm_set_proc_sensitive(argp);
break;
}
default:
pr_err("Invalid IOCTL: %d\n", cmd);
return -EINVAL;
}
return ret;
}
static int sdp_mm_open(struct inode *inode, struct file *file)
{
int ret = 0;
printk("SDP_MM: entering open\n");
return ret;
}
static const struct file_operations sdp_mm_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = sdp_mm_ioctl,
.open = sdp_mm_open,
};
static int sdp_mm_probe(struct platform_device *pdev)
{
int rc;
struct device *class_dev;
printk("SDP_MM: entering probe\n");
rc = alloc_chrdev_region(&sdp_mm_device_no, 0, 1, SDP_MM_DEV);
if (rc < 0) {
pr_err("alloc_chrdev_region failed %d\n", rc);
return rc;
}
driver_class = class_create(THIS_MODULE, SDP_MM_DEV);
if (IS_ERR(driver_class)) {
rc = -ENOMEM;
pr_err("SDP_MM: class_create failed %d\n", rc);
goto exit_unreg_chrdev_region;
}
class_dev = device_create(driver_class, NULL, sdp_mm_device_no, NULL,
SDP_MM_DEV);
if (!class_dev) {
pr_err("SDP_MM: class_device_create failed %d\n", rc);
rc = -ENOMEM;
goto exit_destroy_class;
}
cdev_init(&sdp_mm.cdev, &sdp_mm_fops);
sdp_mm.cdev.owner = THIS_MODULE;
rc = cdev_add(&sdp_mm.cdev, MKDEV(MAJOR(sdp_mm_device_no), 0), 1);
if (rc < 0) {
pr_err("SDP_MM: cdev_add failed %d\n", rc);
goto exit_destroy_device;
}
INIT_LIST_HEAD(&sdp_mm.sdp_proc_list_head);
spin_lock_init(&sdp_mm.sdp_proc_list_lock);
return 0;
exit_destroy_device:
device_destroy(driver_class, sdp_mm_device_no);
exit_destroy_class:
class_destroy(driver_class);
exit_unreg_chrdev_region:
unregister_chrdev_region(sdp_mm_device_no, 1);
return rc;
}
static int sdp_mm_remove(struct platform_device *pdev)
{
int ret = 0;
cdev_del(&sdp_mm.cdev);
device_destroy(driver_class, sdp_mm_device_no);
class_destroy(driver_class);
unregister_chrdev_region(sdp_mm_device_no, 1);
return ret;
}
static struct platform_driver sdp_mm_plat_driver = {
.probe = sdp_mm_probe,
.remove = sdp_mm_remove,
.driver = {
.name = "sdp_mm",
.owner = THIS_MODULE,
},
};
static int __init sdp_mm_init(void)
{
int rc;
struct device *class_dev;
printk("SDP_MM: entering************************************************\n");
rc = alloc_chrdev_region(&sdp_mm_device_no, 0, 1, SDP_MM_DEV);
if (rc < 0) {
pr_err("SDP_MM: Alloc_chrdev_region failed %d\n", rc);
return rc;
}
driver_class = class_create(THIS_MODULE, SDP_MM_DEV);
if (IS_ERR(driver_class)) {
rc = -ENOMEM;
pr_err("SDP_MM: class_create failed %d\n", rc);
goto exit_unreg_chrdev_region;
}
class_dev = device_create(driver_class, NULL, sdp_mm_device_no, NULL,
SDP_MM_DEV);
if (!class_dev) {
pr_err("SDP_MM: class_device_create failed %d\n", rc);
rc = -ENOMEM;
goto exit_destroy_class;
}
cdev_init(&sdp_mm.cdev, &sdp_mm_fops);
sdp_mm.cdev.owner = THIS_MODULE;
rc = cdev_add(&sdp_mm.cdev, MKDEV(MAJOR(sdp_mm_device_no), 0), 1);
if (rc < 0) {
pr_err("SDP_MM: cdev_add failed %d\n", rc);
goto exit_destroy_device;
}
INIT_LIST_HEAD(&sdp_mm.sdp_proc_list_head);
spin_lock_init(&sdp_mm.sdp_proc_list_lock);
return 0;
exit_destroy_device:
device_destroy(driver_class, sdp_mm_device_no);
exit_destroy_class:
class_destroy(driver_class);
exit_unreg_chrdev_region:
unregister_chrdev_region(sdp_mm_device_no, 1);
return rc;
}
static void __exit sdp_mm_exit(void)
{
platform_driver_unregister(&sdp_mm_plat_driver);
}
module_init(sdp_mm_init);
module_exit(sdp_mm_exit);
MODULE_AUTHOR("HP");
MODULE_LICENSE("GPL");