Что будет, если прямо сейчас написать новую ОС с нуля? Можно ли сделать её лучше других? Можно ли повысить безопасность и надежность? Можно ли предотвратить непредвиденное взаимодействие между приложениями?
«Как бы выглядела программная платформа, если бы она была построена с нуля с основной целью "обеспечение надежности"?»
Это те вопросы, на которые команда Microsoft Research пыталась ответить около 18 лет назад, именно тогда они придумали довольно крутое название для своей новой ОС - Singularity.
Цели
Singularity была направлена на устранение некоторых недостатков существующих операционных систем, таких как:
Общие уязвимости безопасности
Сбои из-за расширений, драйверов, дополнений
Непредвиденные взаимодействия между приложениями
Недостатки надежности
Стратегия
Использование безопасного языка программирования
Использование инструментов верификации
Улучшение системной архитектуры и дизайна
Архитектура Singularity
Singularity предоставляет 3 основных абстракции:
Программно-изолированные процессы (Software-isolated processes, SIP)
Контрактные каналы (Contract-based channels)
Программы на основе манифестов (Manifest-based programs, MBP)
Давайте подробнее рассмотрим каждый из них.
Программно-изолированные процессы, SIP
SIP похож на обычный процесс - он содержит ресурсы обработки, контекст и контейнер потоков. Довольно удивительно то, что все SIP-ы и ядро работают в одном адресном пространстве, что также означает, что пользовательский код работает с полными аппаратными привилегиями.
Разве это не контр-интуитивно? Ведь только что было упомянуто, что нужно улучшить безопасность, это одна из главных целей, но это изменение, похоже, только ухудшает ситуацию.
Во-первых, давайте подумаем, зачем вообще нужно это изменение, оно что-нибудь улучшает? Ответ положительный (очевидно), это улучшает производительность. Поскольку все SIP находятся в одном адресном пространстве, переключение контекста выполняется быстрее:
Нет необходимости переключать таблицы страниц
Нет необходимости аннулировать и повторно заполнять TLB-ы
Более того, системные вызовы также быстрее:
CPL всегда равен 0
Не нужно загружать стек ядра
Вместо отправки прерывания можно просто вызвать функцию
Убедившись, что с этим изменением производительность улучшится, давайте займемся кажущейся проблемой безопасности.
Каждый SIP на самом деле заблокирован - их нельзя изменить извне. Нет разделяемой памяти между разными SIP, нет сигналов, только явный IPC. Также нет никаких модификаций кода изнутри - нет JIT, загрузчиков классов, динамических библиотек.
Чтобы гарантировать, что SIP действительно заблокированы, используются следующие ограничения:
SIP указывает только на свои собственные данные - никаких указателей на другие SIP
Никаких указателей на ядро
SIP получает монопольный доступ к памяти, которую ему предоставило ядро
SIP не может создавать новые указатели - указатели могут быть предоставлены из надежного источника, такого как ядро.
С этими ограничениями, несмотря на наличие общего адресного пространства, совместного использования данных нет.
Контрактные каналы
Можно думать о каналах как о возможностях. Каждый SIP может иметь несколько каналов, через которые можно создавать IPC (inter-process communication, межпроцессное взаимодействие). Например, открытый файл - это канал, полученный от файлового сервера. Если SIP получает этот канал, это означает, что у него есть разрешение на доступ к нему.
Программы на основе манифестов, MBP
Манифест описывает возможности, необходимые ресурсы и зависимости SIP. SIP ничего не может сделать без манифеста и каналов. При установке манифеста проверяется, что он соответствует всем требованиям безопасности, все его зависимости соблюдены и он не создает конфликта с ранее установленным манифестом. Например, манифест драйвера предоставляет «свидетельство» того, что он не имеет доступа к оборудованию другого драйвера.
Вот еще несколько рисунков и таблиц, иллюстрирующих сравнение Singularity и других хорошо известных операционных систем.
Заключение
Singularity - лишь одна из множества экспериментальных операционных систем. Её последний релиз был в ноябре 2008 года, и с тех пор проект был остановлен.
Вот исходный код на Github.
Комментарии (16)
UncleAndy
29.09.2021 15:19-1На С++? А как-же "Использование безопасного языка программирования"? Я думал, они на Rust операционку пишут. Это было-бы реально безопасно.
mihail_romanov
29.09.2021 17:14+7Почему C++?
Не, там всё гораздо интереснее... Если я ничего не путаю (за давностью лет, увы, мог что-то и забыть), основной язык там Sing#, который расширяет Spec# для описания тех самых каналов, которые описываются в статье.
А Spec#, в свою очередь, это С# (на момент 2004 года, т.е. это C# v1.1), дополненный элементами контрактного программирования (от привычных уже not-nullable types, до весьма навороченных типа пред-/пост- условий, и т.д.)
Т.е. там получалась цепочка: программа/драйвер/модуль ядра пишется на управляемом языке (C#/Spec#/Sing#/ ... - в зависимости от того, какой уровень верификации требуется), компилятор выдает MSIL код, снабженный всякими доп. атрибутами.
В момент развертывания это всё докомпилируется в нативный код и верифицируется специальным компилятором, благодаря чему мы и получаем безопасный код.
На самом деле там (в Singularity) проделана громадная работа, которая, увы, осталась невостребованной (опять же, на сколько я знаю - но может быть я тут не прав и кто-то сможет дополнить).
crion
29.09.2021 17:05Нет, не взлетит. Для того что бы создать что то новое если это касаеться сингулярности, необходимо создавать новые инструменты, новые практики и подходы. К примеру возьмём такой простой пример как станок для выреза по металу. Так вот мы не можем просто так с нуля создать станок который будет резать до одно микрона, это всё этапы, с начало крупные детали а потом всё менее и менее. А SingularityОС использует старые инструменты, на счёт практи и подходов не не скажу.
mihail_romanov
30.09.2021 07:31Для того что бы создать что то новое если это касаеться сингулярности, необходимо создавать новые инструменты, новые практики и подходы
А чем вас не устраивает перечисленное в статье? Там было реально создано новое - управляемый язык, заточенный под нужды системной разработки.
Ну и подходы - уход от аппаратной защиты на уровне отдельных процессов, в сторону верифицируемого кода, исполняющегося в едином адресном пространстве?
Как по мне - вполне.
Vindicar
29.09.2021 17:09SIP не может создавать новые указатели — указатели могут быть предоставлены из надежного источника, такого как ядро.
Т.е. byte* data = (byte*)0xDEADBEEF не прокатит? Мне очень интересно, как это вообще в принципе может быть реализовано.mihail_romanov
29.09.2021 20:05+1За счет использования промежуточного языка (MSIL), у которого подобная операция (получение произвольного указателя) не реализована.
В принципе, понятие указателя и адресной арифметики в MSIL есть (хоть и очень ограниченное), но их можно контролировать или вовсе запретить.Vindicar
29.09.2021 22:19То есть ОС по сути является виртуальной машиной для такого языка? Потому что если приложение выполняет обычный машинный код для целевой архитектуры, оно может нарисовать такую инструкцию без проблем.
А виртуальная машина съест весь выигрыш в производительности…mihail_romanov
30.09.2021 07:28+1Смотря что вы понимаете под "виртуальной машиной". Например, если взять какой-нибудь классический учебник по архитектуре компьютера или ОС, то там наверняка будет предложено рассматривать ОС как виртуальную машину, изолирующую программы от аппаратуры.
Но я так понимаю вы спрашиваете о том, что ОС занимается интерпретацией инструкций промежуточного языка? Нет, это не так.
Как я писал в соседнем комментарии, базовая идея этого исследовательского проекта (ну или как минимум одна из идей) была в том, чтобы использовать для разработки managed code/managed environment, в котором(ой) одна из составляющих - это компиляция программы не сразу в машинный код, а в некий промежуточный (P-code, байт-код), который:
- имеет ограниченный набор инструкций (в том смысле, что там нет привилегированных команд, типа переключения контекста или записи в порты ввода-вывода)
- не имеет команд прямого обращения к памяти по адресу - вместо этого он везде использует обращения к конкретным структурам: локальным переменным, полям объектов, элементам массива, ...
- использует контролируемые механизмы выделения памяти (т.е., например, по запросу можно создать объект и получить его адрес, к которому можно потом будет применить команду из предыдущего пункта, но нельзя просто "получить простой кусок памяти").
Далее, такой промежуточный код докомпилируется в машинный код конечной платформы (это происходит или в момент выполнения, или в момент развертывания - т.е. мы исключаем вариант "установили готовый бинарник, заявив, что он безопасный, а на деле нет"). Исходно это задумывалось для целей переносимости, но здесь это играет еще и роль механизма безопасности - вы просто физически не можете в терминах промежуточного языка описать небезопасное поведение. А если оно всё же потенциально возможно, есть дополнительные проверки в момент докомпиляции.
Понятно, что когда тот же драйвер должен обращаться непосредственно к оборудованию, он делает это через небольшую прослойку HAL (hardware abstraction layer), которая написана на неуправляемом языке. Но:
- это ооочень маленькая часть кода
- обращение к таким API тоже можно контролировать (в runtime или в момент докомпиляции - это уже надо смотреть).
Ну вот собственно Singularity и должна была дать ответ на вопрос:
- на сколько такая схема жизнеспособно
- можно ли при использовании managed кода (который всё же несколько уступает по скорости unmanaged - там всё не так очевидно, но давайте не будем здесь углубляться), получить сравнимую производительность в достаточно низкоуровневых операциях, за счет убирания механизмов аппаратной защиты и необходимости переключения контекста.
Как бы ответ на оба вопроса - Да.yuriv
30.09.2021 09:41Ответ на оба вопроса очевидно нет. Поэтому МС и остановила разработку. Дорастовская попытка ограничить возможности программера языком ппрограммирования вместо интеллектуального анализа исходного кода и указания проблемных мест. Раст идёт в тот же тупик.
mihail_romanov
30.09.2021 10:55+2Ответ на оба вопроса очевидно нет.
Вы можете свое утверждение как-то подтвердить?
Мои аргументы:
- за пару лет небольшой команде исследователей удалось создать ОС с поддержкой приличного набора функционала. Тут и сетевой стек, и файловая система и работа с аппаратурой. При этом, помимо самой ОС (которая разрабатывалась на совсем не традиционных принципах), было сделана еще куча доработок, а также статьи, тесты, ... Так что результат - схема рабочая
- ну а тесты производительности в самой статье.Дорастовская попытка ограничить возможности программера языком ппрограммирования вместо интеллектуального анализа исходного кода и указания проблемных мест.
А где вы увидели ограничения языка программирования? Я говорил о контроле на уровне промежуточного кода. MSIL это вполне себе высокоуровневый ассемблер. Да, он запрещает прямой доступ к памяти по адресу, но имеет огромные возможности по обращению к известным структурам (т.е. тем, для которых известна вся метаинформация).
Ну а анализ там всё равно присутствует. Даже штатный JIT в .Net делает достаточно много различных (пусть и не очень "интеллектуальных" проверок).
А конкретно в Singularity при компиляции используется Boogie (это язык и среда для верификации программного кода). Как именно и в каких местах, увы, не подскажу, но если посмотреть исходные коды, то там обнаружится куча файлов с расширением .bpl (BoogiePL)Поэтому МС и остановила разработку.
Разве?
На сколько я помню, формальная причина закрытия проекта звучала как-то очень обтекаемо как раз в стиле "мы сделали всё планировавшееся и переходим к новым проектам".
А то, что конкретно этот проект не продолжил развитие, так это логично - какова ниша этой разработки?
Если бы у MS не было на тот момент собственной ОС, которая её полностью устраивала я бы еще поверил в то, что она может очертя голову броситься в проект разработки новой ОС. Но даже если бы Singularity показала бы какие-то бешенные результаты - сколько еще требуется вложить, чтобы довести её хотя бы до уровня ОС середины 90-х?
Ну а других ниш, интересных MS на тот момент я не вижу (Embedded была занята Windows CE, ОС для микроконтроллеров были практически не распространены или там жило что-то уровня MS DOS, ... что еще?)
easyman
30.09.2021 01:47-1Странно, что про https://github.com/CosmosOS/Cosmos никто не пишет.
Это ос на dotnet. Но пока не очень популярна. Отличается от singularity лицензией, для сборки потребуется Windows. Для запуска - VMware
hello_my_name_is_dany
30.09.2021 02:17Лет 5 назад ещё хоть как-то был жив, но сейчас тоже мёртвый проект
SShtole
… а выпустили, в итоге, «Висту».