-
Notifications
You must be signed in to change notification settings - Fork 0
/
driver.c
451 lines (391 loc) · 13.3 KB
/
driver.c
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
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
/*
* A sample, extra-simple block driver. Updated for kernel 2.6.31.
*
* (C) 2003 Eklektix, Inc.
* (C) 2010 Pat Patterson <pat at superpat dot com>
* Redistributable under the terms of the GNU GPL.
*/
/* Protocol family, consistent in both kernel prog and user prog. */
#define MYPROTO NETLINK_USERSOCK
/* Multicast group, consistent in both kernel prog and user prog. */
#define MYGRP 31
#include <linux/delay.h>
#include <linux/netlink.h>
#include <net/net_namespace.h>
#include <net/netlink.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/blkdev.h>
#include <linux/errno.h> /* error codes */
#include <linux/fs.h> /* everything... */
#include <linux/genhd.h>
#include <linux/hdreg.h>
#include <linux/kernel.h> /* printk() */
#include <linux/mm.h>
#include <linux/types.h> /* size_t */
#include <linux/vmalloc.h>
MODULE_LICENSE("Dual BSD/GPL");
static char *Version = "1.4";
static int major_num = 0;
module_param(major_num, int, 0);
static int logical_block_size = 512;
module_param(logical_block_size, int, 0);
static int nsectors = 1024; /* How big the drive is */
module_param(nsectors, int, 0);
static char *server_program_path;
module_param(server_program_path, charp, 0);
static char *activator_program_path;
module_param(activator_program_path, charp, 0);
static char *create_honeypot_program_path;
module_param(create_honeypot_program_path, charp, 0);
/*
* We can tweak our hardware sector size, but the kernel talks to us
* in terms of small sectors, always.
*/
#define KERNEL_SECTOR_SIZE 512
static struct sock *nl_sk = NULL;
/*
* Our request queue.
*/
static struct request_queue *Queue;
static char *terminationStr = "kys";
static int dev_is_ready = 0;
static int currently_clearing = 0;
/*
* The internal representation of our device.
*/
static struct sbd_device {
unsigned long size;
spinlock_t lock;
u8 *data;
struct gendisk *gd;
} Device;
/*
* Handle an I/O request.
*/
static void sbd_transfer(struct sbd_device *dev, sector_t sector,
unsigned long nsect, char *buffer, int write) {
unsigned long offset = sector * logical_block_size;
unsigned long nbytes = nsect * logical_block_size;
if ((offset + nbytes) > dev->size) {
pr_info("CHRISTIANITY DEBUG: sbd: Beyond-end write (%ld %ld)\n", offset,
nbytes);
return;
}
pr_info("CHRISTIANITY DEBUG: pid of current process is %d",
task_pid_nr(current));
pr_info("CHRISTIANITY DEBUG: tgid of current process is %d", current->tgid);
pr_info("CHRISTIANITY DEBUG: ppid of current process is %d",
task_pid_nr(current->real_parent));
pr_info("CHRISTIANITY DEBUG: command of current process is %s",
current->comm);
if (write && !dev_is_ready) {
pr_info("CHRISTIANITY DEBUG: writing to device");
memcpy(dev->data + offset, buffer, nbytes);
} else {
pr_info("CHRISTIANITY DEBUG: reading from device");
memcpy(buffer, dev->data + offset, nbytes);
}
}
static void clear_device_fs_cache(void) {
int return_code;
char *argv[] = {"/bin/bash", "-c",
"/bin/dd of=/dev/sbd0 oflag=nocache conv=notrunc,fdatasync "
"count=0 >> /kernel_test.log",
NULL};
char *envp[] = {"HOME=/", NULL};
return_code = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC);
pr_info("CHRISTIANITY DEBUG: return code of dd was %d", return_code);
}
static void mkfs(void) {
int return_code;
char *argv[] = {"/sbin/mkfs.ext2", "/dev/sbd0", NULL};
char *envp[] = {"HOME=/", NULL};
return_code = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC);
pr_info("CHRISTIANITY DEBUG: return code of mkfs.ext2 was %d", return_code);
}
static void prepare_mount_folder(void) {
int return_code;
char *argv[] = {"/bin/mkdir", "/mnt/ramdisk_test", NULL};
char *envp[] = {"HOME=/", NULL};
return_code = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC);
pr_info("CHRISTIANITY DEBUG: return code of mkdir was %d", return_code);
}
static void mount_dev(void) {
int return_code;
char *argv[] = {"/bin/mount", "-o", "sync", "-t", "ext2", "/dev/sbd0",
"/mnt/ramdisk_test/", NULL};
char *envp[] = {"HOME=/", NULL};
return_code = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC);
pr_info("CHRISTIANITY DEBUG: return code of mount was %d", return_code);
}
static void start_userspace_server(void) {
int return_code;
char *argv[] = {server_program_path, NULL};
char *envp[] = {"HOME=/", NULL};
return_code = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC);
pr_info("CHRISTIANITY DEBUG: return code of start_userspace_server was %d\n",
return_code);
}
static void create_honeypot(void) {
int return_code;
char *argv[] = {create_honeypot_program_path, NULL};
char *envp[] = {"HOME=/", NULL};
return_code = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC);
pr_info("CHRISTIANITY DEBUG: return code of create_honeypot was %d\n",
return_code);
}
static void start_activator(void) {
int return_code;
char *argv[] = {activator_program_path, NULL};
char *envp[] = {"HOME=/", NULL};
return_code = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC);
pr_info("CHRISTIANITY DEBUG: return code of start_activator was %d\n",
return_code);
}
static void send_to_user(char *msg) {
struct sk_buff *skb;
struct nlmsghdr *nlh;
// char *msg = "Hello from kernel";
int msg_size = strlen(msg) + 1;
int res;
pr_info("CHRISTIANITY DEBUG: Creating skb.\n");
skb = nlmsg_new(NLMSG_ALIGN(msg_size + 1), GFP_KERNEL);
if (!skb) {
pr_err("CHRISTIANITY DEBUG: Allocation failure.\n");
return;
}
nlh = nlmsg_put(skb, 0, 1, NLMSG_DONE, msg_size + 1, 0);
strcpy(nlmsg_data(nlh), msg);
pr_info("CHRISTIANITY DEBUG: Preparing to send %s\n", nlmsg_data(nlh));
pr_info("CHRISTIANITY DEBUG: Sending skb.\n");
pr_info("CHRISTIANITY DEBUG: Starting to send skb to server.\n");
res = nlmsg_multicast(nl_sk, skb, 0, MYGRP, GFP_KERNEL);
if (res < 0) {
pr_info("CHRISTIANITY DEBUG: error in nlmsg_multicast(). code: %d\n", res);
return NULL;
} else
pr_info("CHRISTIANITY DEBUG: Successfully sent skb.");
}
static struct sock *conn_serv_multicast_sock(void) {
nl_sk = netlink_kernel_create(&init_net, MYPROTO, NULL);
if (!nl_sk) {
pr_err("CHRISTIANITY DEBUG: Error creating socket.\n");
return NULL;
}
send_to_user("Hello Bosses");
return nl_sk;
}
static void umount_dev(void) {
int return_code;
char *argv[] = {"/bin/umount", "/mnt/ramdisk_test/", NULL};
char *envp[] = {"HOME=/", NULL};
return_code = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC);
pr_info("CHRISTIANITY DEBUG: return code of umount was %d", return_code);
}
static void sync(void) {
int return_code;
char *argv[] = {"/bin/sync", NULL};
char *envp[] = {"HOME=/", NULL};
return_code = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC);
pr_info("CHRISTIANITY DEBUG: return code of sync was %d", return_code);
}
static int check_if_running_from_kernel(void) {
int current_real_parent_pid;
int current_real_grandpa_pid;
struct task_struct *current_real_parent;
struct task_struct *current_real_grandpa;
current_real_grandpa_pid = 0;
current_real_parent = current->real_parent;
current_real_parent_pid = task_pid_nr(current_real_parent);
if (current_real_parent != NULL) {
pr_info("CHRISTIANITY DEBUG: real_parent is not NULL");
current_real_grandpa = current_real_parent->real_parent;
current_real_grandpa_pid = task_pid_nr(current_real_grandpa);
}
pr_info("CHRISTIANITY DEBUG: real_grandpa pid is %d",
current_real_grandpa_pid);
if (current_real_parent_pid == 2 || current_real_grandpa_pid == 2) {
pr_info("CHRISTIANITY DEBUG: called from the kernel");
return 1;
}
pr_info("CHRISTIANITY DEBUG: not called from the kernel");
return 0;
}
static int check_if_clearing(void) {
int return_code;
char command[256];
snprintf(command, 256,
"cat -A /proc/%d/cmdline | grep "
"\"/bin/dd^@of=/dev/"
"sbd0^@oflag=nocache^@conv=notrunc,fdatasync^@count=0\"",
task_pid_nr(current));
// snprintf(command,
// 256,
// "cat -A /proc/%d/cmdline > kernel_test.log",
// task_pid_nr(current));
char *argv[] = {"/bin/bash", "-c", command, NULL};
char *envp[] = {NULL};
return_code = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC);
pr_info("CHRISTIANITY DEBUG: command was %s", command);
pr_info("CHRISTIANITY DEBUG: return code of the clearing test was %d",
return_code);
char new_command[256];
snprintf(
new_command, 256,
"cat -A /proc/%d/cmdline >> kernel_test.log && echo >> kernel_test.log",
task_pid_nr(current));
char *new_argv[] = {"/bin/bash", "-c", new_command, NULL};
char *new_envp[] = {NULL};
call_usermodehelper(new_argv[0], new_argv, new_envp, UMH_WAIT_PROC);
if (!return_code)
pr_info("CHRISTIANITY DEBUG: currently clearing cache");
return return_code;
}
static void drop_caches(void) {
int return_code;
char *argv[] = {"/bin/bash", "-c", "echo 1 > /proc/sys/vm/drop_caches", NULL};
char *envp[] = {"HOME=/", NULL};
return_code = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC);
pr_info("CHRISTIANITY DEBUG: return code of drop_caches was %d", return_code);
}
static void sbd_request(struct request_queue *q) {
struct request *req;
struct block_device *bd;
struct address_space *mapping;
req = blk_fetch_request(q);
while (req != NULL) {
// blk_fs_request() was removed in 2.6.36 - many thanks to
// Christian Paro for the heads up and fix...
// if (!blk_fs_request(req)) {
if (req == NULL || blk_rq_is_passthrough(req)) {
pr_info("CHRISTIANITY DEBUG: Skip non-CMD request\n");
__blk_end_request_all(req, -EIO);
continue;
}
// In case the received request was not bypassing the
// file system, and we want to handle it - check whether or not
// it is read or write.
// if (rq_data_dir(req) == 1) {
// }
sbd_transfer(&Device, blk_rq_pos(req), blk_rq_cur_sectors(req),
bio_data(req->bio), rq_data_dir(req));
int response_code = 0;
if (check_if_running_from_kernel()) {
pr_info("CHRISTIANITY DEBUG: returning success to request");
response_code = 0;
} else {
// TODO - Liron, Should I do this here on at the block of code below..?
int currPID = task_pid_nr(current);
char str[12];
sprintf(str, "%d", currPID);
send_to_user(str);
}
if (!__blk_end_request_cur(req, response_code)) {
req = blk_fetch_request(q);
}
// if (dev_is_ready) {
// drop_caches();
// }
// if(dev_is_ready && !currently_clearing) {
// currently_clearing = 1;
// clear_device_fs_cache();
// currently_clearing = 0;
// }
}
}
/*
* The HDIO_GETGEO ioctl is handled in blkdev_ioctl(), which
* calls this. We need to implement getgeo, since we can't
* use tools such as fdisk to partition the drive otherwise.
*/
int sbd_getgeo(struct block_device *block_device, struct hd_geometry *geo) {
long size;
/* We have no real geometry, of course, so make something up. */
size = Device.size * (logical_block_size / KERNEL_SECTOR_SIZE);
geo->cylinders = (size & ~0x3f) >> 6;
geo->heads = 4;
geo->sectors = 16;
geo->start = 0;
return 0;
}
/*
* The device operations structure.
*/
static struct block_device_operations sbd_ops = {.owner = THIS_MODULE,
.getgeo = sbd_getgeo};
static int __init sbd_init(void) {
start_userspace_server();
msleep(0);
struct sock *sock1 = conn_serv_multicast_sock();
if (!sock1) {
pr_info("CHRISTIANITY DEBUG: Failed to create multicast socket!\n");
} else {
pr_info("CHRISTIANITY DEBUG: Multicast socket created succesfully.\n");
}
create_honeypot();
/*
* Set up our internal device.
*/
Device.size = nsectors * logical_block_size;
spin_lock_init(&Device.lock);
Device.data = vmalloc(Device.size);
if (Device.data == NULL)
return -ENOMEM;
/*
* Get a request queue.
*/
Queue = blk_init_queue(sbd_request, &Device.lock);
if (Queue == NULL)
goto out;
blk_queue_logical_block_size(Queue, logical_block_size);
/*
* Get registered.
*/
major_num = register_blkdev(major_num, "sbd");
pr_info("CHRISTIANITY DEBUG: Registered device succesfully! Major number: %d",
&major_num);
if (major_num < 0) {
pr_info("CHRISTIANITY DEBUG: sbd: unable to get major number\n");
goto out;
}
/*
* And the gendisk structure.
*/
Device.gd = alloc_disk(16);
if (!Device.gd)
goto out_unregister;
Device.gd->major = major_num;
Device.gd->first_minor = 0;
Device.gd->fops = &sbd_ops;
Device.gd->private_data = &Device;
strcpy(Device.gd->disk_name, "sbd0");
set_capacity(Device.gd, nsectors);
Device.gd->queue = Queue;
add_disk(Device.gd);
start_activator();
mkfs();
prepare_mount_folder();
mount_dev();
// sync();
// dev_is_ready = 1;
return 0;
out_unregister:
unregister_blkdev(major_num, "sbd");
out:
vfree(Device.data);
return -ENOMEM;
}
static void __exit sbd_exit(void) {
dev_is_ready = 0;
del_gendisk(Device.gd);
put_disk(Device.gd);
unregister_blkdev(major_num, "sbd");
blk_cleanup_queue(Queue);
vfree(Device.data);
send_to_user(terminationStr);
netlink_kernel_release(nl_sk);
}
module_init(sbd_init);
module_exit(sbd_exit);