capabilities: getcap и setcap
Выдать программе отдельную привилегию root без setuid — setcap cap_net_bind_service=ep, getcap -r, setcap -r
Права root в Linux разбиты на отдельные capabilities: открыть порт ниже 1024 (cap_net_bind_service), читать любые файлы (cap_dac_override), отправлять сырые пакеты (cap_net_raw) и так далее. Их можно записать прямо в исполняемый файл — тогда программа, запущенная обычным пользователем, получит только эту привилегию, а не все права root, как при setuid. setcap записывает, getcap показывает (пакет libcap2-bin). Хранятся они в расширенном атрибуте security.capability.
Синтаксис
setcap 'cap_имя[,cap_имя…]=флаги' файл # записать
setcap -r файл # удалить
getcap файл… # показать
getcap -r каталог # найти все файлы с capabilities
Флаги
| Флаг | Набор | Смысл |
|---|---|---|
p | permitted | процессу разрешено пользоваться привилегией |
e | effective | привилегия включена сразу при запуске; без e программа должна включить её сама |
i | inheritable | может передаваться дальше через exec (нужно редко) |
Почти всегда пишут =ep: «разрешить и сразу включить». Операторы: = — задать ровно эти флаги, + — добавить, - — убрать. cap_net_raw+ep и cap_net_raw=ep на пустом файле дают одно и то же.
Опции
| Команда | Что делает |
|---|---|
setcap -r файл | удалить все capabilities файла |
setcap -v 'caps' файл | проверить, совпадают ли capabilities; файл: OK и код 0, иначе код 1 |
setcap -q … | не печатать сообщения |
setcap - файл | прочитать capabilities из stdin (до пустой строки) |
getcap -r каталог | рекурсивный поиск; файлы без capabilities не печатаются |
getcap -v файл | печатать и файлы без capabilities |
getcap -n файл | показать rootid, если capability записана для user namespace |
Частые capabilities
| Capability | Что разрешает |
|---|---|
cap_net_bind_service | слушать порты ниже 1024 (веб-сервер на 80/443 без root) |
cap_net_raw | сырые сокеты: ping, tcpdump, arping |
cap_net_admin | настраивать сеть: интерфейсы, маршруты, iptables |
cap_dac_override | игнорировать права rwx на файлы и каталоги |
cap_dac_read_search | читать любые файлы и обходить любые каталоги |
cap_chown / cap_fowner | менять владельца любого файла / действовать как владелец файла |
cap_kill | посылать сигналы чужим процессам |
cap_setuid / cap_setgid | менять UID/GID процесса — фактически root |
cap_sys_admin | «почти root»: mount, многое другое |
cap_sys_ptrace | отлаживать чужие процессы (strace -p) |
cap_sys_nice | повышать приоритет (nice ниже нуля) |
cap_sys_time | менять системное время |
Полный список — man 7 capabilities. Расшифровать маску из /proc/PID/status: capsh --decode=0000000000000400.
Как читать вывод
/usr/bin/ping cap_net_raw=ep
/usr/local/bin/app cap_net_bind_service,cap_net_raw=ep
Путь, затем список capabilities и флаги. Если у файла их нет, getcap ничего не печатает и возвращает 0. В ls -l capabilities не видны — в отличие от setuid (s) и ACL (+).
Capabilities процесса: строки CapPrm/CapEff в /proc/PID/status (шестнадцатеричная маска) или capsh --print для текущей оболочки.
Примеры
# у ping уже есть capability — поэтому он работает без root
getcap /usr/bin/ping
# все файлы с capabilities в системе (аудит безопасности)
getcap -r / 2>/dev/null
# разрешить своему серверу слушать порт 80 без root
setcap 'cap_net_bind_service=ep' /usr/local/bin/myserver
getcap /usr/local/bin/myserver
# несколько capabilities сразу
setcap 'cap_net_bind_service,cap_net_raw=ep' /usr/local/bin/myserver
# проверить в скрипте, что capability на месте
setcap -v 'cap_net_bind_service=ep' /usr/local/bin/myserver && echo ok
# снять
setcap -r /usr/local/bin/myserver
# для интерпретатора — только на реальный файл, не на символическую ссылку
setcap 'cap_net_bind_service=ep' "$(readlink -f /usr/bin/python3)"
# какие capabilities у работающего процесса
grep Cap /proc/$$/status
capsh --decode=$(awk '/CapEff/{print $2}' /proc/$$/status)
Подводные камни
setcapзаменяет набор целиком.setcap cap_net_raw+ep файлна файле сcap_net_bind_service,cap_net_raw=epоставит толькоcap_net_raw. Перечисляй все нужные capabilities в одной команде.- Без
eпривилегия не включится у обычной программы: с=pфайл получит право, ноcatилиpythonего не активируют и получат «Permission denied». Пиши=ep. - Только обычный файл. На символическую ссылку
setcapотвечает «Invalid file … for capability operation» — используйreadlink -f. - Скрипты не работают. Capabilities на
script.shс#!/bin/bashигнорируются: запускается интерпретатор, а у него их нет. Выдают их бинарнику (или интерпретатору — но тогда привилегию получит любой скрипт на этом языке). - capabilities слетают при
chown, при любой записи в файл (обновление пакета,cpповерх) и не копируются обычнымcp. Сохраняютcp -a/--preserve=xattrиrsync -X(rsync -aбез-X— нет);tar— только с--xattrsпри упаковке и--xattrs --xattrs-include='*'при распаковке. После обновления программы выдай их заново. - Ограничение bounding set. Если capability нет в bounding set процесса (в контейнере это норма, например
cap_dac_read_search,cap_sys_admin), файл с ней не запустится вовсе: «Operation not permitted». СмотриCapBndв/proc/self/status. - В Docker-контейнере порты ниже 1024 и
pingи так доступны обычному пользователю: Docker ставитnet.ipv4.ip_unprivileged_port_start=0и широкийping_group_range. Проверяй эффектcap_net_bind_serviceна обычной машине или на другой capability, напримерcap_dac_override. - Ставить capabilities может только root (нужна
cap_setfcap), иначе «unable to set CAP_SETFCAP effective capability». cap_setuid,cap_sys_admin,cap_dac_overrideна интерпретаторе или редакторе равносильны выдаче root — именно их ищут при аудите черезgetcap -r /.