ugidctl — модуль apache2

Весь предыдущий код, который я написал для ядра не имеет смысла, если не будет реального применения в userspace-окружении. Как можно дагадаться из всей идеи, основное применение — это apache. У него достаточно гибкая архитектура, которая позволила мне написать весь функционал для работы с ugidctl в виде модуля. Название соответствующее — mod_ugidctl

Аналогично модулю ядра, я упаковал его в rpm’ки для el6/el7

CentOS6 / RHEL6 (x86_64 only)

CentOS7 / RHEL7

Теперь можно делать в конфигурации apache вот так:

А на файловой системе вот так:


Список процессов при работе будет выглядель примерно так:

В этом примере pid’ы 14230, 14298 и 14302 обрабатывают запросы соответствующих хостов.

Совместимость
Модуль спроектирован для работы с MPM prefork. Не запускайте его для других MPM.

Безопасность
Модуль открывает /dev/ugidctl и конфигурирует его из основного процесса, который работает под root’ом. Открытый файловый дескриптор оставляет всем своим дочерним процессам, которые непосредственно обрабатывают запросы. Также во время конфигурации основной процесс получает от модуля ядра случайный ключ для доступа к функциям UGIDCTL_SETUID / UGIDCTL_SETGID / UGIDCTL_SETGROUPS. Этот ключ хранится в памяти как основного процесса, так и всех дочерних. Теоретически, во время обработки запроса зловредный код может найти этот ключ и начать «гулять» по всем uid’ам и gid’ам, которые описаны в файле конфигурации apache. На практике достать этот ключ так-же сложно, как и найти загруженные приватные ключи модуля mod_ssl.

Отдельное внимание надо уделить многопоточности. В linux у каждой нити собственные права. Поэтому, glibc, например, для совместимости с POSIX, использует достаточно сложный алгоритм при вызове setuid(2) / setgid(2) / setgroups(2), который гарантирует всем нитям процесса работу с одинаковыми правами. Мой модуль практически напрямую пользуется системными вызовами в обход glibc, поэтому меняется пользователь только основной нити. Из этого следует, что если во время обработки запроса будет запущена новая нить и не остановлена перед его завершением, она может достаться другому пользователю «как есть», т.е. с правами процесса, которые он имел во время её запуска. Следует избегать использования многопоточных приложений при обработке запросов.

Масштабируемость
Масштабируется аналогично простому apache2. После обработки запроса процесс не убивает себя, а возвращает себе привилегии основного пользователя и ждет нового запроса. Единственное ограничение — встроенные лимиты на количество пользователей и групп в модуле ядра. При написании модуля я выбрал их достаточно большими — чуть больше 1-го миллиона uid’ов и gid’ов (1048576).

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *