⚠️ Важная информация Все материалы, инструкции, команды и скрипты предоставлены исключительно в ознакомительных целях. Их применение может повлиять на работу операционной системы, баз данных и сетевого оборудования. Перед выполнением действий обязательно создайте резервную копию. При отсутствии необходимой квалификации обратитесь к ИТ-специалистам.
BPF: program rejected by verifier (infinite loop / memory access) Linux / DevOps

BPF program rejected by verifier — Ошибки BPF верификатора в Linux

Обновлено: 18.08.2026  ·  Официальная база знаний

Архитектура ошибки и симптомы сбоя

Ошибка «BPF: program rejected by verifier (infinite loop / memory access / R1 invalid mem access)» генерируется встроенным в ядро статическим анализатором безопасности eBPF Verifier при выполнении системного вызова bpf(BPF_PROG_LOAD, ...). Верификатор выполняет доказательство безопасности (Directed Acyclic Graph analysis) и блокирует загрузку программы, если обнаруживает риск бесконечного цикла, выход за границы указателя (Out-of-Bounds Memory Access), разыменование непроверенного NULL-указателя или превышение лимита сложности инструкций (1M instructions).

Диагностическая таблица параметров сбоя

ПараметрЗначениеИнженерный смысл сбоя
eBPF VerifierStatic Code AnalyzerЯдерный верификатор безопасности: гарантирует, что программа никогда не подвесит и не уронит ядро.
R0..R10 RegistersVirtual Register StateОтслеживание типов и диапазонов значений (min/max bounds) регистров процессора eBPF.
Back-edge / LoopInfinite Loop DetectionОбнаружение циклов без доказанного условия завершения за конечное число шагов.

Пошаговое дерево решений и сценарии траблшутинга

Сценарий 1: Просмотр полного лога верификатора (Verifier Log Buffer)

# Запуск программы с выводом отладочного лога верификатора:
# В libbpf задайте размер буфера логов или запустите через bpftrace -v:
sudo bpftrace -v script.bt

# Пример ошибки: 'R2 min value is negative, either use unsigned or 'var &= const''

Сценарий 2: Добавление явных проверок границ памяти (Bounds Checking)

Верификатор требует обязательной проверки смещений перед обращением к массиву или сетевому пакету:

// ОШИБКА: Прямой доступ к памяти пакета
// void *data = (void *)(long)ctx->data;
// char val = *((char *)data + offset);

// ИСПРАВЛЕНИЕ: Явная проверка границ перед чтением
void *data = (void *)(long)ctx->data;
void *data_end = (void *)(long)ctx->data_end;

if ((void *)((char *)data + offset + 1) > data_end) {
    return XDP_DROP; // Проверка пройдена, верификатор спокоен
}
char val = *((char *)data + offset);

Сценарий 3: Исправление циклов через #pragma unroll или ограниченные циклы (Bounded Loops)

Начиная с Linux 5.3 ядро поддерживает циклы, но требует доказуемого конечного счетчика итераций:

// Принудительное разворачивание цикла компилятором:
#pragma unroll
for (int i = 0; i < 16; i++) {
    // Тело цикла
}

// Ограничение переменного цикла для верификатора:
#pragma clang loop unroll(disable)
for (int i = 0; i < 100; i++) {
    if (i >= dynamic_count) break; // Явный break
}

Сценарий 4: Безопасное чтение памяти ядра через bpf_probe_read_kernel

// Безопасное чтение произвольной структуры ядра без падения верификатора:
struct task_struct *task = (struct task_struct *)bpf_get_current_task();
int pid;
bpf_probe_read_kernel(&pid, sizeof(pid), &task->tgid);
Собственные eBPF/XDP микросервисы отклоняются верификатором ядра?
ITSTM проводит аудит eBPF кода, исправление состояний регистров для верификатора и оптимизацию сетевых XDP-драйверов.
Практический опыт инженера: Всегда используйте хелпер bpf_core_read() из фреймворка BPF CO-RE (libbpf) для доступа к полям структур ядра. Это гарантирует автоматическую генерацию безопасного кода чтения, удовлетворяющего верификатор на любых версиях ядра.

Частые вопросы (FAQ)

Почему eBPF верификатор ругается на переменную, хотя в C-коде все корректно?

Компилятор Clang может оптимизировать код так, что связь между проверкой условия (if) и чтением памяти теряется в ассемблерных инструкциях BPF. Для верификатора регистр теряет статус проверенного диапазона (bounds), что приводит к отклонению программы.

Каков максимальный лимит инструкций, проверяемых BPF верификатором?

В современных ядрах Linux верификатор анализирует максимум 1 000 000 состояний инструкций (ранее лимит был 4096). Если программа слишком сложна и разветвлена, верификатор прекратит анализ с ошибкой 'program too complex'.

Что означает ошибка 'R1 invalid mem access 'inv''?

Она означает, что в регистре R1 находится невалидное скалярное значение (invalid pointer), которое программа пытается разыменовать как указатель памяти.

Как функция bpf_tail_call помогает обойти лимиты сложности верификатора?

Механизм хвоcтовых вызовов (Tail Calls) позволяет разбить монолитную сложную BPF программу на серию небольших независимых программ, каждая из которых проходит верификацию отдельно.

Telegram Telegram Max Max Позвонить Позвонить E-mail E-mail