Initial implementation
This commit is contained in:
commit
4542a65fb6
|
@ -0,0 +1,4 @@
|
||||||
|
config SYSCALL_OVERRIDE
|
||||||
|
tristate "Syscall Override"
|
||||||
|
--help--
|
||||||
|
Help messagage for SYSCALL_OVERRIDE
|
|
@ -0,0 +1,14 @@
|
||||||
|
KVER := $(shell uname -r)
|
||||||
|
KSRC := /lib/modules/$(KVER)/build
|
||||||
|
|
||||||
|
export CONFIG_SYSCALL_OVERRIDE = m
|
||||||
|
|
||||||
|
EXTRA_CFLAGS += $(USER_EXTRA_CFLAGS)
|
||||||
|
EXTRA_CFLAGS += -I$(src)/include
|
||||||
|
|
||||||
|
obj-m += syscall_override.o
|
||||||
|
|
||||||
|
all: modules
|
||||||
|
|
||||||
|
modules:
|
||||||
|
$(MAKE) -C $(KSRC) M=$(shell pwd) modules
|
|
@ -0,0 +1,238 @@
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/fs.h>
|
||||||
|
#include <linux/syscalls.h>
|
||||||
|
#include <asm/errno.h>
|
||||||
|
#include <asm/unistd.h>
|
||||||
|
#include <linux/mman.h>
|
||||||
|
#include <asm/proto.h>
|
||||||
|
#include <asm/delay.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/highmem.h>
|
||||||
|
#include <linux/sched.h>
|
||||||
|
|
||||||
|
static asmlinkage long (*real_clock_gettime)(const clockid_t which, struct timespec __user *tp);
|
||||||
|
static asmlinkage time_t (*real_time)(time_t __user *tloc);
|
||||||
|
|
||||||
|
static sys_call_ptr_t *sct;
|
||||||
|
|
||||||
|
static int enable;
|
||||||
|
|
||||||
|
static long offset;
|
||||||
|
|
||||||
|
asmlinkage long
|
||||||
|
patched_clock_gettime(const clockid_t which, struct timespec __user *tp)
|
||||||
|
{
|
||||||
|
long rc;
|
||||||
|
struct timespec kernel_tp;
|
||||||
|
|
||||||
|
rc = (*real_clock_gettime)(which, tp);
|
||||||
|
if (rc != 0)
|
||||||
|
return rc;
|
||||||
|
if (memcmp(current->comm, "pvs", 3) != 0)
|
||||||
|
return rc;
|
||||||
|
if (which != CLOCK_REALTIME && which != CLOCK_REALTIME_COARSE)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
printk("clock_gettime called from pvs\n");
|
||||||
|
if (copy_from_user(tp, &kernel_tp, sizeof(kernel_tp)))
|
||||||
|
return -EFAULT;
|
||||||
|
kernel_tp.tv_sec += offset;
|
||||||
|
if (copy_to_user(tp, &kernel_tp, sizeof(kernel_tp)))
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
asmlinkage time_t
|
||||||
|
patched_time(time_t __user *tloc)
|
||||||
|
{
|
||||||
|
long rc;
|
||||||
|
time_t t;
|
||||||
|
|
||||||
|
rc = (*real_time)(tloc);
|
||||||
|
if (rc == -EFAULT)
|
||||||
|
return rc;
|
||||||
|
if (memcmp(current->comm, "pvs", 3) != 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
printk("time called from pvs\n");
|
||||||
|
if (tloc) {
|
||||||
|
if (copy_from_user(tloc, &t, sizeof(t)))
|
||||||
|
return -EFAULT;
|
||||||
|
t += offset;
|
||||||
|
if (copy_to_user(tloc, &t, sizeof(t)))
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
rc += offset;
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
pte_ro(pte_t *pte)
|
||||||
|
{
|
||||||
|
set_pte_atomic(pte, pte_wrprotect(*pte));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
pte_rw(pte_t *pte)
|
||||||
|
{
|
||||||
|
set_pte_atomic(pte, pte_mkwrite(*pte));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
override_disable(void)
|
||||||
|
{
|
||||||
|
unsigned int level = 0;
|
||||||
|
pte_t *pte;
|
||||||
|
|
||||||
|
pte = lookup_address((unsigned long)sct, &level);
|
||||||
|
pte_rw(pte);
|
||||||
|
sct[__NR_time] = (sys_call_ptr_t)real_time;
|
||||||
|
sct[__NR_clock_gettime] = (sys_call_ptr_t)real_clock_gettime;
|
||||||
|
pte_ro(pte);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
override_enable(void)
|
||||||
|
{
|
||||||
|
unsigned int level = 0;
|
||||||
|
pte_t *pte;
|
||||||
|
|
||||||
|
pte = lookup_address((unsigned long)sct, &level);
|
||||||
|
printk("%s: call pte_rw\n", __func__);
|
||||||
|
pte_rw(pte);
|
||||||
|
printk("%s: modify sct\n", __func__);
|
||||||
|
sct[__NR_clock_gettime] = (sys_call_ptr_t)patched_clock_gettime;
|
||||||
|
sct[__NR_time] = (sys_call_ptr_t)patched_time;
|
||||||
|
printk("%s: call pte_ro\n", __func__);
|
||||||
|
pte_ro(pte);
|
||||||
|
printk("%s: exit\n", __func__);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*** sysfs interface ***/
|
||||||
|
|
||||||
|
static ssize_t
|
||||||
|
enable_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
|
||||||
|
{
|
||||||
|
return sprintf(buf, "%d\n", enable);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t
|
||||||
|
enable_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
int val;
|
||||||
|
|
||||||
|
ret = sscanf(buf, "%d", &val);
|
||||||
|
if (ret != 1)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (val != enable) {
|
||||||
|
switch (val) {
|
||||||
|
case 0:
|
||||||
|
override_disable();
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
override_enable();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
enable = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t
|
||||||
|
offset_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
|
||||||
|
{
|
||||||
|
return sprintf(buf, "%ld\n", offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t
|
||||||
|
offset_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
long val;
|
||||||
|
|
||||||
|
ret = sscanf(buf, "%ld", &val);
|
||||||
|
if (ret != 1)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
offset = val;
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*** init and exit ***/
|
||||||
|
|
||||||
|
static struct kobject *syscalloverride_kobj;
|
||||||
|
|
||||||
|
static struct kobj_attribute enable_attr =
|
||||||
|
__ATTR(enable, 0644, enable_show, enable_store);
|
||||||
|
|
||||||
|
static struct kobj_attribute offset_attr =
|
||||||
|
__ATTR(offset, 0644, offset_show, offset_store);
|
||||||
|
|
||||||
|
static int __init
|
||||||
|
mod_init(void)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
sys_call_ptr_t *sct1;
|
||||||
|
|
||||||
|
printk("Module init\n");
|
||||||
|
ret = 0;
|
||||||
|
sct1 = (sys_call_ptr_t*)kallsyms_lookup_name("sys_call_table");
|
||||||
|
printk("sct1=%p\n", (void*)sct1);
|
||||||
|
real_clock_gettime = (void*)kallsyms_lookup_name("sys_clock_gettime");
|
||||||
|
printk("orig sys_clock_gettime=%p\n", real_clock_gettime);
|
||||||
|
real_time = (void*)kallsyms_lookup_name("sys_time");
|
||||||
|
printk("orig sys_time=%p\n", real_time);
|
||||||
|
|
||||||
|
sct = sct1;
|
||||||
|
|
||||||
|
syscalloverride_kobj = kobject_create_and_add("syscalloverride", kernel_kobj);
|
||||||
|
if (!syscalloverride_kobj) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = sysfs_create_file(syscalloverride_kobj, &enable_attr.attr);
|
||||||
|
if (ret) {
|
||||||
|
pr_err("%s: cannot create sysfs file\n", __func__);
|
||||||
|
goto out_put;
|
||||||
|
}
|
||||||
|
ret = sysfs_create_file(syscalloverride_kobj, &offset_attr.attr);
|
||||||
|
if (ret) {
|
||||||
|
pr_err("%s: cannot create sysfs file\n", __func__);
|
||||||
|
goto out_put;
|
||||||
|
}
|
||||||
|
|
||||||
|
printk("Module init successful\n");
|
||||||
|
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
out_put:
|
||||||
|
kobject_put(syscalloverride_kobj);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __exit
|
||||||
|
mod_exit(void)
|
||||||
|
{
|
||||||
|
printk("Module exit\n");
|
||||||
|
|
||||||
|
if (enable) {
|
||||||
|
override_disable();
|
||||||
|
}
|
||||||
|
|
||||||
|
kobject_put(syscalloverride_kobj);
|
||||||
|
}
|
||||||
|
|
||||||
|
module_init(mod_init);
|
||||||
|
module_exit(mod_exit);
|
||||||
|
MODULE_LICENSE("GPL");
|
Loading…
Reference in New Issue