Удивительно, но факт: mod_ugidctl + ugidctl всё ещё компилируются и работают на fedora 23
1 2 3 4 |
[root@localhost ~]# rpm -q httpd httpd-2.4.18-1.fc23.x86_64 [root@localhost ~]# rpm -q kernel kernel-4.5.6-200.fc23.x86_64 |
Удивительно, но факт: mod_ugidctl + ugidctl всё ещё компилируются и работают на fedora 23
1 2 3 4 |
[root@localhost ~]# rpm -q httpd httpd-2.4.18-1.fc23.x86_64 [root@localhost ~]# rpm -q kernel kernel-4.5.6-200.fc23.x86_64 |
Весь предыдущий код, который я написал для ядра не имеет смысла, если не будет реального применения в userspace-окружении. Как можно дагадаться из всей идеи, основное применение — это apache. У него достаточно гибкая архитектура, которая позволила мне написать весь функционал для работы с ugidctl в виде модуля. Название соответствующее — mod_ugidctl
Аналогично модулю ядра, я упаковал его в rpm’ки для el6/el7
CentOS6 / RHEL6 (x86_64 only)
1 2 3 |
# cd /etc/yum.repos.d # wget https://ibuffed.com/pub/repo/el6/ibuffed-com.repo # yum install mod_ugidctl |
CentOS7 / RHEL7
1 2 3 |
# cd /etc/yum.repos.d # wget https://ibuffed.com/pub/repo/el7/ibuffed-com.repo # yum install mod_ugidctl |
Теперь можно делать в конфигурации apache вот так:
1 2 3 4 5 6 7 8 9 10 11 12 |
<VirtualHost *:80> ServerName host1.example.com ServerAdmin webmaster1@example.com ServerUserGroup user1 group1 DocumentRoot /var/www/host1 </VirtualHost> <VirtualHost *:80> ServerName host2.example.com ServerAdmin webmaster2@example.com ServerUserGroup user2 group2 DocumentRoot /var/www/host2 </VirtualHost> |
А на файловой системе вот так:
1 2 3 4 5 6 |
# ls -la /var/www total 16 drwxr-xr-x 4 root root 4096 Oct 27 16:10 . drwxr-xr-x. 21 root root 4096 Oct 26 01:13 .. drwxr-x--- 2 user1 group1 4096 Oct 27 16:10 host1 drwxr-x--- 2 user1 group2 4096 Oct 27 16:10 host2 |
Для удобства использования модуля, я собрал его в rpm’ки для el6/el7.
CentOS6 / RHEL6 (x86_64 only)
1 2 3 4 |
# cd /etc/yum.repos.d # wget https://ibuffed.com/pub/repo/el6/ibuffed-com.repo # yum install kmod-ugidctl # modprobe ugidctl |
CentOS7 / RHEL7
1 2 3 4 |
# cd /etc/yum.repos.d # wget https://ibuffed.com/pub/repo/el7/ibuffed-com.repo # yum install kmod-ugidctl # modprobe ugidctl |
Теперь я буду собирать все элементы мозаики в кучу. Отдельного внимания разве что стоит механизм, которым я буду разрешать ядру переключать uid/gid или дополнительные группы, если мои проверки прошли успешно, но процесс непривелигерован. План такой:
Пора придумать как хранить списки uid’ов и gid’ов в ядре. Из основных особенностей этих списков должны быть следующие:
В голову сразу приходят двоичные деревья. У обычных есть куча недостатков, таких как практически линейный поиск, если заполнять их отсортированными элементами. Ядро linux явно уже содержит какую-нибудь более эффективную реализацию двоичных деревьев, ею и воспользуюсь. Это красно-черные деревья. Подробней можно причитать тут.
Тем временем для хранения узлов деревьев нужно будет динамически выделять и освобождать небольше куски памяти ядра. Они у меня все будут одинакового размера.
Читать далее
В прошлом посте я уже сделал небольшой модуль ядра, который при инициализации находит адреса обработчиков системных вызовов setuid(2), setgid(2) и setgroups(2). Пора в него добавить средства коммуникации с usersapce окружением. Выбор механизмов достаточно широк, но я решил решил остановиться на старом и добром ioctl(2). Он позволяет передавать адрес буфера с данными при вызове и возвращать статус операции в виде int’а. Назову char-device соответственно — /dev/ugidctl.
Теперь пора придумать протокол общения userspace-окружения с ядром. Разделю его на 2 части. Первые несколько вызовов будут работать когда вызывающий процесс обладает правами рута, т.е. в моем случае «взведены» CAP_SETUID и CAP_SETGID. Эти вызовы будут инициализировать список uid’ов и gid’ов, между которыми процесс сможет свободно переключаться, будучи непривилегированным. Остальная часть вызовов будет непосредственно проверять права и обращаться к sys_setuid, sys_setgid и sys_setgroups. В качестве дополнительной защиты введу случайный ключ, который процесс может получить только во время стадии инициализации ugidctl и будет обязан предоставлять в процессе переключения при каждом вызове. Также ограничу процессы, которые могут совершать переключения проверкой PID’а (идентификатора процесса), PGID’а (идентификатора группы процессов) или SID’а (идентификатора сессии), потому как открытый файловый дескриптор моего устройства процесс может намеренно или случайно передать другому.
Читать далее
Всем привет!
Буду делать механизм, позволяющий в userspace одному процессу относительно безопасно прыгать между заранее определенными uid’ами и gid’ами.
Должно выйти что-то типа такого:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
int main(void) { uid_t uids[] = {99,1000,1001,1002,1003}; /* root */ allow_setuid(5, uids); /* nobody */ setuid(99); while (1) { // ... /* user1002 */ setuid(1002); // ... /* back to nobody */ setuid(99); } return 0; } |
К сожалению CAP_SETUID/CAP_SETGID не позволяют ограничить список пользователей, поэтому буду делать модуль ядра.
Читать далее