Сперва признаюсь, что я не профессионал в данной области. За жизнь я не прочел ни одной книги по программированию или информационной безопасности. Я — обычный юзер, который кое-чего захотел и не нашел готовых решений, которые бы ему подошли.
Известно, что в UNIX-подобных ОС (да и в Windows) любая программа, запущенная пользователем, наследует все права пользователя. По-умолчанию, нет ничего, что помешало бы любой запущенной нами программе удалить или передать кому-то наши приватные файлы. Да мы такой активности и не заметим.
Существует множество способов ограничить права недоверенным программам: запуск от имени другого пользователя; песочницы; виртуальные машины; SELinux итп.
Взглянем на концепцию domain transition в SELinux. Не вдаваясь в подробности, это работает как-то так:
- В SELinux существуют «домены», которые могут накладывать на программы дополнительные ограничения (в добавок к стандартным).
- Изначально пользователь работает в доверенном домене (назовем его «A»). Любая программа, запущенная пользователем, наследует домен и имеет доступ к приватным файлам пользователя.
- Пользователь может создать ограниченный домен («B») и запретить ему доступ к приватным файлам.
- Пользователь может указать следующее: «Если доверенный домен A запускает программу, помеченную такой-то меткой, то я хочу, чтоб эта программа работала в домене B, а не наследовала домен A».
Круто ведь? Если мы не доверяем, скажем, приложению «Skype», то можем ограничить его в правах аж так, чтоб он вообще не имел доступа ни к чему, что не является критически необходимым для его работы. Вот только создание такой политики лично у меня занимало часы. И я хотел иного.
Я хотел, чтоб все программы считались недоверенными, если я не указал иначе. Чтоб ни одна программа не имела доступа к файлам, которые я считаю приватными, если я не дал ей на это права. Так вам, программы!
А потом я захотел еще большего: иметь разные категории приватных файлов («заметки», «фото», «запасы аниме» итп.) и возможность предоставлять программе доступ к одной из категорий, не давая доступ к остальным.
Самым умным я себя не считаю. Сначала описал задачу на stackoverflow, stackexchange и форуме fedora. Но подходяшего мне варианта никто не прежложил. А так хотелось…
Пришлось придумывать собственную модель и интегрировать свой модуль в ядро Linux. К счастью, у Linux есть API (LSM) специально для создания модулей безопасности.
Итак, модель… Для меня важно, чтоб более опытные люди сообщили в комментариях о всех дырах, которые они видят в моей логике.
1. Пользователь может объявить до 64 «прав». Идентификатором права является целое число, но они могут иметь и понятные псевдонимы.
Примеры:
- Право читать приватные фото.
- Право читать/изменять приватные текстовые файлы.
- Право читать/изменять кукисы браузера.
2. Пользователь может быстро и легко для любого файла установить следующее:
а) Права, необходимые для чтения этого файла.
б) Права, необходимые для изменения этого файла.
в) Права, который этот файл может иметь, если это программа.
Примеры:
- Помечаем директорию с фотографиями как требующую права «чтение приватных фото» для доступа к ней.
- Помечаем программу firefox как не способную иметь никаких прав (не имеет смысла т.к. это метка по-умолчанию).
- Помечаем программу cat как способную иметь любые права.
3. Программа (процесс) не может иметь прав, которых не имел её родитель (запустившая её программа).
Примеры:
- недоверенный firefox не может использовать доверенный cat, чтоб считать приватный файл.
4. Процесс с pid 1 (родитель всех юзерспейс процессов) имеет все права. А далее права процесса определяются чтением метки исполняемого файла и удалением прав, которых не имел родитель. По-умолчанию, у исполняемых файлов нет прав.
С точки зрения пользователя, это выглядит как-то так:
Я хочу защитить приватные документы. Я объявляю, что право №10 будет означать «доступ к приватным документам». Одной командой я указываю, что директория /home/sion/docs теперь требует этого права для доступа к ней. С этого момента все приложения, которым я не дам упомянутое право, теряют доступ к этой директории.
Моя реализация называется Chariot LSM.
Право №63 на данный момент зарезервировано и определяет, позволено ли программе подключаться к любым IP, кроме localhost. Файрволл, короче. Так же воможно задавать требуемые права нодам в /dev (если мы хотим, к примеру, запретить доступ к микрофону или камере).
Тестирую и дорабатываю модуль уже около двух недель. Пока всё устраивает и даже нравится. Но пришлось выдать полные права некоторым процессам: systemd, agetty, bash, sh итп. Думаю, понятно, почему.
Так же есть возможность посмотреть «цепочку родителей» для любого процесса, если нужно узнать, в какой момент он потерял какое-либо право.
Обязательно сообщите, если вы видите критические дыры в этой модели.
Автор: бро