Что будет, если прямо сейчас написать новую ОС с нуля? Можно ли сделать её лучше других? Можно ли повысить безопасность и надежность? Можно ли предотвратить непредвиденное взаимодействие между приложениями?

«Как бы выглядела программная платформа, если бы она была построена с нуля с основной целью "обеспечение надежности"?»

Это те вопросы, на которые команда Microsoft Research пыталась ответить около 18 лет назад, именно тогда они придумали довольно крутое название для своей новой ОС - Singularity.

Цели

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)


  1. SShtole
    29.09.2021 13:02
    +1

    … а выпустили, в итоге, «Висту».


  1. UncleAndy
    29.09.2021 15:19
    -1

    На С++? А как-же "Использование безопасного языка программирования"? Я думал, они на Rust операционку пишут. Это было-бы реально безопасно.


    1. Alex_ME
      29.09.2021 15:28
      +4

      Когда игралось с Singularity, никакого Rust не существовало.


    1. ioccy
      29.09.2021 15:32

      Это было больше десяти лет назад, никто уже ничего не пишет.


    1. alhel
      29.09.2021 16:46
      +2

      C# с модификациями


    1. mihail_romanov
      29.09.2021 17:14
      +7

      Почему C++?
      Не, там всё гораздо интереснее... Если я ничего не путаю (за давностью лет, увы, мог что-то и забыть), основной язык там Sing#, который расширяет Spec# для описания тех самых каналов, которые описываются в статье.
      А Spec#, в свою очередь, это С# (на момент 2004 года, т.е. это C# v1.1), дополненный элементами контрактного программирования (от привычных уже not-nullable types, до весьма навороченных типа пред-/пост- условий, и т.д.)

      Т.е. там получалась цепочка: программа/драйвер/модуль ядра пишется на управляемом языке (C#/Spec#/Sing#/ ... - в зависимости от того, какой уровень верификации требуется), компилятор выдает MSIL код, снабженный всякими доп. атрибутами.
      В момент развертывания это всё докомпилируется в нативный код и верифицируется специальным компилятором, благодаря чему мы и получаем безопасный код.

      На самом деле там (в Singularity) проделана громадная работа, которая, увы, осталась невостребованной (опять же, на сколько я знаю - но может быть я тут не прав и кто-то сможет дополнить).


  1. crion
    29.09.2021 17:05

    Нет, не взлетит. Для того что бы создать что то новое если это касаеться сингулярности, необходимо создавать новые инструменты, новые практики и подходы. К примеру возьмём такой простой пример как станок для выреза по металу. Так вот мы не можем просто так с нуля создать станок который будет резать до одно микрона, это всё этапы, с начало крупные детали а потом всё менее и менее. А SingularityОС использует старые инструменты, на счёт практи и подходов не не скажу.


    1. mihail_romanov
      30.09.2021 07:31

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

      А чем вас не устраивает перечисленное в статье? Там было реально создано новое - управляемый язык, заточенный под нужды системной разработки.
      Ну и подходы - уход от аппаратной защиты на уровне отдельных процессов, в сторону верифицируемого кода, исполняющегося в едином адресном пространстве?

      Как по мне - вполне.


  1. Vindicar
    29.09.2021 17:09

    SIP не может создавать новые указатели — указатели могут быть предоставлены из надежного источника, такого как ядро.

    Т.е. byte* data = (byte*)0xDEADBEEF не прокатит? Мне очень интересно, как это вообще в принципе может быть реализовано.


    1. mihail_romanov
      29.09.2021 20:05
      +1

      За счет использования промежуточного языка (MSIL), у которого подобная операция (получение произвольного указателя) не реализована.
      В принципе, понятие указателя и адресной арифметики в MSIL есть (хоть и очень ограниченное), но их можно контролировать или вовсе запретить.


      1. Vindicar
        29.09.2021 22:19

        То есть ОС по сути является виртуальной машиной для такого языка? Потому что если приложение выполняет обычный машинный код для целевой архитектуры, оно может нарисовать такую инструкцию без проблем.
        А виртуальная машина съест весь выигрыш в производительности…


        1. mihail_romanov
          30.09.2021 07:28
          +1

          Смотря что вы понимаете под "виртуальной машиной". Например, если взять какой-нибудь классический учебник по архитектуре компьютера или ОС, то там наверняка будет предложено рассматривать ОС как виртуальную машину, изолирующую программы от аппаратуры.

          Но я так понимаю вы спрашиваете о том, что ОС занимается интерпретацией инструкций промежуточного языка? Нет, это не так.

          Как я писал в соседнем комментарии, базовая идея этого исследовательского проекта (ну или как минимум одна из идей) была в том, чтобы использовать для разработки managed code/managed environment, в котором(ой) одна из составляющих - это компиляция программы не сразу в машинный код, а в некий промежуточный (P-code, байт-код), который:
          - имеет ограниченный набор инструкций (в том смысле, что там нет привилегированных команд, типа переключения контекста или записи в порты ввода-вывода)
          - не имеет команд прямого обращения к памяти по адресу - вместо этого он везде использует обращения к конкретным структурам: локальным переменным, полям объектов, элементам массива, ...
          - использует контролируемые механизмы выделения памяти (т.е., например, по запросу можно создать объект и получить его адрес, к которому можно потом будет применить команду из предыдущего пункта, но нельзя просто "получить простой кусок памяти").

          Далее, такой промежуточный код докомпилируется в машинный код конечной платформы (это происходит или в момент выполнения, или в момент развертывания - т.е. мы исключаем вариант "установили готовый бинарник, заявив, что он безопасный, а на деле нет"). Исходно это задумывалось для целей переносимости, но здесь это играет еще и роль механизма безопасности - вы просто физически не можете в терминах промежуточного языка описать небезопасное поведение. А если оно всё же потенциально возможно, есть дополнительные проверки в момент докомпиляции.

          Понятно, что когда тот же драйвер должен обращаться непосредственно к оборудованию, он делает это через небольшую прослойку HAL (hardware abstraction layer), которая написана на неуправляемом языке. Но:
          - это ооочень маленькая часть кода
          - обращение к таким API тоже можно контролировать (в runtime или в момент докомпиляции - это уже надо смотреть).

          Ну вот собственно Singularity и должна была дать ответ на вопрос:
          - на сколько такая схема жизнеспособно
          - можно ли при использовании managed кода (который всё же несколько уступает по скорости unmanaged - там всё не так очевидно, но давайте не будем здесь углубляться), получить сравнимую производительность в достаточно низкоуровневых операциях, за счет убирания механизмов аппаратной защиты и необходимости переключения контекста.

          Как бы ответ на оба вопроса - Да.


          1. yuriv
            30.09.2021 09:41

            Ответ на оба вопроса очевидно нет. Поэтому МС и остановила разработку. Дорастовская попытка ограничить возможности программера языком ппрограммирования вместо интеллектуального анализа исходного кода и указания проблемных мест. Раст идёт в тот же тупик.


            1. mihail_romanov
              30.09.2021 10:55
              +2

              Ответ на оба вопроса очевидно нет.

              Вы можете свое утверждение как-то подтвердить?

              Мои аргументы:
              - за пару лет небольшой команде исследователей удалось создать ОС с поддержкой приличного набора функционала. Тут и сетевой стек, и файловая система и работа с аппаратурой. При этом, помимо самой ОС (которая разрабатывалась на совсем не традиционных принципах), было сделана еще куча доработок, а также статьи, тесты, ... Так что результат - схема рабочая
              - ну а тесты производительности в самой статье.

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

              А где вы увидели ограничения языка программирования? Я говорил о контроле на уровне промежуточного кода. MSIL это вполне себе высокоуровневый ассемблер. Да, он запрещает прямой доступ к памяти по адресу, но имеет огромные возможности по обращению к известным структурам (т.е. тем, для которых известна вся метаинформация).

              Ну а анализ там всё равно присутствует. Даже штатный JIT в .Net делает достаточно много различных (пусть и не очень "интеллектуальных" проверок).

              А конкретно в Singularity при компиляции используется Boogie (это язык и среда для верификации программного кода). Как именно и в каких местах, увы, не подскажу, но если посмотреть исходные коды, то там обнаружится куча файлов с расширением .bpl (BoogiePL)

              Поэтому МС и остановила разработку.

              Разве?
              На сколько я помню, формальная причина закрытия проекта звучала как-то очень обтекаемо как раз в стиле "мы сделали всё планировавшееся и переходим к новым проектам".

              А то, что конкретно этот проект не продолжил развитие, так это логично - какова ниша этой разработки?
              Если бы у MS не было на тот момент собственной ОС, которая её полностью устраивала я бы еще поверил в то, что она может очертя голову броситься в проект разработки новой ОС. Но даже если бы Singularity показала бы какие-то бешенные результаты - сколько еще требуется вложить, чтобы довести её хотя бы до уровня ОС середины 90-х?
              Ну а других ниш, интересных MS на тот момент я не вижу (Embedded была занята Windows CE, ОС для микроконтроллеров были практически не распространены или там жило что-то уровня MS DOS, ... что еще?)


  1. easyman
    30.09.2021 01:47
    -1

    Странно, что про https://github.com/CosmosOS/Cosmos никто не пишет.

    Это ос на dotnet. Но пока не очень популярна. Отличается от singularity лицензией, для сборки потребуется Windows. Для запуска - VMware


    1. hello_my_name_is_dany
      30.09.2021 02:17

      Лет 5 назад ещё хоть как-то был жив, но сейчас тоже мёртвый проект