Ограничиваем файловую систему в Debian

Материал из Linux Wiki
Версия от 15:16, 16 марта 2013; Rain (обсуждение | вклад) (про биндинг файлов. http://chatlogs.linuxoid.in/linuxoid@conference.linuxoid.in/2013/03/07.html#08:16:40.97780)

Перейти к: навигация, поиск

В этой статье я попытаюсь собрать в одну кучу наработки по ограничению доступа в файловой системе Linux. Описание делается с уклоном в сторону Debian и Debian based-систем, но легко может быть адаптировано и для других дистрибутивов.

Основная идея описанного ниже - превращение необходимых каталогов в точки монтирования, после чего ограничение прав уже непосредственно точек монтирования. Кроме этого, активно используется фича, добавленная в ядрах 2.6.26+ - bind'инг каталогов в режиме read only.

Все действия делаются последовательными операциями монтирования и целиком описываются в /etc/fstab:


# Каталог ядра и файлов загрузчика. Не меняется во время работы, тут ни исполняемых файлов, ни устройств, ни SUID-файлов
# Если /boot на отдельном разделе - параметры монтирования переносятся на него.
/boot                  /boot                   auto       bind                                           0       0
/boot                  /boot                   auto       bind,remount,ro,nodev,nosuid,noexec            0       0
 
# Пример конфигурирования /tmp для использования с tmpfs
# В Debian Wheezy можно сделать /tmp в tmpfs, задав RAMTMP=yes в /etc/default/tmpfs. Там же задаются размеры этой
# и другой точек tmpfs.
# Еще одна "публично" доступная tmp-точка - это /var/tmp. По FHS там может быть временный контент,
# который не удаляется при перезагрузке. На деле такое встречал только в KDE - там хранился кэш браузера.
# В остальных случаях - а, тем более, на сервере - удобнее сделать /var/tmp симлинком на /tmp
tmpfs                  /tmp                    tmpfs      defaults,size=1G,noexec,nosuid,nodev           0       0
 
# Данная точка описывается, если для /usr не выделен отдельный раздел. Если выделен - переносим параметры туда
# /usr не меняется во время работы, поэтому можно держать его в RO. Исключением может быть /usr/src. При необходимости
# его можно вынести в отдельный каталог (например, сделать /var/src), а в /usr сделать симлинк.
# Кроме того, в /usr не бывает файлов устройств
/usr                   /usr                    auto       bind                                           0       0
/usr                   /usr                    auto       bind,remount,nodev,ro                          0       0
 
# Аналогично /usr - если есть отдельный раздел под него - делаем описание параметров там
# Данный раздел в RW, но тут не бывает SUID-бинарников
# Плюс в /var практически нет исполняемых файлов - возможно, стоит подробнее описать каталоги, где они находятся, 
# а /var сделать noexec
/var                   /var                    auto       bind                                           0       0
/var                   /var                    auto       bind,remount,nodev,nosuid                      0       0
 
# Некоторый софт ставится в /opt - защищаем его.
/opt                   /opt                    auto       bind                                           0       0
/opt                   /opt                    auto       bind,remount,ro,nodev                          0       0
 
# Защищаем от записи каталоги исполняемых файлов
/bin                   /bin                    auto       bind                                           0       0
/bin                   /bin                    auto       bind,remount,ro,nodev                          0       0
 
/sbin                  /sbin                   auto       bind                                           0       0
/sbin                  /sbin                   auto       bind,remount,ro,nodev                          0       0
 
# Защищаем от записи каталог основных системных библиотек и модулей ядра
/lib                   /lib                    auto       bind                                           0       0
/lib                   /lib                    auto       bind,remount,ro,nodev,nosuid                   0       0
 
# Внутри /var переопределяем параметры отдельного каталога, где хранится основная база установленных пакетов
# Делаем его доступным только на чтение, а также отключаем возможность размещения там файлов устройств и SUID-файлов
/var/lib/dpkg          /var/lib/dpkg           auto       bind                                           0       0
/var/lib/dpkg          /var/lib/dpkg           auto       bind,remount,ro,nosuid,nodev                   0       0

После применения подобных изменений даже случайное выполнение от рута rm -rf / или рекурсивного chown/chmod от корня оставит шанс на быстрое восстановление системы, пока она еще работает - ведь сохранятся неизменными основные библиотеки, исполняемые файлы, база пакетов и т.п.

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

Особенности

При использовании такой конфигурации всплывают 2 особенности:

  • Во-первых, некоторые приложения - а особенно APT - требуют, чтобы /tmp был исполняемый - там размещаются и выполняются скрипты настроек в процессе установки и конфигурации пакетов.
  • Во-вторых, как ставить пакеты или обновлять систему, если большая часть ФС в Read Only?

Обе проблемы решаются добавлением нескольких строк в конфиг-файл APT - /etc/apt/apt.conf:


Dpkg::Pre-Invoke {"for i in /boot /usr /opt /bin /sbin /lib /var/lib/dpkg ; do mount -o remount,rw $i ; done";};
Dpkg::Post-Invoke {"for i in /boot /usr /opt /bin /sbin /lib /var/lib/dpkg ; do mount -o remount,ro $i ; done";};
APT::ExtractTemplates::TempDir "/root";

Первые 2 строки перемонтируют перечисленные точки монтирования в RW до начала установки пакетов и обратно в RO - после.

Третья строка переопределяет временный каталог размещения скриптов. Это может быть любой exec-каталог, доступный на запись руту.

Заметки

  • В Debian Squeeze немного странная организация монтирований ФС при старте системы - есть некий /lib/init/rw, который монтируется в tmpfs и где находятся какие-то флаги. Однако если /lib при старте будет в RO, то вылетает ошибка на создании различных файлов в этом каталоге, в том числе фейлится монтирование /var/run и /var/lock в tmpfs. Возможно, проблема из-за неправильной последовательности монтирования каталогов. В Wheezy этой проблемы нет.
  • apt-get update упорно пытается что-то сделать с лок-файлом /var/lib/dpkg/lock во время перечитывания списка пакетов. Причем, файл есть что до обновления, что в процессе, что после. Если туда поместить какой-то контент - он остается. Пересоздается (если не существует) во время чтения списка загруженных пакетов. Опции для задания другого пути к файлу не нашел. Для того, чтобы всякие скрипты, проверяющие обновления по крону, не ругались на недоступный для записи файл, можно выполнять обновление с опцией:
apt-get -o Debug::NoLocking=1 update
  • Не забываем, что "все есть файл" - и раз монтировать можно каталоги, то почему бы не монтировать файлы в самих себя? Пример реализации ниже:
rain@elitebook:/tmp$ mkdir dir
rain@elitebook:/tmp$ touch dir/file
rain@elitebook:/tmp$ sudo mount -o bind dir dir
rain@elitebook:/tmp$ sudo mount -o bind,remount,ro dir dir
rain@elitebook:/tmp$ sudo mount -o bind dir/file dir/file
mount: warning: dir/file seems to be mounted read-only.
rain@elitebook:/tmp$ sudo mount -o bind,remount,rw dir/file
rain@elitebook:/tmp$ echo 123 > dir/somefile
bash: dir/somefile: Файловая система доступна только для чтения
rain@elitebook:/tmp$ echo 123 > dir/file
rain@elitebook:/tmp$ cat dir/file
123

Т.е., имеем доступный только на чтение каталог с файлами (одним файлом в данном случае), но доступным на запись одним файлом. Например, можно сделать RO каталог /etc, но открыть на запись /etc/passwd, /etc/shadow, чтобы пользователи могли менять пароли или шелл. И так далее в том же духе.

Ссылки