Jprobe для 'do_execve' в Ubuntu 14 не работает, но работает в Ubuntu 12
Я пытаюсь подключиться к функции do_execve() в ядре Linux, используя Jprobes, но у меня проблемы с некоторыми системами. Я попытался использовать этот код, который я нашел в сети на Ubuntu 12, 64-битная версия (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
Модуль работал как положено. Сначала он был правильно скомпилирован в системе, а затем вставлен с помощью функции "insmod" (с привилегиями ROOT). Запуск dmesg показывает правильный вывод:
Planted Jprobes at [ADDRESS HERE], handler addr [ADDRESS HERE]
do_execve for /bin/sh from wcstatusd [PRINTED FOR ANY EXECUTED PROCESS]
Проблема возникла, когда я попробовал тот же код в Ubuntu 14, 64-битная система (версия ядра 3.13). Я перекомпилировал его в системе и вставил так же, как в предыдущей системе, однако на этот раз он не работал. Я не получаю никаких ошибок, и сообщение об успехе ("Установленный jprobe в [АДРЕС БЫЛ ЗДЕСЬ], обработчик addr [АДРЕС БЫЛ ЗДЕСЬ]") печатается, но строка 'do_execve' не печатается. Я сканировал Google, но не смог найти объяснение или решение. Есть идеи?
ПРИМЕЧАНИЕ: я также попытался подключить do_fork() к Ubuntu 14, и это сработало! Это просто что-то с do_execve(), и я не могу понять, что!
1 ответ
Определение для do_execve() находится в exec.c http://lxr.free-electrons.com/source/fs/exec.c?v=3.11#L1584
Вот код для do_execve(). Просто добавьте строку после
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.
Этот файл будет в linux / fs / exec.c. Добавьте строку EXPORT_SYMBOL() после fuction. И после этого выполните make, make install и перезагрузите компьютер. Это почти как перехват, потому что мы должны снова собрать и установить ядро. Учитывая, что вы не перехватываете вызов путем изменения адреса системного вызова во время выполнения.