Операционная система с кибериммунитетом: кто, зачем и как создает KasperskyOS


|
Здравствуйте! Мы подразделение «Лаборатории Касперского», которое разрабатывает безопасную операционную систему KasperskyOS. Наша цель — создать ОС, у которой есть кибериммунитет, поэтому ей не страшно доверить управление умными автомобилями, сложными техническими процессами и важными информационными системами.

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

Содержание
Зачем нужна еще одна ОС
Может показаться, что в мире существуют ОС под любые задачи. Есть операционки общего назначения, такие как Windows, macOS или дистрибутивы на базе ядра Linux. Есть специализированные — для авиации и промышленности, с real-time-характеристиками и доказанной надежностью. Но полностью безопасных нет.
Обычно меры защиты разрабатываются в ответ на существующие или потенциальные известные угрозы. Но этот подход не дает 100% гарантий. С завидной регулярностью возникают новые классы угроз, которые разработчики не принимали в расчет.
Классический пример — техника возвратно-ориентированного программирования (return-oriented programming). Еще совсем недавно считалось, что исполнение вредоносного кода станет невозможным, если выполнить 2 условия:
  • запретить исполнение кода в областях, куда могут попасть пользовательские данные;
  • защитить от модификаций области памяти, где находится программный код.
Это не помешало хакерам и исследователям в области безопасности найти способ обойти защиту. Оказалось, что с помощью подмены адреса возврата из процедуры и используя части кода самого приложения и системных библиотек можно выполнить сложные действия и получить результат, который требуется злоумышленнику.
Мы в «Лаборатории Касперского» решили подойти к проблеме радикально: разработать подход, обеспечивающий надежную защиту от любых атак — как известных, так и перспективных. Изначально мы не ставили себе цель сделать новую операционную систему и рассчитывали, что задачу можно решить, используя уже разработанные ОС.
Как в KasperskyOS обеспечивается безопасность
Для начала немного теории. Как понять, безопасно решение или нет? Нужно с самого начала установить цели безопасности — требования, выполнение которых должно обеспечиваться при любых сценариях работы системы. Следовательно, в безопасном решении нужно сделать невозможным выполнение любых операций, способных повлиять на достижение целей безопасности.
 
Принцип очень простой: в процессе работы решения нужно проверять, способна ли та или иная операция негативным образом повлиять на безопасное функционирование системы, и если да, то такую операцию необходимо блокировать. Однако есть 2 сложности: нужно понять, какие операции надо контролировать, и оценить влияние этих операций на безопасную работу системы.
Александр Шадрин
руководитель группы разработки (Secure Hypervisor Development)
Начиная с 70-х годов прошлого века ведется активная разработка принципов создания безопасных систем, разрабатываются формальные модели разделения решений на домены с различным уровнем доступа.
В дальнейшем, к началу двухтысячных, когда технологии доросли до требований, предъявляемых теоретическими концепциями, получил развитие подход Multiple Independent Levels of Security (MILS). Он предусматривает разделение системы на изолированные домены безопасности и контроль всех операций, связанных с передачей данных между доменами. На этом подходе базируется большинство современных систем, к которым предъявляются высокие требования к безопасности и надежности их работы.
Экран диагностики KasperskyOS
Представим набор полностью изолированных программных компонентов. Они безопасны, пока не взаимодействуют друг с другом и окружающим миром. Ни кривой код, ни уязвимости в этих компонентах не страшны системе. Однако на практике полная изоляция бессмысленна и не нужна. Для выполнения функциональных задач различные компоненты ПО должны взаимодействовать как между собой, так и с внешним миром. Но чтобы поведение системы оставалось безопасным, все взаимодействия компонентов должны проводиться под контролем. Как это организовать?
Первое: нужно предоставить гарантии изоляции компонентов друг от друга. В MILS-системах за эту задачу отвечает ядро разделения (Separation Kernel). Обычно эту функцию выполняет микроядро или гипервизор.
Второе: нужно строго описать, как каждый программный компонент может взаимодействовать с другими. Тогда в результате появится возможность перечислить все подлежащие контролю операции.
Третье: создать в системе компонент-медиатор, через который будут проходить абсолютно все взаимодействия. Тогда у него будет возможность разрешать безопасные операции и запрещать опасные. Решение о том, какая операция является безопасной, принимается отдельным компонентом — вычислителем вердиктов безопасности (Policy Decision Point).
 
Впервые отделить логику вычисления вердиктов (Policy Decision Point) от их применения (Policy Enforcement Point) было предложено в 90-е годы в рамках проекта Flux Advanced Security Kernel (FLASK). На подходах, разработанных в рамках этого проекта, базируются многие решения в области безопасности, например, SELinux.
Екатерина Рудина
руководитель группы системных аналитиков
При вычислении вердикта нужно принимать в расчет сведения об особенностях реализации решения, о контексте, в котором выполняется операция, о целях безопасности и т. д. Для доказательства корректности взаимодействия компонентов можно вынести за скобки всю их внутреннюю активность — они изолированы, и им запрещено все, что явно не разрешено.
 
У нас есть декларация интерфейса взаимодействия, включающая описание всего, что необходимо для понимания специфики операций. Если найти способ преобразовать эти данные в параметры моделей безопасности, появится возможность задавать формальные политики безопасности с учетом особенностей каждого конкретного решения.
Александр Шадрин
руководитель группы разработки (Secure Hypervisor Development)
Policy Decision Point принимает решения, от которых зависит безопасность всей системы, поэтому мы должны быть полностью уверены в чистоте и безошибочности его кода. Правила вычисления вердиктов должны быть однозначны и математически корректны.
Воплощая эту концепцию в жизнь, мы создали специальный компилятор. Он принимает на вход декларативные описания взаимодействующих компонентов и конфигурацию безопасности.
Результат работы компилятора — программный код на языке C, определяющий функциональность Policy Decision Point. У автоматически генерируемого кода есть несколько преимуществ:
  • Доверие к такому коду выше, чем к написанному вручную. Например, вместе с кодом, сгенерированным на основе формальной модели, можно сгенерировать и набор тестов, проверяющих его соответствие модели. Упрощается и процесс формального доказательства определенных свойств полученного кода, например, предельного времени выполнения.
  • Становится возможным использовать простые наборы правил взаимодействия компонентов. Корректная работа правильно спроектированной системы предполагает лишь малое число стандартных потоков исполнения, которые требуется описывать. В то же время правила вычисления вердиктов могут быть сложными и разнообразными — это уже забота компилятора.
  • Инженер безопасности описывает поведение системы в терминах, с применением которых она была спроектирована. Есть возможность всесторонне учесть специфику решения.
  • Описание безопасности выполняется независимо от бизнес-логики решения.
Так появился движок, который выполняет вычисление вердиктов безопасности, — Kaspersky Security System (KSS).
Почему не Linux или другая операционная система
По сути, KasperskyOS — это идеальная специальным образом оптимизированная среда для работы KSS. Расскажем, почему мы не стали использовать существующие ОС в качестве такой среды.
Например, на базе Linux создано несколько механизмов и модулей безопасности: SELinux, AppArmor, GR security, SMACK, контейнеры и т. д. Однако все они оказываются бесполезными, когда скомпрометировано ядро ОС. Linux — классическое монолитное ядро, где все компоненты работают в одном адресном пространстве и могут влиять друг на друга. Да, код ядра Linux просматривают миллионы глаз, но по-настоящему тщательной ревизии подвергаются только наиболее ответственные компоненты ядра. В ядре Linux более 15 млн строк кода, и значительная его часть остается вне зоны пристального контроля Linux-сообщества. В результате часто обнаруживаются критичные уязвимости, эксплуатация которых позволяет скомпрометировать ядро Linux. Тем самым не реализуется главное требование по обеспечению безопасности — изоляция между доменами. Кардинально поменять архитектуру Linux вряд ли получится, уж если у Таненбаума не получилось переубедить Торвальдса, то у нас и вовсе шансов нет :)
Евгений Касперский с сетевым устройством на базе KasperskyOS
Что же с существующими микроядерными операционными системами? Ядро в таких системах обычно весьма компактно и благодаря этому лишено описанных выше недостатков, свойственных монолитным и гибридным архитектурам. Микроядра идеально подходят для создания ядер разделения в MILS-системах. Более того, есть несколько хороших защищенных микроядерных операционных систем с открытым исходным кодом, например, seL4.
Несмотря на все плюсы использования готового микроядра, мы пришли к выводу, что возможности существующих систем в области безопасности недостаточны для реализации нашего подхода. Обычно создатели ОС пытаются контролировать доступ к ресурсам. Именно ресурсами в первую очередь оперирует модель безопасности object-capability, которая используется в большинстве микроядерных операционных систем. Дальнейшие более изощренные свойства безопасности реализуются в виде прикладной логики. Возможности политик безопасности будут сильно ограничены, если мы возьмем только модель object capabilities.
Таким образом, оказалось, что использование готовых ОС не позволяет реализовать идеальную среду для работы KSS так, как мы ее видим. Поэтому и пришлось разрабатывать новую операционную систему.
Какие принципы лежат в основе KasperskyOS
Создавая KasperskyOS, мы следовали 3 основным концепциям:
I. Микроядерная архитектура. Чем компактнее ядро ОС, тем проще его исследовать и тем меньше возможностей для возникновения уязвимостей. На текущий момент базовая функциональность KasperskyOS реализована всего лишь в нескольких десятках тысяч строк кода.
II. Минимально возможная поверхность атаки на ядро ОС. Поверхность атаки на ядро ОС определяется числом системных вызовов и других каналов внешних воздействий. Если архитектура микроядерная, то в ядре нет драйверов, оно не взаимодействует через оборудование с внешними источниками воздействий. В этом случае поверхность атаки зависит лишь от количества используемых системных вызовов. У KasperskyOS всего 3 вызова не контролируются монитором безопасности — это вызовы, отвечающие за IPC. Для сравнения, у другой распространенной микроядерной ОС — QNX — их 116.
III. Гарантии изоляции. Необходимо исключить любую возможность обмена данными между процессами в обход KSS. Это зона ответственности микроядра операционной системы. Все эти составляющие в сумме позволили создать ОС с высоким уровнем безопасности.
Есть ли особенности в приложениях под KasperskyOS
Не всякое решение, созданное с применением KasperskyOS, безопасно по определению. Его необходимо правильно спроектировать. Для начала нужно определить те свойства решения, наличие которых мы считаем критичным с точки зрения безопасности. Исходя из данных требований, функциональность решения нужно разбить на изолированные компоненты, определить все возможные варианты их взаимодействия и, наконец, описать политики безопасности так, чтобы поведение системы оставалось безопасным.
Часть компонентов при этом могут быть недоверенными, на гарантии безопасности решения в целом это не повлияет. Отдельные компоненты могут быть атакованы, но в правильно спроектированной системе атака не приведет к нарушению этих гарантий, даже если злоумышленник получит возможность выполнять произвольный код. Это свойство информационной системы мы называем кибериммунитетом.
Как создается экосистема KasperskyOS
В фундаментальных компонентах KasperskyOS, таких как микроядро или Kaspersky Security System, нет заимствованного кода, там все выверено и оптимизировано нашей командой. В то же время основная прикладная функциональность системы у нас базируется на open source решениях.
Портируемые в ОС компоненты выбираем по их популярности. Например, библиотека Qt для создания графических приложений, WebKit и веб-сервер nginx очень востребованы, поэтому у нас они есть. Решения узкого назначения адаптируются под KasperskyOS по запросу, а те, которые все используют (какой-нибудь OpenCV), сами добавляем на «дорожную карту» и портируем.
Рабочие места в «Лаборатории» украшают как собственный дом
Большинство опенсорсных приложений портируется совершенно понятным способом — обычно за счет использования подмножества POSIX, которое KasperskyOS в существенной степени поддерживает. На сторонних разработчиков софта под KasperskyOS не накладывается никаких дополнительных ограничений, кроме тех, которые диктует сама архитектура системы.
В перспективе мы планируем открыть часть нашего кода.
То же самое касается сторонних библиотек с нашими изменениями, тем более что в случае GPL этого требует лицензия. Это позволит всем желающим самим портировать отдельные компоненты под нашу ОС и интегрировать их в общую систему сборки. Что касается перевода всего проекта в open source — такую возможность не исключаем, но пока четких планов на этот счет нет.
Кто и как создает KasperskyOS
Исторически команда KasperskyOS представляла собой отдельное подразделение. Поначалу операционная система была исследовательским проектом, потом напоминала бизнес-инкубатор для обкатки концепций, а на текущий момент относится к сфере продуктовой разработки.
Процесс разработки у нас разбит на итерации, как у многих Agile-команд. Мы упорно стремимся совместить Agile-практики с требованиями регуляторов. Индустриальные стандарты выдвигают требования не только к качеству кода, но и к процессам в компании: как должны вестись разработка, тестирование, проектирование. Зачастую стандарты описывают множество аспектов работы организации, вплоть до бюджетирования. У такой разработки сильный крен в сторону waterfall. Поэтому мы ведем разработку в стиле Agile, но нам приходится держать в голове множество дополнительных факторов.
В отделе разработки безопасной платформы существует несколько направлений.
Есть команда, которая занимается микроядром, а также разрабатывает драйверы для оборудования. Микроядро находится в фазе активного развития. В планах на 2020 год — улучшение поддержки многопоточности, совершенствование механизмов внутренних коммуникаций компонентов, расширение функциональности, связанной с безопасностью. Также в приоритете работа ОС в реальном времени и поддержка новых процессорных архитектур, например, ARMv8.
Команда KSS разрабатывает на Haskell и C. В эту команду входят люди с математической подготовкой. Они разрабатывают матмодели и с помощью формальных методов доказывают различные свойства нашей системы и отдельных ее компонентов.
Самой многочисленной является команда SDK. Она ведет разработку различных компонентов ОС, включая графическую систему, звук, файловые системы, слой совместимости с POSIX. Заодно команда поддерживает работу с open source компонентами: портирование, merge изменений и т. д.
Существует также команда разработки безопасного гипервизора, который позволяет запускать внешние ОС в отдельной партиции и интегрировать ее в систему с использованием KSS.
Наконец, сейчас формируется команда разработки инфраструктуры. Ей предстоит создавать сервисы для сборки и тестирования, анализа дампов и логов — всего, что может потребоваться для CI/CD и поддержки наших решений.
 
В «Лаборатории Касперского» есть много команд со своими интересными задачами. Например, группа, занимающаяся automotive-решениями, готовит на C++ реализацию стандарта AUTOSAR Adaptive Platform. Еще одна команда работает над концепцией защищенного корпоративного смартфона.
Максим Юдин
руководитель отдела разработки безопасной платформы (Secure Platform Development)
На каких языках пишется KasperskyOS
Один из самых активно используемых языков для разработки в KasperskyOS — это C++. Но микроядро, KSS и многие ключевые системные компоненты написаны на C, так как этот язык проще и удобнее, если речь идет о сертификации и доказательстве требуемых свойств программного обеспечения. С С++ сложностей в этом плане гораздо больше.
Кроме С++ и С, для создания средств разработки KasperskyOS мы активно используем Haskell. Например, на нем написан компилятор системы безопасности и ряд других внутренних инструментов.
Для доказательств заданных свойств программ и алгоритмов мы используем Event B. Все средства могут быть хороши, если они ведут к результатам.
Как нам живется на карантине
Эпидемия коронавируса внесла свои коррективы в работу подразделения. С середины марта мы всем офисом перешли на удаленку. Команда KasperskyOS переключилась на новый формат работы довольно легко — сервисы компании были готовы к такому событию. «Лаборатория Касперского» — международная компания, которая имеет офисы и партнеров по всему миру. Эффективное удаленное взаимодействие — это корпоративный стандарт компании на протяжении уже многих лет. Поэтому для перевода всех сотрудников на удаленку никаких дополнительных мер предпринимать не потребовалось.
Лаборатория Касперского разъехалась по домам, офис опустел
Эффективность удаленной работы подтверждается цифрами. Мы подсчитали ежесуточное число коммитов в целом по компании до дня X и после. Оказалось, что их поток почти не изменился. Никаких признаков сколько-нибудь существенных проблем нет. Только за первую неделю в новом режиме сотрудники стали созваниваться в десять раз чаще и в семь раз чаще устраивать встречи в онлайне. Можно сказать, что онлайн-работа кипит.
Многим из нас некомфортно без «живого» контакта. Но мы научились взаимодействовать в новых социально-культурных условиях и надеемся, что эти умения помогут нам эффективнее работать и после того, как COVID-19 сдаст свои позиции.
Как попасть в нашу команду
Зеленый Слон заскучал в одиночестве
В нашем подразделении работает около 40 человек, и мы продолжаем расти. В команду нужны:
  • программисты, которые глубоко разбираются в железе;
  • C / С++ программисты, которые великолепно знают какой-то аспект одной из современных ОС, к примеру, сети, файловую или графическую подсистему (особенно в команды, которые делают security-подсистему и SDK);
  • разработчики C++, которые будут создавать компоненты более высокого уровня в продуктовых командах;
  • специалисты по формальным моделям и по функциональному программированию;
  • Python-программисты, которые умеют разрабатывать отказоустойчивые распределенные системы (в инфраструктурную команду);
  • аналитики, которые помогут анализировать архитектуру решений на предмет рисков безопасности, строить модели угроз, формировать цели безопасности для продуктов.
Откликнуться на вакансии KasperskyOS можно здесь.
Каких навыков мы еще ждем от кандидатов?
Базовые требования к члену команды: глубокая техническая экспертиза, самостоятельность, готовность разобраться в сложной новой теме, умение работать в команде и внятно передавать друг другу информацию. Конечно, мы бы хотели видеть у себя людей, мотивированных развиваться. В ситуации, когда человек не знает, как решить задачу, один умоет руки, а другой задастся вопросом: «Как научиться решать такие задачи?» Начнет читать книги и статьи и обнаружит, что казавшееся невозможным еще как возможно.
Бэкграунд в компьютерной безопасности — огромный плюс. Создавая любой компонент, разработчик должен понимать связанные с ним риски безопасности и способы их устранения.
Поскольку разработка у нас ведется в основном из-под Linux, знание этой ОС и средств администрирования в ней тоже актуальны. В принципе, в команде встречаются люди, которые ведут разработку в Visual Studio под Windows и компилируют написанный код на Linux. Но это для нас, скорее, исключение.
Задачи у нас нестандартные, и решение может прийти с какой угодно стороны. Если у человека есть специфический опыт, которого нет больше ни у кого в команде, шансы устроиться к нам на работу возрастают.
 
Отбор кандидатов проходит в три этапа. Сначала короткий опрос по телефону на предмет базовых знаний, затем глубокое техническое собеседование на 2–4 часа. Финальный этап — собеседование с руководителем.
Максим Юдин
руководитель отдела разработки безопасной платформы (Secure Platform Development)
Понятно, что разработчиков, обладающих всеми нужными нам навыками, скорее всего, не существует в природе. Поэтому мы готовы брать специалистов с хорошими скилами в одной области, но в чем-то не дотягивающих до наших стандартов в другой, мотивированных при этом развиваться и учиться. Новичка можем посадить писать какой-нибудь не очень сложный драйвер, портировать third-party пакет на KasperskyOS или сделать небольшую фичу. Мы ожидаем, что человек не будет долго разгоняться и месяц кряду только читать документацию, а на примере конкретной задачи начнет вникать в проект.
Джуниоров у нас нет. Правда, мы подумываем о том, чтобы брать стажеров — в других отделах «Лаборатории Касперского» опыт со стажировками был удачным, и в компании уже налажен процесс отбора кандидатов — Kaspersky SafeBoard. Если вы заинтересовались, следите за новостями. Вы можете оставить нам свои контакты, и мы сообщим, когда придет время подавать заявку.
Карьерный рост в нашей команде типичен для R&D-департаментов. Сначала можно вырасти до старшего разработчика, потом до software-эксперта. Также можно пойти по административной линии — переквалифицироваться в тимлида, менеджера группы и т. д. Впрочем, мы стараемся строить команды так, чтобы и менеджеры у нас имели основательную техническую экспертизу.
В «Лаборатории Касперского» созданы условия для продуктивной работы. У нас комфортный офис с двумя тренажерными залами с саунами, массажный кабинет. В соцпакет входит ДМС со стоматологией для сотрудников и их детей. Есть программы релокации из регионов, обучение hard- и soft-скилам и 13 иностранным языкам, а также многое другое.
 
Чтобы лучше понять, чем занимается команда KasperskyOS, 20–21 мая подключайтесь к онлайн-конференции «KasperskyOS Night: Активируем кибериммунитет». Мероприятие будет интересно разработчикам и тимлидам, а также широкому кругу IT-специалистов. Участие бесплатное, регистрация по ссылке.
Андрей Духвалов
Стратег по развитию технологий «Лаборатории Касперского»
Что почитать до того, как устраиваться в команду KasperskyOS
Тем читателям Хабра, кто захочет прийти к нам на собеседование, рекомендуем почитать книги, знания из которых повысят шансы на успешное трудоустройство.
Современная инженерная культура:
Для тех, кто хочет разрабатывать инфраструктуру:
  • «Designing Data-Intensive Applications» M. Kleppmann
База для новичков:
Кое-что по Linux:
По операционным системам:
Исчерпывающая открытая книга по параллельному программированию:
Про память, кэши и прочее:
Оптимизация на C, C++ и ассемблере для x86:
По алгоритмам:
Математика для программистов:
Введение в ассемблер для ARMv8:
Современный C:
Введение в разработку бэкенда компилятора:
Список для разработчиков компиляторов от Квентина Карбоне:
Челлендж от команды KasperskyOS
«Лаборатория Касперского» подготовила несколько задач для желающих войти в команду. Можно решить одну из двух задач на выбор или обе. Присылайте результаты на tatyana.derevyanko@kaspersky.com или заполняйте форму в конце раздела, а команда экспертов выберет самые крутые варианты и пригласит их авторов на финальное собеседование.
Задача про системное программирование
Описание задачи
Sand — игрушечный sandbox, реализованный с использованием технологии VT-x. Он может запускать 32-битный код под контролем гипервизора.
Требуется внести ряд улучшений в его работу.
Замечание: руководство по настройке рабочего окружения использует материалы из статьи.
Рабочее окружение
Для тестирования гипервизора потребуется компьютер с поддержкой технологии аппаратной виртуализации VT-x и расширением EPT.
Предполагается, что на компьютере установлена операционная система GNU/Linux, а в ядро Linux загружены модули kvm и kvm_intel.
Замечание: проверить, поддерживаются ли процессором необходимые расширения, можно, просмотрев содержимое файла /proc/cpuinfo. В поле flags должны встречаться значения vmx и ept. Также нужно убедиться, что в KVM включена вложенная виртуализация. Это можно сделать, прочитав специальный файл /sys/module/kvm_intel/parameters/nested. Если опция включена, вы увидите значение Y. Если опция выключена, включить ее можно, перезагрузив модуль командой: modprobe -r kvm_intel; modprobe kvm_intel nested=1.
Так как гипервизор — модуль ядра, тестировать его на рабочей машине непосредственно может быть плохой идеей. Поэтому для экспериментов будет использоваться Qemu/KVM. Создадим минимальную сборку системы GNU/Linux для запуска в Qemu, а модуль ядра будем линковать в ядро гостевой Linux.
Для сборки ядра потребуется установить несколько дополнительных пакетов.
Замечание: данная инструкция описывает создание рабочего окружения для дистрибутива Ubuntu, но использование Ubuntu не является обязательным. Для других дистрибутивов процедура настройки рабочего окружения будет аналогичной.
Потребуются следующие пакеты:
ncurses-dev build-essential libssl-dev libelf-dev 
Замечание: возможно, при сборке выяснится, что упущены еще какие-то зависимости. Тогда требуемые пакеты также следует установить.
  • Создадим папку sand в удобном месте на файловой системе.
  • В папке sand создадим подкаталоги build и source.
  • Скачаем архив с исходным кодом ядра Linux версии 5.5.11 с сайта kernel.org в sand/source и разархивируем.
  • Скачаем архив с исходным кодом свежего busybox c сайта busybox.net в sand/source и разархивируем.
  • Создадим в папке sand/build подкаталоги linux-5.5.11 и busybox-1.31.1.
  • Находясь в папке sand, запомним положение на файловой системе в переменную окружения PROJ=`pwd`.
  • Перейдем в каталог sand/source/linux-5.5.11 и сконфигурируем сборку:
make O=$PROJ/build/linux-5.5.11 x86_64_defconfig
make O=$PROJ/build/linux-5.5.11 kvmconfig 
  • Соберем ядро, параметр -j зависит от количества ядер в системе, не переборщите:
make O=$PROJ/build/linux-5.5.11 -j4
  • Перейдем в каталог sand/source/busybox-1.31.1 и сконфигурируем сборку:
make O=$PROJ/build/busybox-1.31.1 defconfig
make O=$PROJ/build/busybox-1.31.1 menuconfig
Надо включить опцию «Build BusyBox as a static binary» в Busybox Settings, опцию можно найти через поиск Kbuild (введите '/', как в vi).
  • Соберем busybox, для этого перейдем в sand/build/busybox-1.31.1 и введем:
make -j4
make install
  • Создадим минимальную файловую систему, для этого создадим папку sand/build/initramfs и перейдем в нее.
  • Введем следующие команды:
mkdir -pv {bin,sbin,etc,proc,sys,usr/{bin,sbin}}
cp -av $PROJ/build/busybox-1.31.1/_install/*
  • Создадим init-скрипт:
touch init
chmod +x init
  • Введем в него следующий код:
#!/bin/sh
mount -t proc none /proc
mount -t sysfs none /sys
mount -t devtmpfs none /dev
echo -e "Hello, Mr. Sandman!\n"
exec /bin/sh
  • Соберем initramfs:
find . -print0 \
| cpio --null -ov --format=newc \
| gzip -9 > $PROJ/build/initramfs.cpio.gz
  • Проверим, что система работает, запустим ее в qemu следующей командой из каталога sand:
qemu-system-x86_64 \
-kernel build/linux-5.5.11/arch/x86_64/boot/bzImage \
-initrd build/initramfs.cpio.gz \
-nographic -append "console=ttyS0" \
-cpu host \
-machine q35 \
-enable-kvm
Замечание: выйти из терминала Qemu можно, нажав Ctrl+A, C и следом q, Enter.
Работа над задачей
Перейдем в sand/source/linux-5.5.11 и наложим патч 0001-Introduce-skeleton-of-VTX-sandbox.patch (кнопка для скачивания ниже).
Изменения будем делать в каталоге sand/source/linux-5.5.11/drivers/misc/sand, а сборку будем запускать в sand/build/linux-5.5.11, вызывая make.
Для начала соберем утилиту sandctl, которая понадобится для работы на initramfs. Перейдем в sand/source/linux-5.5.11/drivers/misc/sand и выполним команды.
gcc sandctl.c -o sandctl -static
cp sandctl $PROJ/build/initramfs/usr/bin
find . -print0 \
| cpio --null -ov --format=newc \
| gzip -9 > $PROJ/build/initramfs.cpio.gz
Пересоберем ядро после наложения патча, для этого, находясь в каталоге sand/build/linux-5.5.11, выполним:
make -j4
Запустим Qemu, чтобы проверить, что все работает. Команда уже указывалась выше.
В гостевой сессии вызовем команду:
sandctl 0x83 0xC0 0x01 0xF4
Вывод должен быть примерно таким:
Will run the following code: 83 C0 1 F4 
[ 50.113457] sand: Going to run 4 bytes of code
[ 50.114073] sand: Pin based exec control: 1f
[ 50.114568] sand: Cpu based VM exec control: 40061f2
[ 50.115155] sand: VM exit controls: 36ffb
[ 50.115617] sand: VM entry controls: 11fb
[ 50.116133] sand: VM Exit Reason c
[ 50.116550] sand: ip: 1003
Finished sandbox properly, state:
eax = 1
ebx = 0
ecx = 0
edx = 0
0x83 0xC0 0x01 0xF4 — программа, прибавляющая 1 к содержимому регистра eax и вызывающая инструкцию HLT. Как результат, мы видим в eax виртуального процессора единицу после исполнения. Мы также видим, что регистр eip виртуальной машины сместился на 3 от точки входа 0x1000. А выход из виртуальной машины произошел из-за инструкции HLT (VM Exit Reason c).
Теперь все готово, чтобы приступить к решению задач.
Важные ограничения и дополнения
На гостевой код накладываются следующие ограничения:
  1. Код может использовать для хранения состояния только регистры и стек (растет с адреса 4096 вниз).
  2. Код не должен переходить по адресам ниже 4096 (там расположен стек) и выше 8192, там память не отображена.
  3. Длина кода не может превышать 4096 байт.
Код запускается при помощи утилиты sandctl, ей в качестве аргумента передается последовательность из байт в HEX-кодах. Это код, который требуется запустить.
Перед началом выполнения регистровое состояние sandbox сбрасывается в нуль. В случае успешного исполнения кода под контролем гипервизора sandctl выводит
финальное состояние регистров eax, ebx, ecx и edx.
Sandctl обращается к драйверу sand, который и реализует функциональность
гипервизора. Обращение происходит через вызов IOCTL misc-устройства /dev/sand.
Задания
Замечание: не обязательно выполнять все задания. Пожалуйста, выполните те задания, которые сможете.
  1. Сделайте так, чтобы при деинициализации модуля на всех процессорах в системе вызывалась инструкция VMXOFF.
  2. Можно написать гостевой код, который никогда не завершится. Sandbox так и зависнет в контексте ядра. Сделайте возможность досрочного завершения такого зависшего кода. Подойдет любой способ, позволяющий завершить sandbox раньше по таймауту.
  3. Ограничение #1 мешает писать функциональный код для исполнения в sandbox. Сделайте так, чтобы по адресу 8192 была доступна память для глобальных данных. Напишите гостевой код, который будет демонстрировать использование этой памяти. Для лучшей демонстрации результирующее состояние регистров должно формироваться на основе вычислений с использованием глобальных переменных.
  4. Чтобы гостевой код мог получать данные из внешнего мира, реализуйте обработку гипер-вызовов. Напишите код, демонстрирующий получение значения от гипервизора и выполнение вычислений с использованием этого значения.
  5. Sand_vm_launch выполняет не все требования System V x86_64 ABI, дополните функцию так, чтобы сохранялись и восстанавливались все callee-saved ресурсы.
  6. Sand не использует EPT (второй уровень трансляции адресов). В результате код, исполняемый в sandbox, не может управлять трансляцией адресов самостоятельно. К тому же гость не может использовать физическую память выше 4 гигабайт. Сделайте простое отображение гостевой физической памяти в хостовую через EPT, измените гостевые таблицы трансляции, чтобы отобразить гостевые виртуальные адреса на гостевые физические один-к-одному.
  7. Если в госте исполнить INT3 (инструкция 0xCC), то получится Triple Fault. Реализуйте возможность обработки простейших исключений в sandbox. Пусть в момент, когда приходит гостевое исключение, хост получает уведомление через гипервызов.
Дополнительные вопросы
  • Какие проблемы с организацией кода вы можете заметить? Попробуйте исправить код на свой вкус.
  • Есть ли в коде ошибки? Как их исправить?
  • При сборке модуля objtool ругается на странную работу со стеком в функции sand_vm_launch. Попробуйте при помощи аннотаций в коде объяснить objtool, что происходит.
Задача про справки
Гражданин обращается за справками с0, c1, c2, ..., cN в различные конторы k0, k1, k2, ..., km.
Начальный набор справок, которые гражданин имеет на руках, может быть непустым.
Целевых справок, которые требуется получить гражданину, может быть несколько.
После подачи справки c1 в контору k1 она переходит в состояние 2, где может выдавать справку c2.
Для получения справок гражданин подает заявление в контору. Заявление на получение справки может быть подано, если выполнены условия конторы (набор справок, которые надо подать в контору для получения следующей справки). Если какая-либо из целевых справок не получена, и при этом возможностей для подачи заявлений нет, это означает, что гражданин не достиг своей цели.
Пример описания правил работы контор:
k1[0] (с1, с2, с3) -> k1[1] (c0)
k2[0] () -> k2[1] (с1)
k2[0] () -> k2[0] (с4)
k3[0] () -> k3[1] (с2)
k3[1] (с1) -> k3[2] (c3)
k4[0] (с4) -> k4[1] (c1)
Требуется
1. Определить, что целевые справки в принципе можно получить при заданных правилах работы контор.
2. Составить алгоритм получения целевых справок, гарантирующий, если это возможно, получение всего целевого набора справок.
3. Составить такой алгоритм получения целевых справок, чтобы количество обращений гражданина в конторы было бы минимальным.
Дополнительные условия
Получение справок может занимать время и стоить денег.
4. Предложите алгоритм, позволяющий минимизировать время, затрачиваемое на получение целевого набора справок.
5. Предложите алгоритм, позволяющий минимизировать стоимость получения целевого набора справок.
Пусть каждая справка имеет срок действия, а конторе для выдачи справки требуется время.
Таким образом, может случиться ситуация, при которой срок действия какой-либо имеющейся на руках справки истечет, при этом другие справки из целевого набора еще не будут выданы.
6. Требуется определить, что при заданных правилах работы контор с учетом сроков действия справок и сроков подготовки справок может быть получен целевой набор справок так, что ни для одной из них срок действия еще не истек.