Обзор
Модель безопасности Linux строится послойно: DAC (Discretionary Access Control — классические UNIX-права rwx) → capabilities (гранулярные привилегии вместо монолитного root) → MAC (Mandatory Access Control через LSM — SELinux/AppArmor) → seccomp (фильтрация системных вызовов) → audit (аудит событий). Каждый слой компенсирует слабости предыдущего. DAC недостаточен, потому что скомпрометированный root-процесс обходит все ограничения. MAC решает это: даже root подчиняется политике, определённой администратором.
В FreeBSD аналогичная послойная модель: DAC → MAC framework (аналог LSM) → capsicum (аналог seccomp) → securelevel (глобальное ограничение привилегий). Но реализации существенно отличаются.
DAC: классическая модель
DAC — владелец объекта (файла, директории) определяет права доступа. User/group/other × read/write/execute + SUID/SGID/sticky bit. ACL (Access Control Lists, setfacl/getfacl) расширяют модель, позволяя задать права для произвольных пользователей/групп.
Фундаментальная слабость DAC: если процесс получает привилегии root (через эксплойт, misconfiguration, SUID binary), он обходит все DAC-ограничения. Поэтому DAC — необходимый, но недостаточный уровень.
Capabilities: гранулярный root
Традиционно UNIX знает два уровня привилегий: обычный пользователь и root (UID 0). Capabilities (с ядра 2.2) разбивают привилегии root на ~40 дискретных capabilities:
CAP_NET_BIND_SERVICE — привязка к портам <1024. CAP_NET_RAW — raw sockets (ping, tcpdump). CAP_SYS_PTRACE — отладка процессов других пользователей. CAP_DAC_OVERRIDE — обход проверок прав доступа к файлам. CAP_SYS_ADMIN — "мусорная корзина" привилегий: mount, swapon, настройка hostname, ядерные namespace operations и десятки других. По сути — почти root.
Capabilities назначаются на три уровня: file capabilities (через setcap, хранятся в extended attributes — замена SUID), thread capabilities (наследуются/изменяются при exec()), ambient capabilities (с 4.3, позволяют передать capabilities дочерним процессам без file capabilities).
# Назначить capability на файл (вместо SUID root)
setcap cap_net_bind_service+ep /usr/bin/myserver
# Проверить capabilities файла
getcap /usr/bin/myserver
# Запустить процесс с ограниченными capabilities
# systemd: в unit-файле
CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_NET_RAW
AmbientCapabilities=CAP_NET_BIND_SERVICE
# Посмотреть capabilities процесса
cat /proc/<PID>/status | grep Cap
getpcaps <PID>
systemd интегрирован с capabilities: каждый сервис может декларировать CapabilityBoundingSet (максимум доступных) и AmbientCapabilities (переданных при exec). Вместе с User=, ProtectHome=, ProtectSystem= это формирует sandbox без SELinux/AppArmor (см. статью 2).
LSM: Linux Security Modules
LSM — фреймворк ядра, предоставляющий hooks (точки перехвата) для модулей безопасности. Hooks размещены во всех критических точках: открытие файла, exec(), создание сокета, изменение прав, ptrace и т.д. LSM hooks выполняются после DAC-проверок и могут дополнительно запретить операцию.
Текущие LSM в ядре (2026, по списку CONFIG_LSM в mainline): AppArmor, SELinux, Smack, TOMOYO, Yama, LoadPin, SafeSetID, Lockdown, Landlock, IPE (Integrity Policy Enforcement), BPF (LSM BPF с ядра 5.7). Major LSMs (SELinux, AppArmor, Smack) — exclusive: только один может быть active одновременно. Minor LSMs (Yama, Lockdown, Landlock, capabilities) могут работать параллельно с major.
SELinux
Разработан NSA, дефолт в RHEL/Fedora/CentOS. Label-based: каждый объект (файл, процесс, порт, сокет) имеет security context (метку) в формате user:role:type:level. Политика определяет, какие типы могут взаимодействовать.
# Контекст файла
ls -Z /var/www/html/index.html
# unconfined_u:object_r:httpd_sys_content_t:s0
# Контекст процесса
ps -eZ | grep httpd
# system_u:system_r:httpd_t:s0 /usr/sbin/httpd
Правило политики (упрощённо): allow httpd_t httpd_sys_content_t:file { read open getattr }; — процесс типа httpd_t может читать файлы типа httpd_sys_content_t.
Targeted policy (дефолт в RHEL) — конфайнит только определённые сервисы, остальные работают в unconfined_t. MLS/MCS — многоуровневая секретность (используется в government/military setups) и Multi-Category Security (изоляция контейнеров).
Режимы: Enforcing (политика применяется), Permissive (нарушения логируются, но не блокируются), Disabled (SELinux полностью отключён — не рекомендуется, переключение обратно требует relabeling всей ФС). Начиная с RHEL 9 третий режим через конфиг уже не работает как раньше: SELINUX=disabled в /etc/selinux/config оставляет подсистему включённой, но без загруженной политики, а для настоящего отключения нужен параметр ядра selinux=0.
getenforce # текущий режим
setenforce 0 # переключить в Permissive (до перезагрузки)
# Постоянное изменение: /etc/selinux/config → SELINUX=enforcing
# Troubleshooting — главная причина «SELinux всё ломает»
ausearch -m avc -ts recent # последние denial'ы из audit.log
audit2why < /var/log/audit/audit.log # объяснить причину denial
audit2allow -a -M mypolicy # сгенерировать policy module из denial'ов
semodule -i mypolicy.pp # установить policy module
# Исправление контекстов файлов (частая проблема)
restorecon -Rv /var/www/html/ # восстановить дефолтные контексты
chcon -t httpd_sys_content_t file # изменить контекст вручную (не переживёт relabel)
semanage fcontext -a -t httpd_sys_content_t "/srv/www(/.*)?" # постоянное правило
restorecon -Rv /srv/www/
AppArmor
Дефолт в Ubuntu и Debian; SUSE от него ушла — Tumbleweed переключился на SELinux со снапшота 20250211 (февраль 2025), а SLE 16 (ноябрь 2025) и построенный на нём openSUSE Leap 16 ставятся с SELinux в enforcing, AppArmor в них остаётся опцией для ручного включения. Path-based: профили определяют, к каким путям файловой системы и с какими правами может обращаться программа.
# /etc/apparmor.d/usr.sbin.nginx
/usr/sbin/nginx {
# Сеть
network inet stream,
network inet6 stream,
# Файлы
/etc/nginx/** r,
/var/log/nginx/** rw,
/var/www/** r,
/run/nginx.pid rw,
# Capabilities
capability net_bind_service,
capability setuid,
capability setgid,
# Запретить всё остальное (implicit deny)
}
Режимы: Enforce (блокировка + лог), Complain (только лог — аналог SELinux Permissive). aa-genprof запускает приложение в complain-mode и интерактивно генерирует профиль на основе наблюдаемого поведения.
aa-status # все загруженные профили и их режимы
aa-enforce /etc/apparmor.d/usr.sbin.nginx
aa-complain /etc/apparmor.d/usr.sbin.nginx
aa-logprof # обновить профиль по логам нарушений
SELinux vs AppArmor: архитектурный trade-off
SELinux — label-based (метки на inode): переименование файла не меняет его тип, hard link сохраняет контекст. Гранулярнее (type enforcement, role-based, MLS/MCS), но значительно сложнее в настройке и отладке. Типичная реакция администратора — setenforce 0 (отключить).
AppArmor — path-based: профили привязаны к путям. Проще писать и понимать, но если файл доступен по другому пути (hard link, bind mount), профиль может быть обойдён. Частично компенсируют это ядерные ограничения fs.protected_hardlinks и fs.protected_symlinks: они начинали жизнь в Yama, но давно переехали в общий код VFS, и systemd включает их своим sysctl.d/50-default.conf — сам Yama сегодня отвечает только за ptrace_scope.
Для контейнеров SELinux предоставляет MCS-изоляцию: каждый контейнер получает уникальную категорию (s0:c1,c2), что предотвращает доступ между контейнерами даже при escaping namespace isolation. Docker и Podman автоматически назначают MCS-метки.
seccomp: фильтрация системных вызовов
seccomp-bpf (с ядра 3.5) позволяет процессу установить BPF-фильтр, определяющий, какие системные вызовы разрешены. Фильтр — одностороннее ограничение: установленный, он не может быть снят или ослаблен.
seccomp дополняет LSM: LSM контролирует доступ к объектам ядра (файлы, сокеты), seccomp контролирует интерфейс между userspace и ядром (syscalls). Ограничение seccomp: BPF-фильтры не могут разыменовывать указатели, поэтому seccomp не может проверить содержимое аргументов-строк (путь файла в open()).
Docker применяет default seccomp-профиль, блокирующий ~44 опасных syscall'а (из ~300+): mount, reboot, clock_settime, init_module, ptrace и др. Для большинства приложений это прозрачно. Podman использует аналогичный дефолтный профиль.
systemd предоставляет SystemCallFilter= в unit-файлах: SystemCallFilter=@system-service (предопределённые группы syscall'ов).
Landlock: application-level sandboxing
Landlock (с ядра 5.13, стабилен с 5.19) — LSM, позволяющий непривилегированному процессу ограничить свой собственный доступ к файловой системе и сети. В отличие от SELinux/AppArmor (требуют root для загрузки политики), Landlock позволяет приложению самостоятельно sandbox'ить себя.
Концептуально Landlock ближе к FreeBSD Capsicum и OpenBSD pledge(): программа декларирует, что ей нужно (чтение /etc/config, запись в /tmp), а всё остальное запрещается ядром. С ядра 6.7 Landlock поддерживает и сетевые ограничения (bind/connect для TCP).
Возможности Landlock нумеруются собственной версией ABI, и ориентироваться нужно на неё, а не на версию ядра: ABI 6 (ядро 6.12) добавил изоляцию абстрактных unix-сокетов и сигналов, ABI 7 (6.15) — запись отказов в audit, ABI 8 (7.0) — флаг LANDLOCK_RESTRICT_SELF_TSYNC, ABI 10 (7.2) — UDP. Флаг TSYNC важнее остального: до него ruleset применялся только к вызывающему потоку и его потомкам, так что многопоточной программе приходилось ограничивать каждый поток отдельно.
auditd: аудит событий
Linux Audit Framework — подсистема ядра для записи security-relevant событий. auditd — демон, принимающий события от ядра и записывающий в /var/log/audit/audit.log.
# Правила аудита (/etc/audit/rules.d/)
# Мониторинг изменений в /etc/passwd
-w /etc/passwd -p wa -k identity
# Мониторинг exec() с UID 0
-a always,exit -F arch=b64 -S execve -F euid=0 -k root-commands
# Мониторинг загрузки модулей ядра
-a always,exit -F arch=b64 -S init_module,finit_module -k module-load
# Поиск по логам
ausearch -k identity # по ключу
ausearch -m USER_LOGIN --success no # неудачные логины
aureport --auth # сводка аутентификации
aureport --summary # общая сводка
auditd критичен для compliance (PCI DSS, HIPAA, SOX). На серверах с высокой нагрузкой audit может генерировать значительный I/O; аудит-правила должны быть targeted, не blanket.
SSH hardening
SSH — основной вектор remote-доступа и частый target атак. Ключевые настройки (/etc/ssh/sshd_config):
PermitRootLogin no # запретить root login (использовать sudo)
PasswordAuthentication no # только ключи
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys
MaxAuthTries 3
AllowUsers deploy admin # whitelist пользователей
LoginGraceTime 30
ClientAliveInterval 300 # timeout неактивных сессий
ClientAliveCountMax 2
fail2ban / sshguard — анализ логов и блокировка IP после N неудачных попыток. fail2ban работает через iptables/nftables jails; sshguard — более лёгкая альтернатива. На серверах с публичным SSH fail2ban — минимально необходимая мера.
Практика: уровни hardening
# 1. Проверка текущего состояния безопасности
getenforce # SELinux
aa-status # AppArmor
sysctl user.max_user_namespaces # user namespaces, вентиль mainline
sysctl kernel.unprivileged_userns_clone # downstream-патч Debian/Ubuntu
sysctl kernel.apparmor_restrict_unprivileged_userns # Ubuntu 24.04+, по умолчанию 1
sysctl kernel.yama.ptrace_scope # Yama ptrace restriction
cat /proc/sys/kernel/dmesg_restrict # ограничение dmesg для non-root
# 2. Базовый hardening через sysctl
kernel.dmesg_restrict = 1 # скрыть kernel messages от non-root
kernel.kptr_restrict = 2 # скрыть указатели ядра из /proc
kernel.yama.ptrace_scope = 1 # ptrace только для дочерних процессов
# Значения all, default и <iface> ядро комбинирует по-разному: rp_filter — как
# max(all, <iface>), redirects на узле без форвардинга — как OR, а default действует
# только на созданные позже интерфейсы; systemd вдобавок раздаёт rp_filter = 2 (loose)
net.ipv4.conf.all.rp_filter = 1 # reverse path filtering
net.ipv4.conf.*.rp_filter = 1 # glob понимает systemd-sysctl, но не procps
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.*.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.*.send_redirects = 0
kernel.unprivileged_bpf_disabled = 1 # запретить BPF для non-root
kernel.io_uring_disabled = 2 # отключить io_uring (attack surface)
# 3. Lockdown LSM (с ядра 5.4)
# integrity mode: запретить загрузку неподписанных модулей, /dev/mem доступ
# confidentiality mode: + скрыть ядерные данные из /proc
# Включается через kernel cmdline: lockdown=integrity
# 4. Проверка SUID-бинарей (минимизировать attack surface)
find / -perm -4000 -type f 2>/dev/null
find / -perm -2000 -type f 2>/dev/null
Нюансы и trade-off'ы
«Просто отключите SELinux» — антипаттерн. SELinux denial в 90% случаев указывает на реальную проблему: неправильный файловый контекст (решается restorecon), нестандартный порт (semanage port -a), или действительно нежелательное поведение приложения. audit2why объясняет причину человеческим языком. Отключение SELinux убирает критический слой защиты, особенно важный для контейнеров (MCS isolation).
AppArmor path-based ≠ слабый. Path-based подход имеет реальную слабость (hard links, bind mounts), но для большинства серверных сценариев (confined daemons) этого достаточно. Docker на Ubuntu использует AppArmor-профили, и они эффективно ограничивают контейнеры.
Capabilities vs полный root. На практике многие приложения запрашивают CAP_SYS_ADMIN, который даёт почти полный root. Это «мусорная capability» — разделение неполное. Работа по разделению CAP_SYS_ADMIN на более гранулярные capabilities продолжается, но медленно из-за backward compatibility.
seccomp overhead. Каждый системный вызов проходит через BPF-фильтр. Overhead зависит от сложности фильтра: для дефолтного Docker-профиля (~44 rules) — менее 1%. Для сложных кастомных профилей может быть заметнее. В contrast, LSM hooks имеют фиксированный overhead (вызов функции на каждом hook point), который может достигать единиц процентов для SELinux с полной политикой.
io_uring как attack surface. io_uring — высокопроизводительный I/O-интерфейс ядра, добавленный в 5.1. Из-за сложности реализации он стал постоянным источником уязвимостей (десятки CVE). Google и другие крупные пользователи рекомендуют отключать io_uring на серверах, где он не нужен: kernel.io_uring_disabled=2.
LSM BPF (с ядра 5.7) — новое направление: eBPF-программы, подключаемые к LSM hooks, позволяющие реализовать кастомные MAC-политики без написания kernel module. Более гибко, чем SELinux/AppArmor, с меньшим overhead (~15% в worst case vs ~110% для AppArmor в некоторых бенчмарках). В production используется в Cilium, Android, ChromeOS.
Сравнение с FreeBSD
MAC Framework. FreeBSD имеет собственный MAC framework (аналог LSM), с модулями: mac_bsdextended (файловый firewall на правилах), mac_portacl (привязка к портам без root), mac_seeotheruids (скрытие процессов других пользователей). Менее развит, чем SELinux/AppArmor — нет эквивалента targeted policy для каждого сервиса. Реальное использование MAC в FreeBSD значительно реже, чем SELinux в RHEL.
Securelevel. kern.securelevel — глобальный уровень безопасности, который можно только повышать: на уровне 1 запрещается загрузка модулей и запись в /dev/mem, на уровне 2 — изменение правил firewall и запись в блочные устройства. Простой и эффективный механизм для production-серверов. В Linux аналог — Lockdown LSM (integrity/confidentiality modes), появившийся значительно позже (ядро 5.4).
Capsicum. Capability-based sandbox framework — процесс входит в capability mode и теряет доступ к глобальному namespace (файловые пути, сетевые адреса). Доступ только через явно переданные file descriptors с ограниченными правами. Концептуально чище, чем seccomp (который фильтрует syscalls, а не объекты). В Linux аналогом является Landlock + seccomp, но capsicum элегантнее архитектурно.
chflags. FreeBSD файловые флаги (schg — system immutable, sunlnk — undeletable) — в сочетании с securelevel делают файлы неизменяемыми даже для root. В Linux аналог — chattr +i (immutable), но без securelevel root может снять этот флаг.
blacklistd. FreeBSD-аналог fail2ban, встроенный в base system. Интегрирован с sshd, ftpd, smtpd — при N неудачных попыток IP автоматически блокируется через PF. Проще и надёжнее, чем парсинг логов fail2ban.
Источники
- Linux Security Modules — kernel.org — документация LSM
- SELinux User's and Administrator's Guide — Red Hat — практическое руководство
- AppArmor — Ubuntu Wiki — документация AppArmor
- Landlock — kernel.org — API Landlock
- seccomp — kernel.org — документация seccomp
- capabilities(7) — man page по capabilities
- Linux Audit — Red Hat — настройка auditd
- LSMs vs seccomp — Star Lab — сравнение
- Practical Guide to LSM BPF — eBPF-based security
- FreeBSD Handbook: MAC — для сравнения
Связанные заметки
- Linux — контейнеризация — namespaces и seccomp как средства изоляции
- Linux — сеть: стек, конфигурация, firewall — nftables и фильтрация трафика
- sudo, doas и sudo-rs — повышение привилегий: механизм setuid и сравнение реализаций
- FreeBSD — безопасность — MAC-фреймворк и securelevel, для сравнения
- Linux — сводный cheatsheet — быстрая справка по security-командам
- Обратный прокси и TLS: nginx vs Caddy — публичная точка входа и доверие к заголовкам
- OpenVPN против WireGuard — VPN-демон в модели защиты хоста: от чьего имени он работает и что открывает наружу
- SSH углублённо — та же технология как инструмент:
~/.ssh/config, бастионы, сертификаты, ограниченные ключи - Linux — пользователи, группы, PAM и systemd-logind — модель учётных записей и стек PAM, на который опираются эти механизмы
- Linux — время и синхронизация — расхождение часов ломает TOTP, Kerberos и проверку сроков сертификатов
- Эксплуатация локальных ИИ-сервисов — песочница для сервиса, которому нужен доступ к видеокарте:
PrivateDevices=здесь неприменим - Карта памяти ядра: половины, прямое отображение, KASLR — механизм под теми же настройками: KPTI, KASLR и права на секции ядра изнутри
- Вход в ядро и переключение контекста — механизм под контрмерами: граница доверия ядра, SMEP/SMAP и цена спекулятивных заплат на каждом переходе
Из библиотеки института уносят только знания. Читателей здесь не считают: посещение не регистрируется, отметок в издании не остаётся, счётчиков нет ни у одного издания фонда.
Издание пополняется и пересверяется. Текст доступен на условиях CC BY-SA 4.0 — унесённое можно передавать дальше на тех же условиях.