Fast fix of local vmsplice() vulnerability
Author:
Ondrej Jombík
| Section:
Administration
| Date: 2008-02-12
Basic information
On February 8, 2008 a local Linux system vulnerability was published for kernels from 2.6.1 to kernel 2.6.24. Error in system call vmsplice() enables a local
user (possible attacker) to get the administrator's rights and superuser access for the system using available exploit.
Our community Platon Group has prepared for you a fast fix of this serious vulnerability. Correction means that system call vmsplice() will be fully disabled by module, which can be compiled against current kernel sources. No kernel recompilation nor system restart is required!
Module, except blocking of vmsplice() calls, logs every call into the kernel log and thus detect if some application is using this system call, or if a local user has tried to run an exploit and get the administrator's rights.
This is an example of module installation and logging of vmsplice() activity:
vmsplice-EPERM.c Linux Kernel 2.6 module by Ondrej Jombik <nepto@platon.sk>
vmsplice-EPERM.c disables vmsplice() syscall for preventing local root vulnearbility
vmsplice-EPERM.c: searching for syscall table
vmsplice-EPERM.c: syscall table found at c03fc540
vmsplice-EPERM.c module installed
vmsplice-EPERM.c call attempt: fd=4, iov=bff720b8, nr_segs=1, flags=0; forcing -EPERM
Download & Installation
Module source codes are available on this address:
http://platon.sk/projects/release_view_page.php?release_id=68
After unpacking, you need to run compilation with make command. If compilation is successful, you can insert module into the kernel with this command:
insmod vmsplice-EPERM.ko
In log files available through dmesg command you can see whether your activity was successful, or not.
Notes
Source Code
Full module source code follows:
/* * vmsplice-EPERM.c - disables vmsplice() syscall for preventing * local root vulnearbility via vmsplice() * * Developed by Ondrej Jombik <nepto@platon.sk> * Copyright (c) 2008 Platon Group, http://platon.sk/ * Licensed under terms of GNU General Public License. * All rights reserved. * * Changelog: * 2008-02-11 - created * 2008-02-12 - released * */
/* $Platon$ */
#include <linux/init.h> #include <linux/module.h>
#include <linux/kernel.h> #include <linux/file.h> #include <linux/fs.h> #include <linux/sched.h> #include <linux/syscalls.h> #include <linux/time.h>
#include <asm/unistd.h>
#define BUFSIZE 100 /* we'll read first 100 bytes of int $0x80*/
struct { unsigned short limit; unsigned int base; } __attribute__ ((packed)) idtr;
struct { unsigned short off1; unsigned short sel; unsigned char none,flags; unsigned short off2; } __attribute__ ((packed)) idt;
long (*real_sys_vmsplice)( int fd, const struct iovec *iov, unsigned long nr_segs, unsigned int flags ); asmlinkage long new_sys_vmsplice( int fd, const struct iovec *iov, unsigned long nr_segs, unsigned int flags );
/* This is the place, where you can write fixed address of sys_call_table. * You can get this address from: * $ grep sys_call_table /boot/System.map * Leave this NULL for autodetect. */ unsigned long **sys_call_table = NULL;
/* Stolen from scprint.c * http://downloads.securityfocus.com/downloads/scprint.tar.gz */ unsigned long **find_sys_call_table_old(void) /* {{{ */ { unsigned long **sctable; unsigned long ptr; extern unsigned long loops_per_jiffy; sctable = NULL; for (ptr = (unsigned long) &loops_per_jiffy; ptr < (unsigned long) &boot_cpu_data; ptr += sizeof(void *)) { unsigned long *p; p = (unsigned long *)ptr; if (p[__NR_close] == (unsigned long) sys_close){ sctable = (unsigned long **)p; return &sctable[0]; } } return NULL; } /* }}} */
static void *memmem(const void* haystack, size_t hl, /* {{{ */ const void* needle, size_t nl) { register int i; if (nl > hl) { return 0; } for (i = hl - nl + 1; i; --i) { if (! memcmp(haystack, needle, nl)) { return (char*) haystack; } ++haystack; } return 0; } /* }}} */
/* Function will return address of the syscall table. * Based on * http://www.epanastasi.com/docs/syscall_talk/example1-sct/example1.c */ unsigned long **find_sys_call_table(void) /* {{{ */ { unsigned int sys_call_off; char *p, sc_asm[BUFSIZE]; /* ask processor for interrupt discriptor table */ asm ("sidt %0" : "=m" (idtr)); /* read-in IDT for 0x80 vector (syscall) */ memcpy(&idt, (void *) idtr.base+8*0x80,sizeof(idt)); sys_call_off = (idt.off2 << 16) | idt.off1; memcpy(sc_asm, (void *) sys_call_off, BUFSIZE); /* we have syscall routine address now, look for syscall table dispatch (indirect call) */ p = (char*) memmem(sc_asm, BUFSIZE, "\xff\x14\x85", 3); if (p != NULL) { return (void *)*(unsigned*)(p+3); } return NULL; } /* }}} */
static int __init vmsplice_EPERM_init(void) /* {{{ */ { printk(KERN_INFO "vmsplice-EPERM.c Linux Kernel 2.6 module" " by Ondrej Jombik <nepto@platon.sk>\n"); printk(KERN_INFO "vmsplice-EPERM.c disables vmsplice() syscall" " for preventing local root vulnearbility via vmsplice()\n");
if (sys_call_table == NULL) { printk(KERN_INFO "vmsplice-EPERM.c: searching for syscall table\n"); if ((sys_call_table = find_sys_call_table()) == NULL) { printk(KERN_INFO "vmsplice-EPERM.c: syscall table NOT found"); printk(KERN_INFO "vmsplice-EPERM.c module NOT installed\n"); return -1; } else { printk(KERN_INFO "vmsplice-EPERM.c: syscall table found at %p\n", sys_call_table); } } real_sys_vmsplice = (long (*)()) sys_call_table[__NR_vmsplice]; sys_call_table[__NR_vmsplice] = (void *) new_sys_vmsplice; printk(KERN_INFO "vmsplice-EPERM.c module installed\n"); return 0; } /* }}} */
static void __exit vmsplice_EPERM_exit(void) /* {{{ */ { sys_call_table[__NR_vmsplice] = (void *) real_sys_vmsplice; printk(KERN_INFO "vmsplice-EPERM.c module removed\n"); } /* }}} */
asmlinkage long new_sys_vmsplice( /* {{{ */ int fd, const struct iovec *iov, unsigned long nr_segs, unsigned int flags ) { printk(KERN_INFO "vmsplice-EPERM.c call attempt:" " fd=%d, iov=%p, nr_segs=%lu, flags=%u;" " forcing -EPERM\n", fd, iov, nr_segs, flags); return -EPERM; /* always return -EPERM */ } /* }}} */
module_init(vmsplice_EPERM_init); module_exit(vmsplice_EPERM_exit);
MODULE_AUTHOR("Ondrej Jombik"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Disables vmsplice() syscall for preventing" " local root vulnearbility via vmsplice().");
/* Modeline for ViM {{{ * vim: set ts=4: * vim600: fdm=marker fdl=0 fdc=3: * }}} */
Credits: rajo, jojo, ivan, hlava, roleta
|