
Основанный на eBPF LSM мандатный контроль доступа и изолятор
Мандатный контроль доступа для Linux на основе eBPF.
Этот проект представляет собой полную переработку закрытого исходного кода BpfJailer и является полностью экспериментальным. Он использует новые возможности, такие как bpf arena, которые были недоступны при написании внутренней версии BpfJailer. Ожидаются проблемы, и они не подлежат вознаграждению за обнаружение уязвимостей и не считаются находками в области безопасности. После надлежащей оценки он заменит внутреннюю закрытую версию.
BpfJailer использует программы eBPF LSM для помещения процессов в изолированные среды, называемые подами (pods), каждый из которых привязан к роли из политики TOML. Под наследуется через fork и exec. Дополнительные возможности политики:
kill и ptrace — целевые роли/поды, которым можно отправлять сигналы или к которым можно подключаться.bpf — карты и программы eBPF каких ролей может открывать роль, или может ли она вообще вызывать bpf(2).keyring — в какие keyring'и fs-verity каких ролей роль может добавлять сертификаты, или может ли она вообще записывать в keyring'и.Отказы и события жизненного цикла записываются в закреплённые (pinned) кольцевые буферы. bpfjlog выводит человекочитаемую диагностику BPF и структурированные события и отслеживает кольцевые буферы при замене политики на лету.
Бинарный файл может заявить роль через xattr user.bpfj.policy.exec и зачисляется в неё во время exec. Запущенные процессы также могут быть зачислены напрямую, а непривилегированный процесс может зачислить себя через bpfjsrv/bpfjclient.
| Каталог | Бинарный файл | Назначение |
|---|---|---|
bpfj/ | Основная библиотека и программы BPF: jailer, enforcers, парсер политики, C++-хелперы libbpf. | |
ctl/ | bpfjctl | Универсальный инструмент для подключения, перезагрузки, инспектирования и отключения jailer'а, а также для зачисления процессов. |
cmd/ | bpfjcmd | bpfjctl со встроенными аргументами и, опционально, политикой. Он игнорирует argv, поэтому может быть статически слинкован и подписан через fs-verity как единое целое. |
srv/ | bpfjsrv | Активируемый через сокет сервер, который зачисляет непривилегированных вызывающих в роли, которые это разрешают. |
client/ | bpfjclient | Минимальный клиент для bpfjsrv, без зависимостей от libbpf или BPF-тулчейна. |
log/ | bpfjlog | Потребитель закреплённых кольцевых буферов диагностики и структурированных событий. |
tests/ | bpfjtest | Набор тестов. |
CONFIG_BPF_LSM=y и bpf в загрузочном параметре lsm=). BpfJailer тестируется только на 6.16+, более старые ядра не поддерживаются.bpftool и компилятор C++20.openssl, fsverity и setfattr, а также статические архивы, перечисленные в Makefile (STATIC=1).Задайте LIBBPF_CFLAGS / LIBBPF_LIBS, если pkg-config не может найти libbpf. Указывайте LIBARENA на копию репозитория libarena при каждой сборке:
Каждый make ниже также требует LIBARENA (см. Требования), заданный в командной строке или экспортированный в окружении.
make # build/bpfjctl
make STATIC=1 # bpfjctl без зависимостей от разделяемых объектов
make client # build/bpfjclient, BPF-тулчейн не нужен
make log # build/bpfjlog
make signing-key # generate a development signing key and certificate
make signed SIGNING_KEY=... SIGNING_CERT=... # static, fs-verity signed bpfjctl
make srv SIGNING_KEY=... SIGNING_CERT=... # static, signed bpfjsrv
make cmd SIGNING_KEY=... SIGNING_CERT=... \
CMD_ARGS="replace-compiled" CMD_POLICY=policy.toml CMD_ROLE=bpfjailer
make clean
Весь вывод помещается в build/. Задайте BUILD=, чтобы собирать в другом месте, например make BUILD=build-asan SANITIZE=address,undefined.
make test
Тесты должны запускаться от root, поскольку каждый из них создаёт пространство имён монтирования и монтирует bpffs. make test собирает от имени вызывающего пользователя и запускает только тестовый бинарный файл под sudo.
По умолчанию тесты выполняются последовательно, поскольку одновременное отсоединение BPF LSM может вызвать панику на затронутых ядрах. Используйте make test TEST_ARGS=Suite.Test для конкретного случая и включайте -j N или BPFJTEST_JOBS=N только внутри одноразовой виртуальной машины.
sudo bpfjctl check policy.toml # parse a policy and report what it holds
sudo bpfjctl attach policy.toml # load and pin the jailer
sudo bpfjctl replace policy.toml # reload without releasing jailed tasks
sudo bpfjctl wrap ROLE USER_ID -- CMD # run CMD in a new pod
sudo bpfjctl enroll ROLE USER_ID PID [NAME=VALUE...] # enroll with variables
sudo bpfjctl show PID # pods a process is in
sudo bpfjctl list # every pod and its processes
sudo bpfjctl detach # unpin and unload
По умолчанию программы закрепляются в /sys/fs/bpf/bpfj-pins. Используйте --bpffs-path и --pin-dir, чтобы изменить это. Они остаются загруженными до выполнения detach.
bpfjctl wrap без --drop-cap и с ненулевым --uid оставляет команду способной удалить себя из изоляции. См. bpfjctl wrap --help.
Запустите sudo build/bpfjlog, пока jailer подключён, чтобы наблюдать за ним. Диагностика BPF записывается в stderr, а структурированные события — в stdout. Логгер автоматически переподключается, когда replace подменяет новый набор закреплённых карт.
replace загружает полный второй jailer рядом с активным, мигрирует членство в подах, переменные и отслеживаемое владение ресурсами, затем атомарно меняет деревья закреплений. Оба дерева остаются подключёнными во время передачи, fork и зачисление координируются с миграцией, а изменения владения журналируются и воспроизводятся. Замена завершается отказом (fail closed), если сохранённые версии раскладки несовместимы или состояние не может быть безопасно скопировано.
base-role = "floor" # optional: enroll every process on the host
vars = ["vm_uuid"] # known variable names
[certs]
corp-ca = "MIIDXTCCAkWgAwIBAgIJAK..." # PEM or base64 DER certificate
[roles.floor]
any = true # open tracking-only base role