LINUX.ORG.RU

eBPF: перехватывать выполнение функций

 , ,


0

2

Читаю про bpf kprobes, вроде как этот механизм позволяет перехватывать системные вызовы, ну и наверное любые другие функции. А вот можно ли с помощью kprobe полностью подменить функцию и, например, сразу возвращать ошибку?

Может быть я не туда смотрю и kprobe не позволяет это делать? Тогда какие есть другие варианты (мне хотелось бы сделать это средствами ebpf)?

★★

перехватывать системные вызовы, ну и наверное любые другие функции.

Интересует перехват «любых других функций» в кернелспейсе? Или это нужно для какого-то процесса, работающего в юзерспейсе?

SZT ★★★★★
()

Конечно же kprobes может перехватывать не любые функции ядра:
https://www.kernel.org/doc/Documentation/kprobes.txt

When a kprobe is registered, Kprobes makes a copy of the probed instruction and replaces the first byte(s) of the probed instruction with a breakpoint instruction (e.g., int3 on i386 and x86_64)

...

Kprobes can probe most of the kernel except itself. This means that there are some functions where kprobes cannot probe. Probing (trapping) such functions can cause a recursive trap (e.g. double fault) or the nested probe handler may never be called. Kprobes manages such functions as a blacklist.

Если int3 поставить в обработчик для int3, будет double fault. Если int3 поставить еще и в обработчик для double fault, будет triple fault, что приведет к выключению компа.

SZT ★★★★★
()
Ответ на: комментарий от SZT

Да, мне нужно перехватывать определенные «ядерные» функции (то есть это множество API конечное).

cruz7 ★★
() автор топика
Ответ на: комментарий от cruz7

Попробовол в действии kprobe и kretprobe, достаточно мощный инструмент. Но я хотел бы немного другое. Предположим следующий фиктивный код выполняемый в ядре:

int my_function()
{
   int err;
   ...
   err = func1();
   if (err)
     goto out;

   ...
   err = func2();
   if (err)
     goto out;

   ...
   err = func3();
   if (err)
     goto out;
   ...

   out:
     cleanup();
   return err;
}

Причем func1(), func2() или func3() могут выполняться и в других частях ядра.

Так вот, я ищу нечто что могло бы в процессе выполнения _только_ my_function() перехватывать выполнение func1()..func(3) по типу того что делает kprobe/kretprobe. То есть в идеале что-то такое:

int my_function()
{
   int err;
   ...
   KPROBE((err = func1()), func_id1);
   if (err)
     goto out;

   ...
   KPROBE((err = func2()), func_id2);
   if (err)
     goto out;

   ...
   KPROBE((err = func3()), func_id3);
   if (err)
     goto out;
   ...

   out:
     cleanup();
   return err;
}

Например через интерфейс /sys/fs/debug/tracing/* или похожее я включаю kprobe для func_id1...func_id3.

Имеется ли что-то рабочее для моих хотелок?

cruz7 ★★
() автор топика
Ответ на: комментарий от cruz7

Так вот, я ищу нечто что могло бы в процессе выполнения _только_ my_function() перехватывать выполнение func1()..func(3)

Почему б в таком случае не перехватывать саму my_function() и вместо нее выполнять my_function_DBG() где вместо func1()..func(3) будет func1_DBG()..func_DBG(3) ?

И вообще, зачем создавать себе сложности, можно ж просто отредактировать исходники ядра и пересобрать

SZT ★★★★★
()
Последнее исправление: SZT (всего исправлений: 1)
Ответ на: комментарий от SZT

Почему б в таком случае не перехватывать саму my_function() и вместо нее выполнять my_function_DBG() где вместо func1()..func(3) будет func1_DBG()..func_DBG(3) ?

То есть вы предлагаете полностью повторить логику кода my_function() в my_function_DBG() ?

И вообще, зачем создавать себе сложности, можно ж просто отредактировать исходники ядра и пересобрать

Ну вот именно этого я и хочу избежать :) Иначе и kprobe/ftrace не нужны, просто трать время и пересобирай себе ядро с добавленными printk :-)

cruz7 ★★
() автор топика
Ответ на: комментарий от cruz7

То есть вы предлагаете полностью повторить логику кода my_function() в my_function_DBG() ?

Как вариант. Можно придумать еще что-нибудь, например есть такая фича в компиляторе GCC: https://gcc.gnu.org/onlinedocs/gcc/Return-Address.html - по адресу возврата можно узнать, из какого места вызывалась та или иная функция (при условии что там ничего не заинлайнилось - When inlining the expected behavior is that the function returns the address of the function that is returned to. To work around this behavior use the noinline function attribute.) и таким образом сделать особенное поведение только для тех вызовов func1()..func(3), которые были произведены из какой-то конкретной функции.

Еще есть Kpatch, kGraft, Ksplice которые тоже могут быть использованы для замены одной функции другой

SZT ★★★★★
()
Последнее исправление: SZT (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.