В предыдущей статье мы рассмотрели сборку и установку пакета на Linux системах, в которой упомянули про Linux Kernel Module (LKM) и обещали раскрыть позднее подробности о пути к нему и его создании. Ну что ж, настало его время. LKM – мы выбираем тебя. "Windows драйвер мы заменили на Linux Kernel Module LKM…" итак, вернёмся мысленно к самому началу пути. Мы имеем Windows драйвер, который обеспечивает отслеживание и перехват событий обращения к файлу. Как его перенести или чем заменить в Linux системах?  Покопавшись в архитектуре, почитав про перехват и реализацию подобных технологий в Linux – мы поняли, что задача абсолютно нетривиальная, содержащая кучу подводных камней. Inotify Закинув удочки на пару форумов, посоветовавшись с коллегами, было принято решение «копать» в сторону Inotify. Inotify – файловый монитор, который логирует события в системе уже после того, как они произошли. Но у него есть «брат» – fanotify. В нём мы можем добавить ограничение доступности на события открытия, копирования файла. Но нам необходимо иметь такую же возможность и для событий удаления, переименования, перемещения, а, следовательно, fanotify нам в этом не поможет. Хочу заметить, что fanotify – это userspace утилита, соответственно при её использовании нет проблем с платформопереносимостью.  Virtual File System Следующим этапом изучения стала возможность реализации перехвата обращений при помощи VFS. После анализа VFS на основе Dtrace, eBPF и bcc, стало понятно, что при использовании данной технологии возможно выполнять мониторинг событий, происходящих в системе. В данном случае, перехват осуществляется через LKM. В рамках изучения реализации различных модулей под разные ядра выявлено следующее:     •   перехват не всегда позволяет отследить полный путь к файлу;      •   при перехвате обращения к файлу через открытое приложение, а не из проводника, отсутствует путь к файлу в аргументах;      •   для каждого ядра необходима своя реализация. Janus, SElinux и AppArmor В ходе исследования, была найдена статья по расширению функциональности системы безопасности ядра Linux. Отсюда следует, что на рынке существует достаточное количество решений. Самым легко реализуемым является Janus. Минусом решения выступает отсутствие поддержки свежих ядер и все вышеописанные проблемы LKM хука. Реализация SELinux и AppArmor представляет квинтэссенцию всего описанного и изученного ранее. Модуль SELinux включает в себя основные компоненты:     •   сервер безопасности;     •   кэш вектора доступа (англ. Access Vector Cache, AVC);     •   таблицы сетевых интерфейсов;     •   код сигнала сетевого уведомления;     •   свою виртуальную файловую систему (selinuxfs) и реализацию функций-перехватчиков.  После всех этих бесконечных «но», на помощь нам пришёл Хабр!  Наткнувшись на статью, стало ясно, что это наш случай. Обработка перехвата Изучив предложенные данные по ftrace  и реализации из самой статьи, сделали аналогичный LKM модуль на базе ftrace. Данная утилита, в свою очередь, работает на базе файловой системы debugfs, которая в большинстве современных дистрибутивов Linux смонтирована по умолчанию. Hook'и добавили на события к уже имеющимся clone и open:     •   openat,     •   rename,     •   unlink,     •   unlinkat. Таким образом, удалось обработать открытие, переименование, перемещение, копирование, удаление файла.  Взаимодействие Теперь нам нужно реализовать связь между модулем ядра и приложением userspace. Для решения данной задачи существуют разные подходы, но в основном выделяют два:     •   socket между kernel и userspace;     •   запись/чтение в системной директории в файл.  В итоге, мы выбрали netlink socket, так как в Windows мы используем аналогичный интерфейс - FltSendMessage. Можно было использовать inet socket, но это наименее защищённое решение.  Также столкнулись с такой проблемой, что на .Net Core, на которой реализовано userspace приложение, отсутствует реализация netlink. Поэтому пришлось реализовывать динамическую библиотеку с реализацией netlink и уже её подключать в проект.  Также, в дальнейшем оказалось, что некоторые функции отсутствуют в Net.Core – например поиск по pid процесса имени пользователя, которому принадлежит этот процесс. Примеров данной реализации оказалась масса, но, в рамках нашего приложения, не удалось их реализовать. Поэтому реализовали в той же библиотеке свою функцию нахождения uid пользователя, по которому используя системные функции можно найти имя.  Доработка модуля По итогу добавили соединение по netlink в инициализацию LKM.  Socket ожидает перехвата события обращения к файлу. Модуль, перехватывая событие, передаёт имя файла, pid и имя процесса. Userspace приложение, получая данную информацию, обрабатывает её и отвечает, что делать с файлом (блокировать или разрешать доступ). Впоследствии модуль возвращает соответствующий системный вызов. Позднее, для работы другого приложения в данный модуль, добавили возможность блокирования доступа к определённому файлу (по его полному пути) для всех процессов, кроме определённого (определяем по pid процесса). Интеграция в процесс установки Так как первые два минуса LKM удалось преодолеть через реализацию ftrace, третий никто не отменял. Мало того, что под каждое ядро нужна сборка модуля, уже в процессе использования он может «протухнуть». Было принято решение добавить его пересборку перед каждым запуском userspace приложения.  В статье по сборке Linux пакетов было описано, что «службу», для которой мы реализовываем обработку перехвата обращения к файлу, мы «демонизировали» путём добавления в system. Поэтому для демона.service добавляем два дополнительных пункта, помимо ExecStart и ExecStop будут: а в сам prestart.sh: В завершение хочется отметить: возможно, путь, по которому мы пошли, не самый «красивый и элегантный», но он содержит отработанную и проверенную логику работы на ОС Windows. Было бы полезно услышать в комментариях мнение читателей статьи. Возможно, есть более разумное решение задачи. Например, наш DevOps в тот момент, когда мы автоматизировали сборку пакета Linux и обрабатывали/добавляли LKM, предложил реализовать логику с использованием Access Control List (ACL). Скорее всего в дальнейшем мы займёмся переработкой нашего продукта под Linux.  И да, скоро будет новая статья о том, как мы переносили MS Forms на Avalonia и его интеграции в Linux. Статья по созданию LKM на базе ftrace Где мы можем получить uid пользователя в системе по pid процесса Netlink socket Разработчик