capabilities

В исходных текстах ядра список capabilities определён в файле capabilities.h.

Количество capabilities в современных версиях ядра около 40. Точное количество можно узнать через интерфейс /proc

cat /proc/sys/kernel/cap_last_cap

Список текущих capabilities shell можно получить командой

capsh --print

Просмотр capabilities процесса

cat /proc/<pid>/status | grep Cap

Эта команда выведет пять строк со значениями в виде набора двоичных флагов:

  • CapInh (Inheritable) — Наследуемые при загрузке исполняемого файла вызовом execve()
  • CapPrm (Permitted) — Текущий набор capabilities
  • CapEff (Effective)
  • CapBnd (Bounding set) — Ограничение на capabilities "сверху". Загрузка исполняемого файла не может добавить процессу capabilities сверх перечисленных
  • CapAmb (Ambient set)

Пример вывода для команды ping (pid 1234):

$ cat /proc/1234/status | grep Cap
CapInh: 0000000000000000
CapPrm: 0000000000003000
CapEff: 0000000000000000
CapBnd: 000001ffffffffff
CapAmb: 0000000000000000

Для декодирования двоичных флагов можно выполнить команду capsh --decode=<bits>:

$ capsh --decode=0000000000003000
0x0000000000003000=cap_net_admin,cap_net_raw

также можно воспользоваться командой getpcaps <pid>

$ getpcaps 1234
Capabilities for `1234': = cap_net_admin,cap_net_raw+p

Просмотр/установка аттрибутов исполняемого файла

$ getcap /usr/bin/ping
/usr/bin/ping = cap_net_admin,cap_net_raw+p

$ setcap cap_net_admin,cap_net_raw+p /usr/bin/ping

Формат задания capabilities в getcap/setcap имя1,имя2...<op><set> где

  • <op> — +, -, =
  • <set> — e, i, p (Effective, Inheritable, Permitted).

Подробнее этот формат описан в man 3 cap_from_text

Запуск приложений с помощью capsh.

Без ограничений

$ capsh -- -c "/usr/bin/ping -c 1 localhost"
PING localhost.localdomain (127.0.0.1) 56(84) bytes of data.
...

С отобранными capabilities

$ sudo capsh --drop=cap_net_raw -- -c "/usr/bin/ping -c 1 localhost"
ping: socket: Operation not permitted

Системные вызовы

Вызов capget для процесса с ping = 1234 (вывод strace)

$ strace -e capget getpcaps 1234
capget({version=_LINUX_CAPABILITY_VERSION_3, pid=1234}, {effective=0, permitted=1<<CAP_NET_ADMIN|1<<CAP_NET_RAW, inheritable=0}) = 0

Установка capabilities делается вызовом capset().

Capabilities для доступа к файлу

Какие бы права не были выставлены на файл, root будет иметь к нему доступ на чтение, запись и исполнение благодаря capability CAP_DAC_OVERRIDE. То же справедливо для любого процесса, который получил эту capability. Например, для /bin/passwd достаточно было бы иметь CAP_DAC_OVERRIDE для записи в /etc/passwd и /etc/shadow.

Есть тонкость, связанная с флагом на исполнение. Если флаг на исполнение не выставлен ни в одной из позиций (user, group, other), то root выполнить файл не может, а вот права типа --- --- --x уже достаточны для выполнения файла.

Другие capabilities, связанные с правами доступа:

  • CAP_FSETID — позволяет копировать файлы с сохранением suid, sgid. Применяет sgid для процессов, которые не входят в группу, которой принадлежит файл
  • CAP_CHOWN — право на смену владельца и группы файла
  • CAP_DAC_READ_SEARCH — эквивалентно применению прав r-x на все каталоги
  • CAP_FOWNER — эквивалентно применения прав, которые обычно принадлежат только владельцу объекта, в том числе: chmod, управление ACL, запись в файлы в каталогах со stiky bit (/tmp). Для записи в чужие файлы в таком каталоге CAP_DAC_OVERRIDE будет недостаточно.