Аргумент mode является битовой маской, состоящей из одной или из нескольких констант, приведенных в табл. 15.5, которые объединены с помощью операции ИЛИ (|). Если все права доступа, указанные в данном аргументе, предоставлены файлу с именем пути pathname, то системный вызов access() возвращает 0; если недоступно хотя бы одно из запрашиваемых прав доступа (или если возникла ошибка), то системный вызов access() возвращает –1.
Таблица 15.5. Константы mode для системного вызова access()
Константа — Описание
F_OK — Существует ли файл?
R_OK — Можно ли читать файл?
W_OK — Можно ли записывать файл?
X_OK — Можно ли выполнять файл?
Наличие временного интервала между системным вызовом access() и последующей операцией над файлом означает следующее: нет никакой гарантии того, что информация, возвращенная системным вызовом access(), останется истинной к моменту выполнения операции (вне зависимости от того, насколько краток этот интервал). Такая ситуация может привести к возникновению брешей в системе безопасности ряда приложений.
Допустим, к примеру, что у нас есть команда установки бита set-user-ID-root, которая применяет системный вызов access() для проверки доступности файла программой, использующей реальный идентификатор пользователя и выполняющей операцию над файлом (например, open() или exec()), если он доступен.
Проблема заключается вот в чем: если передаваемое системному вызову access() имя пути является символической ссылкой, а злоумышленнику удается до начала второго этапа изменить данную ссылку так, чтобы она указывала на другой файл, то это может привести к тому, что команда set-user-ID-root будет работать с файлом, у которого нет прав доступа для реального идентификатора пользователя. (Это пример состояния соперничества, возникающего на основе значений времени проверки и времени использования, как сказано в разделе 38.6.) Исходя из вышесказанного рекомендуется всецело избегать применения системного вызова access() (см., например, работу [Borisov, 2005]). В только что приведенном примере мы можем осуществить это, временно изменив действующий (или относящийся к файловой системе) идентификатор пользователя для процесса set-user-ID, пытающегося выполнить желаемую операцию (например, open() или exec()), а затем проверить возвращенное значение и параметр errno, чтобы установить, не была ли связана ошибка выполнения операции с нарушением прав доступа.
GNU-библиотека C предлагает аналогичную нестандартную функцию euidaccess() (синонимичное название — eaccess()), которая проверяет права доступа к файлу с помощью действующего идентификатора пользователя для процесса.
15.4.5. Биты set-user-ID, set-group-ID и закрепляющий
Помимо девяти битов, служащих для указания прав доступа владельца, группы и остальных, маска прав доступа содержит три дополнительных бита, называемых
В ранних реализациях UNIX данный бит служил как средство более быстрого выполнения часто применяемых программ. Если он был установлен для файла программы, то при первом запуске копия ее текста сохранялась в области подкачки — закреплялась в ней и загружалась быстрее при последующих выполнениях. В современных реализациях UNIX системы управления памятью более сложные, и поэтому приведенный вариант использования закрепляющего бита устарел.
Имя константы для бита закрепления, которое приведено в табл. 15.4, S_ISVTX, происходит от его альтернативного названия «бит сохраненного текста» (saved-text).
В современных реализациях UNIX (включая также Linux) бит закрепления служит совершенно другой цели. Для каталогов он действует как флаг