Life in a shell

bash$ tiagosh

Hijacking kernel functions

When I was developing RNAT I needed to change one kernel function (ip_options_compile), but I didn’t want the users to recompile their kernels. So then I discovered here that it was possible to hijack a kernel function by using a kernel module, and it solved my problem for that moment.

To exemplify the hijacking process, the code below shows how to hijack sys_mkdir() system call, preventing any user from creating a directory.

Don’t forget to change the old_sys_mkdir pointer to your real sys_mkdir() function.

——————- newmkdir.c —————-

#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>

MODULE_LICENSE(“GPL”);

static spinlock_t kern_lock = SPIN_LOCK_UNLOCKED;
unsigned long slock_flags;

#define LOCK_KERN spin_lock_irqsave(&kern_lock, slock_flags)
#define UNLOCK_KERN spin_unlock_irqrestore(&kern_lock, slock_flags)

static unsigned char pr_jump[7]=”\xbf\x00\x00\x00\x00″ /* mov $0,%edi */
“\xff\xe7”; /* jmp *%edi */
static unsigned char pr_save[7];

unsigned char * old_sys_mkdir = (unsigned char *) 0xc01c79d0; /* grep sys_mkdir$ /proc/kallsyms */

/* function prototype from /usr/include/linux/syscalls.h */
asmlinkage long new_sys_mkdir(const char __user *pathname, int mode)
{
printk(“Tried to create: %s, mode: %d\n”, pathname, mode);
/* return Access Denied */
return -EACCES;
}

static int __init new_sys_mkdir_init(void)
{
/* fill pr_jump zero’s with the pointer to our new_sys_mkdir() */
*(long *)&pr_jump[1] = (long)new_sys_mkdir;
LOCK_KERN;

/* replace the inital 7 bytes from the original sys_mkdir() with our jump to  new_sys_mkdir() */
memcpy(pr_save, old_sys_mkdir, 7);
memcpy(old_sys_mkdir, pr_jump, 7);

UNLOCK_KERN;
return 0;
}

static void __exit new_sys_mkdir_exit(void)
{
LOCK_KERN;
/* copy the old initial 7 bytes back */
memcpy(old_sys_mkdir, pr_save, 7);
UNLOCK_KERN;
}

module_init(new_sys_mkdir_init);
module_exit(new_sys_mkdir_exit);

——————– Makefile —————-

obj-m := newmkdir.o

KDIR := /lib/modules/`uname -r`/build
PWD := $(shell pwd)
default:
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

October 7, 2007 - Posted by | general information, RNAT, xnx

3 Comments »

  1. Going to hijack your hijacked function, what do you think about that? Eh???? 😛

    Comment by salvador | October 7, 2007 | Reply

  2. ok I got it somehow, honestly I am not sure how but I patched my install (now running kernel-headers 2.6.24-21 generic) and rebooted, sudo -i, just tried running make and it worked.

    Comment by Annabelle Mcgowan | January 16, 2013 | Reply

    • interesting, I thought this method was not working for newer kernels.

      Comment by tiagosh | January 16, 2013 | Reply


Leave a comment