Linux программирование в примерах
11.7. Работа со всеми тремя ID:
иgetresuid()(Linux)setresuid()Linux предоставляет дополнительные системные вызовы, посредством которых вы можете непосредственно работать с действительными, эффективными и сохраненными ID пользователя и группы:
#include <sys/types.h> /* Linux */#include <unistd.h>int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid);int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid);int setresuid(uid_t ruid, uid_t euid, uid_t suid);int setresgid(gid_t rgid, gid_t egid, gid_t sgid);Функции следующие:
int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid)Получает значения действительного, эффективного и сохраненного set-user ID. Возвращаемое значение 0 в случае успеха и -1 при ошибке,
указывает проблему.errnoint getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid)Получает значения действительного, эффективного и сохраненного set-group ID. Возвращаемое значение 0 в случае успеха и -1 при ошибке,
обозначает проблему.errnoint setresuid(uid_t ruid, uid_t euid, uid_t suid)Устанавливает значения действительного, эффективного и сохраненного set-user ID соответственно. Когда значение параметра равно -1, соответствующий UID остается без изменения.
Когда процесс действует как
, параметрами могут быть любые произвольные значения. Однако, использование ненулевого значения дляrootвызывает постоянную, безвозвратную утерю привилегииeuid). В противном случае параметры должны быть одним из значений действительного, эффективного или сохраненного set-user ID.rootint setresgid(gid_t rgid, gid_t egid, gid_t sgid)Устанавливает значения действительного, эффективного и сохраненного set-group ID соответственно. Когда значение параметра равно -1, соответствующий GID остается без изменений.
Эта функция аналогична
.setresuid()Функции
иsetresuid()особенно ценны, поскольку их семантика ясно определена. Программист точно знает, каким может быть результат их вызова.setresgid()Более того, вызовы являются операциями типа «все или ничего»: они либо полностью успешны в осуществлении нужного изменения, либо терпят полную неудачу, оставляя текущее состояние как есть. Это повышает надежность, поскольку, опять-таки можно быть точно уверенным в том, что случилось.
11.8. Пересечение минного поля безопасности: setuid
rootНастоящие минные поля трудно, но не невозможно перейти. Однако, это не является чем-то, что можно сделать легко, без тренировки или опыта
Точно также написание программ, которые используют setuid
, является трудной задачей. Имеется много, очень много проблем, о которых нужно знать, и почти все может иметь неожиданные последствия в плане безопасности. Такая попытка должна предприниматься очень осторожно.rootВ частности, стоит специально изучить проблемы безопасности Linux/Unix и потратить время на обучение написанию программ setuid root. Если вы сразу нырнете в эту проблему, прочитав лишь эту книгу и ничего более, можно быть уверенным, что ваша система будет взломана, легко и сразу. Маловероятно, что вы или ваши клиенты будут довольны.
Вот несколько руководящих принципов:
• Как можно меньше действуйте в качестве
. Скупо используйте свои чрезвычайные полномочия, лишь тогда, когда это абсолютно необходимоroot• Соответствующим образом проектируйте свою программу. Разделите программу на составные части таким образом, чтобы все операции
были выполнены заранее, а оставшаяся программа работала в качестве обычного пользователя.root• При изменении или сбрасывании привилегий используйте
, если она у вас есть. В противном случае используйтеsetresuid()поскольку у этих функций самая чистая семантика. Используйтеsetreuid(),, лишь когда вы хотите сделать постоянное изменение.setuid()• Переходите от
к обычному пользователю в соответствующем порядке: сначала установите набор групп и значения GID, затем значения UID. Будьте особенно осторожны сrootиfork(); действительные и эффективные UID при их вызове не изменяются, если вы не измените их явным образом.exec()• Рассмотрите использование прав доступа setgid и особой группы для вашего приложения. Если это будет работать, это убережет вас от большой головной боли.
• Рассмотрите отказ от наследуемого окружения. Если вам нужно сохранить некоторые переменные окружения, сохраните как можно меньше. Убедитесь в предоставлении подходящих значений для переменных окружения
иPATH.IFS• Избегайте
иexeclp(), которые зависят от значения переменной окруженияexecvp()(хотя это менее проблематично, если вы сами восстанавливаетеPATH).PATHЭто просто некоторые из множества тактик по пересечению опасной зоны, известной своими подвохами, минами-ловушками и фугасами. Ссылки на другие источники информации см. в следующем разделе.
11.9. Рекомендуемая литература
Безопасность Unix (а следовательно, и GNU/Linux) является темой, требующей знаний и опыта для того, чтобы справиться с ней должным образом. В Эпоху Интернета она стала лишь труднее, не проще.
1. Practical UNIX & Internet Security, 3rd edition, by Simson Garfinkel, Gene Spafford, and Alan Schwartz, O'Reilly & Associates, Sebastopol, CA, USA, 2003. ISBN: 0-596-00323-4.
Это стандартная книга по безопасности Unix.
2. Building Secure Software. How to Avoid Security Problems the Right Way, by John Viega and Gary McGraw. Addison-Wesley, Reading, Massachusetts, USA, 2001. ISBN: 0-201-72152-X.
Это хорошая книга по написанию безопасного программного обеспечения, она включает проблемы setuid. Предполагается, что вы знакомы с основными API Linux/Unix; к моменту прочтения данной книги вы должны быть готовы к ее прочтению.
3. "Setuid Demystified," by Hao Chen, David Wagner, and Drew Dean. Proceedings of the 11th USENIX Security Symposium, August 5–9, 2002 http://www.cs.berkeley.edu/~daw/papers/setuid-usenix02.pdf.
Гарфинкель, Спаффорд и Шварц (Garfinkel, Spafford, Schwartz) рекомендуют прочтение этого материала «до того, как вы даже подумаете о написании кода, который пытается сохранять и восстанавливать привилегии». Мы всецело согласны с ними.
11.10. Резюме
• Использование значений ID пользователя и группы (UID и GID) для идентификации файлов и процессов — вот что превращает Linux и Unix в многопользовательские системы. Процессы имеют значения как действительных, так и эффективных UID и GID, а также набор дополнительных групп. Обычно именно эффективный UID определяет, как один процесс может повлиять на другой, и эффективные UID, GID и набор групп проверяются на соответствие с правами доступа к файлу. Пользователи с эффективным UID, равным нулю, известные как
или суперпользователи, могут делать все, что захотят; система не использует для такого пользователя проверку прав доступа.root