Having trouble wrapping functions in the linux kernel
- by Corey Henderson
I've written a LKM that implements Trusted Path Execution (TPE) into your kernel:
https://github.com/cormander/tpe-lkm
I run into an occasional kernel OOPS (describe at the end of this question) when I define WRAP_SYSCALLS to 1, and am at my wit's end trying to track it down.
A little background:
Since the LSM framework doesn't export its symbols, I had to get creative with how I insert the TPE checking into the running kernel. I wrote a find_symbol_address() function that gives me the address of any function I need, and it works very well. I can call functions like this:
int (*my_printk)(const char *fmt, ...);
my_printk = find_symbol_address("printk");
(*my_printk)("Hello, world!\n");
And it works fine. I use this method to locate the security_file_mmap, security_file_mprotect, and security_bprm_check functions.
I then overwrite those functions with an asm jump to my function to do the TPE check. The problem is, the currently loaded LSM will no longer execute the code for it's hook to that function, because it's been totally hijacked.
Here is an example of what I do:
int tpe_security_bprm_check(struct linux_binprm *bprm) {
int ret = 0;
if (bprm->file) {
ret = tpe_allow_file(bprm->file);
if (IS_ERR(ret))
goto out;
}
#if WRAP_SYSCALLS
stop_my_code(&cs_security_bprm_check);
ret = cs_security_bprm_check.ptr(bprm);
start_my_code(&cs_security_bprm_check);
#endif
out:
return ret;
}
Notice the section between the #if WRAP_SYSCALLS section (it's defined as 0 by default). If set to 1, the LSM's hook is called because I write the original code back over the asm jump and call that function, but I run into an occasional kernel OOPS with an "invalid opcode":
invalid opcode: 0000 [#1] SMP
RIP: 0010:[<ffffffff8117b006>] [<ffffffff8117b006>] security_bprm_check+0x6/0x310
I don't know what the issue is. I've tried several different types of locking methods (see the inside of start/stop_my_code for details) to no avail. To trigger the kernel OOPS, write a simple bash while loop that endlessly starts a backgrounded "ls" command. After a minute or so, it'll happen.
I'm testing this on a RHEL6 kernel, also works on Ubuntu 10.04 LTS (2.6.32 x86_64).
While this method has been the most successful so far, I have tried another method of simply copying the kernel function to a pointer I created with kmalloc but when I try to execute it, I get: kernel tried to execute NX-protected page - exploit attempt? (uid: 0). If anyone can tell me how to kmalloc space and have it marked as executable, that would also help me solve the above problem.
Any help is appreciated!