#include #include #include #include #include #include #include #include #include #include #include // ATTENTION: SEE THE ATTACHED MAKEFILE, IT IS REQUIRED FOR THIS HOTPATCH TO WORK // http://home.powertech.no/oystein/ptpatch2008/ MODULE_AUTHOR("Oystein 'edison@irc' Homelien "); MODULE_DESCRIPTION("Patch a vulnerability without rebooting"); MODULE_LICENSE("GPL"); // credits to mik-@irc for bringing the bug to my attention #define DPRINT printk void **syscalls; static asmlinkage long (*original_sys_vmsplice)(int fd, const struct iovec __user *iov, unsigned long nr_segs, unsigned int flags); asmlinkage long ptpatch2008_sys_vmsplice(int fd, const struct iovec __user *iov, unsigned long nr_segs, unsigned int flags) { printk("ptpatch2008: possible EXPLOIT attempt by uid %d.\n", current->uid); return -EINVAL; }; // credits to the dazuko project static void** dazuko_get_sct(void) { unsigned char **p; #ifdef SYS_CALL_TABLE_ADDR p = (unsigned char **)SYS_CALL_TABLE_ADDR; if (p != NULL) { if (p[__NR_close] == (unsigned char *)sys_close) { return (void **)p; } } #else unsigned long ptr; extern unsigned long loops_per_jiffy; for (ptr=(unsigned long)&loops_per_jiffy ; ptr<(unsigned long)&boot_cpu_data ; ptr+=sizeof(void *)) { p = (unsigned char **)ptr; if (p[__NR_close] == (unsigned char *)sys_close) { return (void **)p; } } #endif return NULL; } static int dazuko_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; } #define DAZUKO_HOOK(syscall_func) do \ { \ original_sys_##syscall_func = syscalls[__NR_##syscall_func]; \ syscalls[__NR_##syscall_func] = ptpatch2008_sys_##syscall_func; \ DPRINT(("hooked sys_" #syscall_func "\n")); \ } \ while (0) #define DAZUKO_UNHOOK(syscall_func) do \ { \ if (syscalls[__NR_##syscall_func] != ptpatch2008_sys_##syscall_func) \ printk("dazuko: " #syscall_func " system call has been changed (system may be left in an unstable state!)\n"); \ syscalls[__NR_##syscall_func] = original_sys_##syscall_func; \ DPRINT(("dazuko: unhooked sys_" #syscall_func "\n")); \ } \ while (0) static int __init ptpatch2008_init(void) { int sc_ro; printk("ptpatch2008: init, (c) 2008 oystein@powertech.no\n"); syscalls = dazuko_get_sct(); if (syscalls == NULL) { printk("ptpatch2008: no sct, bailing out\n"); return -1; }; printk("ptpatch2008: syscalls %p\n", syscalls); if (current == 0) { printk("ptpatch2008: !current\n"); return -1; }; sc_ro = !dazuko_is_address_writable((unsigned long) syscalls); if (sc_ro) { printk("ptpatch2008: syscall table might be readonly\n"); change_page_attr(virt_to_page(syscalls), 1, PAGE_KERNEL); global_flush_tlb(); //return -1; } DAZUKO_HOOK(vmsplice); return 0; }; static void __exit ptpatch2008_exit(void) { printk("ptpatch2008: exit\n"); DAZUKO_UNHOOK(vmsplice); printk("ptpatch2008: done\n"); }; module_init(ptpatch2008_init); module_exit(ptpatch2008_exit);