jprobe do_execve не работает с ядром 4.1

Я хочу установить хук jprobe на do_execve, чтобы перехватывать каждую исполняемую программу.

Мой код работает на <= 3.2 ядре Linux (Debian). Это мой вывод о ядре Linux 3.2:

[  628.534037] registered: do_execve, ret: 0
[  723.995797] execve: /usr/bin/vi
[  726.807025] execve: /bin/dmesg

на ядре 4.1 у меня тот же результат (все прописано) но нет "execve":

[ 8621.430568] registered: do_execve, ret: 0

И это мой код:

static struct jprobe jprobe_hooks[] = {
{
    .entry = jdo_execve,
    .kp = { .symbol_name = "do_execve" }
}};

static long jdo_execve(const char *filename, const char __user *const __user *argv, const char __user *const __user *envp, struct pt_regs *regs)
{
   printk(KERN_INFO "execve: %s", filename );
}

// 
// registration
//
int ret, x, reg_error;

reg_error = 0;
for (x = 0; x < sizeof(jprobe_hooks) / sizeof(jprobe_hooks[0]); x++)
{
    ret = register_jprobe(&jprobe_hooks[x]);
    if (ret < 0)
    {
        printk(KERN_INFO "register_jprobe failed, returned %d, item: %s\n", ret, jprobe_hooks[x].kp.symbol_name);
        reg_error++;
    }
    else
    {
        printk(KERN_INFO "registered: %s, ret: %u\n", jprobe_hooks[x].kp.symbol_name, ret);
    }
}

Когда я делаю grep на kallsyms, я получаю 3.2:

 grep do_execv /proc/kallsyms
 ffffffff81100650 T do_execve

и на 4.2:

grep do_execv /proc/kallsyms
ffffffff811d2950 T do_execve
ffffffff811d2980 T do_execveat

Я даже пытался изменить функцию (потому что прототип do_execve изменился) на это:

static int jdo_execve(struct filename *fname, const char __user *const __user *__argv, const char __user *const __user *__envp)
{
    int i = 0;

    printk(KERN_INFO "execve: %s ", fname->name );
}

и даже это не помогло.

Я могу установить хуки на другие функции, такие как do_fork или sys_open, но не на do_execve. Зачем? У кого-нибудь есть идеи? Почему это больше не работает?

Редактировать:

Я также подключаю do_execveat:

 static int jdo_execveat(int fd, struct filename *fname, const char __user *const __user *__argv, const char __user *const __user *__envp, int flags)

1 ответ

Есть несколько проблем, которые могут помешать вам сообщения jprobe:

  1. Вы не заканчиваете печатные сообщения printk(KERN_INFO "execve: %s", filename ); с новой строкой, таким образом, ваш буфер журнала не очищается.
  2. API изменился. Сейчас do_execve имеет параметр имени файла как struct filename,
  3. Ваш код jprobe глуп: у вас нет входа в модуль, процедура jprobe должна заканчиваться на jprobe_return() звони и тд. Посмотрите примеры в дереве исходного кода ядра в "samples/kprobes"

Попробуйте это исправить - возможно, это поможет.

Во всяком случае, я попробовал это сам - вот код - и все, действительно, выглядит странно. Когда я загружаю модуль, он регистрирует 2 jprobes - один для do_execve, другой для do_execveat. Но я не вижу сообщений при выполнении программ. НО я вижу периодические сообщения, подобные этому:

jprobe: execve: /usr/lib/systemd/systemd-cgroups-agent

Это означает, что сам jprobe работает, но не для каждого execve вызов.

Поэтому я написал простую C-программу для вызова execve просто чтобы быть уверенным, что он действительно называется, а у меня все еще ничего не происходит, за исключением systemd-cgroups-agent.

Другие вопросы по тегам