Томас Бёчлер (Tomas Bächler), перевод: attila
Оригинал
http://archlinux.me/brain0/
В традиционных системах UNIX существовал единственный уровень привилегий: суперпользователь (root). Если вы root, вам позволено все. Но и простые пользователи иногда должны иметь возможность выполения привилегированных операций.
Есть два простых решения:
- временное получение прав суперпользователя, используя su или sudo;
- установка setuid бита на исполняемом файле.
В обоих случаях вы получаете привилегии суперпользователя целиком, и хотя таким образом обычно запустить только весьма ограниченное команд, ошибки в этих программах или библиотеках создают угрозу взлома. Злоумышленник может заставить делать программу то, для чего она изначально не предназначалась, вплоть до запуска командой оболочки root’а.
В 1997 году комитет по стандартам (POSIX 1003.1e) создал черновую версию стандарта расширений механизма защиты. Одно из таких расширений разбивает привилегии root на части, позволяя давать задача лишь часть его привилегий. Хотя этот стандарт так и остался черновиком, спецификация была завершена и фактически реализована в ядре Linux.
Начиная с версии 2.2, ядро Linux при выполнении системного вызова проверяет, есть ли у процесса необходимые разрешения, вместо проверки root ли вы. Процесс имеет три набора прав доступа: доступный (permitted), наследуемый (inheritable) и текущий (effective). Именно последний набор используется ядром при проверке, дозволяется ли процессу выполнение определенных операций. Наследуемые разрешения передаются новой программе при выполнении execve. Доступные же разрешения ограничивают множество всех возможных текущих разрешений, на которые только процесс может рассчитывать. Кроме того, процесс может добавлять в свой наследуемый набор только разрешения из доступного набора (если только у процесса не имеется разрешения CAP_SETPCAP в списке текущих, об этом позже).
Как процесс может управлять своими наборами разрешений, подробно описано в [4].
В ядре 2.6.24 был реализован механизм «файловых разрешений», позволяющий администратору присваивать разрешения определенным исполняемым файлам, которые получат пользователи, когда запустят их.
Полный список разрешений приведен в ман-странице capabilities (7) и в заголовочном файле /include/linux/capability.h. Примеры ниже будут касаться разрешения CAP_NET_RAW. Но прежде всего вы должны убедиться, что библиотека libcap 2.X установлена в системе. (Если вы используете Arch Linux, скорее всего, она уже установлена как зависимость coreutils).
$ pacman -Q libcap
libcap 2.19-1
$ pacman -Ql libcap | grep bin/
libcap /usr/sbin/
libcap /usr/sbin/capsh
libcap /usr/sbin/getcap
libcap /usr/sbin/getpcaps
libcap /usr/sbin/setcap
{
Для Debian'а:
$ aptitude show libcap2 libcap2-bin
$ apt-file show libcap2 | grep bin/ | grep -v doc
libcap2-bin: /sbin/capsh
libcap2-bin: /sbin/getcap
libcap2-bin: /sbin/getpcaps
libcap2-bin: /sbin/setcap
}
Мы будем использовать утилиту setcap для управления разрешениями файлов. Для этого файловая система должна поддерживать расширенные атрибуты файлов (это, например, ext2/ext3/ext4). Прежде чем мы, наконец, начнем действовать, рассмотрим, что означают термины доступный, наследуемый и текущий наборы в контексте файловых разрешений.
Доступные разрешения исполняемого файла становятся доступными разрешениями процесса после запуска файла, вне зависимости от наследуемых разрешений процесса. Наследуемые разрешения файла соотносятся с наследуемыми разрешениями процесса, и «пересечение» добавляется к доступным разрешениям процесса. Текущее разрешение файла — это даже не набор, а единственный бит. Если он установлен, после запуска файла все доступные разрешения процесса становятся его текущими разрешениям, если нет — ни одно из доступных разрешений не будет текущим.
Итак, начнем. Файл /bin/ping традиционно имеет установленный setuid-бит для работы:
$ ls -l /bin/ping
-rwsr-xr-x 1 root root 30824 Фев 23 21:40 /bin/ping
Уберем его и установим текущий бит и CAP_NET_RAW разрешение:
$ chmod -s /bin/ping
$ setcap cap_net_raw=ep /bin/ping
$ getcap /bin/ping
/bin/ping = cap_net_raw+ep
ping продолжает работать! То же самое можно проделать и с traceroute. Но есть программы, с которыми это не проходит. Некоторые программисты считают нужным проверить, root ли вы, перед выполнение определенного системного вызова. Так, программа tcptraceroute содержит такой код:
if (getuid() & geteuid())
fatal("Got root?\n");
Эта программа не будет работать без прав суперпользователя, даже если разрешить CAP_NET_RAW.
Хорошо, но как сделать, чтобы привилегированные функции программы были доступны лишь некоторым пользователям? Чтобы решить эту проблему, Tomas Bächler написал небольшую утилиту, capsudo. Для работы этой утилиты необходмо наличие libcap и iniparser в системе. Сборка и установка выполняется командами make и make install. Исполняемый файл capsudo должен иметь установленное разрешение CAP_SETPCAP. CAP_SETPCAP позволяет процессу добавлять в набор наследуемых любые разрешения, даже те, которые отсутствуют среди доступных, но не позволяют им быть доступными, пока не будет выполнена программа с установленным соотетсвтующим наследуемым разрешением файла.
Установим для /bin/ping CAP_NET_RAW в качестве наследуемого разрешения:
$ setcap cap_net_raw=ei /bin/ping
и добавим следующую секцию в /etc/capsudoers:
[ping]
caps = cap_net_raw
command = /bin/ping
users = user1 user2
allow_user_args = 1
Теперь пользователи user1 и user2 могут запускать ping без прав суперпользователя командой
capsudo ping 127.0.0.1
Просто команда `ping’ работать уже не будет, так как у файла /bin/ping есть только наследуемое разрешение, а не доступное. Процесс же capsudo, проверив права пользователя в /etc/capsudoers, добавляет CAP_NET_RAW-разрешение в список своих наследуемых разрешений (это ему позволено, так как у файла capsudo установлено разрешение CAP_SETPCAP). Когда capsudo запускает ping, наследуемое разрешение файла совпадает с наследуемым разрешением процесса и добавляется в список доступных (и, соответсвенно, текущих, так как у файла /bin/ping установлен текущий бит).
Другое решение, менее гибкое, состоит в использовании pam. Суть этого решения в том, что при логине процесс пользователя получает определенный набор наследуемых разрешений. Пользователь, таким образом, получает возможность запускать файлы, у которых установлено соответствующее наследуемое разрешение.
Итак, у файла /bin/ping разрешения остаются прежними
getcap /bin/ping
/bin/ping = cap_net_raw+ei
В /etc/pam.d/login добавляем строчку:
auth required pam_cap.so
Файл /etc/security/capability.conf приводим к виду:
cap_net_raw user1
none *
После входа в систему командная оболочка пользователя user1 будет иметь установленное наследуемое разрешение cap_net_raw. Действительно:
$ getpcaps $$
Capabilities for `3658': = cap_net_raw+i
Теперь пользователь user1 будет иметь возможность запускать программу ping, если заходит в систему обычным образом (и не будет иметь такой возможности, когда заходит, например, по ssh, так как использование модуля pam_cap прописано только в /etc/pam.d/login).
Ссылки:
[1] man 7 capabilities
http://www.kernel.org/doc/man-pages/online/pages/man7/capabilities.7.html
[2],[3] Tomas Bächler, его блог
http://archlinux.me/brain0/
http://archlinux.me/brain0/2009/07/28/using-posix-capabilities-in-linux-part-one/
http://archlinux.me/brain0/2010/01/05/using-posix-capabilities-in-linux-part-two/
[4] Серж Е. Халлин, «Разрешение POSIX для файлов: разделяем полномочия root»
http://www.ibm.com/developerworks/ru/library/l-posixcap/l-posixcap.html#
[5] Chris Friedhoff, POSIX Capabilities & File POSIX Capabilities
http://www.friedhoff.org/posixfilecaps.html
Примечение переводчика:
Слово ‘capability’ всюду переведено словом „разрешение“, как это сделано в [4].
Копипаст
http://posix.ru/freenotes/linux/51, касательно Debian'а - отсебятина ;)