-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathrkit_helper.h
More file actions
176 lines (143 loc) · 4.99 KB
/
Copy pathrkit_helper.h
File metadata and controls
176 lines (143 loc) · 4.99 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
#ifndef RKIT_HELPER_H
#define RKIT_HELPER_H
#include <linux/kprobes.h>
#include <linux/ftrace.h>
#include <linux/linkage.h>
#include <linux/kprobes.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/module.h>
#include <linux/set_memory.h>
static bool ibt_status = false;
#define HOOK(_func_name, _new_func, _orig_func) \
{ \
.func_name = (_func_name), \
.new_func = (_new_func), \
.orig_func = (_orig_func), \
}
typedef unsigned long (*kallsyms_lookup_name_t)(const char *symbol_name);
typedef struct fhook hook;
static kallsyms_lookup_name_t get_kallsyms_lookup_name(void);
static void notrace ftrace_callback(unsigned long ip, unsigned long parent_ip, struct ftrace_ops *op, struct ftrace_regs *regs);
static int hook_kfunction(hook *hk, unsigned int hk_cnt);
static int unhook_kfunction(struct fhook *hk, unsigned int hk_cnt);
static void ibt_toggle(void);
static bool ibt_is_on(void);
#define FLAG_TRACED (1 << 1)
#define FLAG_FILTERED (1 << 2)
#define MSR_IA_S_CET 0x6a2
#define IBT_BIT_POSITION 2
struct fhook {
const char *func_name;
void *new_func;
void *orig_func;
unsigned long mcount_inst_addr;
int status_flag;
struct ftrace_ops fops;
};
static kallsyms_lookup_name_t get_kallsyms_lookup_name(void)
{
kallsyms_lookup_name_t kallsyms_lookup_name_fptr = NULL;
struct kprobe kp = {
.symbol_name = "kallsyms_lookup_name"
};
if(!register_kprobe(&kp)) {
kallsyms_lookup_name_fptr = (kallsyms_lookup_name_t)kp.addr;
unregister_kprobe(&kp);
}
return kallsyms_lookup_name_fptr;
}
static void notrace ftrace_callback(unsigned long ip, unsigned long parent_ip, struct ftrace_ops *op, struct ftrace_regs *regs)
{
struct fhook *hk = (struct fhook*) container_of(op, struct fhook, fops);
struct pt_regs * _regs;
_regs = (struct pt_regs*)regs;
if(!within_module(parent_ip, THIS_MODULE))
_regs->ip = (unsigned long)hk->new_func;
}
static int hook_kfunction(struct fhook *hk, unsigned int hk_cnt)
{
int error;
kallsyms_lookup_name_t kallsyms_lookup_name;
ibt_status = ibt_is_on();
if(ibt_status)
pr_debug("Detected Indirect Branch Tracking...");
if(ibt_status)
ibt_toggle();
kallsyms_lookup_name = get_kallsyms_lookup_name();
for(int i = 0; i < hk_cnt; i++, hk++) {
/*
* Initially hk->mcount_inst_addr will hold the desired function to be hooked.
* However after instrumentation with ftrace the address would point to the instrumentation code for ftrace.
*/
hk->mcount_inst_addr = kallsyms_lookup_name(hk->func_name);
if(!hk->mcount_inst_addr) {
pr_debug("kallsyms_lookup_name() failed when locating %s function\n", hk->func_name);
return -1;
}
hk->fops.func = ftrace_callback;
hk->fops.flags = FTRACE_OPS_FL_SAVE_REGS | FTRACE_OPS_FL_RECURSION | FTRACE_OPS_FL_IPMODIFY;
if((error = ftrace_set_filter_ip(&hk->fops, hk->mcount_inst_addr, 0, 0))) {
pr_debug("ftrace_set_filter_ip() failed with error code %d for function %s\n", error, hk->func_name);
return -1;
}
hk->status_flag = FLAG_FILTERED;
if((error = register_ftrace_function(&hk->fops))) {
pr_debug("register_ftrace_function failed with error code %d for function %s\n", error, hk->func_name);
return -1;
}
hk->status_flag |= FLAG_TRACED;
pr_debug("%s function hooked\n", hk->func_name);
*((unsigned long*)hk->orig_func) = hk->mcount_inst_addr;
}
return 0;
}
static int unhook_kfunction(struct fhook *hk, unsigned int hk_cnt)
{
int error;
pr_debug("unregistering hooks and removing any filters...");
for(int i = 0; i < hk_cnt; i++, hk++) {
if((hk->status_flag & FLAG_TRACED) && (error = unregister_ftrace_function(&hk->fops))) {
pr_debug("unregister_ftrace_function() failed with error code %d for function %s\n", error, hk->func_name);
return -1;
}
if((hk->status_flag & FLAG_FILTERED) && (error = ftrace_set_filter_ip(&hk->fops, *((unsigned long*)hk->orig_func), 1, 0))) {
pr_debug("ftrace_set_filter_ip() failed with error code %d for function %s\n", error, hk-> func_name);
return -1;
}
pr_debug("%s function unhooked\n", hk->func_name);
}
if(ibt_status)
ibt_toggle();
return 0;
}
static void ibt_toggle(void)
{
u64 msr_value;
asm volatile (
"rdmsr"
: "=A" (msr_value)
: "c" (MSR_IA_S_CET)
);
msr_value ^= (1ULL << IBT_BIT_POSITION);
asm volatile (
"wrmsr"
:
: "c" (MSR_IA_S_CET),
"A" (msr_value)
);
}
static bool ibt_is_on(void)
{
u64 msr_value;
if(boot_cpu_has(X86_FEATURE_IBT)) {
asm volatile (
"rdmsr"
: "=A" (msr_value)
: "c" (MSR_IA_S_CET)
);
return test_bit(IBT_BIT_POSITION, (unsigned long *)&msr_value);
}
return false;
}
#endif