ОПИСАНИЕ
Для выполнения проверки прав доступа в обычных реализациях UNIX процессы
разделяют на две категории: привилегированные (ID эффективного
пользователя равен 0, как у суперпользователя или root), и не
привилегированные (ID эффективного пользователя не равен нулю). Для
привилегированных процессов все проверки прав в ядре не выполняются, а для
не привилегированных процессов выполняется полная проверка на основе
мандатов процесса (обычно, эффективного UID, эффективного GID и списка
дополнительных групп).
В ядре Linux начиная с версии 2.2, все привилегии, обычно связываемые с суперпользователем, разделены на несколько частей, называемых мандатами (capabilities), которые можно разрешать и запрещать независимо друг от друга. Мандаты являются атрибутом нити.
Список мандатов
В следующим списке показаны мандаты, реализованные в Linux, а также операции или поведение, которые эти мандаты разрешают:CAP_AUDIT_CONTROL (начиная с Linux 2.6.11) Позволяет включать или выключать аудит ядра; изменять фильтрующие правила аудита; получать состояние аудита и фильтрующие правила.
CAP_AUDIT_READ (начиная с Linux 3.16) Позволяет читать протокол аудита через мультикастовый сокет netlink.
CAP_AUDIT_WRITE (начиная с Linux 2.6.11) Позволяет записывать данные в журнал аудита ядра.
CAP_BLOCK_SUSPEND (начиная с Linux 3.5) Позволяет использовать возможности, которые могут приводить к блокированию приостановки системы (epoll(7) EPOLLWAKEUP, /proc/sys/wake_lock).
CAP_CHOWN Позволяет выполнять произвольные изменения файловых UID и GID (смотрите chown(2)).
CAP_DAC_OVERRIDE Позволяет пропускать проверки доступа к файлу на чтение, запись и выполнение (DAC (discretionary access control) — избирательный контроль доступа).
CAP_DAC_READ_SEARCH
CAP_FOWNER
CAP_FSETID Позволяет не очищать биты режима set-user-ID и set-group-ID при изменении файла; устанавливать бит set-group-ID на файл, у которого GID не совпадает с битом файловой системы или любыми дополнительными GID вызывающего процесса.
CAP_IPC_LOCK Позволяет блокировать память (mlock(2), mlockall(2), mmap(2), shmctl(2)).
CAP_IPC_OWNER Позволяет не выполнять проверки доступа для операций с объектами System V IPC.
CAP_KILL Позволяет не выполнять проверки при отправке сигналов (смотрите kill(2)). Сюда относится использование ioctl(2) с операцией KDSIGACCEPT.
CAP_LEASE (начиная с Linux 2.4) Позволяет устанавливать аренду на произвольные файлы (смотрите fcntl(2)).
CAP_LINUX_IMMUTABLE Позволяет устанавливать inode-флаги FS_APPEND_FL и FS_IMMUTABLE_FL (смотрите chattr(1)).
CAP_MAC_ADMIN (начиная с Linux 2.6.25) Позволяет замещать мандатный контроль доступа (MAC). Реализован в Smack Linux Security Module (LSM).
CAP_MAC_OVERRIDE (начиная с Linux 2.6.25) Разрешает изменять настройку MAC или состояние. Реализован в Smack LSM.
CAP_MKNOD (начиная с Linux 2.4) Позволяет создавать специальные файлы с помощью mknod(2).
CAP_NET_ADMIN Позволяет выполнять различные сетевые операции:
CAP_NET_BIND_SERVICE Позволяет привязывать сокет к привилегированным портам домена интернета (номера портов меньше 1024).
CAP_NET_BROADCAST (не используется) Позволяет осуществлять широковещание с сокета и прослушивание многоадресных рассылок.
CAP_NET_RAW
CAP_SETGID Позволяет выполнять произвольные действия с GID процесса и списком дополнительных GID; подделывать GID при передаче мандатов сокета через доменные сокеты UNIX; записывать отображение ID группы в пользовательское пространство имён (смотрите user_namespaces(7)).
CAP_SETFCAP (начиная с Linux 2.6.24) Позволяет назначать файловые мандаты.
CAP_SETPCAP Если файловые мандаты не поддерживаются: позволяет предоставлять и отзывать любой мандат в списке разрешённых мандатов вызывающего или любого другого процесса (это свойство CAP_SETPCAP недоступно, если ядро собрано с поддержкой файловых мандатов, так как CAP_SETPCAP имеет полностью другую семантику у таких ядер).
Если файловые мандаты поддерживаются: позволяет добавлять любой мандат из ограничивающего набора вызывающей нити в её наследуемый набор; отзывать мандаты из ограничивающего набора (с помощью prctl(2) с операцией PR_CAPBSET_DROP); изменять флаги securebits.
CAP_SETUID Позволяет выполнять произвольные действия с UID процесса (setuid(2), setreuid(2), setresuid(2), setfsuid(2)); подделывать UID при передаче мандатов сокета через доменные сокеты UNIX; записывать отображение ID пользователя в пользовательское пространство имён (смотрите user_namespaces(7)).
CAP_SYS_ADMIN
CAP_SYS_BOOT Позволяет использовать reboot(2) и kexec_load(2).
CAP_SYS_CHROOT Позволяет использовать chroot(2).
CAP_SYS_MODULE Позволяет загружать и выгружать модули ядра (смотрите init_module(2) и delete_module(2)); в ядрах до версии 2.6.25: позволяет отзывать мандаты из системного ограничивающего набора мандатов.
CAP_SYS_NICE
CAP_SYS_PACCT Позволяет использовать acct(2).
CAP_SYS_PTRACE
CAP_SYS_RAWIO
CAP_SYS_RESOURCE
CAP_SYS_TIME Позволяет настраивать системные часы (settimeofday(2), stime(2), adjtimex(2)) и часы реального времени (аппаратные).
CAP_SYS_TTY_CONFIG Позволяет использовать vhangup(2); задействовать различные привилегированные операции ioctl(2) с виртуальными терминалами.
CAP_SYSLOG (начиная с Linux 2.6.37)
CAP_WAKE_ALARM (начиная с Linux 3.0) Позволяет вызывать что-либо при пробуждении системы (устанавливать таймеры CLOCK_REALTIME_ALARM и CLOCK_BOOTTIME_ALARM).
Старая и текущая реализации
Для полной реализации мандатов требуется:1. Для всех привилегированных операций ядро должно проверять, имеет ли нить требуемый мандат в его эффективном наборе.
2. Ядро должно предоставлять системные вызовы, позволяющие получать и изменять наборы мандатов нити.
3. Файловая система должна поддерживать присоединение мандатов к исполняемому файлу для того, чтобы при исполнении файла у процесса повышались права согласно этим мандатам.
До ядра версии 2.6.24 были реализованы только первые два пункта; начиная с версии 2.6.24 реализованы все три пункта.
Наборы мандатов нити
Каждая нить имеет три набора мандатов, содержащих ноль или более перечисленных выше мандатов:Permitted: Ограничивающий набор эффективных мандатов, которыми наделяется нить. Этот набор также ограничивает список мандатов, которые могут быть добавлены в наследуемый набор для нити, которая не имеет мандата CAP_SETPCAP в своём эффективном наборе.
Если нить сбрасывает мандат в своём разрешительном наборе, то она не сможет получить его назад (если только не выполняется execve(2) для программы с set-user-ID-root или программа, чьи соответствующие мандаты файла предоставляют этот мандат).
Inheritable: Этот набор мандатов сохраняется при вызове execve(2). Наследуемые мандаты остаются наследуемыми при выполнении любой программы, и наследуемые мандаты добавляются в разрешительный набор, если выполняющаяся программа имеет соответствующие установленные биты в файловом наследуемом наборе. Так как наследуемые мандаты, обычно, не сохраняются после execve(2), если выполнение происходит не от суперпользователя, то для приложений, которым нужно выполнять вспомогательные программы с повышенными мандатами, нужно использовать наружные мандаты (ambient capabilities), описанные ниже.
Effective: Данный набор мандатов используется ядром при выполнении проверок прав нити.
Ambient (начиная с Linux 4.3): Данный набор мандатов сохраняется после execve(2) для непривилегированных программ. Для набора наружных мандатов (ambient capability set) соблюдается правило, что ни один мандат не сможет быть наружным, если он одновременно разрешающий и наследуемый.
Набор наружных мандатов можно непосредственно изменять с помощью prctl(2). Наружные мандаты автоматически понижаются, если понижаются соответствующие разрешительные или наследуемые мандаты.
У выполняющейся программы, у которой изменились UID или GID из-за бит set-user-ID или set-group-ID, или у выполняющейся программы установлен любой набор файловых мандатов,очищается наружный набор. Наружные мандаты добавляются в разрешающий набор и назначаются в эффективный набор при вызове execve(2).
Потомок, созданный fork(2), наследует копии наборов мандатов своего родителя. Далее смотрите описание отношения к мандатами при execve(2).
С помощью capset(2) нить может изменять свои наборы мандатов (смотрите далее).
Начиная с Linux 3.2, файл /proc/sys/kernel/cap_last_cap содержит числовое значение самого большого мандата, поддерживаемого работающим ядром; это может быть использовано для определения наибольшего бита, который может быть установлен в наборе мандатов.
Файловые мандаты
Начиная с ядра версии 2.6.24, поддерживается связь наборов мандатов с исполняемым файлом с помощью setcap(8). Наборы мандатов файла хранятся в расширенном атрибуте (смотрите setxattr(2)) с именем security.capability. Для записи в этот расширенный атрибут требуется мандат CAP_SETFCAP. Наборы файловых мандатов вместе с наборами мандатов нити определяют наборы мандатов нити после выполнения execve(2).Три файловых набора мандатов:
Permitted (ранее называвшийся forced): Эти мандаты автоматически разрешаются нити независимо от унаследованных мандатов нити.
Inheritable (ранее называвшийся allowed): Этот набор объединяется (AND) с унаследованным набором нити для определения, какие унаследованные мандаты будут включены в разрешительный набор нити после execve(2).
Effective: В действительности, это не набор, а одиночный бит. Если бит включён, то при вызове execve(2) все новые разрешённые мандаты нити будут также добавлены в эффективный набор. Если бит выключен, то после execve(2) ни один из новых разрешённых мандатов не будет добавлен в новый эффективный набор.
Включение эффективного файлового мандатного бита подразумевает, что любой файловый разрешительный или наследуемый мандат, который позволяет нити получить соответствующий разрешительный мандат при execve(2) (смотрите правила преобразования, описанные далее), также получит этот мандат в эффективном наборе. Поэтому, когда назначаются мандаты файлу (setcap(8), cap_set_file(3), cap_set_fd(3)), если мы укажем эффективный флаг как включённый для любого мандата, то эффективный флаг должен также быть указан включённым для всех остальных мандатов, для которых включён соответствующий разрешительный или наследуемый флаги.
Преобразование мандатов при execve()
При execve(2) ядро вычисляет новые мандаты процесса по следующему алгоритму:
P'(ambient) = (привилегированный файл) ? 0 : P(ambient) P'(permitted) = (P(inheritable) & F(inheritable)) | (F(permitted) & cap_bset) | P'(ambient) P'(effective) = F(effective) ? P'(permitted) : P'(ambient) P'(inheritable) = P(inheritable) [т. е., не изменяется]где:
P значение набора мандатов нити до execve(2)
P' значение набора мандатов после execve(2)
F файловый набор мандатов
cap_bset значение ограничивающего набора мандатов (описано далее).
Привилегированный файл — это файл, имеющий мандаты или для него установлен бит set-user-ID или set-group-ID.
Мандаты и выполнение программы с правами root
Чтобы предоставить всю мощь набора мандатов root в execve(2):1. Если выполняется программа с установленным битом set-user-ID-root, или ID реального пользователя процесса равен 0 (root), то предоставляются полные файловые и наследуемые наборы мандатов (т. е., разрешены все мандаты).
2. Если выполняется программа с установленным битом set-user-ID-root, то эффективный файловый бит равен единице (установлен).
Результат вышеупомянутых правил, объединённых с преобразованиями мандатов описанными выше, таков: когда процесс выполняет execve(2) для программы с битом set-user-ID-root, или когда процесс с эффективным UID 0 выполняет execve(2), то он получает все мандаты из разрешительного и эффективного наборов, за исключением тех, которые отменены ограничивающим набором мандатов. Это предоставляет семантику, совпадающую с обычными системами UNIX.
Ограничивающий набор мандатов
Ограничивающий набор мандатов — это механизм безопасности, который можно использовать для ограничения мандатов, которые могут быть получены при execve(2). Ограничивающий набор используется так:Заметим, что ограничивающий набор скрывает файловые разрешительные мандаты, но не наследуемые мандаты. Если нить имеет мандат в своём наследуемом наборе, который отсутствует в ограничивающем наборе, то она по-прежнему обладает этим мандатом в своём разрешительном наборе при выполнении файла, который имеет мандат в своём наследуемом наборе.
В зависимости от версии ядра ограничивающий набор мандатов является либо системным свойством, либо атрибутом процесса.
Ограничивающий набор мандатов до Linux 2.6.25
В ядрах до версии 2.6.25 ограничивающий набор мандатов был системным атрибутом, который влиял на все нити системы. Ограничивающий набор доступен через файл /proc/sys/kernel/cap-bound (по непонятной причине, данный параметр, битовая маска, в /proc/sys/kernel/cap-bound записывался в виде знакового десятичного числа).
Только процесс init может задавать мандаты в ограничивающем наборе мандатов; помимо этого, суперпользователь (точнее, программы с мандатом CAP_SYS_MODULE) могут только удалять мандаты из набора.
В стандартной системе в ограничивающем наборе мандатов всегда удаляется мандат CAP_SETPCAP. Чтобы убрать это ограничение (опасно!), нужно изменить определение CAP_INIT_EFF_SET в include/linux/capability.h и пересобрать ядро.
Системное свойство, ограничивающий набор мандатов, было добавлено в ядро Linux версии 2.2.11.
Ограничивающий набор мандатов начиная с Linux 2.6.25
Начиная с Linux 2.6.25, ограничивающий набор мандатов является атрибутом нити (системного ограничивающего набора мандатов больше нет).
Ограничивающий набор наследуется при fork(2) от нити родителя и сохраняется при execve(2).
Нить может удалять мандаты из своего ограничивающего набора мандатов с помощью вызова prctl(2) с операцией PR_CAPBSET_DROP при наличии мандата CAP_SETPCAP. После удаления мандата из ограничивающего набора обратно его восстановить невозможно. Нить может определить наличие мандата в своём ограничивающем наборе с помощью вызова prctl(2) с операцией PR_CAPBSET_READ.
Удаление мандатов из ограничивающего набора доступно только, если ядро собрано с поддержкой файловых мандатов. В ядре Linux до версии 2.6.33 файловые мандаты являлись необязательным свойством, настраиваемым параметром CONFIG_SECURITY_FILE_CAPABILITIES. Начиная с Linux 2.6.33, параметр настройки был удалён и теперь файловые мандаты всегда являются частью ядра. Когда файловые мандаты в ядре, процесс init (предок всех процессов) запускается с полным ограничивающим набором. Если файловые мандаты не добавлены в ядро, то init запускается с полным ограничивающим набором минус CAP_SETPCAP, так как этот мандат имеет другое значение, если файловые мандаты отсутствуют.
Удаление мандата из ограничивающего набора не удаляет его из наследуемого набора нити. Однако это предотвращает от добавления мандата обратно в наследуемый набор нити в будущем.
Влияние на мандаты при изменении пользовательского ID
Для сохранения привычной семантики при переходе от 0 к ненулевым пользовательским ID, ядро делает следующие изменения наборов мандатов нити при изменении у нити реального, эффективного, сохранённого ID и пользовательского ID файловой системы (с помощью setuid(2), setresuid(2) или подобных):1. Если ранее реальный, эффективный или сохранённый пользовательский ID не был равен 0, и в результате изменения UID все эти ID получили ненулевое значение, то все мандаты удаляются из разрешительного и эффективного наборов мандатов.
2. Если эффективный пользовательский ID изменяется с 0 на ненулевое значение, то все мандаты удаляются из эффективного набора мандатов.
3. Если эффективный пользовательский ID изменяется с ненулевого значения на 0, то разрешительный набор копируется в эффективный набор.
4. Если пользовательский ID файловой системы изменяется с 0 на ненулевое значение (смотрите setfsuid(2)), то следующие мандаты удаляются из эффективного набора: CAP_CHOWN, CAP_DAC_OVERRIDE, CAP_DAC_READ_SEARCH, CAP_FOWNER, CAP_FSETID, CAP_LINUX_IMMUTABLE (начиная с Linux 2.6.30), CAP_MAC_OVERRIDE и CAP_MKNOD (начиная с Linux 2.6.30). Если пользовательский ID файловой системы изменяется с ненулевого значения на 0, то любой из мандатов, включённых в разрешительный набор, включается в эффективном наборе.
Если нить, у которой один или более пользовательских ID равно 0, хочет предотвратить удаление разрешительных мандатов при сбросе всех пользовательских ID в ненулевые значения, то она может использовать вызов prctl(2) с операцией PR_SET_KEEPCAPS или флагом безопасности SECBIT_KEEP_CAPS, описанном далее.
Программное изменение наборов мандатов
Нить может получать и изменять свои наборы мандатов с помощью системных вызовов capget(2) и capset(2). Однако для этой цели лучше использовать cap_get_proc(3) и cap_set_proc(3) из пакета libcap. Следующие правила применяются при изменении наборов нити:1. Если вызывающий не имеет мандата CAP_SETPCAP, то новый наследуемый набор должен быть поднабором комбинации существующего наследуемого и разрешительного наборов.
2. (начиная с Linux 2.6.25) Новый наследуемый набор должен быть поднабором комбинации существующего наследуемого и ограничивающего наборов.
3. Новый разрешительный набор должен быть поднабором существующего разрешительного набора (т. е., невозможно приобрести разрешительные мандаты, которых нить не имеет).
4. Новый эффективный набор должен быть поднабором нового разрешительного набора.
Флаги securebits: организация исключительно мандатного окружения
Начиная с ядра версии 2.6.26 с включённой поддержкой файловых мандатов, в Linux реализован набор флагов securebits (для каждой нити), который можно использовать для отключения специальных действий мандатов для UID 0 (root). К этим флагам относятся:SECBIT_KEEP_CAPS Установка этого флага позволяет нити, у которой один и более UID равен 0, сохранить свои мандаты при изменении всех её UID на ненулевые значения. Если этот флаг не установлен, то изменение UID приведёт к тому, что нить потеряет все мандаты. Этот флаг всегда сбрасывается при execve(2) (этот флаг предоставляет те же возможности, что и старый вызов prctl(2) с операцией PR_SET_KEEPCAPS).
SECBIT_NO_SETUID_FIXUP Установка этого флага не даёт ядру изменить наборы мандатов при изменении эффективного UID и UID файловой системы с 0 на ненулевое значение (смотрите раздел Влияние на мандаты от изменения пользовательского ID).
SECBIT_NOROOT Если этот бит установлен, то ядро не предоставляет мандаты при исполнении программы, имеющей бит set-user-ID-root, или когда процесс с эффективным или реальным UID равным 0 вызывает execve(2) (смотрите раздел Мандаты и выполнение программа от root).
SECBIT_NO_CAP_AMBIENT_RAISE Установка этого флага запрещает повышение наружных мандатов посредством prctl(2)с операцией PR_CAP_AMBIENT_RAISE.
Каждый из перечисленных выше «базовых» флагов имеет дополнительный флаг «блокировки». Установка любого из флагов «блокировки» необратима и запрещает дальнейшие изменения соответствующего «базового» флага. Флаги блокировки: SECBIT_KEEP_CAPS_LOCKED, SECBIT_NO_SETUID_FIXUP_LOCKED, SECBIT_NOROOT_LOCKED и SECBIT_NO_CAP_AMBIENT_RAISE.
Флаги securebits можно изменять и получать с помощью вызова prctl(2) с операциями PR_SET_SECUREBITS и PR_GET_SECUREBITS. Для изменения флагов требуется мандат CAP_SETPCAP.
Флаги securebits наследуются дочерними процессами. При execve(2) все флаги сохраняются, за исключением SECBIT_KEEP_CAPS, который всегда сбрасывается.
Приложение может использовать следующий вызов для собственной блокировки и помещение всех своих потомков в окружение, в котором есть только один способ добавить права — запустить программу со связанными с ней файловыми мандатами:
prctl(PR_SET_SECUREBITS, SECBIT_KEEP_CAPS_LOCKED | SECBIT_NO_SETUID_FIXUP | SECBIT_NO_SETUID_FIXUP_LOCKED | SECBIT_NOROOT | SECBIT_NOROOT_LOCKED);
Взаимодействие с пользовательскими пространствами имён
Обсуждение связи мандатов с пространствами пользователя смотрите в user_namespaces(7).
СООТВЕТСТВИЕ СТАНДАРТАМ
Стандарты, описывающие мандаты, отсутствуют, но реализация мандатов в Linux основывается на изъятом черновике стандарта POSIX.1e; смотрите
ЗАМЕЧАНИЯ
Начиная с ядра версии 2.5.27 по 2.6.26, мандаты являются необязательным
компонентом ядра, и могут быть включены/выключены с помощью параметра
настройки ядра CONFIG_SECURITY_CAPABILITIES.
Файл /proc/PID/task/TID/status можно использовать для просмотра набора мандатов нити. В файле /proc/PID/status отражён набор мандатов главной нити процесса. До Linux 3.8, несуществующие мандаты в этих наборах показывались как включённые (1). Начиная с Linux 3.8, все несуществующие мандаты (после CAP_LAST_CAP) показываются выключенными (0).
В пакете libcap содержится набор процедур для установки и получения
мандатов; он удобнее и менее подвержен изменениям, чем интерфейс
предоставляемый capset(2) и capget(2). Также данный пакет
предоставляет программы setcap(8) и getcap(8) . Его можно найти здесь:
До ядра версии 2.6.24, и начиная с версии 2.6.24 по 2.6.32, если файловые мандаты не включены, то нить с мандатом CAP_SETPCAP может управлять мандатами других нитей. Однако, это возможно только теоретически, так как ни одна из нитей не имеет CAP_SETPCAP в любом из двух случаев: