352 lines
9.7 KiB
C
352 lines
9.7 KiB
C
/*
|
|
* 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");
|
|
|