From e560158cbcdc0c395276a70706510f5c6ee4d78a Mon Sep 17 00:00:00 2001 From: zy Date: Mon, 27 Nov 2023 20:34:06 -0500 Subject: [PATCH] reinit --- rootkit.pty | 1 - source/module/monitor_kernel.c | 3 +- source/module/monitor_kernel_lib.c | 4 +- source/module/monitor_timer.h | 4 +- source/uapi/monitor_user.c | 4 +- source/uapi/monitor_user.h | 4 +- source/uapi/monitor_user_sw.h | 130 +++++++---------------------- source/ucli/ucli | Bin 1257064 -> 0 bytes testcase/helloworld.c | 62 ++++++-------- testcase/hptest.c | 2 +- 10 files changed, 65 insertions(+), 149 deletions(-) delete mode 120000 rootkit.pty delete mode 100755 source/ucli/ucli diff --git a/rootkit.pty b/rootkit.pty deleted file mode 120000 index 64fe38d..0000000 --- a/rootkit.pty +++ /dev/null @@ -1 +0,0 @@ -/dev/pts/6 \ No newline at end of file diff --git a/source/module/monitor_kernel.c b/source/module/monitor_kernel.c index 2e6e35c..23648ab 100644 --- a/source/module/monitor_kernel.c +++ b/source/module/monitor_kernel.c @@ -10,6 +10,7 @@ #define DEVICE_NAME "variable_monitor" +//!todo check name // for character device static dev_t dev_num; static struct cdev *watch_cdev; @@ -56,7 +57,7 @@ static long device_ioctl(struct file *file, unsigned int ioctl_num, printk(KERN_INFO "variable_monitor fun: %s with ioctl_num %d\n", __FUNCTION__, ioctl_num); - + //!todo check style switch (ioctl_num) { case 0: // copy watch_arg diff --git a/source/module/monitor_kernel_lib.c b/source/module/monitor_kernel_lib.c index 2d12ef6..554bc4d 100644 --- a/source/module/monitor_kernel_lib.c +++ b/source/module/monitor_kernel_lib.c @@ -28,7 +28,7 @@ static unsigned char w_arg2k_w_arg(void *kptr, watch_arg warg, k_watch_arg->kptr = kptr; k_watch_arg->length_byte = warg.length_byte; k_watch_arg->threshold = warg.threshold; - k_watch_arg->unsigned_flag = warg.unsigned_flag; + k_watch_arg->is_unsigned = warg.is_unsigned; k_watch_arg->above_threshold = warg.above_threshold; return 0; } @@ -297,7 +297,7 @@ enum hrtimer_restart check_variable_cb(struct hrtimer *timer) { for (i = 0; i < k_watch_timer->sentinel; i++) { kwarg = &k_watch_timer->k_watch_args[i]; if (read_and_compare(kwarg->kptr, kwarg->length_byte, kwarg->above_threshold, - kwarg->unsigned_flag, kwarg->threshold)) { + kwarg->is_unsigned, kwarg->threshold)) { k_watch_timer->threshold_buffer[j] = i; j++; } diff --git a/source/module/monitor_timer.h b/source/module/monitor_timer.h index 3db413e..1bdab9f 100644 --- a/source/module/monitor_timer.h +++ b/source/module/monitor_timer.h @@ -11,7 +11,7 @@ typedef struct { void *ptr; // virtual address int length_byte; // byte long long threshold; // threshold value - unsigned char unsigned_flag; // unsigned flag (true: unsigned, false: signed) + unsigned char is_unsigned; // unsigned flag (true: unsigned, false: signed) unsigned char above_threshold; // reverse flag (true: >, false: <) unsigned long time_ns; // timer interval (ns) } watch_arg; @@ -23,7 +23,7 @@ typedef struct { void *kptr; // kernel address + offset int length_byte; // byte long long threshold; // threshold value - unsigned char unsigned_flag; // unsigned flag (true: unsigned, false: signed) + unsigned char is_unsigned; // unsigned flag (true: unsigned, false: signed) unsigned char above_threshold; // reverse flag (true: >, false: <) } kernel_watch_arg; diff --git a/source/uapi/monitor_user.c b/source/uapi/monitor_user.c index 1a90008..be78e5a 100644 --- a/source/uapi/monitor_user.c +++ b/source/uapi/monitor_user.c @@ -45,14 +45,14 @@ int cancel_watch() { void init_watch_arg(watch_arg *wg, char *name, void *ptr, int length_byte, long long threshold, - unsigned char unsigned_flag, + unsigned char is_unsigned, unsigned char above_threshold, unsigned long time_ns){ wg->task_id = getpid(); strncpy(wg->name, name, (MAX_NAME_LEN + 1)); wg->ptr = ptr; wg->length_byte = length_byte; wg->threshold = threshold; - wg->unsigned_flag = unsigned_flag; + wg->is_unsigned = is_unsigned; wg->above_threshold = above_threshold; wg->time_ns = time_ns; } diff --git a/source/uapi/monitor_user.h b/source/uapi/monitor_user.h index 257217f..fb648d4 100644 --- a/source/uapi/monitor_user.h +++ b/source/uapi/monitor_user.h @@ -14,13 +14,13 @@ typedef struct { void *ptr; // virtual address int length_byte; // byte long long threshold; // threshold value - unsigned char unsigned_flag; // unsigned flag (true: unsigned, false: signed) + unsigned char is_unsigned; // unsigned flag (true: unsigned, false: signed) unsigned char above_threshold; // reverse flag (true: >, false: <) unsigned long time_ns; // timer interval (ns) } watch_arg; void init_watch_arg(watch_arg *wg, char *name, void *ptr, int length_byte, - long long threshold, unsigned char unsigned_flag, + long long threshold, unsigned char is_unsigned, unsigned char above_threshold, unsigned long time_ns); // start watch diff --git a/source/uapi/monitor_user_sw.h b/source/uapi/monitor_user_sw.h index 15c19e5..9e12e71 100644 --- a/source/uapi/monitor_user_sw.h +++ b/source/uapi/monitor_user_sw.h @@ -1,164 +1,94 @@ #ifndef UAPI_MONITOR_SW_H #define UAPI_MONITOR_SW_H +//!todo SWATCH_CHAR #define SWATCH_CHAR(name, ptr, threshold) \ do { \ - watch_arg w_arg; \ - w_arg.task_id = getpid(); \ - strncpy(w_arg.name, name, MAX_NAME_LEN); \ - w_arg.ptr = ptr; \ - w_arg.length_byte = sizeof(char); \ - w_arg.threshold = threshold; \ - w_arg.unsigned_flag = 0; \ - w_arg.above_threshold = 0; \ - w_arg.time_ns = 0; \ + watch_arg w_arg = {0}; \ + init_watch_arg(&w_arg, name, ptr, sizeof(char), threshold, 0, 1, 0); \ start_watch(w_arg); \ } while (0) #define SWATCH_CHAR_LESS(name, ptr, threshold) \ do { \ - watch_arg w_arg; \ - w_arg.task_id = getpid(); \ - strncpy(w_arg.name, name, MAX_NAME_LEN); \ - w_arg.ptr = ptr; \ - w_arg.length_byte = sizeof(char); \ - w_arg.threshold = threshold; \ - w_arg.unsigned_flag = 0; \ - w_arg.above_threshold = 1; \ - w_arg.time_ns = 0; \ + watch_arg w_arg = {0}; \ + init_watch_arg(&w_arg, name, ptr, sizeof(char), threshold, 0, 0, 0); \ start_watch(w_arg); \ } while (0) #define SWATCH_UCHAR(name, ptr, threshold) \ do { \ - watch_arg w_arg; \ - w_arg.task_id = getpid(); \ - strncpy(w_arg.name, name, MAX_NAME_LEN); \ - w_arg.ptr = ptr; \ - w_arg.length_byte = sizeof(unsigned char); \ - w_arg.threshold = threshold; \ - w_arg.unsigned_flag = 1; \ - w_arg.above_threshold = 0; \ - w_arg.time_ns = 0; \ + watch_arg w_arg = {0}; \ + init_watch_arg(&w_arg, name, ptr, sizeof(unsigned char), threshold, 1, 1, \ + 0); \ start_watch(w_arg); \ } while (0) #define SWATCH_UCHAR_LESS(name, ptr, threshold) \ do { \ - watch_arg w_arg; \ - w_arg.task_id = getpid(); \ - strncpy(w_arg.name, name, MAX_NAME_LEN); \ - w_arg.ptr = ptr; \ - w_arg.length_byte = sizeof(unsigned char); \ - w_arg.threshold = threshold; \ - w_arg.unsigned_flag = 1; \ - w_arg.above_threshold = 1; \ - w_arg.time_ns = 0; \ + watch_arg w_arg = {0}; \ + init_watch_arg(&w_arg, name, ptr, sizeof(unsigned char), threshold, 1, 0, \ + 0); \ start_watch(w_arg); \ } while (0) #define SWATCH_INT(name, ptr, threshold) \ do { \ watch_arg w_arg = {0}; \ - init_watch_arg(&w_arg, name, ptr, sizeof(int), threshold, 0, 1, 0); \ + init_watch_arg(&w_arg, name, ptr, sizeof(int), threshold, 0, 1, 0); \ start_watch(w_arg); \ } while (0) #define SWATCH_INT_LESS(name, ptr, threshold) \ do { \ - watch_arg w_arg; \ - w_arg.task_id = getpid(); \ - strncpy(w_arg.name, name, MAX_NAME_LEN); \ - w_arg.ptr = ptr; \ - w_arg.length_byte = sizeof(int); \ - w_arg.threshold = threshold; \ - w_arg.unsigned_flag = 0; \ - w_arg.above_threshold = 1; \ - w_arg.time_ns = 0; \ + watch_arg w_arg = {0}; \ + init_watch_arg(&w_arg, name, ptr, sizeof(int), threshold, 0, 0, 0); \ start_watch(w_arg); \ } while (0) #define SWATCH_UINT(name, ptr, threshold) \ do { \ - watch_arg w_arg; \ - w_arg.task_id = getpid(); \ - strncpy(w_arg.name, name, MAX_NAME_LEN); \ - w_arg.ptr = ptr; \ - w_arg.length_byte = sizeof(unsigned int); \ - w_arg.threshold = threshold; \ - w_arg.unsigned_flag = 1; \ - w_arg.above_threshold = 0; \ - w_arg.time_ns = 0; \ + watch_arg w_arg = {0}; \ + init_watch_arg(&w_arg, name, ptr, sizeof(unsigned int), threshold, 1, 1, \ + 0); \ start_watch(w_arg); \ } while (0) #define SWATCH_UINT_LESS(name, ptr, threshold) \ do { \ - watch_arg w_arg; \ - w_arg.task_id = getpid(); \ - strncpy(w_arg.name, name, MAX_NAME_LEN); \ - w_arg.ptr = ptr; \ - w_arg.length_byte = sizeof(unsigned int); \ - w_arg.threshold = threshold; \ - w_arg.unsigned_flag = 1; \ - w_arg.above_threshold = 1; \ - w_arg.time_ns = 0; \ + watch_arg w_arg = {0}; \ + init_watch_arg(&w_arg, name, ptr, sizeof(unsigned int), threshold, 1, 0, \ + 0); \ start_watch(w_arg); \ } while (0) #define SWATCH_LONG(name, ptr, threshold) \ do { \ - watch_arg w_arg; \ - w_arg.task_id = getpid(); \ - strncpy(w_arg.name, name, MAX_NAME_LEN); \ - w_arg.ptr = ptr; \ - w_arg.length_byte = sizeof(long); \ - w_arg.threshold = threshold; \ - w_arg.unsigned_flag = 0; \ - w_arg.above_threshold = 0; \ - w_arg.time_ns = 0; \ + watch_arg w_arg = {0}; \ + init_watch_arg(&w_arg, name, ptr, sizeof(long), threshold, 0, 1, 0); \ start_watch(w_arg); \ } while (0) #define SWATCH_LONG_LESS(name, ptr, threshold) \ do { \ - watch_arg w_arg; \ - w_arg.task_id = getpid(); \ - strncpy(w_arg.name, name, MAX_NAME_LEN); \ - w_arg.ptr = ptr; \ - w_arg.length_byte = sizeof(long); \ - w_arg.threshold = threshold; \ - w_arg.unsigned_flag = 0; \ - w_arg.above_threshold = 1; \ - w_arg.time_ns = 0; \ + watch_arg w_arg = {0}; \ + init_watch_arg(&w_arg, name, ptr, sizeof(long), threshold, 0, 0, 0); \ start_watch(w_arg); \ } while (0) #define SWATCH_ULONG(name, ptr, threshold) \ do { \ - watch_arg w_arg; \ - w_arg.task_id = getpid(); \ - strncpy(w_arg.name, name, MAX_NAME_LEN); \ - w_arg.ptr = ptr; \ - w_arg.length_byte = sizeof(unsigned long); \ - w_arg.threshold = threshold; \ - w_arg.unsigned_flag = 1; \ - w_arg.above_threshold = 0; \ - w_arg.time_ns = 0; \ + watch_arg w_arg = {0}; \ + init_watch_arg(&w_arg, name, ptr, sizeof(unsigned long), threshold, 1, 1, \ + 0); \ start_watch(w_arg); \ } while (0) #define SWATCH_ULONG_LESS(name, ptr, threshold) \ do { \ - watch_arg w_arg; \ - w_arg.task_id = getpid(); \ - strncpy(w_arg.name, name, MAX_NAME_LEN); \ - w_arg.ptr = ptr; \ - w_arg.length_byte = sizeof(unsigned long); \ - w_arg.threshold = threshold; \ - w_arg.unsigned_flag = 1; \ - w_arg.above_threshold = 1; \ - w_arg.time_ns = 0; \ + watch_arg w_arg = {0}; \ + init_watch_arg(&w_arg, name, ptr, sizeof(unsigned long), threshold, 1, 0, \ + 0); \ start_watch(w_arg); \ } while (0) diff --git a/source/ucli/ucli b/source/ucli/ucli deleted file mode 100755 index 03b867de89fba171123214975daf7875f2276db4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1257064 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