commit 4542a65fb6633814f3c4047ed897e8c878bcf2e2 Author: Tom Marshall Date: Fri Aug 24 20:14:59 2018 +0200 Initial implementation diff --git a/Kconfig b/Kconfig new file mode 100644 index 0000000..e305332 --- /dev/null +++ b/Kconfig @@ -0,0 +1,4 @@ +config SYSCALL_OVERRIDE + tristate "Syscall Override" + --help-- + Help messagage for SYSCALL_OVERRIDE diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..7494f8c --- /dev/null +++ b/Makefile @@ -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 diff --git a/syscall_override.c b/syscall_override.c new file mode 100644 index 0000000..b045350 --- /dev/null +++ b/syscall_override.c @@ -0,0 +1,238 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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");