Когда приложение выполняется с EUID отличным от его RUID, оно предоставляет
пользователю привилегии, которые ему нужны, но которых у него нет (доступ к
файлу, зарезервированный системный вызов...). Однако данные привелегии нужны
только на очень короткое время, например при открытии файла, в остальное время
приложение может выполняться с привилегиями своего пользователя. Возможно
временное изменение EUID приложения при помощи системного вызова:
int seteuid (uid_t uid);
Процесс всегда может поменять значение своего EUID и присвоить ему
значение RUID. В этом случае старый UID хранится в сохранном месте, называемом
SUID (Saved UID - сохраненный UID), не путать с SID (Session ID -
ID сессии), который используется для взаимодействия с управляющим
терминалом. Всегда возможно вернуть назад SUID в качестве EUID. Естественно,
программа с нулевым EUID (root) может менять по желанию как свой EUID
так и RUID (таким образом работает /bin/su).
Чтобы уменьшить риск атак, советуется менять EUID и использовать вместо него
RUID пользователя. Когда части кода требуются привилегии владельца файла,
возможно поместить сохраненный UID в EUID. Вот пример:
uid_t e_uid_initial;
uid_t r_uid;
int
main (int argc, char * argv [])
{
/* Сохраняем различные UID-ы */
e_uid_initial = geteuid ();
r_uid = getuid ();
/* Ограничиваем права доступа до прав пользователя,
* запустившего программу */
seteuid (r_uid);
...
privileged_function ();
...
}
void
privileged_function (void)
{
/* Возвращаем назад начальные привилегии */
seteuid (e_uid_initial);
...
/* Часть кода, которой нужны привилегии */
...
/* Назад к правам пользователя, запустившего программу */
seteuid (r_uid);
}
Данный метод намного безопаснее чем к сожалению общепринятый, состоящий в
использовании начального EUID, а затем к временному уменьшению привелегий перед
"рисковаными" операциями. Однако, данное уменьшение привилегий бесполезно при
атаках на переполнение буфера. Как мы увидим в следующей статье, эти атаки
пытаются заставить приложение выполнить свои инструкции, которые могут содержать
системные вызовы, нужные для повышения уровня привилегий. И все-таки данный
подход защищает от вызова внешних команд и большинства ситуаций перехвата.