opt
/
kaspersky
/
kav4fs
/
src
/
kernel
/
module.linux
➕ New
📤 Upload
✎ Editing:
interceptor.c
← Back
#include "module.h" #include <linux/sched.h> #include <linux/delay.h> #include <linux/list.h> #include <linux/smp_lock.h> #ifndef LINUX_KERNEL26 extern void* sys_call_table[]; #else void** sys_call_table = (void**)SYSCALL_TABLE_ADDR; #endif #define sys_calls_table sys_call_table static asmlinkage long (*old_sys_open)(const char*, int, int); static asmlinkage int (*old_sys_close)(unsigned int fd); static asmlinkage int (*old_sys_unlink)(const char*); static asmlinkage int (*old_sys_rename)(const char*, const char*); static asmlinkage long new_sys_open(const char* u_file, int flags, int mode); // static asmlinkage int new_sys_close (unsigned int fd); static asmlinkage int new_sys_unlink(const char* u_file); static asmlinkage int new_sys_rename(const char* u_old_file, const char* u_new_file); static atomic_t intercepting = ATOMIC_INIT(0); static atomic_t syscallcount = ATOMIC_INIT(0); static atomic_t release_count = ATOMIC_INIT(0); static atomic_t registered = ATOMIC_INIT(0); #ifdef SYS_CALL_TABLE_READONLY static int is_address_writable(unsigned long address) { pgd_t* pgd = pgd_offset_k(address); #ifdef PUD_SIZE pud_t* pud; #endif pmd_t* pmd; pte_t* pte; if (pgd_none(*pgd)) return -1; #ifdef PUD_SIZE pud = pud_offset(pgd, address); if (pud_none(*pud)) return -1; pmd = pmd_offset(pud, address); #else pmd = pmd_offset(pgd, address); #endif if (pmd_none(*pmd)) return -1; if (pmd_large(*pmd)) pte = (pte_t*)pmd; else pte = pte_offset_kernel(pmd, address); if (!pte || !pte_present(*pte)) return -1; return pte_write(*pte) ? 1 : 0; } int syscalls_rw(int on) { DEBUG_MSG("change mode for syscalls table to %s\n", on ? "on" : "off"); if (!is_address_writable(sys_calls_table)) { DEBUG_MSG("modify permissions for syscalls table"); change_page_attr(virt_to_page(sys_calls_table), 1, PAGE_KERNEL); global_flush_tlb(); if (!is_address_writable(sys_calls_table)) { DEBUG_MSG("Canot modify permissions for syscalls"); return 0; } } return 1; } #endif #define NEW_SYS(call) \ old_sys_##call = sys_calls_table[__NR_##call]; \ sys_calls_table[__NR_##call] = new_sys_##call; #define USE_SYS(call) old_sys_##call = sys_calls_table[__NR_##call]; struct foperations { struct file_operations* fops; int (*release)(struct inode*, struct file*); struct list_head list; }; static LIST_HEAD(fopslist); static DECLARE_MUTEX(fopslock); static int fopskill = 0; #define FMODE_CLOSE 0x8000 static int new_file_release(struct inode* inode, struct file* f) { struct foperations* fpos = NULL; int ret = 0; down(&fopslock); if (fopskill) { up(&fopslock); return 0; } list_for_each_entry(fpos, &fopslist, list) if (fpos->fops == f->f_op) break; up(&fopslock); if (fpos && fpos->release) fpos->release(inode, f); atomic_inc_and_test(&release_count); ret = ((f->f_mode & FMODE_WRITE) && !(f->f_mode & FMODE_CLOSE)) ? kavoas_after_close(f->f_dentry->d_inode, f) : 0; atomic_dec_and_test(&release_count); return ret; } static int fops_add(struct file_operations* fops) { struct foperations* fpos = NULL; int ret = 0; down(&fopslock); if (fopskill) goto fops_out; list_for_each_entry(fpos, &fopslist, list) if (fpos->fops == fops) goto fops_out; if (fops->release == new_file_release) BUG(); fpos = MEM_ALLOC(sizeof(struct file_operations)); if (!fpos) ret = -ENOMEM; else { fpos->release = fops->release; fpos->fops = fops; fpos->fops->release = new_file_release; list_add_tail(&fpos->list, &fopslist); } fops_out: up(&fopslock); return ret; } static void fops_clr(void) { struct foperations *fpos, *ftmp; while (atomic_read( &release_count)) // Wait until all release operations are finished ssleep(1); down(&fopslock); fopskill = 1; list_for_each_entry_safe(fpos, ftmp, &fopslist, list) { if (fpos->fops->release != new_file_release) { printk("nfr %p: str %p: now %p: fop %p\n", new_file_release, fpos->release, fpos->fops->release, fpos->fops); BUG(); } fpos->fops->release = fpos->release; list_del_init(&fpos->list); MEM_FREE(fpos); } up(&fopslock); } int Monitor_intercept_construct(void) { lock_kernel(); #ifdef SYS_CALL_TABLE_READONLY if (!syscalls_rw(1)) { unlock_kernel(); return 1; } #endif open_proc_mounts(); binary_handler_init(); fopskill = 0; NEW_SYS(open); USE_SYS(close); NEW_SYS(unlink); NEW_SYS(rename); #ifdef SYS_CALL_TABLE_READONLY syscalls_rw(0); #endif atomic_xchg(®istered, 1); unlock_kernel(); return 0; } #define OLD_SYS(call) sys_calls_table[__NR_##call] = old_sys_##call; int Monitor_intercept_init(void) { if (!atomic_read(®istered)) if (Monitor_intercept_construct()) return 1; return atomic_inc(&intercepting); } int Monitor_intercept_exit(void) { return atomic_xchg(&intercepting, 0); } int Monitor_intercept_destroy(void) { if (sys_calls_table[__NR_open] != new_sys_open) return 1; // if (sys_calls_table[__NR_close] != new_sys_close) return 1; if (sys_calls_table[__NR_unlink] != new_sys_unlink) return 1; if (sys_calls_table[__NR_rename] != new_sys_rename) return 1; lock_kernel(); #ifdef SYS_CALL_TABLE_READONLY if (!syscalls_rw(1)) { unlock_kernel(); return 1; } #endif atomic_xchg(®istered, 0); OLD_SYS(open); // OLD_SYS(close); OLD_SYS(unlink); OLD_SYS(rename); fops_clr(); #ifdef SYS_CALL_TABLE_READONLY syscalls_rw(0); #endif drop_proc_mounts(); binary_handler_exit(); unlock_kernel(); while (atomic_read(&syscallcount)) ssleep(1); return 0; } int Monitor_intercept_ping(void) { if (!atomic_read(&intercepting)) return 0; lock_kernel(); binary_handler_exit(); binary_handler_init(); unlock_kernel(); return 0; } static inline int dump_syscall(char const* syscall, int fd, struct dentry* dentry, int error) { // return printk("%10s: [%4i] %6u %16s %s = %i\n", syscall, //atomic_read(&syscallcount), // current->pid, current->comm, dentry ? dentry->d_name.name : NULL, error); return 0; } asmlinkage long new_sys_open(const char* u_file, int flags, int mode) { long fd; struct file* f; if (!atomic_read(&intercepting)) { // printk("new_sys_open: Not intercepting %s\n", u_file); return old_sys_open(u_file, flags, mode); } atomic_inc(&syscallcount); fd = old_sys_open(u_file, flags, mode); f = (fd < 0) ? NULL : fget(fd); if (f) { int out = dump_syscall("pre_open", fd, f->f_dentry, 0); int err = kavoas_before_open(f->f_dentry->d_inode, f); if (out) dump_syscall("sys_open", fd, f->f_dentry, err); if (f->f_op && f->f_op->release != new_file_release) fops_add(f->f_op); if (err) f->f_mode |= FMODE_CLOSE; fput(f); if (err) { old_sys_close(fd); fd = err; } } else { int out = dump_syscall("non_open", fd, NULL, 0); } return (atomic_dec(&syscallcount), fd); } asmlinkage int new_sys_unlink(const char* u_file) { struct nameidata nd; int err; int ret = 0; if (!atomic_read(&intercepting)) { // printk("new_sys_unlink: not_intercepting file %s\n", u_file); return old_sys_unlink(u_file); } err = (atomic_inc(&syscallcount), user_path_walk_link(u_file, &nd)); if (!err) { int out = dump_syscall("pre_unlink", 0, nd.dentry, 0); kavoas_unlink(nd.dentry->d_parent->d_inode, nd.dentry); if (out) dump_syscall("sys_unlink", 0, nd.dentry, err); path_release(&nd); } else { int out = dump_syscall("non_unlink", 0, NULL, ret); } ret = old_sys_unlink(u_file); return (atomic_dec_and_test(&syscallcount), ret); } asmlinkage int new_sys_rename(const char* u_old_file, const char* u_new_file) { struct nameidata old_nd, new_nd; int err_o; int err_n; int ret = 0; if (!atomic_read(&intercepting)) { // printk("new_sys_rename: not_intercepting %s\n", u_old_file); return old_sys_rename(u_old_file, u_new_file); } err_o = (atomic_inc_and_test(&syscallcount), user_path_walk_link(u_old_file, &old_nd)); err_n = err_o ? err_o : __user_walk(u_new_file, 0, &new_nd); if (!err_n) { int out = dump_syscall("pre_rename", 0, old_nd.dentry, err_o); kavoas_rename(old_nd.dentry->d_parent->d_inode, old_nd.dentry, new_nd.dentry->d_parent->d_inode, new_nd.dentry); if (out) dump_syscall("sys_rename", 0, new_nd.dentry, err_n); path_release(&new_nd); } else { int out = dump_syscall("non_rename", 0, NULL, ret); } if (!err_o) path_release(&old_nd); ret = old_sys_rename(u_old_file, u_new_file); return (atomic_dec_and_test(&syscallcount), ret); } int kavoas_ulib(struct file* file) { int out; int err; if (!atomic_read(&intercepting)) { // printk("kavoas_ulib: not intercepting\n"); dump_syscall("sys_execve", 0, file->f_dentry, 0); return -ENOEXEC; } out = (atomic_inc(&syscallcount), dump_syscall("pre_execve", 0, file->f_dentry, 0)); err = kavoas_before_open(file->f_dentry->d_inode, file); if (out) dump_syscall("sys_execve", 0, file->f_dentry, err); return (atomic_dec(&syscallcount), (err ? err : -ENOEXEC)); } int kavoas_exec(struct file* file) { return kavoas_ulib(file); }
💾 Save Changes
Cancel
📤 Upload File
×
Select File
Upload
Cancel
➕ Create New
×
Type
📄 File
📁 Folder
Name
Create
Cancel
✎ Rename Item
×
Current Name
New Name
Rename
Cancel
🔐 Change Permissions
×
Target File
Permission (e.g., 0755, 0644)
0755
0644
0777
Apply
Cancel