реальный=1000 действующий=1000 сохраненный=200
Когда процесс выполняет непривилегированную программу, действующий UID процесса становится сохраненным, в результате чего значения пользовательских идентификаторов будут иметь такой вид:
реальный=1000 действующий=200 сохраненный=1000
Привилегированные программы, запущенные пользователем, никогда не должны запускать командную оболочку (напрямую или опосредованно, с помощью библиотечных функций system(), popen(), execlp(), execvp() и им подобных). Сложность и обширные возможности командных оболочек (и других многофункциональных интерпретаторов, таких как awk) делают практически невозможным устранение всех лазеек, связанных с безопасностью, даже если отключить интерактивный режим. Это, в свою очередь, дает возможность выполнять произвольные консольные команды от имени пользователя с действующим идентификатором процесса. Если вам необходимо запустить командную оболочку, заранее откажитесь от повышенных привилегий.
Пример бреши в безопасности, которая может возникнуть в результате запуска командной оболочки, приводится при описании функции system() в разделе 27.6.
Немногочисленные реализации UNIX учитывают биты с идентификаторами пользователя и группы, установленные для интерпретируемых скриптов (см. раздел 27.3); благодаря этому процесс, запускающий скрипт, исходит из того, что тот будет выполняться от имени какого-то другого (привилегированного) пользователя. Но ввиду рисков безопасности, описанных выше, Linux, как и некоторые другие UNIX-системы, просто игнорирует эти биты при выполнении скриптов. Но даже если система поддерживает установку UID и GID для скриптов, этой возможностью следует пренебрегать.
В разделе 27.4 отмечалось, что файловые дескрипторы по умолчанию остаются открытыми на протяжении всей работы вызова exec(). Привилегированная программа может открыть файл, недоступный обычным процессам. Полученный файловый дескриптор представляет привилегированный ресурс. Перед выполнением exec() он должен быть закрыт, чтобы запускаемая программа не смогла получить доступ к связанному с ним файлу. Для этого можно либо вручную закрыть файловый дескриптор, либо установить флаг FD_CLOEXEC (см. раздел 27.4).
Если программа считывает деликатную информацию (например, пароль), она должна удалить ее из памяти сразу же после выполнения всех необходимых задач (пример этого продемонстрирован в разделе 8.5). В противном случае могут возникнуть риски безопасности, проистекающие из следующих причин.
• Страница виртуальной памяти, содержащая данные, может быть сброшена на диск (если только она не была заблокирована с помощью вызова mlock() или аналогичного) и прочитана оттуда привилегированной программой.
• Процесс может сгенерировать файл с дампом памяти, получив соответствующий сигнал; этот файл может быть использован для получения данных.
Учитывая последний пункт, можно прийти к выводу, что безопасная программа в целом не должна генерировать дампы памяти, так как из них можно извлечь деликатную информацию. Для этого можно обнулить ограничение на ресурсы RLIMIT_CORE, воспользовавшись вызовом setrlimit() (см. раздел 36.3).
По умолчанию Linux не разрешает программе, устанавливающей пользовательский идентификатор, генерировать дамп памяти в ответ на сигнал (см. раздел 22.1), даже если она отказалась от всех привилегий. Однако в других системах этот элемент безопасности может отсутствовать.
В этом разделе мы рассмотрим различные способы изоляции программы, которые позволяют ограничить потенциальный ущерб в случае ее взлома.
В Linux существует система, позволяющая разделить традиционную для UNIX структуру привилегий («все или ничего») на отдельные элементы, которые называются
Кроме того, используя возможности в сочетании с