Проблема этой структуры заключается в ее недостаточной гибкости. Если мы хотим разрешить процессу некоторые операции, доступные только администратору (например, изменять системное время), нам придется запускать его с действующим идентификатором равным 0 (если пользователю нужно выполнить такие операции, для этого обычно приходится устанавливать UID администратора). Однако этим мы позволяем процессу выполнять целый ряд других действий — например, обходить любые проверки прав доступа при работе с файлами. Тем самым мы рискуем создать дыру в безопасности, если программа начнет вести себя непредсказуемо (из-за непредвиденных обстоятельств или как следствие целенаправленных действий злоумышленника). Традиционный способ борьбы с этой проблемой был описан в предыдущей главе: мы отказываемся от действующих привилегий (то есть меняем действующий идентификатор пользователя, равный 0, на какой-то другой, сохраняя его на будущее) и временно их возвращаем, когда они нужны.
Система возможностей Linux позволяет решать эту задачу с большей точностью. Вместо того чтобы использовать сразу все привилегии администратора (пользователя с идентификатором 0), выполняя проверки безопасности на уровне ядра, мы разделяем их на отдельные категории, которые называются возможностями. Каждая привилегированная операция связывается с определенной возможностью и доступна для выполнения только в том случае, если эта возможность присутствует у текущего процесса (независимо от действующего UID). Иными словами, когда в этой книге говорится о привилегированном процессе, речь идет о наличии у него возможностей, подходящих для выполнения определенной операции.
Большую часть времени система возможностей Linux работает незаметно для пользователей. Дело в том, что в программе, которая рассчитывает получить нулевой пользовательский идентификатор, выдается полный набор возможностей, даже если она о них не подозревает.
Реализация возможностей в Linux основана на проекте стандарта POSIX 1003.1e (http://wt.tuxomania.net/publications/posix.1e/). Эта инициатива не была доведена до логического завершения, провалившись еще в конце 1990-х, но предварительное описание стандарта, которое она породила, стало фундаментом для различных систем управления возможностями (некоторые возможности, перечисленные в табл. 39.1, являются частью проекта стандарта POSIX.1e, но в большинстве своем это расширения, появившиеся в Linux).
Системы возможностей присутствуют и в нескольких других реализациях UNIX — например, в Solaris 10 компании Sun и в более ранних версиях Trusted Solaris, таких как Trusted Irix компании SGI и как часть проекта TrustedBSD для FreeBSD ([Watson, 2000]). Аналогичные механизмы существуют и в других операционных системах; например, похожим образом организованы привилегии в системе VMS компании Digital.
В табл. 39.1 перечислены возможности, доступные в Linux, а также краткое (неполное) описание операций, к которым они относятся.
Каждый процесс имеет три набора возможностей:
39.3.1. Возможности процесса
Для каждого процесса ядро предоставляет три набора возможностей (реализованных в виде битовых масок).
•
•
Каждый из трех наборов возможностей для каждого процесса представлен в шестнадцатеричном виде в файле /proc/PID/status (поля CapInh, CapPrm и CapEff).
Программа getpcap (которая входит в пакет libcap, описанный в разделе 39.7) позволяет вывести возможности процесса в удобном для чтения формате.
Дочерний процесс, созданный с помощью вызова fork(), наследует копии возможностей своего родителя. То, как наследуются возможности во время выполнения exec(), будет описано в разделе 39.5.