Reputation: 53
I am trying to perform a hook to the function 'do_execve()' on Linux kernel using Jprobes, but I'm having issues with certain systems. I tried using this code I found online on an Ubuntu 12, 64 bit (Kernel Version 3.11):
Hook.c:
/* Trace do_execv. Taken basically from Documentation/kprobes.txt */
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/kprobes.h>
#include <linux/kallsyms.h>
/*
* Pre-entry point for do_execve.
*/
static int my_do_execve(char * filename,
char __user *__user *argv,
char __user *__user *envp,
struct pt_regs * regs)
{
printk("do_execve for %s from %s\n", filename, current->comm);
/* Always end with a call to jprobe_return(). */
jprobe_return();
/*NOTREACHED*/
return 0;
}
static struct jprobe my_jprobe = {
.entry = (kprobe_opcode_t *) my_do_execve
};
int init_module(void)
{
int ret;
my_jprobe.kp.addr =
(kprobe_opcode_t *) kallsyms_lookup_name("do_execve");
if (!my_jprobe.kp.addr) {
printk("Couldn't find %s to plant jprobe\n", "do_execve");
return -1;
}
if ((ret = register_jprobe(&my_jprobe)) <0) {
printk("register_jprobe failed, returned %d\n", ret);
return -1;
}
printk("Planted jprobe at %p, handler addr %p\n",
my_jprobe.kp.addr, my_jprobe.entry);
return 0;
}
void cleanup_module(void)
{
unregister_jprobe(&my_jprobe);
printk("jprobe unregistered\n");
}
MODULE_LICENSE("GPL");
Makefile:
# This is taken straight from Documentation/kprobes.txt
obj-m := trace-exec.o
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
default:
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
clean:
rm -f *.mod.c *.ko *.o
The module worked as expected. It was first compiled correctly on the system, and then inserted with the function 'insmod' (with ROOT privileges). Running dmesg shows the correct output:
Planted Jprobes at [ADDRESS HERE], handler addr [ADDRESS HERE]
do_execve for /bin/sh from wcstatusd [PRINTED FOR ANY EXECUTED PROCESS]
The problem occurred when I tried the same code on Ubuntu 14, 64 bit (kernel version 3.13) system. I recompiled it on the system and inserted it just as I did on the previous system, however it didn't work this time. I don't get any errors, and the success message ("Planted jprobe at [ADDRESS WAS HERE], handler addr [ADDRESS WAS HERE]") is printed, but the 'do_execve' line isn't printed. I scanned Google but couldn't find an explanation or a solution. Any ideas?
NOTE: I also tried hooking 'do_fork()' on Ubuntu 14 and it worked! It's just something with 'do_execve()' and I can't figure what!
Upvotes: 2
Views: 751
Reputation: 569
Definition for do_execve() is in exec.c http://lxr.free-electrons.com/source/fs/exec.c?v=3.11#L1584
Here is the code for do_execve(). Just add a line after
int do_execve(struct filename *filename,const char __user *const __user *__argv,const char __user *const __user *__envp)
{
struct user_arg_ptr argv = { .ptr.native = __argv };
struct user_arg_ptr envp = { .ptr.native = __envp };
return do_execveat_common(AT_FDCWD, filename, argv, envp, 0);
}
EXPORT_SYMBOL(do_execve); // Add this line.
This file will be in linux/fs/exec.c. Add the EXPORT_SYMBOL() line after the fuction.And after that do make, make install, and reboot. Its almost like the hooking because we have to build and install the kernel again. Given that you are not intercepting the call by modifying the systemcall address at runtime.
Upvotes: 2