mirror of
https://github.com/AetherDroid/android_kernel_samsung_on5xelte.git
synced 2025-09-08 01:08:03 -04:00
Fixed MTP to work with TWRP
This commit is contained in:
commit
f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions
7
security/sdp/Makefile
Normal file
7
security/sdp/Makefile
Normal 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
70
security/sdp/cache_cleanup.c
Executable 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
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
107
security/sdp/dek_aes.c
Normal 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
129
security/sdp/dek_sysfs.c
Normal 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
352
security/sdp/fs_handler.c
Executable 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
306
security/sdp/kek_pack.c
Normal 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
519
security/sdp/pub_crypto_emul.c
Executable 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
310
security/sdp/sdp_dlp.c
Normal 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
301
security/sdp/sdp_mm.c
Normal 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");
|
Loading…
Add table
Add a link
Reference in a new issue