Russian Fedora

cообщество русскоязычных участников
международного проекта Fedora

Wayland и Google

Инженеры Google продолжают увеличивать свою вовлеченность в дело разработки Wayland. Не так давно они предложили расширить протокол Wayland добавлением поддержки игровых устройств. Расширение протокола будет совместимо со стандартом W3С для игровых устройств.

Как мы и предполагали, 2017 год будет интересным. Недаром, все-таки, в 2016 году Google наняли Kristian Høgsberg, архитектора Wayland.

Разработка SELinux-модуля для приложения

На Хабрахабре опубликовали статью, посвященную настройке SELinux:

Давным-давно, в далекой-далекой стране

image1… государственная служба NSA разработала систему безопасности для ядра и окружения Linux, и назвала ее SELinux. И с тех пор люди разделились на две категории: disabled/permissive и enforcing. Сегодня я покажу вам путь Силы и переведу на другую сторону всех желающих.

Предположения

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

  • Имеет какое-то приложение (демон), которое должно работать с SELinux
  • Просмотрел разницу между DAC, MAC и RBAC
  • Знаком с администрированием Linux
  • Что-то читал про SELinux и может расшифровать user_u:user_r:user_home_t:s0
  • Имеет под рукой CentOS 7
  • На котором установлены пакеты setools-console, policycoreutils-devel, selinux-policy-devel
  • И включен SELinux в режиме permissive с политикой targeted или minimum

Это все про вас? Тогда поехали!

Базовые типы

В качестве подопытного я взял jnode — достаточно типичное приложение, которое общается по сети, ходит в базу, читает конфиги, пишет свои данные и tmp-файлы и мониторит свое состояние (cpu, mem, disk). Создадим файл jnode.te (te = Type Enforcement) С чего нужно начать писать модуль? С описания базовых типов:

policy_module(jnode, 1.0.0)
# тип для процесса
type jnode_t;
# тип для исполняемого файла
type jnode_exec_t;
# тип для конфиг-файлов
type jnode_conf_t;
# тип для кэша (аналог /var/cache/)
type jnode_cache_t;
# тип для лог-файла
type jnode_log_t;
# тип для временных файлов
type jnode_tmp_t;
# тип для порта, который слушает jnode (протокол binkp)
type binkp_port_t;

Почему так много? Потому, что это разные категории доступа для системы, например:

  • jnode_exec_t будет исполняемым для всех и к нему будут применены правила перехода типов.
  • jnode_t будет типом процесса и именно на него будут вешаться все разрешения.
  • jnode_conf_t будет r/o для приложения и r/w для администратора.
  • jnode_cache_t будет append_only для приоложения и r/w для администратора.
  • jnode_log_t будет append_only для приложения и r/w для syslog/logrotate/journald
  • jnode_tmp_t будет r/w для приложения и denied для всех остальных.
  • binkp_port_t нужен для управления портами, которые может слушать приложение.

Лирическое отступление

Теоретически, почти на этом месте (добавив только правило перехода) можно прекратить писать модуль, скомпилировать его, установить в систему и промаркировать файловую систему при помощи chcon. После этого собрать логи при помощи утилиты audit2allow и получить несколько сотен абсолютно непонятных строк, которые будут что-то разрешать. Из них в дальнейшем получится модуль, который даже будет работать. Но понимания это вам не добавит, не так ли? Поэтому я предлагаю другой путь: читать заголовочные файлы и выбирать там то, что вам нужно. В /usr/share/selinux/devel/include/ можно найти несколько сотен .if-файлов, в которых содержатся стандартные макросы базовой политики SELinux. К сожалению, вам придется использовать grep и cat самостоятельно, я лишь покажу несколько основных макросов и то, как они облегчают жизнь.

Макросы атрибутов

Для облегчения жизни в SELinux существует понятие attribute — некого контейнера типов, (к) которому тоже можно назначать права доступа. Таким образов, добавив свой новый тип в тот или иной аттрибут мы автоматически выдаем ему стандартные права для этого атрибута. Чтоб не запоминать все эти атрибуты есть уже готовые макросы, которые размечают типы по атрибутам (часто по нескольким). Смотрите:

#  это конфиг-файлы
files_config_file(jnode_conf_t)
# это какие-то файлы
files_type(jnode_cache_t)
# это лог-файлы
logging_log_file(jnode_log_t)
#  это временные файлы
files_tmp_file(jnode_tmp_t)
# а это порт
corenet_port(binkp_port_t)

Макросы стандартных разрешений

Когда типы определены, можно назначить стандартное поведения для приложения. Для этого тоже воспользуемся макросами, они достаточно легко находятся по ключевым словам и делают код человекочитаемым:

# Макрос приложения: добавляет тип jnode_t в список приложений
# и разрешает ему стартовать из типа  jnode_exec_t
application_domain(jnode_t, jnode_exec_t)
# Макрос демона: добавляет тип jnode_t в список демонов,
# разрешает его запускать через systemd
# и назначает переход: если systemd запустит файл с типом jnode_exec_t,
# то процесс получит тип jnode_t
init_daemon_domain(jnode_t, jnode_exec_t)
# разрешает типу jnode_t исполнять стандартные бинарники (/bin, /usr/bin)
corecmd_exec_bin(jnode_t)
# разрешает типу jnode_t подключать библиотеки
libs_use_ld_so(jnode_t)
# разрешает типу jnode_t читать состояние системы (cpu, memory)
kernel_read_system_state(jnode_t)
# разрешает типу jnode_t писать в /tmp
files_rw_generic_tmp_dir(jnode_t)
# разрешает типу jnode_t читать конфиг сети (/etc/resolv.conf итд)
sysnet_read_config(jnode_t)
# разрешает типу jnode_t получать случайные числа из /dev/(u)random
dev_read_rand(jnode_t)
# разрешает типу jnode_t получать аттрибуты файловой системы (свободное место)
fs_getattr_xattr_fs(jnode_t)
# разрешает типу jnode_t делать dns resolve
sysnet_dns_name_resolve(jnode_t)
# разрешает типу jnode_t ходить в /var/log (r/o)
logging_search_logs(jnode_t)
# назначает правило: логи, которые создает процесс jnode_t,
# будут иметь тип jnode_log_t
logging_log_filetrans(jnode_t, jnode_log_t, file)
# назначает правило: tmp-файлы, которые создает процесс jnode_t,
# будут иметь тип jnode_tmp_t
files_poly_member_tmp(jnode_t, jnode_tmp_t)
# разрешает jnode_t делать bind() на любой адрес
corenet_tcp_bind_generic_node(jnode_t)
# разрешает jnode_t общаться с postgresql по unix-сокету
postgresql_stream_connect(jnode_t)
# разрешает jnode_t общаться с postgresql по сети
corenet_tcp_connect_postgresql_port(jnode_t)

Файл контекстов

Теперь пришла пора привязать созданные типы к файловой системе. Создадим файл jnode.fc (fc = File Context).

# исполняемый файл
/opt/jnode/jnode.run        --  gen_context(system_u:object_r:jnode_exec_t)
# все что r/o для сервиса назовем "конфигом"
/opt/jnode(/.*)?            gen_context(system_u:object_r:jnode_conf_t)
/opt/jnode/jar(/.*)         gen_context(system_u:object_r:jnode_conf_t)
# и отдельно сами конфиги
/opt/jnode/point/.*\.cfg        gen_context(system_u:object_r:jnode_conf_t)
# сюда сервис сможет добавлять файлы ( но не удалять )
/opt/jnode/fileechoes(/.*)?         gen_context(system_u:object_r:jnode_cache_t)
/opt/jnode/point(/.*)?          gen_context(system_u:object_r:jnode_cache_t)
# тут будут появляться и исчезать временные файлы и папки
/opt/jnode/(inbound|temp)(/.*)?     gen_context(system_u:object_r:jnode_tmp_t)
# а сюда будут писаться логи
/var/log/jnode(/.*)? gen_context(system_u:object_r:jnode_log_t)

Сборка и установка

Создадим какую-нибудь папку и положим туда файлы jnode.te и jnode.fc. Перейдем туда и выполним сборку:

[root@jnode jnode]# make -f /usr/share/selinux/devel/Makefile
Compiling targeted jnode module
/usr/bin/checkmodule:  loading policy configuration from tmp/jnode.tmp
/usr/bin/checkmodule:  policy configuration loaded
/usr/bin/checkmodule:  writing binary representation (version 17) to tmp/jnode.mod
Creating targeted jnode.pp policy package
rm tmp/jnode.mod.fc tmp/jnode.mod

Установим модуль командой semodule -i jnode.pp и включим его командой semodule -e jnode. Назначим номер порта для типа binkp_port_t: semanage port -a -t binkp_port_t -p tcp 24554. Теперь необходимо переназначить контексты в соответствии с файлом контекстов: restoreconn -Rv /opt/jnode. Запускаем сервис через systemctl и начинаем ждать.

Финальный audit2allow

Через некоторое время (час, сутки — зависит от активности сервиса) можно выполнить команду audit2allow -b -r -t jnode_t и посмотреть, что еще приложение просит помимо того, что ему уже было дано. Разрешений получится немного — может 10-15 строчек, причем не все из них ему реально нужны. Тут уже решать вам — что оставить, а что убрать. В «ненужной» части замените allow на dontaudit — это избавит от повторяющегося мусора в логах. Кстати, обновите версию модуля — это позволит ядру понять, что его нужно обновить.

setenforce 1

Когда audit2allow покажет «пусто» — это значит, что все работает по плану и можно включать enforcing. Поздравляю, вы нашли Силу. Распоряжайтесь ею с умом.

Полезные ссылки

Автор статьи также оставил интересный ответ, почему просто не использовать трюк с audit2allow:

Q: А просто добавлять выхлоп audit2allow пока приложение не заведётся в модуль, а потом действительно денёк покурить и один раз повторить напоследок не проще?

A: Проще, но:

  • audit2allow не делает правила по переходам типов ( type_transition, type_member итд )
  • audit2allow делает две сотни правил вида allow service_t long_file_type_t:lnk_file { getattr };
  • если не включить типы в нужные атрибуты ( что audit2allow тоже не умеет делать ), то придется писать для каждого нового типа разрешения от всех других типов ( включая unconfined_t ), что еще в сотню раз увеличит размер модуля.
  • в итоге понять, к чему именно приложение попросило доступ — сложнее, чем погрепать два часа по include и найти все необходимые макросы.

Новости нашей инфраструктуры

В новом 2017 году мы ожидаем значительного улучшения в нашей инфраструктуре.

Для начала, мы окончательно закрываем хостинг проектов на fedorahosted.org. Там у нас, со времен, когда еще не было GitHub, крутился Trac, и хостились git-проекты с помощью gitosis. Раньше в этом был смысл, а теперь, когда появился GitHub, Launchpad, GitLab, и другие молодежные социальные сети, народ перестал посещать fedorahosted, и там засели спаммеры и хакеры. Проще выключить, чем пытаться это как-то улучшить. Окончательно fedorahosted переведут в read-only режим с марта 2017, а отключат на несколько месяцев позднее (пока не решили окончательно, когда).

Тем не менее, для проектов, которые придется хранить в нашей контролируемой инфраструктуре (ну мало ли, какие причины для этого), у нас будет вариант. Это Pagure, о котором мы уже говорили. Сначала мы подумывали, чтобы просто развернуть GitLab, но не осилили упаковать нужные версии сотен RoR-библиотек. Проще оказалось переписать на Python, благо среди наших коллег разработчиков на нем полно (в т.ч. и тех, кто пишут сам Python). Получилось, в общем, неплохо, хотя, конечно, до функционала GitLab не дотягивает. Но лучше, чем Trac и gitosis.

Опять о SELinux и безопасности

В который раз SELinux успешно блокировал очередную уязвимость. Вы же не настолько наивны, что его выключаете, следуя протухшим хаутушкам и советам самозваных форумных линукс-гуру? Если выключаете, то прежде, чем читать дальше, немедленно его включите обратно. В этот раз уязвимость была в Docker, в котором вообще проблем с безопасностью хватает, и если б не наши коллеги, то было бы еще больше.

Забавно, что когда наши коллеги указали, что стандартная инсталляция RHEL или Fedora, со включенным SELinux неуязвима для эксплойта, то у представителей Docker Inc., как это говорится, бомбануло. Неясно, связана ли такая враждебность с тем, что Red Hat зарабатывает на Docker больше, чем Docker Inc.? Скорее всего, нет. Просто так злятся.

Вообще, с контейнерами (т.е. просто cgroups + namespaces) надо быть осторожными. Мы уже предупреждали вас, что контейнеры не ограничивают приложения так, как бы это хотелось. Наши коллеги из CoreOS, например, в довесок к SELinux добавили специальный функционал в свой конкурирующий с Docker продукт, rkt. Они даже сделали безопасность и изоляцию основными отличительными чертами нового релиза rkt 1.14.

Мы идем своим путем, выстраивая систему безопасности с самого низа до верха. Внизу находится загрузчик с UEFI и SecureBoot, который позволяет, например, блокировать ядро от изменения из userspace. В самом ядре, в дополнение в namespaces и cgroups, наши колеги постоянно добавляют новый функционал. Недавно Daniel Mack предложил механизм фильтрации трафика в зависимости от cgroups, основанный на eBPF, что теоретически позволит очень гибко управлять трафиком контейнеров. На этом же уровне реализован SELinux.

Выше идет система инициализации системы и/или запуска контейнеров, тот же systemd, Kubernetes, rkt, Docker, fleet. Например, помимо использования SELinux, мы можем эффективно ограничивать возможности демонов благодаря функционалу systemd. Сам systemd уже нравится не только нам, но и, например, Facebook, и очень странно, что еще остались упирающиеся.

Из-за одной уязвимости, к тому же остановленной SELinux, мы, конечно, не призываем бойкотировать Docker, как другие. Просто оглянитесь вокруг - возможно вам будет удобнее управлять контейнерами используя другие механизмы (systemd, Kubernetes, rkt).

Новости RISC-V

Положительно завершается процесс добавления поддержки архитектуры RISC-V в GCC. К сожалению, процесс был сильно заторможен юристами, поэтому не факт, что успеют в срок для GCC 7. Дело в том, что разработка шла в университете Беркли, и их юристы были потив того, чтобы копирайт на работу был передан FSF. Пришлось даже переписать все с чистого листа.

Нам это все интересно, потому что сравнительно недавно наш коллега, Rich W.M. Jones, объявил о том, что он работает над поддержкой RISC-V в Fedora. Он использовал для сборки первый, заблокированный юристами, порт GCC, и с ним добился видимого прогресса - готовы образы Fedora для загрузки в эмуляторе. В качестве эмулятора можно использовать Qemu, а можно и более экзотичный RISCVEMU. В процессе пересборки Rich был вынужден вносить патчи для самых разных компонентов, таких, как RPM и systemd. Текущее состояние дел можно узнать на странице рабочей группы RISC-V в Fedora

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

PulseAudio 10.0

Вышел PulseAudio 10. Из изменений этой версии хочется отметить использование по умолчанию функционала memfd, впервые включенного в PulseAudio 9.0, и полная поддержка OpenSSL 1.1.0, с которой у нас много проблем при подготовке к Fedora 26. Это обновление OpenSSL оказалось настолько болезненное, что его уже внесли в список типичных анти-паттернов разработки. К сожалению, ситуация для криптобиблиотек довольно типичная. Они, порой, как будто специально внедряют антипаттерны разработки.

Эти и другие изменения уже обсуждаются коллегами-аналитиками на OpenNET.ru и на ЛОРе.

Canonical потеряла еще пару разработчиков

Сanonical продолжает терять квалифицированный персонал. Сначала уже известный вам разработчик systemd, Martin Pitt, объявил в своем блоге, что уходит в Red Hat. Пруфпик!

/images/martin_pitt_redhat.jpg

Сразу же за ним о своем уходе объявил и другой инженер Canonical, Daniel Holbach. Он пока не решил, где будет работать дальше.

Как стать контрибьютором в open source проект — идеи для первого патча и прочие рекомендации

По случаю перезапуска сайта хочется привести без сокращений статью, которую написал Aleksander Alekseev. Удивительно, но нас до сих пор спрашивают некоторые начинающие OSS-энтузиасты, с чего бы им начать общение с OSS-сообществом? Как раз на этот вопрос и пытается ответить Aleksander в этой статье:

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

Между прочим, интересный вопрос — а зачем это вообще кому-то может быть нужно? Для большинства людей работа над открытыми проектами — это в первую очередь возможность получить колоссальный опыт разработки, а также сделать нечто, чем будут пользоваться миллионы людей по всему миру (возможно, даже не зная об этом) ну как минимум еще ближайшие лет 10. Не стоит также списывать со счетов желание понять, как внутри устроены, скажем, операционные системы или компиляторы. Я пишу здесь об этом по той причине, что без достаточно сильной мотивации вы вряд ли найдете лишнее время для работы над каким-то там опенсорсом. Поэтому первым делом поймите для себя, что именно привлекает вас в данном конкретном проекте.

Примечание: Также вас может заинтересовать статья Как я прокачиваю владение английским языком. В мире open source, как правило, все разработчики общаются между собой на английском языке.

Далее предполагается, что вы определились с проектом, а также разобрались, как он компилируется, как прогоняются тесты, как происходит установка, а также нашли описание процесса разработки и место, куда нужно посылать патчи. Это не сложно. Примеры см в заметках Сборка LLVM-стека из исходников и чем она так интересна, PostgreSQL: сборка из исходников и настройка под Linux и Памятка по сборке ядра Linux из исходного кода. Также не повредит разобраться, как отлаживать проект. Тут все сильно зависит, помимо прочего, от используемого в проекте языка программирования, а также используемой вами ОС. Если проект написан на C или C++, то обратите внимание на мои заметки, посвященные GDB, LLDB и WinDbg. В любой непонятной ситуации не стесняйтесь обратиться за помощью в мейлинг лист или IRC-канал проекта.

Итак, с чего же можно начать:

  • Опечатки. Начните с малого. В любом достаточно крупном проекте полно опечаток, как в документации, так и в комментариях к коду. Патчу, который их исправляет, гарантированно все будут очень рады, а шансы сломать что-то таким патчем равны нулю. А значит его почти наверняка быстро примут. В процессе у вас сложится хорошее понимание, как в данном конкретном проекте нужно оформлять патчи, куда их нужно слать, и так далее.
  • Code review. Большинство программистов обожают писать код, но не очень любят читать или тестировать его. Поэтому многие проекты испытывают нехватку в ревьюверах. Будучи новичком в проекте, вы совершенно бесценны, как ревьювер! Ведь вещи, которые другим разработчикам могут казаться «очевидными», для вас таковыми не являются. При этом делать code review сравнительно просто. Как минимум, нужно проверить, что код действительно делает то, что нужно, ничего не ломает, проходит все тесты и сам покрыт тестами, не сыпет ворнингами при компиляции, хорошо документирован, оформлен в соответствии с принятым в проекте code style, не ломает обратную совместимость, и не содержит явных ошибок (например, утечки ресурсов). Что интересно, читая чужой код, вы быстро разберетесь во внутреннем устройстве проекта. Не бойтесь пропустить какие-то ошибки. Коммиттер, а также другие ревьюверы, прекрасно понимают, что вы работаете над проектом недавно, и в любом случае перепроверят за вами.
  • Исправление багов. На какие-то баги вы можете налететь сами. Особенно, если проект, над которым вы работаете — это библиотека. Но куда большие багов обычно репортят другие пользователи проекта. Проверьте багтрекер. Найдите первый понравившийся баг и попытайтесь его воспроизвести. Если не получается, постарайтесь выяснить у багрепортера детали. Может оказаться, что баг не воспроизводится или даже уже был исправлен. Закрыв тикет без какого-либо исправления, вы тоже окажете помощь проекту. Еще в поиске багов вам могут помочь санитайзеры и статические анализаторы кода.
  • Оптимизация. Обычно это халява, так как в сущности от вас требуется переписать код, чтобы он делал то же самое, только быстрее. Правда, чтобы найти настоящее «бутылочное горлышко», нужно не просто придумать синтетический бенчмарк, а иметь какую-то реальную и достаточно большую нагрузку. Само собой разумеется, выполнение оптимизации потребует от вас хорошего владения средствами профилирования кода.
  • Тесты. Печально, но факт — тесты программисты писать тоже не любят. Определите степень покрытия кода тестами, найдите непокрытые участки кода, напишите для них тесты. Удивительно, но многие программисты не понимают разницу между модульными и интеграционными тестами и никогда не слышали про property-based тесты. Если в проекте нет одного из этих видов тестов, предложите патч, который его добавляет.
  • Документация. А еще программисты часто не любят писать документацию. Проверьте, нет ли белых пятен в официальной документации или man-страницах проекта. Бывает еще так, что в документации есть несостыковки, устаревшая информация, или просто битые ссылки. Возможно, документацию можно улучшить, добавив в нее наглядных примеров.
  • Рефакторинг. В любом достаточно старом проекте есть места, которые можно переписать чуть лучше, чем они написаны сейчас. Большой файл с исходным кодом можно разбить на несколько, десяток параметров, передаваемых процедуре, можно объединить в одну структуру, и так далее. Важно, чтобы код не только решал стоящую перед ним задачу, но и был при этом читаемым!

Если позволите, хотелось бы дать еще пару советов. (1) Чем меньше ваш патч, чем больше шансов, что его примут. В частности, «заодно» подправлять отступы в не связанных с вашим патчем местах — очень плохая идея. (2) На первых порах любая прихоть коммиттера для вас — закон. Если коммиттер просит вас что-то исправить в патче, просто сделайте это, даже если ваши предпочтения не совпадают с предпочтениями коммиттера. Спор с ним попросту ни к чему не приведет. (3) Будьте предельно вежливы, используйте как можно больше слов please, thank you, и так далее. Любая грубость, троллинг, сарказм и так далее совершенно недопустимы!

Также не забывайте, что контрибьютить можно не только в виде патчей. Отвечать на вопросы в IRC и пользовательском списке рассылки, дополнять и исправлять wiki-сайт проекта, освещать новости проекта в своем блоге (можно создать рассылку ProjectName Weekly, если ее еще нет), писать обучающие статьи или, возможно, даже книги, посвященные проекту, организовать локальные юзергруппы, и так далее — все это тоже очень важные вклады в развитие проекта!

А контрибьютите ли вы в open source проекты и если да, то в какие, и каким образом?

Расписание DevConf.cz 2017

Помимо FOSDEM 2017 уже довольно давно опубликовали и расписание DevConf.cz 2017. К сожалению, в этом году организаторы были вынуждены ввести обязательную регистрацию участников, которая, по правде говоря, совсем не обременительная. В этом году мероприятие будет проходить с 27 по 29 января. Приезжайте в Брно, будем раны увидеться.