Авторские статьи

Среда выполнения snap.


Четвёртая статья, в которой рассматривается размещение и свойства файловой системы во время выполнения программы в snap пакете.

С точки зрения пользователя ничего особенного не происходит. Он запускает программу, щёлкнув по значку на Рабочем столе или запустив из Терминала. Внутренне snapd делает ряд шагов, которые подробно будут рассмотрены в следующих статьях, для конфигурирования процесса приложения.

(ch)root файловой системы и немного магии

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

Core snap меняет корневую файловую систему для среды выполнения (runtime) данного приложения. Можно представлять это как chroot, только учитывать что файловые системы snap доступны только на чтение и core snap не исключение.

Некоторые каталоги в core snap примонтированы через bind (можно представлять их как специальный тип символической ссылки или жёсткой ссылки на каталог, хотя оба сравнения неточны) к некоторым местам в хостовой системе:

  • /dev/
  • /etc/ (за исключением /etc/alternatives)
  • /home/
  • /root/
  • /proc/
  • /snap/
  • /sys/
  • /var/snap/
  • /var/lib/snapd/
  • /var/tmp/
  • /var/log/
  • /run/
  • /media/
  • /lib/modules/
  • /usr/src/

Заметьте, что нет путей /usr/lib/ или /usr/bin/. Если программе в snap требуется библиотека или бинарник, то нужное должно присутствовать в данном снап пакете. Исключение состоит только в низкоуровневых библиотеках типа libc, которые находятся в core snap.

Подсказка: исследуйте core snap, чтобы узнать что там. Если есть хотя бы один установленный пакет, то можно посмотреть /snap/ubuntu-core/current/

Со всеми этим точками монтирования (mounts) и chroots можно задаться вопросами, а как эти точки монтирования выглядят для всех остальных процессов в системе? Ответ прост. Они выглядят, как будто ничего специально связанного со snappy нет.

Для понимания ответа вам нужно знать немного о Linux namespaces. Пространства имён (namespaces) - это возможность создать раздельный вид различных аспектов Linux систем на уровне каждого приложения. Вместо виртуальных машин, которые эмулируют работу отдельного компьютера с возможностью запуска другой операционной системы, namespaces легковесны. Snappy использует только одну из доступных пространств имён - mount namespace. Не буду вас обманывать, в то время как идея выглядит просто - "точки монтирования внутри namespace изолированы от точек снаружи", в реальности всё сложнее из-за "разделяемых поддеревьев" (shared-subtrees). Одно из интересных следствий их использования: смонтированное, к примеру /media/, видимо только данному приложению, к примеру VLC, а не наоборот. Если злонамеренный snap пытается, несмотря на различные механизмы защиты, монтировать что-то, скажем, в /usr/, то изменения будут видны только процессу в данном snap.

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

Подсказка: Если пробовали исследовать core snap, как советовала подсказка №1, то вы видели файлы. А как выглядит в реальности система для runtime? Установите пакет snapd-hacker-toolbelt и запустите snapd-hacker-toolbelt.busybox sh. Вы запустите оболочку со знакомыми командами, которые помогут исследовать изнутри.

Рассмотрим пару моментов, без подробного объяснения:

  • Каждый процесс получает свой приватный /tmp/ со свежим tmpfs. Это ради безопасности. Простое следствие из этого состоит в том, что нельзя обмениваться файлами через данный временный каталог и нельзя создавать огромные файлы, так как tmpfs имеет ограничение, связанное с доступной ОЗУ.
  • Своя копия /dev/pts/ с эмуляторами терминала. Это ещё одна мера безопасности. На практике об этом мало приходится беспокоится.
  • Вся файловая система хоста примонтирована в /var/lib/snapd/hostfs. Это можно использовать в интерфейсах подобно интерфейсу, обеспечивающему обмен контентом, для примера. Это супер интересная штука будет рассмотрена в отдельной статье.
  • Специальный код для поддержки закрытых драйверов Nvidia. Интересная тема для разработчиков игр будет также рассмотрена в отдельной статье.
  • Вполне может оказаться невозможным сохранить текущий рабочий каталог через всю эту магию из chroot, mount и bind-mount. Лёгкий способ проверить - создать к примеру каталог /tmp/foo/ и попытаться запустить любую команду snap оттуда. The easiest way to experience this is to create a directory in /tmp (e.g. /tmp/foo) and try to run any snap command there. Because of the private (and empty) /tmp directory the /tmp/foo directory does not exist for the snap application process. Snap-confine выведет информационное сообщение и не откажет в запуске.

На данном моменте для программы присутствуют привычные места и они содержат данные, знакомые данной программе. Это не означает, что эти каталоги доступны для чтения или записи! Они только лишь присутствуют и механизм ограничения (confinement) и интерфейсы будут решать что будет доступно для чтения или записи. И тут подходим к такой части как snap-confine.

Механизм ограничения процесса

Snap-confine поддерживает две технологии песочницы: фильтры системных вызовов seccomp и система мандатного доступа AppArmor.

Seccomp ограничивает программу в списке доступных для неё системных вызовов, которые сами по себе являются интерфейсом между ядром Linux и пользовательским пространством. Очень грубо говоря, некоторые функции в языках программирования реализованы как системные вызовы и seccomp та подсистема linux, которая отвечает за доступ к ним.

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

В строгом режиме ограничения под названием strict, попытки программы использовать системные вызовы, которые не были ей разрешены, вызовут её убийство. В системном журнале будет отображено что-то типа:

sie 08 12:36:53 gateway kernel: audit: type=1326 audit(1470652613.076:27): 
auid=1000 uid=1000 gid=1000 ses=63 pid=66834 comm="links" exe="/snap/links/2/usr/bin/links" 
sig=31 arch=c000003e syscall=54 compat=0 ip=0x7f8dcb8ffc8a code=0x0

Процесс с PID=66834 был убит с сигналом 31 (SIGSYS), так как пытался использовать системный вызов под номером 54 (setsockopt). Номера системных вызовов зависят от архитектуры, в примере подразумевается 64 битная архитектура (amd64).

Даже если системный вызов разрешён, конкретная операция может быть запрещена в AppArmor. Для примера, песочница настроена так, что программы могут писать в пути из переменных $SNAP_USER_DATA (или $SNAP_DATA для сервисов-демонов). И хоть физически $SNAP_USER_DATA указывает на ~/snap/$app-name/$revision/, но чтение и запись в реальную домашнюю директорию пользователя, по умолчанию запрещено.

sie 08 12:56:40 gateway kernel: audit: type=1400 audit(1470653800.724:28): 
apparmor="DENIED" operation="open" profile="snap.snapd-hacker-toolbelt.busybox" 
name="/home/zyga/.ssh/authorized_keys" pid=67013 comm="busybox" requested_mask="r" 
denied_mask="r" fsuid=1000 ouid=1000

Мы видим что процесс PID=67013 пытался открыть файл ключей /home/zyga/.ssh/authorized_keys и ему запретили операцию read (denied_mask="r"). Если программа установлена в режиме devmode, то действие будет разрешено, с занесением информации в журнал.

Подсказка: всякий раз когда вы сталкиваетесь с проблемами, пытайтесь запустить snappy-debug, который помогает с чтением и расшифровкой текста, давая советы по устранению.

AppArmor обладает более широкими возможностями для проверки linux capabilities, UNIX IPC (сигналы и слоты), сообщения DBus, включая вызываемые объекты и методы. Бо́льшая часть ограничений для программ создаётся профилями AppArmor. Все возможности будут рассмотрены в следующих статьях, где с нуля попробуем создать свой интерфейс.

Последняя вещь, которую snap-confine делает, так это в ряде случаев создаёт ...

device control group

Cgroups для устройств создаётся и процесс приложения перемещается в него. Cgroups - это небольшой набор типичных устройств типа /dev/null и дополнительных, но явно указанных, устройств. Это делается с помощью UDEV правил, отмечая соответствующие устройства. Для полноты картины, стоит отметить, что особо загружаться данной темой не нужно. Если возникнет необходимость, мы подробно осветим данную тему и покажем как можно использовать её для упрощения обработки определённых ситуаций. По умолчанию, device control group не используются.

А теперь всё вместе

С учётом всего вышесказанного, snap-confine вызывает через execv скрипт-обёртку, который содержит вызов программы, указанной в снапкрафтером в файле snapcraft.yaml в разделе apps
Пример

apps:
  my-app:
    command: usr/bin/my-app-bin

Механизм ограничения с помощью snap-confine вызывается всякий раз при старте программы. Дополнительную информацию вы можете получить через man 5 snap-confine
В следующий раз мы создадим наш первый, чрезвычайно простой, интерфейс.

Оглавление цикла статей про Snappy.
Предыдущая статья Анатомия интерфейса snappy.

Дата последней правки: 2023-12-27 14:38:03

RSS vasilisc.com   


Разделы

Главная
Новости
Ворох бумаг
Видео Linux
Игры в Linux
Безопасность
Статьи об Astra Linux
Статьи о FreeBSD
Статьи об Ubuntu
Статьи о Snappy
Статьи об Ubuntu Phone
Статьи о Kubuntu
Статьи о Xubuntu
Статьи о Lubuntu
Статьи об Open Source
Карта сайта