diff --git a/driver/LKM/Makefile b/driver/LKM/Makefile index 87474964a..941927ec5 100644 --- a/driver/LKM/Makefile +++ b/driver/LKM/Makefile @@ -36,6 +36,12 @@ ifneq ($(IPV6_SUPPORT),) ccflags-y += -D IPV6_SUPPORT endif +UACCESS_FILES := $(shell find -L $(K_I_PATH) -path \*/asm-generic/uaccess.h) /dev/null +UACCESS_SUPPORT := $(shell sh -c "grep -sE define[[:space:]]\+access_ok $(UACCESS_FILES) | grep type") +ifneq ($(UACCESS_SUPPORT),) +ccflags-y += -D UACCESS_TYPE_SUPPORT +endif + TRACE_EVENTS_HEADER := /lib/modules/$(KERNEL_HEAD)/build/include/linux/trace_events.h TRACE_EVENTS_HEADER_V := $(TRACE_EVENTS_HEADER) TRACE_EVENTS_HEADER_CHECK := $(shell test -e $(TRACE_EVENTS_HEADER_V)) diff --git a/driver/LKM/include/util.h b/driver/LKM/include/util.h index 0cd29f4ea..018274177 100644 --- a/driver/LKM/include/util.h +++ b/driver/LKM/include/util.h @@ -226,15 +226,50 @@ static __always_inline long __must_check smith_strnlen_user(const char __user *s return res; } +/* + * WARNING: + * + * access_ok() might sleep as it 's said, but actaully what it does + * is just a comparison between user addr and current's TASK_SIZE_MAX. + */ +static __always_inline int smith_access_ok(const void __user *from, unsigned long n) +{ +#if defined(UACCESS_TYPE_SUPPORT) + return access_ok(VERIFY_READ, from, n); +#else + return access_ok(from, n); +#endif +} + static __always_inline unsigned long __must_check smith_copy_from_user(void *to, const void __user *from, unsigned long n) { unsigned long res; smith_pagefault_disable(); - res = __copy_from_user_inatomic(to, from, n); + /* validate user-mode buffer: ['from' - 'from' + 'n') */ + if (smith_access_ok(from, n)) + res = __copy_from_user_inatomic(to, from, n); + else + res = n; smith_pagefault_enable(); return res; } +/* get_user() will call might_fault(), which violates + the rules of atomic context (introdcued by kprobe) */ +#define smith_get_user(x, ptr) \ +({ \ + unsigned long __val = 0; \ + int __ret; \ + smith_pagefault_disable(); \ + /* validate user-mode buffer: ['from' - 'from' + 'n') */ \ + __ret = sizeof(*(ptr)); \ + if (smith_access_ok(ptr, __ret)) \ + __ret = __copy_from_user_inatomic(&__val, ptr, __ret); \ + smith_pagefault_enable(); \ + (x) = (__typeof__(*(ptr)))__val; \ + __ret; \ +}) + static __always_inline char *smith_d_path(const struct path *path, char *buf, int buflen) { char *name = DEFAULT_RET_STR; @@ -309,20 +344,6 @@ static __always_inline char *smith_get_exe_file(char *buffer, int size) return exe_file_str; } -/* get_user() will call might_fault(), which violates - the rules of atomic context (introdcued by kprobe) */ -#define smith_get_user(x, ptr) \ -({ \ - unsigned long __val = 0; \ - int __ret; \ - smith_pagefault_disable(); \ - __ret = __copy_from_user_inatomic(&__val, ptr, \ - sizeof(*(ptr))); \ - smith_pagefault_enable(); \ - (x) = (__typeof__(*(ptr)))__val; \ - __ret; \ -}) - static inline void *__get_dns_query(unsigned char *data, int index, char *res) { int i; int flag = -1;