Середа виконання snap
(ch)root файлової системи та трохи магії
Давайте почнемо з найважливішого факту:коренева файлова система - це файлова система операційної системи хоста.Використання файлової системи хоста призведе до несумісностям. Очевидні з них: базові бібліотеки, що відрізняються, потенційно розрізняються схеми розміщення файлів.
Core snap змінює кореневу файлову систему для середовища виконання (runtime) цієї програми. Можна представляти це як chroot, тільки враховувати, що файлові системи snap доступні тільки на читання і core snap не виняток.
Деякі каталоги в core snap примонтовані через bind (можна представляти їх як спеціальний тип символічного посилання або жорсткого посилання на каталог, хоча обидва порівняння неточні) до деяких місць в системі хоста:
Зауважте, що немає шляхів /usr/lib/ або /usr/bin/.Якщо програмі в snap потрібна бібліотека або бінарник, то потрібне має бути присутнім у даному снап пакеті.Виняток полягає тільки в низькорівневих бібліотеках типу libc, які знаходяться в core snap.
З усіма цими точками монтування (mounts) і chroots можна поставити запитання, а як ці точки монтування виглядають для всіх інших процесів у системі? Відповідь проста. Вони виглядають, ніби нічого спеціально пов'язаного зі snappy немає.
Для розуміння відповіді вам потрібно знати трохи про Linux namespaces. Простір імен (namespaces) - це можливість створити роздільний вигляд різних аспектів Linux систем на рівні кожної програми. Замість віртуальних машин, які емулюють роботу окремого комп'ютера з можливістю запуску іншої операційної системи, namespaces легковагні. Snappy використовує лише одну з доступних просторів імен - mount namespace. Не будувас обманювати, тоді як ідея виглядає просто - "точки монтування всередині namespace ізольовані від точок зовні", насправді все складніше через "поддеревьев, що розділяються" (shared-subtrees). Одне з цікавих наслідків їх використання: змонтоване, наприклад /media/, мабуть лише цьому додатку, наприклад VLC, а чи не навпаки. Якщо зловмисний snap намагається, незважаючи на різні механізми захисту, монтувати щось, скажімо, /usr/, то зміни будуть видно тільки процесу в даному snap.
Не хвилюйтеся, якщо не повною мірою поки що зрозуміла дана тема. Суть у тому, що ваша програма бачить інше уявлення файлової системи, але це бачення узгоджується з різними дистрибутивами Linux.
Розглянемо кілька моментів, без докладного пояснення:
- Кожен процес отримує свій приватний /tmp/ зі свіжим tmpfs. Це задля безпеки. Просте наслідок цього полягає в тому, що не можна обмінюватися файлами через даний тимчасовий каталог і не можна створювати величезні файли, оскільки tmpfs має обмеження, пов'язане з доступною ОЗУ.
- Своя копія /dev/pts/ з емуляторами терміналу. Це ще один захід безпеки. Насправді про це мало доводиться турбуватися.
- Вся файлова система хоста вмонтована в /var/lib/snapd/hostfs. Це можна використовувати в інтерфейсах подібно до інтерфейсу, що забезпечує обмін контентом, для прикладу. Ця супер цікава штука буде розглянута в окремій статті.
- Спеціальний код підтримки закритих драйверів Nvidia. Цікава тема для розробників ігор також буде розглянута в окремій статті.
- Цілком може виявитися неможливим зберегти поточний робочий каталог через цю магію з chroot, mount і bind-mount. Легкий спосіб перевірити - створити наприклад каталог/tmp/foo/ та спробувати запустити будь-яку команду snap звідти. Досить добре, щоб зробити це є створення директора в / tmp (e.g. / tmp / foo) і спробувати до будь-якого штриху комбінації. Оскільки private (and empty) /tmp directory /tmp/foo directory не існують для сприйняття application process. Snap-confine виведе інформаційне повідомлення та не відмовить у запуску.
На даний момент для програми є звичні місця і вони містять дані, знайомі даній програмі. Це не означає, що ці каталоги доступні для читання чи запису! Вони тільки присутні і механізм обмеження (confinement) та інтерфейси будуть вирішувати, що буде доступно для читання або запису. І тут підходимо до такої частини, як snap-confine.
Механізм обмеження процесу
Snap-confine підтримує дві технології пісочниці: фільтри системних викликів seccomp та система мандатного доступу AppArmor.
Seccomp обмежує програму в списку доступних для неї системних викликів, які самі по собі є інтерфейсом між ядром Linux і простором користувача. Дуже грубо кажучи, деякі функції в мовах програмування реалізовані як системні виклики та seccomp та підсистема linux, яка відповідає за доступ до них.
Прямо зараз, якщо програма запущена в режимі devmode, ви не отримаєте повідомлення, що в програмі використовуються виклики, які будуть заборонені, оскільки не дозволені при поточному наборі інтерфейсів. За фактом режим devmode в апстрімі проекту називається complain і ситуація з повідомленням може змінитись завтра.
У строгому режимі обмеження під назвою strict, спроби програми використовувати системні виклики, які їй не дозволені, викличуть її вбивство. У системному журналі будевідображено щось на кшталт:
Процес PID=66834 був убитий з сигналом 31 (SIGSYS), так як намагався використовувати системний виклик під номером 54 (setsockopt). Номери системних викликів залежать від архітектури, у прикладі мається на увазі 64 бітна архітектура (amd64).
Навіть якщо системний виклик дозволено, конкретна операція може бути заборонена AppArmor. Наприклад, пісочниця налаштована так, що програми можуть писати в дорозі зі змінних $SNAP_USER_DATA (або $SNAP_DATA для сервісів-демонів). І хоч фізично $SNAP_USER_DATA вказує на
/snap/$app-name/$revision/, але читання та запис у реальну домашню директорію користувача за промовчанням заборонено.
Ми бачимо, що процес PID=67013 намагався відкрити файл ключів /home/zyga/.ssh/authorized_keys і йому заборонили операцію read (denied_mask="r"). Якщо програма встановлена в режимі devmode, то дія буде дозволена, із занесенням інформації до журналу.
Остання річ, яку snap-confine робить, так це у ряді випадків створює .
device control group
Cgroups для пристроїв створюється і процес програми переміщається до нього. Cgroups - це невеликий набір типових пристроїв типу /dev/null та додаткових, але явно вказаних пристроїв. Це робиться за допомогою UDEV правил, позначаючи відповідні пристрої. Для повноти картини, варто зазначити, що особливо завантажуватися цією темою не потрібно. Якщо виникне потреба, ми докладно висвітлимо цю тему і покажемо як можна використовувати її для спрощення обробки певних ситуацій. За промовчанням, device control group не використовуються.
А тепер все разом
З урахуванням всього вищесказаного, snap-confine викликає через execv скрипт-обертку, який містить виклик програми, вказаної у снапкрафтером у файлі snapcraft.yaml у розділіapps Приклад
Механізм обмеження за допомогою snap-confine викликається щоразу під час старту програми. Додаткову інформацію можна отримати через man 5 snap-confine Наступного разу ми створимо наш перший, надзвичайно простий, інтерфейс.