android_kernel_samsung_a7y1.../drivers/security/samsung/icdrv/icd.c
prashantpaddune 3bca37f224 A750FXXU4CTBC
2020-03-27 21:51:54 +05:30

208 lines
4.6 KiB
C

/*
* ICD Driver
*
* Copyright (C) 2018 Samsung Electronics, Inc.
* Egor Uleyskiy, <e.uleyskiy@samsung.com>
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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.
*/
#include <linux/module.h>
#include <linux/debugfs.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/fs.h>
#include <linux/file.h>
#include <linux/version.h>
#include "oemflag.h"
#include "icd_protect_list.h"
#include "five_hooks.h"
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
#include <linux/sched/mm.h>
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0)
#include <linux/string_helpers.h>
#endif
static void icd_hook_integrity_reset(struct task_struct *task);
static struct five_hook_list five_ops[] = {
FIVE_HOOK_INIT(integrity_reset, icd_hook_integrity_reset),
};
static bool contains_str(const char * const array[], const char *str)
{
const char * const *p;
for (p = &array[0]; *p != NULL; ++p) {
if (strncmp(str, *p, PATH_MAX) == 0)
return true;
}
return false;
}
static const char *get_first_argument_from_cmdline(struct task_struct *task)
{
char *buffer, *quoted;
int i, res, pos = 0;
buffer = kmalloc(PAGE_SIZE, GFP_KERNEL);
if (!buffer)
return NULL;
res = get_cmdline(task, buffer, PAGE_SIZE - 1);
buffer[res] = '\0';
/* Collapse trailing NULLs, leave res pointing to last non-NULL. */
while (--res >= 0 && buffer[res] == '\0')
;
/* Find first argument */
for (i = 0; i <= res; i++) {
if (buffer[i] == '\0') {
pos = i;
break;
}
}
if (pos == 0) {
if(buffer)
kfree(buffer);
return NULL;
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0)
/* Make sure result is printable. */
quoted = kstrdup_quotable(buffer+pos+1, GFP_KERNEL);
#else
quoted = kmalloc(PAGE_SIZE, GFP_KERNEL);
strncpy(quoted, buffer+pos+1, strlen(buffer+pos+1));
#endif
kfree(buffer);
return (const char *)quoted;
}
static bool cmdline_check(struct task_struct *task, const char *str)
{
const char *first_arg = NULL;
bool ret = false;
first_arg = get_first_argument_from_cmdline(task);
if (first_arg != NULL) {
pr_debug("IOF: first_arg: %s\n", first_arg);
if (!strncmp(first_arg, str, strlen(str)))
ret = true;
}
kfree(first_arg);
return ret;
}
enum oemflag_id affected_oemflag_id(struct task_struct *task, const char *path)
{
if (contains_str(tz_drm_list, path)
|| cmdline_check(task, "--TZ_DRM"))
return OEMFLAG_TZ_DRM;
if (contains_str(fido_list, path)
|| cmdline_check(task, "--FIDO"))
return OEMFLAG_FIDO;
if (contains_str(cc_list, path)
|| cmdline_check(task, "--CC"))
return OEMFLAG_CC;
if (contains_str(etc_list, path)
|| cmdline_check(task, "--ETC"))
return OEMFLAG_ETC;
return OEMFLAG_NONE;
}
static const char *get_exec_path(struct task_struct *task, char **pathbuf)
{
struct mm_struct *mm;
struct file *exe_file;
struct path *exe_path;
char *pathname = NULL;
mm = get_task_mm(task);
if (!mm)
return ERR_PTR(-ENOENT);
exe_file = get_mm_exe_file(mm);
mmput(mm);
if (!exe_file)
return ERR_PTR(-ENOENT);
exe_path = &exe_file->f_path;
*pathbuf = __getname();
if (*pathbuf) {
pathname = d_absolute_path(exe_path, *pathbuf, PATH_MAX);
if (IS_ERR(pathname)) {
__putname(*pathbuf);
*pathbuf = NULL;
pathname = NULL;
}
}
if (!pathname || !*pathbuf) {
pr_err("ICD: Can't obtain absolute path: %p %p\n",
pathname, *pathbuf);
}
fput(exe_file);
return pathname ?: (const char *)exe_path->dentry->d_name.name;
}
static void icd_hook_integrity_reset(struct task_struct *task)
{
const char *execpath = NULL;
char *pathbuf = NULL;
enum oemflag_id oemid;
pr_debug("ICD: observer t=%pi\n", task);
execpath = get_exec_path(task, &pathbuf);
if (IS_ERR_OR_NULL(execpath)) {
if (execpath) {
pr_err("ICD: get_exec_path err: %ld\n",
PTR_ERR(execpath));
}
goto out;
}
oemid = affected_oemflag_id(task, execpath);
if (oemid != OEMFLAG_NONE) {
int ret;
pr_info("ICD: %s: %u\n", execpath, oemid);
ret = oem_flags_set(oemid);
if (ret)
pr_err("oem_flags_set err: %d\n", ret);
}
out:
if (pathbuf)
__putname(pathbuf);
}
static int __init icd_driver_init(void)
{
int ret = 0;
five_add_hooks(five_ops, ARRAY_SIZE(five_ops));
return ret;
}
static void __exit icd_driver_exit(void)
{
pr_info("Exit ICDriver\n");
}
module_init(icd_driver_init);
module_exit(icd_driver_exit);