kernel_samsung_a53x/security/samsung/mz/mz_ioctl.c
2024-06-15 16:02:09 -03:00

222 lines
5.6 KiB
C
Executable file

/*
* Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
*
* 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.
*/
#include <linux/cdev.h>
#include <linux/kconfig.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include "mz_internal.h"
#include "mz_log.h"
#include "mz_page.h"
#define MZ_DEV "mz_ioctl"
static struct class *driver_class, *driver_class_old;
static dev_t mz_ioctl_device_no, mz_ioctl_device_no_old;
static struct cdev mz_ioctl_cdev;
__visible_for_testing long mz_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
int ret = MZ_SUCCESS;
#ifndef CONFIG_SEC_KUNIT
vainfo mzvainfo = { 0, 0};
uint64_t ava, va, ptwi = 0, len;
uint64_t cur_len;
unsigned long pfn, old_pfn = 0;
#endif /* CONFIG_SEC_KUNIT */
struct mm_struct *mm = current->mm;
pid_t cur_tid = current->pid;
uint8_t __user *buf;
uint8_t pname[MAX_PROCESS_NAME] = "";
if (!mm) {
MZ_LOG(err_level_error, "%s mm_struct fail\n", __func__);
ret = MZ_GENERAL_ERROR;
return ret;
}
#ifndef CONFIG_SEC_KUNIT
ret = mz_kget_process_name(current->tgid, pname);
if (ret != MZ_SUCCESS) {
MZ_LOG(err_level_error, "%s get name fail %d %d %d\n", __func__, current->tgid, cur_tid, ret);
return ret;
}
#endif /* CONFIG_SEC_KUNIT */
MZ_LOG(err_level_info, "%s start %s %d %d", __func__, pname, current->tgid, cur_tid);
switch (cmd) {
case IOCTL_MZ_SET_CMD:
#if IS_ENABLED(CONFIG_MEMORY_ZEROISATION)
#ifndef CONFIG_SEC_KUNIT
ret = copy_from_user(&mzvainfo, (void *)arg, sizeof(mzvainfo));
if (ret)
MZ_LOG(err_level_error, "%s copy from user error\n", __func__);
else ret=MZ_SUCCESS;
va = mzvainfo.va;
len = mzvainfo.len;
buf = mzvainfo.buf;
#endif /* CONFIG_SEC_KUNIT */
#ifndef CONFIG_SEC_KUNIT
if (!isaddrset()) {
ret = set_mz_mem();
if (ret != MZ_SUCCESS) {
MZ_LOG(err_level_error, "%s global list set fail %d\n", __func__, ret);
goto out;
}
}
while (len > 0) {
ava = va + ptwi;
pfn = mz_ptw(ava, mm);
if (pfn == 0) {
MZ_LOG(err_level_error, "%s mz_ptw fail\n", __func__);
goto out;
}
//pfn should be different from old one in normal case. It's for checking system error.
if (old_pfn != pfn) {
if (PAGE_SIZE - (ava & (PAGE_SIZE - 1)) < len)
cur_len = (PAGE_SIZE - (ava & (PAGE_SIZE - 1)));
else
cur_len = len;
MZ_LOG(err_level_debug, "%s %d %llx %d %llx %d\n",
__func__, pfn, va, len, ava, cur_len);
ret = mz_add_target_pfn(cur_tid, pfn, ava & (PAGE_SIZE - 1), cur_len, ava, buf);
if (ret != MZ_SUCCESS) {
MZ_LOG(err_level_error, "%s fail %d\n", __func__, ret);
goto out;
}
len -= cur_len;
ptwi += cur_len;
old_pfn = pfn;
} else {
MZ_LOG(err_level_debug, "%s recheck %d %llx %d %llx %d\n",
__func__, pfn, va, len, ava, cur_len);
ptwi++;
len--;
}
}
#endif /* CONFIG_SEC_KUNIT */
out:
#endif /* IS_ENABLED(CONFIG_MEMORY_ZEROISATION) */
break;
case IOCTL_MZ_ALL_SET_CMD:
#if IS_ENABLED(CONFIG_MEMORY_ZEROISATION)
mz_all_zero_set(cur_tid);
#endif /* IS_ENABLED(CONFIG_MEMORY_ZEROISATION) */
break;
default:
MZ_LOG(err_level_error, "%s unknown cmd\n", __func__);
ret = MZ_INVALID_INPUT_ERROR;
break;
}
MZ_LOG(err_level_info, "%s end %s %d %d\n", __func__, pname, current->tgid, cur_tid);
return ret;
}
static const struct file_operations mz_ioctl_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = mz_ioctl,
.compat_ioctl = mz_ioctl,
};
#ifdef CONFIG_SEC_KUNIT
int mz_ioctl_init(void)
#else
static int __init mz_ioctl_init(void)
#endif
{
int rc;
struct device *class_dev;
MZ_LOG(err_level_info, "%s mz_ioctl\n", __func__);
mz_ioctl_device_no_old = mz_ioctl_device_no;
driver_class_old = driver_class;
rc = alloc_chrdev_region(&mz_ioctl_device_no, 0, 1, MZ_DEV);
if (rc < 0) {
MZ_LOG(err_level_error, "%s alloc_chrdev_region failed %d\n", __func__, rc);
return rc;
}
driver_class = class_create(THIS_MODULE, MZ_DEV);
if (IS_ERR(driver_class)) {
rc = -ENOMEM;
MZ_LOG(err_level_error, "%s class_create failed %d\n", __func__, rc);
goto unregister_chrdev_region;
}
class_dev = device_create(driver_class, NULL, mz_ioctl_device_no, NULL, MZ_DEV);
if (!class_dev) {
rc = -ENOMEM;
MZ_LOG(err_level_error, "%s class_device_create failed %d\n", __func__, rc);
goto class_destroy;
}
cdev_init(&mz_ioctl_cdev, &mz_ioctl_fops);
mz_ioctl_cdev.owner = THIS_MODULE;
rc = cdev_add(&mz_ioctl_cdev, MKDEV(MAJOR(mz_ioctl_device_no), 0), 1);
if (rc < 0) {
MZ_LOG(err_level_error, "%s cdev_add failed %d\n", __func__, rc);
goto class_device_destroy;
}
mzinit();
return 0;
class_device_destroy:
device_destroy(driver_class, mz_ioctl_device_no);
class_destroy:
class_destroy(driver_class);
unregister_chrdev_region:
if (driver_class_old != NULL) {
device_destroy(driver_class_old, mz_ioctl_device_no_old);
class_destroy(driver_class_old);
driver_class_old = NULL;
unregister_chrdev_region(mz_ioctl_device_no_old, 1);
}
driver_class = NULL;
unregister_chrdev_region(mz_ioctl_device_no, 1);
return rc;
}
#ifdef CONFIG_SEC_KUNIT
void mz_ioctl_exit(void)
#else
static void __exit mz_ioctl_exit(void)
#endif
{
MZ_LOG(err_level_info, "%s mz_ioctl\n", __func__);
device_destroy(driver_class, mz_ioctl_device_no);
class_destroy(driver_class);
driver_class = NULL;
unregister_chrdev_region(mz_ioctl_device_no, 1);
}
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Samsung MZ Driver");
MODULE_VERSION("1.00");
#ifndef CONFIG_SEC_KUNIT
module_init(mz_ioctl_init);
module_exit(mz_ioctl_exit);
#endif /* CONFIG_SEC_KUNIT */