-
Notifications
You must be signed in to change notification settings - Fork 21
Expand file tree
/
Copy pathsys_call.c
More file actions
211 lines (188 loc) · 6.76 KB
/
sys_call.c
File metadata and controls
211 lines (188 loc) · 6.76 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
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
#include <linux/syscalls.h>
#include "sys_call_table.h"
#include "sys_call.h"
#include "lkm_util.h"
/*original sys calls*/
#ifdef __NR_socketcall
sys_socketcall_func_ptr_t orig_sys_socketcall = (void *)SYS_SOCKETCALL_EA;
sys_send_func_ptr_t orig_sys_send = (void *)SYS_SEND_EA;
sys_recv_func_ptr_t orig_sys_recv = (void *)SYS_RECV_EA;
#endif
sys_connect_func_ptr_t orig_sys_connect = (void *)SYS_CONNECT_EA;
sys_shutdown_func_ptr_t orig_sys_shutdown = (void *)SYS_SHUTDOWN_EA;
sys_close_func_ptr_t orig_sys_close = (void *)SYS_CLOSE_EA;
sys_exit_func_ptr_t orig_sys_exit = (void *)SYS_EXIT_EA;
sys_exit_func_ptr_t orig_sys_exit_group = (void *)SYS_EXIT_GROUP_EA;
sys_write_func_ptr_t orig_sys_write = (void *)SYS_WRITE_EA;
sys_read_func_ptr_t orig_sys_read = (void *)SYS_READ_EA;
sys_sendto_func_ptr_t orig_sys_sendto = (void *)SYS_SENDTO_EA;
sys_recvfrom_func_ptr_t orig_sys_recvfrom = (void *)SYS_RECVFROM_EA;
sys_poll_func_ptr_t orig_sys_poll = (void *)SYS_POLL_EA;
/*new sys calls*/
#ifdef __NR_socketcall
static sys_socketcall_func_ptr_t new_sys_socketcall = connp_sys_socketcall;
#else //__NR_connect and __NR_shutdown
static sys_connect_func_ptr_t new_sys_connect = connp_sys_connect;
static sys_shutdown_func_ptr_t new_sys_shutdown = connp_sys_shutdown;
static sys_sendto_func_ptr_t new_sys_sendto = connp_sys_sendto;
static sys_recvfrom_func_ptr_t new_sys_recvfrom = connp_sys_recvfrom;
#endif
static sys_close_func_ptr_t new_sys_close = connp_sys_close;
static sys_exit_func_ptr_t new_sys_exit = connp_sys_exit;
static sys_exit_func_ptr_t new_sys_exit_group = connp_sys_exit_group;
static sys_write_func_ptr_t new_sys_write = connp_sys_write;
static sys_read_func_ptr_t new_sys_read = connp_sys_read;
static sys_poll_func_ptr_t new_sys_poll = connp_sys_poll;
static int build_syscall_func_table(unsigned long *sys_call_table, int *nr_min, int *nr_max);
static struct syscall_func_struct syscall_func[] = { //initial.
#ifdef __NR_socketcall //usually for 32 bits.
{
.name = "sys_socketcall",
.sym_addr = SYS_SOCKETCALL_EA,
.real_addr = 0,
.nr = -1,
.new_sys_func = (void **)&new_sys_socketcall,
.orig_sys_func = (void**)&orig_sys_socketcall
},
#else
{
.name = "sys_connect",
.sym_addr = SYS_CONNECT_EA,
.real_addr = 0,
.nr = -1,
.new_sys_func = (void **)&new_sys_connect,
.orig_sys_func = (void**)&orig_sys_connect
},
{
.name = "sys_shutdown",
.sym_addr = SYS_SHUTDOWN_EA,
.real_addr = 0,
.nr = -1,
.new_sys_func = (void **)&new_sys_shutdown,
.orig_sys_func = (void **)&orig_sys_shutdown
},
{
.name = "sys_sendto",
.sym_addr = SYS_SENDTO_EA,
.real_addr = 0,
.nr = -1,
.new_sys_func = (void **)&new_sys_sendto,
.orig_sys_func = (void **)&orig_sys_sendto
},
{
.name = "sys_recvfrom",
.sym_addr = SYS_RECVFROM_EA,
.real_addr = 0,
.nr = -1,
.new_sys_func = (void **)&new_sys_recvfrom,
.orig_sys_func = (void **)&orig_sys_recvfrom
},
#endif
{
.name = "sys_close",
.sym_addr = SYS_CLOSE_EA,
.real_addr = (unsigned long)sys_close,
.nr = -1,
.new_sys_func = (void **)&new_sys_close,
.orig_sys_func = (void **)&orig_sys_close
},
{
.name = "sys_exit",
.sym_addr = SYS_EXIT_EA,
.real_addr = 0,
.nr = -1,
.new_sys_func = (void **)&new_sys_exit,
.orig_sys_func = (void **)&orig_sys_exit
},
{
.name = "sys_exit_group",
.sym_addr = SYS_EXIT_GROUP_EA,
.real_addr = 0,
.nr = -1,
.new_sys_func = (void **)&new_sys_exit_group,
.orig_sys_func = (void **)&orig_sys_exit_group
},
{
.name = "sys_write",
.sym_addr = SYS_WRITE_EA,
.real_addr = 0,
.nr = -1,
.new_sys_func = (void **)&new_sys_write,
.orig_sys_func = (void **)&orig_sys_write
},
{
.name = "sys_read",
.sym_addr = SYS_READ_EA,
.real_addr = 0,
.nr = -1,
.new_sys_func = (void **)&new_sys_read,
.orig_sys_func = (void **)&orig_sys_read
},
{
.name = "sys_poll",
.sym_addr = SYS_POLL_EA,
.real_addr = 0,
.nr = -1,
.new_sys_func = (void **)&new_sys_poll,
.orig_sys_func = (void **)&orig_sys_poll
},
{NULL, 0, 0, -1, NULL, NULL} //end tag.
};
static int build_syscall_func_table(unsigned long *sys_call_table, int *nr_min, int *nr_max)
{
struct syscall_func_struct *p;
int i;
for (p = syscall_func; p->name; p++) {
if (p->real_addr && (p->real_addr != p->sym_addr)) {//check symbol map addr.
printk(KERN_ERR "Current kernel is ambiguous!");
return 0;
}
for (i = 0; i < MAX_SYS_CALL_NUM; i++)
if (sys_call_table[i] == p->sym_addr) {//match the symbol map addr.
p->nr = i;
*p->orig_sys_func = (void *)sys_call_table[i]; //reassign.
break;
}
if (i >= MAX_SYS_CALL_NUM) {
printk(KERN_ERR "Can't find the sys call \"%s\", consider enlarging the macro MAX_SYS_CALL_NUM", p->name);
return 0;
}
if (*nr_min > p->nr)
*nr_min = p->nr;
if (*nr_max < p->nr)
*nr_max = p->nr;
}
return 1;
}
/**
*@brief set syscall table.
*@param flag: 0: replace 1: restore
*/
int connp_set_syscall(int flag)
{
struct syscall_func_struct *p;
unsigned long * sys_call_table;
static int sys_call_span_pages, nr_min, nr_max;
*(unsigned long *)&sys_call_table = get_syscall_table_ea();
if (flag & SYSCALL_REPLACE) { //init.
if (!build_syscall_func_table((unsigned long *)sys_call_table,
&nr_min, &nr_max)) {
return 0;
}
sys_call_span_pages = (((unsigned long)&sys_call_table[nr_max] >> PAGE_SHIFT) - ((unsigned long)&sys_call_table[nr_min] >> PAGE_SHIFT)) + 1;
}
preempt_disable();
page_protection_disable((unsigned long)&sys_call_table[nr_min], sys_call_span_pages);
for (p = syscall_func; p->name; p++) {
if (flag & SYSCALL_REPLACE) { //Replace
xchg(&sys_call_table[p->nr], (unsigned long)*p->new_sys_func);
printk(KERN_INFO "Replace %s: nr %d, addr %p", p->name, p->nr, *p->new_sys_func);
} else if (flag & SYSCALL_RESTORE) { //Restore
xchg(&sys_call_table[p->nr], (unsigned long)*p->orig_sys_func);
printk(KERN_INFO "Restore %s: nr %d, addr %p", p->name, p->nr, *p->orig_sys_func);
}
}
page_protection_enable((unsigned long)&sys_call_table[nr_min], sys_call_span_pages);
preempt_enable();
return 1;
}