Наши партнеры

UnixForum





Библиотека сайта rus-linux.net

Лишение пользователя root привилегий

Оригинал: Making Root Unprivileged
Автор: Serge Hallyn
Дата публикации: 1 августа 2009 г.
Перевод: A.Панин
Дата перевода: 23 октября 2015 г.

Снижаем вероятность применения эксплоитов для приложений с битом setud в вашей системе путем лишения пользователя root привилегий.

Было время, когда для использования компьютера нужно было лишь включить его и дождаться приветствия командной оболочки. Сегодня же в большинстве операционных систем применяется модель безопасности на основе множества учетных записей пользователей. Обычно данные учетной записи, которые вы используете при входе в систему, обуславливают привилегии, которые будут иметь в рамках системы запущенные вами программы. Повседневные рабочие задачи могут вполне успешно решаться и при работе с учетной записью обычного пользователя, которая не предусматривает дополнительных привилегий, что позволяет минимизировать риски, связанные с ошибками пользователя, случайным исполнением вредоносного программного обеспечения, загруженного из сети Интернет и.т.д. Любая программа, которой требуются дополнительные привилегии в системе, должна быть запущена от лица привилегированного пользователя. В системах UNIX числовой идентификатор привилегированного пользователя root всегда равен 0. К сожалению, это означает, что любое приложение, которому требуется привилегии для выполнения лишь одного действия, может стать причиной компрометации всей системы в случае нарушения его работы или проведения успешной атаки на него.

Разрешения POSIX (POSIX capabilities) позволяют решить эту проблему в двух аспектах. Во-первых, они позволяют уйти от модели "все или никакие привилегии" путем предоставления набора семантически отличных привилегий. Это обстоятельство позволяет ограничить набор привилегий, доступных определенным задачам привилегиями, позволяющими, к примеру, создавать файлы устройств или отслеживать исполнение задач других пользователей.

Во-вторых, в случае использования рассматриваемых разрешений привилегии больше не будут связаны с идентификаторами пользователей. Вместо этого привилегии будут связаны с исполняемыми файлами (программами), на основе которых создаются процессы. В конечном счете, каждый пользователь, сидящий за клавиатурой компьютера, будет просто запускать все необходимые ему программы от своего имени. Эти программы, в свою очередь, будут выполнять какую-либо работу. А все программы в любом случае будут обслуживаться системным администратором, который может установить необходимые разрешения в зависимости от того, какие задачи выполняет та или иная программа, кто ее разработал и кто ее установил.

Механизм разрешений POSIX был реализован в рамках ядра Linux много лет назад, но до недавнего времени ядро Linux работало лишь с привилегиями процессов. Ввиду того, что самым простым решением является установка разрешений для файлов, отсутствие реализации соответствующего механизма в ядре Linux приводило в необходимости использования администраторами систем обходных путей для запуска системных служб с заданными привилегиями. Правила работы с разрешениями POSIX были умышленно нарушены для эмуляции привилегий пользователя root.

Несмотря на то, что механизм разрешений POSIX реализован на данный момент в полном объеме, использование учетной записи пользователя root с полным набором привилегий все еще является нормой. В данной статья я постараюсь продемонстрировать простой прототип системы с учетной записью пользователя root без полного набора привилегий.

Обзор разрешений POSIX

Каждый процесс имеет три набора разрешений:

  • Набор эффективных разрешений (effective - pE) содержит разрешения, которые могут использоваться процессом в текущий момент.

  • Набор доступных разрешений (permitted - pP) содержит разрешения, которые могут быть снова добавлены в набор эффективных разрешений.

  • Набор наследуемых разрешений (inheritable - pI) используется для формирования наборов разрешений при исполнении нового бинарного файла.

Файлы также имеют наборы эффективных (fE), доступных (pP) и наследуемых разрешений (fI), которые используются для формирования новых наборов разрешений процессов после исполнения этих файлов.

В любой момент процесс может использовать функцию cap_set_proc() для удаления разрешений из каждого из этих трех наборов.

Разрешения могут быть добавлены в набор эффективных разрешений лишь в том случае, если они находятся в наборе доступных разрешений. При этом они никогда не могут быть добавлены в набор доступных разрешений. И наконец, они могут быть добавлены в набор наследуемых разрешений лишь в том случае, если они находятся в наборе доступных разрешений, а также разрешение CAP_SETCAP находится в наборе эффективных разрешений. В момент, когда процесс инициирует исполнение нового бинарного файла, содержимое наборов разрешений нового процесса вычисляется следующим образом:

  • Набор наследуемых разрешений не претерпевает изменений.

  • Новый набор доступных разрешений заполняется разрешениями из набора доступных разрешений файла (на которые в качестве маски накладывается ограничивающий набор разрешений, но в рамках данной статьи я буду считать, что данный набор является полным), а также любыми разрешениями, присутствующими наборах наследуемых разрешений файла и процесса.

  • Разрешения из набора доступных разрешений файла будут доступны новому процессу - примером использования данных разрешений является утилита ping. Ведь для создания произвольных сетевых пакетов утилите ping требуется лишь разрешение CAP_NET_RAW. Но обычно для данной утилиты устанавливается бит setuid, а ее владельцем является пользователь root, поэтому ее могут использовать все пользователи системы. После добавления разрешения CAP_NET_RAW в набор доступных разрешений утилиты ping, все пользователи будут инициировать создание процесса с разрешением CAP_NET_RAW при запуске утилиты ping.

  • Разрешения из набора наследуемых разрешений файла доступны процессу лишь тогда, когда они также находятся в наборе наследуемых разрешений процесса - примером использования данного механизма является механизм изменения приоритетов процессов других пользователей на основе разрешений. Необходимо просто организовать добавление разрешения CAP_SYS_NICE в набор наследуемых разрешений процесса при входе в систему (о чем я расскажу чуть позднее), а также добавить это же разрешение в список наследуемых разрешений утилиты /usr/bin/renice. После этого обычные пользователи смогут запускать утилиту renice без получения дополнительных привилегий, причем "особые" пользователи смогут также запускать утилиту renice, в отличие от других утилит с разрешением CAP_SYS_NICE.

  • Набор эффективных разрешений по умолчанию пуст или, в случае установки бита legacy (обратитесь к разделу "Набор эффективных разрешений файлов и бит legacy"), содержит разрешения из нового набора доступных разрешений.

Набор эффективных разрешений файлов и бит legacy

В Linux имеется несоответствие между утилитой setcap и выполняемой этой утилитой операцией. Несмотря на то, что утилита setcap ожидает от пользователя перечисления разрешений, которые будут добавлены в набор эффективных разрешений файла, ядро ОС упрощает процесс и использует для определения состава упомянутого набора разрешений "бит legacy". На практике в том случае, если набор эффективных разрешений является пустым, бит legacy не установлен. В том же случае, если все биты наборов доступных и наследуемых разрешений файла находятся и в наборе эффективных разрешений файла, бит legacy установлен. А тогда, когда в наборе эффективных разрешений файла находится лишь часть битов из упомянутых наборов разрешений, утилита setcap вернет ошибку.

Причина подобной реализации утилиты setcap заключается в том, что изменения API ядра Linux для приложений пространства пользователя считаются крайне нежелательными. Бит legacy используется потому, что разработчики ядра ОС желают очищать набор эффективных разрешений при запуске приложений пространства пользователя с поддержкой механизма разрешений. Следовательно, набор эффективных разрешений файла должен быть также пуст за исключением тех случаев, когда приложение не поддерживает механизм разрешений. Но в том случае, если приложение не поддерживает механизм разрешений, все доступные ему разрешения должны находиться в наборе эффективных разрешений начиная с момента запуска приложения.

Привилегированный пользователь root

Как упоминалось ранее, ядро Linux продолжает эмулировать привилегии пользователя root. Эта эмуляция осуществляется путем изменения процедуры передачи разрешений в процессе использования функций exec() и setuid(). Если говорить кратко, то в том случае, если при исполнении бинарного файла ваш эффективный идентификатор пользователя равен 0 или вы исполняете файл с битом setuid, которым владеет пользователь root, будут полностью заполнены наборы доступных и эффективных разрешений. Если же ваш "реальный" идентификатор пользователя равен 0 (например, процесс, запущенный пользователем root, исполняет файл с битом setuid, которым не владеет пользователь root), будет заполнен лишь набор доступных разрешений. Если вы измените ваш идентификатор пользователя с идентификатора пользователя root на идентификатор любого другого пользователя, набор эффективных разрешений будет очищен. При постоянном изменении идентификатора пользователя с идентификатора пользователя root на идентификатор другого пользователя, набор доступных разрешений также будет очищен. А в том случае, если вы вновь измените ваш эффективный идентификатор пользователя на идентификатор пользователя root, разрешения из набора доступных разрешений будут снова скопированы в набор эффективных разрешений.

Описанное поведение контролируется с помощью наборов битов безопасности процессов. Один из битов контролирует поведение функции setuid(), а второй - функции exec(). Эти биты могут изменяться с помощью функции prctl(), а также могут блокироваться таким образом, что ни сам процесс, ни его дочерние процессы не смогут изменить их значения.

Подготовка системы

Для того, чтобы полностью использовать возможности механизма разрешений POSIX необходимо, чтобы и ядро ОС и утилиты пространства пользователя были собраны определенным образом. Простейший и самый безопасный способ проведения эксперимента с этим механизмом связан с использованием виртуальной машины. Несмотря на то, что все описанные в данной статье приемы могут быть применены и к установленной на вашем жестком диске операционной системе на основе ядра Linux, для простоты я буду считать, что вы осуществили установку минимального варианта дистрибутива Fedora в qemu или kvm.

Мой первый прототип системы с учетной записью пользователя root без привилегий основывался на на дистрибутиве Gentoo. Дистрибутивы Ubuntu Interpid и SLES11 должны также поддерживать обсуждаемый в статье механизм разрешений. Однако, лучшая поддержка данного механизма была осуществлена в дистрибутиве Fedora, а именно версии 10, которая была актуальной в момент написания статьи, поэтому я буду использовать его для демонстрации. Для начала следует скачать файл образа диска DVD дистрибутива Fedora 10 из архива проекта Fedora http://archives.fedoraproject.org (измените имя этого файла на f10.iso), после чего следует создать образ жесткого диска qemu и загрузить kvm с помощью следующих команд:

# qemu-img create f10.img 6G
# kvm -hda f10.img -cdrom f10.iso -m 512M -boot d

После этого вы должны выполнить все инструкции установщика дистрибутива Fedora. Убедитесь в том, что вы выбрали группу пакетов программного обеспечения с инструментами для разработки программного обеспечения и не выбрали группы пакетов программного обеспечения с приложениями для офисной и организационной работы в процессе установки системы с использованием загруженного файла образа диска.

После перезагрузки вы должны деактивировать технологию SELinux с помощью приложения из меню "Система - Администрирование - Управление SELinux". Выберите в верхнем раскрывающемся списке значение Disabled (отключено) вместо Enforcing (принудительное использование), после чего снова перезагрузите систему. Несмотря на то, что не существует четко определенной причины деактивации технологии SELinux при работе с механизмом разрешений POSIX, потребуются некоторые модификации политик SELinux.

Так как мы будем пытаться лишить пользователя root дополнительных привилегий, нам придется выдавать дополнительные привилегии всем пользователям системы в момент входа в систему. Эта операция может осуществляться силами модуля PAM с именем pam_cap.so. Для его задействования следует добавить следующую строку:

auth required pam_cap.so

в файл конфигурации PAM, расположенный по пути /etc/pam.d/system-auth. Порядок следования директив в рамках данного файла конфигурации имеет значение, поэтому в случае некорректного размещения указанной директивы она может просто не использоваться. Я расположил данную директиву сразу же после директивы pam_env.so. Теперь протестируем работоспособность данного модуля путем создания учетной записи пользователя с дополнительными привилегиями:

# adduser -m netadmin
# passwd netadmin
# for f in /sbin/ifconfig /sbin/ip /sbin/route; do
#   setcap cap_net_admin=ei $f
# done

Приведенная выше последовательность команд позволяет создать учетную запись пользователя с именем netadmin, установить пароль для этой учетной записи и добавить разрешение cap_net_admin в наборы наследуемых и эффективных разрешений бинарных файлов трех утилит для управления сетевыми соединениями. Теперь в случае выполнения команды ls /sbin/ifconfig вы должны обнаружить, что имя бинарного файла утилиты выделено красным. Аналогичным образом выделяются и бинарные файлы с установленными битами setuid, такие, как /bin/ping, что очень удобно для установления бинарных файлов, в отношении которых должны проявляться дополнительные меры предосторожности, а также для выявления случаев ошибочного повышения привилегий.

Также вы должны создать файл конфигурации /etc/security/capability.conf, данные из которого будут использоваться модулем pam_cap.so при каждом входе пользователя в систему. Этот файл должен содержать следующие строки:

cap_net_admin netadmin
none *

В первой строке приведена директива, позволяющая модулю pam_cap.so добавить разрешение cap_net_admin в набор наследуемых разрешений процесса командной оболочки пользователя. Вторая строка, содержит важную директиву, сообщающую модулю о том, что процессам командных оболочек всех других пользователей (*) не требуется дополнительных разрешений. Теперь войдите в систему как пользователь netadmin и попытайтесь изменить параметры сетевого соединения:

hallyn@kvm# su - netadmin
netadmin@kvm# ifconfig eth0 down

Команда должна завершиться успешно! Таким образом вы сможете деактивировать сетевой интерфейс, не используя учетную запись пользователя root.

Теперь вы готовы к изъятию привилегий у пользователя root. На первом шаге можно просто запретить вход в систему из сети по протоколу SSH. Самым простым методом выполнения данной задачи является запуск демона sshd с помощью прослойки, которая будет блокировать все биты безопасности перед запуском реального демона sshd. Исходный код данной обертки приведен в Листинге 1.

Листинг 1. Обертка для исполнения программы от лица пользователя root без привилегий

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/prctl.h>
#include <sys/capability.h>

int main(int argc, char * argv[])
{
    int   i, ret;
    char  *cmd;
    char  **argvp;
    cap_t cap = cap_get_proc();
    int   v[CAP_LAST_CAP+1];

    if (!cap)
        return -1;

    for (i=0; i<=CAP_LAST_CAP; i++)
        v[i] = i;

    if (cap_set_flag(cap, CAP_INHERITABLE,
                     CAP_LAST_CAP+1, v, CAP_SET))
        return -1;

    if (cap_set_proc(cap))
        return -1;

    cap_free(cap);

    ret = prctl(PR_SET_SECUREBITS, 0xf);
    if (ret) {
        perror("prctl securebits");
        exit(ret);
    }
    argvp = &argv[1];
    cmd   = argvp[0];
    ret   = execv(cmd, argvp);
    perror("execv");
    return ret;
}

Данная обертка устанавливает биты безопасности secure_noroot и secure_nosuidfixup с помощью системного вызова prctl(). После этого она исполняет программу, имя которой передается с помощью первого аргумента (ssh), а также передает остальные аргументы этой программе. Скомпилируйте бинарный файл обертки с именем capwrap и скопируйте его в директорию /sbin:

# gcc -o capwrap capwrap.c -lcap
# cp capwrap /sbin/

После этого следует отредактировать сценарий /etc/init.d/sshd для исполнения бинарного файла обертки capwrap. Найдите функцию start() и разместите строку /sbin/capwrap в начале строки с командой, предназначенной для запуска демона sshd. Результирующая строка должна выглядеть следующим образом:

/sbin/capwrap $SSHD $OPTIONS && success || failure

Разумеется, демону sshd потребуются дополнительные привилегии для изменения идентификаторов пользователя и группы, а также выполнения других операций. Для того, чтобы избежать дополнительной работы, просто добавьте все разрешения в набор эффективных разрешений бинарного файла демона sshd с помощью следующей команды:

hallyn@kvm# setcap all=ei /usr/sbin/sshd

Если вы попробуете перезапустить демон sshd прямо сейчас, вы столкнетесь с ошибкой, о которой не будет выведено никакой информации. Вместо этого следует запустить демон в ручном режиме и ознакомиться с отладочным выводом:

hallyn@kvm# /etc/init.d/sshd stop
hallyn@kvm# /sbin/capwrap /usr/sbin/sshd -Dd

В отладочном выводе вы сможете обнаружить следующие строки:

debug1: permanently_set_uid: 74/74
permanently_set_uid: was able to restore old [e]gid

Демон sshd жалуется на то, что он имеет возможность восстановить свой идентификатор пользователя после его смены на 74 (идентификатор пользователя sshd). Это является проблемой. Так как на уровне обертки был установлен бит безопасности nosuid_fixup, смена идентификатора пользователя с 0 на отличный от нуля идентификатор не приведет к автоматической очистке набора эффективных разрешений процесса. Это означает, что процесс, имеющий разрешения CAP_SETUID и CAP_SETGID может сбрасывать идентификатор пользователя до 0 в любое время.

Оптимальное решение данной проблемы заключается в модификации исходного кода демона sshd с целью отделения механизма для работы с разрешениями от механизма для работы с идентификаторами пользователей. Но, в рамках данного эксперимента, давайте просто внесем в исходный код демона изменения, которые позволят избежать соответствующих жалоб! Это не совсем правильный путь, но он наверняка не является самым плохим, ведь при запуске командной оболочки пользователя силами демона sshd наборы доступных и эффективных разрешений процесса командной оболочки будут заполняться заново в любом случае.

Загрузите файл патча opensshd_caps.patch (обратитесь к разделу "Дополнительные ресурсы" при необходимости уточнения ссылки для загрузки файла) и используйте следующие команды для его наложения:

# yum install audit-libs-devel tcp_wrappers-devel libedit-devel
# yumdownloader --source openssh
# rpm -i openssh-*.rpm
# cd /root/rpmbuild/
# rpmbuild -bc SPECS/openssh*
# cd BUILD/openssh-*/
# patch < /usr/src/opensshd_caps.patch
# make && make install
# setcap all=ei /usr/sbin/sshd
# /etc/init.d/sshd start

Теперь осуществите удаленный вход в систему от лица пользователя root по протоколу SSH и воспользуйтесь утилитой capsh для получения информации о наборах разрешений командной оболочки:

root@kvm# /sbin/capsh --print
Current: =
Bounding set =(full set of capabilities)
Securebits: 057/0x2f
secure-noroot: yes (locked)
secure-no-suid-fixup: yes (locked)
secure-keep-caps: no (unlocked)
uid=0

Из вывода видно, что после удаленного входа в систему создается безопасное окружение с установленными битами безопасности secure-noroot и secure-nosuid-fixup.

Настройка учетных записей администраторов

Идентификатор пользователя root отныне не связан с какими-либо привилегиями, но система в любом случае нуждается в администрировании. А для администрирования системы необходимы соответствующие привилегии. Поэтому давайте создадим несколько учетных записей пользователей с некоторыми привилегиями. При входе в систему процесс командной оболочки каждого из этих пользователей будет получать набор наследуемых разрешений, достаточный для выполнения определенной задачи. Формирование комбинаций наиболее полезных разрешений с целью добавления их в наборы разрешений процессов командных оболочек определенных пользователей является интересной задачей, но на данный момент давайте сфокусируем свое внимание на трех учетных записях пользователей: учетной записи пользователя netadmin, позволяющей изменять настройки сетевых соединений; учетной записи пользователя useradmin, позволяющей создавать учетные записи пользователей в рамках системы или удалять их, а также уничтожать процессы других пользователей и модифицировать их файлы; и учетной записи privadmin, позволяющей изменять наборы разрешений файлов, а также наборы наследуемых разрешений командных оболочек пользователей системы.

Создайте упомянутые учетные записи пользователей:

# adduser -m privadmin
# passwd privadmin
# adduser -m useradmin
# passwd useradmin
# chown privadmin /etc/security/capability.conf

Содержимое файла конфигурации модуля PAM с именем capability.conf должно быть изменено следующим образом:

cap_net_admin netadmin
cap_chown,cap_dac_overide,cap_fowner,cap_kill useradmin
cap_setfcap privadmin
none *

Пользователь privadmin должен иметь возможность модификации наборов разрешений файлов (процесс его командной оболочки должен иметь наследуемое разрешение cap_setfcap), поэтому следует сделать этого пользователя владельцем файла конфигурации capabilities.conf, после чего он сможет также модифицировать начальные состояния наборов наследуемых разрешений процессов других пользователей. Пользователь useradmin должен иметь возможность осуществления манипуляций с файлами и процессами других пользователей. Параметры учетной записи пользователя netadmin остаются неизменными. (Обратите внимание на то, что пользователь privadmin может добавить себе любые желаемые привилегии. Качественная политика аудитов безопасности и ограничение функций инструмента для модификации файла конфигурации capability.conf должны снизить риск злоупотребления данной возможностью.)

Вам также придется установить некоторые наследуемые разрешения бинарных файлов утилит для администрирования системы для того, чтобы позволить использовать данные утилиты упомянутым пользователям. В Листинге 2 показан короткий список разрешений, который можно использовать на начальных этапах настройки системы. Вы можете установить данные разрешения с помощью сценария из Листинга 3, использовав для его запуска команду sh loopcaps.sh amincapslist. Наконец, вам придется разрешить пользователю useradmin исполнять бинарный файл утилиты для создания учетных записей пользователей с помощью команды chmod o+x /usr/sbin/useradd.

Листинг 2. Разрешения бинарных файлов системных утилит для администраторов системы с ограниченными привилегиями

/bin/kill:=ei
/bin/ls:=ei
/bin/cat:=ei
/bin/ls:=ei
/bin/mv:=ei
/bin/touch:=ei
/bin/mount:=ei
/bin/umount:=ei
/bin/vi:=ei
/bin/rm:=ei
/bin/chgrp:=ei
/bin/find:=ei
/bin/chmod:=ei
/bin/chown:=ei
/bin/mkdir:=ei
/usr/sbin/useradd:=ei
/usr/bin/passwd:=ei
/usr/sbin/setcap:cap_setfcap=ei
/bin/ping:cap_net_raw=ep
/bin/su:=ep

Листинг 3. Сценарий для установки разрешений бинарных файлов

#!/bin/sh
for l in `cat $1`; do
    fglob=`echo $l | awk -F: '{ print $1 '}`
    p=`echo $l | awk -F: '{ print $2 '}`

    for f in `/bin/ls $flglob`; do
        setcap $p $f
    done
done

Теперь войдите в систему, используя учетные записи каждого из перечисленных пользователей, и исследуйте систему.

Несмотря на все внесенные изменения, все еще существует несколько проблем. Например, войдите в систему как пользователь useradmin и попытайтесь изменить пароль какого-либо пользователя.

passwd netadmin
passwd: только root может выбрать имя учетной записи.

Это не очень хорошо! Утилита passwd установила, что вы не являетесь пользователем root и не позволяет вам изменить пароль другого пользователя. В процессе экспериментов мы будем обнаруживать все больше и больше кода, разработанного с учетом особенностей различных операционных систем, который должен быть дополнительно усложнен для поддержки нашей модели работы с учетной записью пользователя root без привилегий.

На данный момент вы можете обойти данное ограничение двумя простыми способами. Во-первых, вы можете просто использовать учетную запись пользователя root вместо учетной записи пользователя useradmin. Пользователь root все также не будет иметь привилегий за исключением случаев исполнения (доверенного) файла с установленными разрешениями. Во-вторых, вы можете продолжить использовать имя пользователя useradmin, но изменить идентификатор пользователя на 0. Попытайтесь сделать это самостоятельно. Откройте файл конфигурации /etc/passwd.conf, найдите строку с описанием параметров учетной записи пользователя useradmin и замените числовое значение из первого столбца на 0. После этого выполните команду chown -R /home/useradmin для того, чтобы пользователь имел доступ к файлам из своей домашней директории после изменения идентификатора. Теперь вы можете выйти из системы и снова войти в нее, после чего исполнение команды passwd должно завершиться успешно. На самом деле, после исполнения команды будет выведено сообщение об ошибке, но вы можете самостоятельно убедиться в том, что процесс изменения пароля пользователя завершился успешно.

Ограничения привилегий демона инициализации системы

Теперь, когда вы создали учетные записи администраторов системы с ограниченными привилегиями, самое время ограничить привилегии демона инициализации системы. Эта задача может быть решена путем наложения патча на исходный код ядра ОС, но в нашем случае проще наложить патч на исходный код демона инициализации системы с целью использования системного вызова prctl() таким же образом, как и в обертке capwrap. Ссылка на патч для исходного кода демона инициализации системы upstart, который использовался в ранних версиях дистрибутива Fedora, приведена в разделе "Дополнительные ресурсы". Вы можете наложить этот патч с помощью команд, аналогичных тем, которые использовались для наложения патча на исходный код демона openssh:

# yumdownloader --source upstart
# rpm -i upstart*.rpm
# cd rpmbuild
# rpmbuild -bc SPECS/upstart.spec
# cd BUILD/upstart*
# patch -p1 < /usr/src/upstart.patch
# cp /sbin/init /sbin/init.orig
# make && make install

Также для того, чтобы гарантированно загрузить систему случае каких-либо проблем, следует отредактировать файл конфигурации системного загрузчика /boot/grub/grub.conf, закомментировав строку с директивой hiddenmenu и изменив значение времени показа меню загрузки, которое устанавливается с помощью директивы timeout, с 0 до 10 секунд. Теперь в случае возникновения проблем с загрузкой системы вы можете прервать процесс загрузки и добавить директиву init=/sbin/init.orig в конец строки параметров ядра ОС.

Процесс демона инициализации системы на основе модифицированного исходного кода добавляет все разрешения в свой набор наследуемых разрешений. Он также должен заполнять наборы доступных и эффективных разрешений и при этом иметь возможность удаления множества разрешений из наборов доступных разрешений, а также использовать пустой набор эффективных разрешений большую часть времени. Вам придется установить разрешения для бинарных файлов многих утилит, используемых в процессе запуска системы. В идеальном случае вы должны модифицировать исходный код каждой из этих утилит для того, чтобы избежать установки бита legacy, но это также всего лишь концепция предстоящей работы. Листинг 4 содержит список разрешений, которых достаточно для успешной загрузки дистрибутива Fedora 10.

Листинг 4. Разрешения, необходимые для загрузки дистрибутива Fedora с использованием учетной записи пользователя root без привилегий

/sbin/fsck:=ei
/sbin/udevd:=ei
/sbin/shutdown:=ei
/sbin/e2fsck:=ei
/sbin/mingetty:cap_chown,cap_dac_override,cap_sys_tty_config+ei
/sbin/dhclient:=ei
/sbin/reboot:=ei
/sbin/fsck.ext3:=ei
/sbin/hwclock:cap_sys_time=ei
/bin/setfont:cap_sys_admin,cap_sys_resource,cap_sys_tty_config=ei
/bin/hostname:cap_sys_admin=ei
/bin/loadkeys:cap_sys_admin,cap_sys_resource,cap_sys_tty_config=ei
/usr/bin/stat:cap_dac_override,cap_dac_read_search=ei
/sbin/rsyslogd:cap_sys_admin,cap_audit_write=ei
/bin/login:all=ei
/sbin/MAKEDEV:=ei
/sbin/auditd:=ei
/sbin/auditctl:=ei
/sbin/microcode_ctl:=ei
/usr/bin/hal-*:=ei
/usr/sbin/hald:=ei
/usr/libexec/hal*:=ei
/sbin/insmod:=ei
/sbin/modprobe:=ei
/sbin/rmmod:=ei
/bin/plymouth:=ei
/usr/bin/Xorg:=ei
/usr/sbin/gdm-binary:=ei
/bin/dbus-daemon:=ei
/usr/sbin/avahi-daemon:=ei
/usr/bin/sessreg:=ei
/sbin/pam_console_apply:=ei
/usr/sbin/gpm:=ei
/lib/dbus-1/dbus-daemon-launch-helper:=ep
/sbin/initctl:=ei
/usr/sbin/console-kit-daemon:=ep
/usr/sbin/NetworkManager:=ei
/usr/libexec/gdm*:=ei
/usr/sbin/gdm-binary:=ei

Вы можете установить эти разрешения с помощью сценария, который был приведен ранее (в Листинге 3).

Вам также придется выполнить команду:

chmod go-x /usr/sbin/console-kit-daemon

Вы принудительно устанавливаете разрешения вместо использования механизма их наследования, а не изменяете код утилиты dbus-daemon-launch-helper (для бинарного файла которой обычно устанавливается бит setuid, а владельцем этого файла является пользователь root) для автоматического заполнения набора наследуемых разрешений соответствующего процесса. Это означает, что любой пользователь может получить все привилегии в рамках системы при ее исполнении, поэтому вы разрешаете ее использование лишь владельцу ее бинарного файла, то есть пользователю root.

Заключение

В данной статье продемонстрирован процесс замены системы привилегий дистрибутива Fedora 10 с классической системы на основе идентификаторов пользователей (в которой пользователь root автоматически получает все привилегии) на систему, в которой лишь разрешения бинарного файла устанавливают привилегии исполняющего его пользователя. Пользователь root превращается из привилегированного пользователя в обычного пользователя с особым идентификатором, владеющего большинством файлов системы.

Вы можете удалить привилегированную учетную запись пользователя root из вашей системы. При этом в рамках данного эксперимента не была проделана часть работы по подготовке системы к практическому использованию, а именно, поддержка рассмотренной модели распределения привилегий не была реализована в рамках большинства приложений дистрибутива. Что более важно, код многих приложений делает выводы о привилегиях пользователей на основе их идентификаторов. Создание учетных записей пользователей с ограниченными привилегиями упрощает процесс администрирования системы, а создание работоспособной схемы распределения привилегий может оказаться интересным проектом.

В процессе чтения данной статьи вы можете попытаться самостоятельно использовать механизм распределения привилегий в зависимости от разрешений приложений системы с учетной записью пользователя root без привилегий. Данная статья демонстрирует методику модификации приложений, которые требуют запуска от лица привилегированного пользователя root, но на самом деле не используют все привилегии этого пользователя. Также после прочтения данной статьи вы сможете проектировать новые системные службы, которые будут учитывать разрешения и смогут работать без необходимости использования привилегированной учетной записи пользователя root. Разработка таких служб позволит значительно сократить риски, связанные с эксплуатацией ошибок и применением эксплоитов.

Дополнительные ресурсы

Файлы opensshd_caps.patch и upstart.patch находятся в архиве, расположенном по адресу: ftp.linuxjournal.com/pub/lj/listings/issue184/10249.tgz.