Может ли 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 или seterrno
в-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.