
LID — Linux Integrity Drift: обход AppArmor через переписывание путей в eBPF. Манипулирование аргументами системных вызовов до LSM с нулевым следом в аудите. «Linux is Dying»
```
██╗ ██╗██████╗
██║ ██║██╔══██╗
██║ ██║██║ ██║
██║ ██║██║ ██║
███████╗██║██████╔╝
╚══════╝╚═╝╚═════╝
```
— «Linux умирает» —
Систематическое обнаружение путей в коде ядра, обходящих гарантии безопасности LSM
Ворота никогда не взламывали. Их просто обошли.
У фреймворка Linux Security Module есть одна ключевая гарантия, которая держится уже 20+ лет:
Модули безопасности могут только добавлять ограничения. Они никогда не могут их снимать.
Эта гарантия верна. LID её не нарушает.
LID находит пути в коде ядра, которые полностью обходят хуки LSM — подсистемы, выполняющие чувствительные с точки зрения безопасности операции, не обращаясь к фреймворку LSM. Проверка безопасности корректна. Проблема в том, что ядро её просто не запрашивает.
Каждая находка имеет два различных аспекта, которые не следует смешивать:
Архитектурное слепое пятно. Вопрос не в том, «может ли атакующий это эксплуатировать?», а в следующем:
Если чувствительная с точки зрения безопасности операция выполняется, а уровень принудительного контроля её даже не оценивает, у вас пробел видимости — независимо от того, может ли атакующий практически злоупотребить этим сегодня. Это имеет значение для комплаенса, криминалистики и предположений об эшелонированной обороне.
Вопрос реальной эксплуатируемости:
Это две разные вещи. Находка может быть критическим пробелом видимости (ваш мониторинг слеп), не будучи практическим повышением привилегий (атакующему уже нужен root). И наоборот, находка может быть прямым путём эскалации с минимальными предпосылками.
| Находка | Пробел видимости | Практическая эскалация |
|---|---|---|
| LID-001 | Критический — AppArmor ничего не видит, журнал аудита пуст, ноль криминалистических следов | Ограниченная — требует root или CAP_BPF+CAP_PERFMON (уже привилегирован). Не повышение привилегий. Воздействие: обход политики + слепота аудита. |
| LID-002 | Высокий — security_file_receive() никогда не срабатывает, передача fd невидима для всех LSM | Высокая — работает из непривилегированного пользовательского пространства через io_uring. Пересекает границу принудительного контроля LSM без каких-либо привилегий. |
| LID-003 | Высокий — security_sb_mount() обойдён, политика монтирования AppArmor — мёртвый код | Средняя — требует доступ к namespace монтирования (CAP_SYS_ADMIN в user ns). Доступен во многих конфигурациях контейнеров. |
| LID-004 | Критический — AppArmor ничего не видит, ноль BPF-хуков (0/9), нет следов аудита для любой операции с BPF-токеном | Средняя — требует делегирования bpffs хостом + CAP_BPF в user namespace. Доступен в контейнерных рантаймах с делегированием BPF (LXD/Incus). |
| LID-005 | Средний — классификаторы tc egress на интерфейсе контейнера никогда не оценивают трафик AF_XDP | Ограниченная — обходит tc egress на eth0 контейнера (подтверждено). Cilium НЕ обойдён — применяет контроль на входящем veth со стороны узла + проверку исходного IP (протестировано). Воздействие ограничено конфигурациями plain-Docker с фильтрацией только через tc egress. |
У каждой находки есть конкретные требования к ядру/конфигурации/привилегиям. Если ваше окружение не совпадает, находка не воспроизведётся.
| Условие | Требуется | Примечания |
|---|---|---|
| Версия ядра | 5.x+ | Протестировано на 5.15, 6.1, 6.6, 6.8 |
CONFIG_BPF_SYSCALL | =y | По умолчанию во всех крупных дистрибутивах |
CONFIG_BPF_KPROBE_OVERRIDE | =y | Ubuntu/Debian включают, RHEL нет |
CONFIG_SECURITY_APPARMOR | =y | Целевой LSM должен быть AppArmor |
| Профиль AppArmor | Enforcing, правило deny на целевой путь | Работает с любым правилом deny на основе пути |
| Привилегии | root или CAP_BPF + CAP_PERFMON | Не может работать без привилегий |
kernel.lockdown | none или integrity | Режим confidentiality блокирует присоединение kprobe |
kernel.unprivileged_bpf_disabled | Не важно | В любом случае требуется CAP_BPF |
fs.protected_hardlinks | 0 для межпользовательских ссылок | 1 (по умолчанию) всё ещё разрешает жёсткие ссылки того же пользователя |
| SELinux вместо AppArmor | Не работает | SELinux основан на inode, а не на пути |
| Условие | Требуется | Примечания |
|---|---|---|
| Версия ядра | 6.0+ | IORING_MSG_SEND_FD добавлен в 6.0 |
CONFIG_IO_URING | =y | По умолчанию во всех крупных дистрибутивах |
| Привилегии | Нет | Работает из непривилегированного пользовательского пространства |
sysctl io_uring_disabled | 0 (по умолчанию) | 2 блокирует непривилегированных, 1 блокирует всех |
| Целевой LSM | Любой (SELinux, AppArmor, Smack) | security_file_receive() — универсальный хук LSM |
kernel.lockdown | Не важно | BPF не задействован |
| Условие | Требуется | Примечания |
|---|---|---|
| Версия ядра | 6.9+ | BPF-токен появился в 6.9 |
CONFIG_BPF_SYSCALL | =y | По умолчанию во всех крупных дистрибутивах |
CONFIG_SECURITY_APPARMOR | =y | По умолчанию в Ubuntu/Debian |
| bpffs с делегированием | Да | Хост должен монтировать с опциями delegate_* |
| Привилегии | CAP_BPF в user namespace | Тривиально доступен для root в userns |
| SELinux вместо AppArmor | Не затронут | SELinux реализует все 9 BPF-хуков |
| Условие | Требуется | Примечания |
|---|---|---|
| Версия ядра | 5.2+ | fsopen/fsmount появились в 5.2 |
CONFIG_SECURITY_APPARMOR | =y | Затронут только AppArmor |
| Привилегии | CAP_SYS_ADMIN в user namespace | Доступно с unshare -m |
| SELinux вместо AppArmor | Не работает | SELinux реализует security_sb_kern_mount() |
| Контейнерный рантайм | Зависит от seccomp-фильтра | Стандартный seccomp Docker блокирует fsopen — Podman/LXC могут не блокировать |
| Условие | Требуется | Примечания |
|---|---|---|
| Версия ядра | 4.18+ | AF_XDP появился в 4.18 |
CONFIG_XDP_SOCKETS | =y | По умолчанию во всех крупных дистрибутивах |
| Привилегии | Только CAP_NET_RAW | По умолчанию в Docker и подах Kubernetes |
| Контейнерный рантайм | Docker, K8s, LXC | Стандартный набор capabilities |
| Сетевая политика на основе tc | Да | Cilium eBPF, Calico, tc u32/flower |