Может ли eBPF изменить возвращаемое значение или параметры системного вызова?

Чтобы смоделировать некоторое поведение, я хотел бы присоединить зонд к системному вызову и изменить возвращаемое значение при передаче определенных параметров. В качестве альтернативы, было бы также достаточно изменить параметры функции, прежде чем они будут обработаны.

Это возможно с БНФ?

4 ответа

Решение

Я считаю, что присоединение eBPF к kprobes/kretprobes дает вам доступ для чтения к аргументам функций и возвращаемым значениям, но вы не можете вмешиваться в них. Я НЕ уверен на 100%; Хорошее место для запроса подтверждения - список рассылки проекта IO Visor или канал IRC (#iovisor на irc.oftc.net).

Как альтернативное решение, я знаю, что вы можете по крайней мере изменить возвращаемое значение системного вызова с помощью strace, с помощью -e вариант. Цитирование справочной страницы:

-e inject=set[:error=errno|:retval=value][:signal=sig][:when=expr]
       Perform syscall tampering for the specified set of syscalls.

Кроме того, на Fosdem 2017 была проведена презентация, посвященная этой проблеме и выявлению неисправностей, если она вас заинтересовала. Вот один пример команды из слайдов:

strace -P precious.txt -efault=unlink:retval=0 unlink precious.txt

Редактировать: Как заявил Бен, eBPF для kprobes и tracepoints предназначен только для чтения, для отслеживания и мониторинга вариантов использования. Я также получил подтверждение об этом на IRC.

В тестах ядра (kprobes) виртуальная машина eBPF имеет доступ только для чтения к параметрам syscall и возвращаемому значению.

Однако программа eBPF будет иметь собственный код возврата. Можно применить профиль seccomp, который перехватывает коды возврата BPF (НЕ eBPF; спасибо @qeole) и прерывает системный вызов во время выполнения.

Разрешенные модификации времени выполнения:

  • SECCOMP_RET_KILL: Убить немедленно SIGSYS
  • SECCOMP_RET_TRAP: Отправь на улов SIGSYS, давая возможность подражать системному вызову
  • SECCOMP_RET_ERRNO: Сила errno значение
  • SECCOMP_RET_TRACE: Принять решение для ptracer или set errno в -ENOSYS
  • SECCOMP_RET_ALLOW: Разрешать

https://www.kernel.org/doc/Documentation/prctl/seccomp_filter.txt

SECCOMP_RET_TRACE Метод позволяет изменить выполняемый системный вызов, аргументы или возвращаемое значение. Это зависит от архитектуры, и изменение обязательных внешних ссылок может вызвать ошибку ENOSYS.

Это достигается передачей выполнения ожидающему пользовательскому пространству ptrace, которое может изменять отслеживаемую память процесса, регистры и файловые дескрипторы.

Трассировщик должен вызвать ptrace и затем waitpid. Пример:

ptrace(PTRACE_SETOPTIONS, tracee_pid, 0, PTRACE_O_TRACESECCOMP);
waitpid(tracee_pid, &status, 0);

http://man7.org/linux/man-pages/man2/ptrace.2.html

когда waitpid возвращается, в зависимости от содержимого statusможно получить возвращаемое значение seccomp, используя PTRACE_GETEVENTMSG операция трассировки. Это восстановит seccomp SECCOMP_RET_DATA значение, которое представляет собой 16-битное поле, установленное программой BPF. Пример:

ptrace(PTRACE_GETEVENTMSG, tracee_pid, 0, &data);

Аргументы системного вызова могут быть изменены в памяти перед продолжением работы. Вы можете выполнить одну запись системного вызова или выйти с PTRACE_SYSCALL шаг. Возвращаемые значения системного вызова могут быть изменены в пространстве пользователя перед возобновлением выполнения; соответствующая программа не сможет увидеть, что возвращаемые значения системного вызова были изменены.

Пример реализации: фильтруйте и изменяйте системные вызовы с помощью seccomp и ptrace

Можно внести ошибки в вызов системного вызова с помощью eBPF: https://lwn.net/Articles/740146/

Вызывается функция bpf, которая может переопределить возвращаемое значение вызова. Это пример использования bcc в качестве интерфейса: https://github.com/iovisor/bcc/blob/master/tools/inject.py

Согласно странице руководства Linux :

доступен только в том случае, если ядро ​​было скомпилировано с вариант конфигурации, и в этом случае он работает только с функциями, отмеченными в коде ядра.

Кроме того, помощник доступен только для архитектур, имеющих вариант. На момент написания этой статьи архитектура x86 - единственная, которая поддерживает эту функцию.

В структуру внедрения ошибок можно добавить функцию. Более подробную информацию можно найти здесь: https://github.com/iovisor/bcc/issues/2485

Можно изменить некоторую память пользовательского пространства с помощью eBPF. Как указано в заголовочном файле bpf.h:

 * int bpf_probe_write_user(void *dst, const void *src, u32 len)
 *  Description
 *      Attempt in a safe way to write *len* bytes from the buffer
 *      *src* to *dst* in memory. It only works for threads that are in
 *      user context, and *dst* must be a valid user space address.
 *
 *      This helper should not be used to implement any kind of
 *      security mechanism because of TOC-TOU attacks, but rather to
 *      debug, divert, and manipulate execution of semi-cooperative
 *      processes.
 *
 *      Keep in mind that this feature is meant for experiments, and it
 *      has a risk of crashing the system and running programs.
 *      Therefore, when an eBPF program using this helper is attached,
 *      a warning including PID and process name is printed to kernel
 *      logs.
 *  Return
 *      0 on success, or a negative error in case of failure.

Также цитата из вопросов и ответов по дизайну БНФ:

Программы отслеживания BPF могут перезаписывать пользовательскую память текущей задачи с помощью bpf_probe_write_user(). Каждый раз при загрузке такой программы ядро ​​будет выводить предупреждающее сообщение, поэтому этот помощник полезен только для экспериментов и прототипов. Программы отслеживания BPF являются только корневыми.

Ваш eBPF может записывать данные в ячейки памяти пользовательского пространства. Обратите внимание, что вы по-прежнему не можете изменять структуры ядра из программы eBPF.

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