Флаг SECBIT_KEEP_CAPS не дает сбросить возможности, когда процесс с одним или несколькими нулевыми UID присваивает идентификатору пользователя ненулевое значение. Грубо говоря, это половина той работы, которую выполняет флаг SECBIT_NO_SETUID_FIXUP (как отмечено в табл. 39.2, SECBIT_KEEP_CAPS действует, только если не установлен флаг SECBIT_NO_SETUID_FIXUP). Этот флаг предоставляет параметры securebits, отражающие старшую операцию PR_SET_KEEPCAPS для вызова prctl(), которая отвечает за тот же атрибут (единственное отличие между этими двумя механизмами заключается в том, что для использования операции PR_SET_KEEPCAPS процессу не нужен флаг CAP_SETPCAP).
Ранее мы уже отмечали, что во время выполнения exec() сохраняются все флаги безопасности, кроме SECBIT_KEEP_CAPS. Этот флаг имеет параметры, противоположные другим флагам securebits, благодаря чему он согласуется с обработкой атрибутов, установленных операцией PR_SET_KEEPCAPS.
Операция PR_SET_KEEPCAPS предназначена для использования программами, устанавливающими идентификатор администратора, которые работают на старых ядрах без поддержки системы возможностей. Такие программы могут улучшить свою безопасность, сбрасывая и приобретая возможности по мере необходимости (см. раздел 39.10).
Но даже если программа, устанавливающая идентификатор администратора, сбросит все возможности, кроме тех, что ей требуются, она все равно будет обладать двумя важными привилегиями: доступом к файлам, принадлежащим пользователю
Представьте, что у вас есть программа, написанная без поддержки системы возможностей, которая распространяется исключительно в двоичном виде, или же ее исходный код настолько объемный, что мы не в состоянии понять, какие именно возможности могут понадобиться для ее работы. Если эта программа нуждается в привилегиях, но не должна устанавливать идентификатор администратора, то как определить, какие возможности следует установить ее исполняемому файлу с помощью команды setcap(8)? Ответить на этот вопрос можно двумя способами.
• Мы можем воспользоваться утилитой strace(1), чтобы узнать, какие системные вызовы завершились ошибкой EPERM, которая указывает на отсутствие необходимых возможностей. Сверившись со справочной страницей системного вызова или с исходными текстами ядра, мы можем вычислить ту возможность, которая нам нужна. Данный подход неидеален, поскольку иногда у ошибки EPERM могут быть другие причины, не связанные с возможностями, необходимыми программе. Кроме того, иногда, если для выполнения определенной операции у программы не хватает привилегий, она может откорректировать свое поведение. Иногда сложно отличить такие «ложные срабатывания» от случаев, когда привилегии действительно нужны для работы программы.
• Можно попросить ядро выполнить проверку возможностей и изучить полученный ответ. Пример того, как это делается, приведен в статье [Hallyn, 2007], написанной одним из разработчиков системы возможностей файлов. Для каждого запроса проверки возможности в журнальных записях, прилагаемых к статье, указывается функция ядра, которая была вызвана, возможность, которая запрашивалась, и название программы, выполнившей запрос. Этот подход требует больше усилий, чем использование утилиты strace(1), однако он позволяет более точно определить возможности, которые требуются программе.
Система возможностей в Linux разбивает привилегированные операции на отдельные категории и позволяет выдавать процессу только определенную их часть. Это является шагом вперед по сравнению с традиционным механизмом управления привилегиями, при котором процесс либо получает доступ ко всем операциям сразу (если его UID равен 0), либо полностью его лишается (если пользовательский идентификатор не равен 0). Начиная с версии 2.6.24, ядро Linux поддерживает назначение возможностей файлам, благодаря чему процесс, выполняющий программу, может получить определенный набор возможностей.