Полгода назад я показывал ядро OptimaOS — Rust‑ядро, которое загружается на реальном x86_64. С тех пор вокруг него появились собственная файловая система (ФС), установщик внутри прошивки, формат исполняемых файлов и модель приёмки, где доказательство можно проверить машинно.
Первая статья собрала много вопросов. Зачем ещё одна операционная система (ОС), чем она отличается от Linux, почему GPL, как относиться к коду, написанному с помощью LLM (large language model, большая языковая модель). Постараюсь ответить на все вопросы.
Зачем ещё одна ОС
Вопрос справедливый, так как этого добра много, и большинство умирает на стадии «hello, world» в QEMU. OptimaOS возможно когда‑то пригодится в этих сферах:
Доверенная рабочая среда для госсектора и КИИ (критическая информационная инфраструктура). Тут нужна возможность проверить каждый слой: загрузчик, ядро, ФС, установщик, пакеты. Собрать из исходников, сравнить хеши, проверить подписи и предъявить аудитору доказательства. Коробка с закрытым кодом такого не даёт.
Промышленность и edge (вычисления на периферии). Один и тот же код должен работать на разных устройствах. Форк под каждый SoC (system on chip, система на кристалле) — это отдельный аудит безопасности, отдельная команда, отдельная ветка поддержки и свой набор регрессий. Я строю одно ядро, различия выношу в runtime‑политику (политику времени выполнения).
Исследовательский стенд. В зрелых ОС дорого пробовать capability‑модель (модель мандатов доступа) без root (суперпользователя), новый формат исполняемых файлов, собственную ФС, машинно‑проверяемую приёмку. Здесь это можно сделать на небольшом масштабе и посмотреть, что получится.
Учебная платформа. Системное программирование проще изучать на коде, который можно прочитать целиком за вечер. Ядро Linux целиком за вечер не прочитать: одна подсистема больше иного проекта.
Windows на домашнем ноутбуке я не заменяю, и такой цели нет. Совместимость с играми также не обещаю.
Что появилось с первой статьи
Если коротко: из ядра выросла устанавливаемая система.
Собственный дисковый layout (разметка диска): GPT (GUID Partition Table), ESP (EFI System Partition) и раздел OptimaFS
OptimaFS — ФС с адресацией по содержимому и проверкой целостности
Установщик внутри UEFI‑образа (Unified Extensible Firmware Interface): вставил USB, загрузился, установил, задал логин и пароль, вошёл в рабочий стол
Свой формат исполняемых файлов OPTX и загрузчик
Модель процессов: PID 1 (process identifier), кооперативный планировщик, IPC (inter‑process communication, межпроцессное взаимодействие)
Display server вынесен в отдельный процесс
Драйверы после
ExitBootServices: свой heap (куча), COM1, ATA PIO, AHCI (SATA), NVMe (PCI Express) — с записью и сбросом кеша (flush).Лицензия GPL-2.0-only с DCO (Developer Certificate of Origin) вместо GPL-3 с коммерческой лицензией и CLA (Contributor License Agreement).
Как система загружается
UEFI (Unified Extensible Firmware Interface) — интерфейс прошивки, который приходит на смену BIOS (Basic Input/Output System). Прошивка ищет на ESP (EFI System Partition) файл EFI/BOOT/BOOTX64.EFI и передаёт ему управление. Дальше начинается наш код.
ExitBootServices — точка, где прошивка перестаёт помогать. После неё нельзя пользоваться её сервисами, читать диск через BlockIO (протокол блочного ввода‑вывода UEFI), рисовать через GOP (Graphics Output Protocol) и получать события ввода. Всё, что нужно для жизни, поднимается самостоятельно: свой heap на 32 MiB, COM1 для диагностики, драйверы хранилищ, framebuffer, обработка ввода.
Собственный heap и драйверы меняют статус системы. Она переходит из режима «демонстрация загрузки» в рабочий режим.
Архитектура: механизмы и политика
Главный принцип зафиксирован в ADR-0002: одно ядро, разные runtime‑профили. Ядро отвечает за механизмы. Политика живёт в runtime‑профилях и сервисах пользовательского пространства (userspace).
В ядре находятся:
управление памятью и page tables (PML4 → PDPT → PD → PT);
планировщик и контекстные переключения;
IPC‑шина с типизированными endpoint’ами (точками входа);
capability‑граф с квотами и TTL (time to live);
системные вызовы (syscall) и ABI (application binary interface);
обработка page fault и прерываний;
HAL (hardware abstraction layer) для железа.
В userspace и policy‑слое решается:
какие сервисы запускать и с какими правами;
какие правила политики применять;
как планировать задачи под профиль (home — интерактивность, server — пропускная способность);
какие syscall‑паттерны разрешены конкретному процессу.
В основной части ядра unsafe запрещён на уровне компилятора: код с небезопасными операциями просто не соберётся. Исключения перечислены явно — HAL, MMIO, PCI, APIC, UEFI handoff — и живут в отдельном слое.
Часть драйверов (ATA/AHCI/NVMe) пока поднимается в kernel stage. Цель — вынести их в userspace‑сервисы. Сначала нужно было доказать, что система вообще может читать и писать на реальный диск после выхода из boot services. Этот этап пройден.
Диск, OptimaFS и установщик
Своя разметка диска
Раньше установка заканчивалась генерацией скрипта для Windows diskpart, который создавал ESP и NTFS. Такой подход остался от старых сценариев. К архитектуре OptimaOS он отношения не имел. Теперь у OptimaOS своя разметка диска (layout). LBA (logical block address) в таблице — адрес блока на диске.
# |
Что |
Размер |
Тип |
Содержимое |
|---|---|---|---|---|
0 |
Protective MBR |
LBA 0 |
MBR |
чтобы legacy‑инструменты не снесли GPT |
1 |
GPT header + entries |
LBA 1…33 |
GPT |
primary + backup в конце диска |
2 |
ESP |
256 MiB |
FAT32 |
только |
3 |
SYSTEM |
остаток диска |
OptimaFS (свой GUID) |
|
GPT (GUID Partition Table) — таблица разделов, где каждый раздел описан 128-битным идентификатором. Protective MBR нужен, чтобы старые утилиты приняли диск за занятый и не переписали таблицу. ESP — единственный раздел, который читает прошивка. Она умеет работать только с FAT32 или FAT16, отсюда компромисс.
ESP получается маленьким «трамплином». Всё системное и пользовательское живёт на OptimaFS. Избавиться от FAT на этом слое нельзя: формат диктует внешняя прошивка. Мы на это не влияем.
OptimaFS
OptimaFS (ADR-0012) строится на простой идее: имя объекта — это SHA-256 (хеш‑функция) его содержимого. Объект либо хешируется в свой адрес, либо считается повреждённым.
две копии superblock (суперблока), каждая с собственной контрольной суммой;
content‑addressed (адресация по содержимому) объекты;
append‑only (только добавление) / COW (copy‑on‑write) семантика;
блоки 4 KiB;
backend‑agnostic
BlockStore(не зависит от носителя): один код работает поверх файла, UEFIBlockIOи реального драйвера;проверка целостности при каждом чтении.
Пакетный менеджер использует ту же идею адресации. Пакет и файл в системе проверяются одинаково — по хешу. Это удобно: не нужно объяснять пользователю две разные модели доверия.
Установщик в прошивке
Пользовательский сценарий звучит обыденно: вставил USB, загрузился, установил, задал логин и пароль, вошёл в рабочий стол. Внутри это несколько разных миров.
UEFI‑приложение пишет GPT и создаёт разделы.
Форматирует SYSTEM как OptimaFS через
BlockIO.Копирует payload (полезную нагрузку) из
/OPTIMA/SYSTEM/**на USB в/system/**.Ставит загрузчик в ESP.
Создаёт учётную запись, сохраняет её в OptimaFS, проверяет вход и сообщает результат.
Перезагружается с диска и поднимает login → desktop.
Каждый шаг оставляет маркер: [OPTIMA_INSTALL_OK], [OPTIMA_ACCOUNT_OK], [OPTIMA_LOGIN_OK], [OPTIMA_DESKTOP_OK]. По этим маркерам harness (тестовый стенд) проверяет сценарий. Логи здесь — точка контроля.
Полный цикл установки валидируется в QEMU/OVMF (Open Virtual Machine Firmware). Boot chain на реальном x86_64 проверен. Полный install‑to‑disk на физическом железе — следующий шаг; я не буду делать вид, что он закрыт.
Честно говоря, установщик отнял больше времени, чем драйверы. Я думал, что основная работа — загрузка. Оказалось, самое сложное — поставить систему на чистый диск и снова получить с него рабочий стол.
Userspace: OPTX, PID 1 и display server
Свой формат бинарников
OptimaOS не тащит ELF (Executable and Linkable Format) только потому, что так принято. Формат OPTX минимальный:
0 4 magic "OPTX" 4 2 version 1 6 2 arch 0x8664 (x86_64) 8 4 entry offset от базы 12 4 segment_count ... таблица сегментов + байты сегментов
Загрузчик разбирает заголовок, проверяет границы, отображает сегменты в память и вызывает entry. Сейчас это происходит в ring-0 (уровень ядра). Промежуточный шаг. Цель — ring-3 (уровень пользователя), изоляция адресных пространств, preemption (вытеснение) и SMP (symmetric multiprocessing).
PID 1, планировщик и IPC
Модель процессов:
первый запущенный процесс получает PID 1 и становится супервизором;
у процесса есть имя, состояние (
Ready/Running/Blocked/Exited), код выхода и стек 64 KiB;планировщик кооперативный, round‑robin (по кругу): процесс отдаёт CPU через
yieldили блокируется на пустомrecv;переключение реальное: callee‑saved (сохраняемые вызываемым) регистры,
rsp, отдельный стек;IPC —
send/recvс доставкой сообщений между процессами.
Системные вызовы уже не один write: write, getpid, yield, spawn, send, recv, exit, плюс present для display server и input для ввода. ABI фиксирован, тесты проверяют контракт.
Рабочий стол как процесс
Теперь ядро композитит кадр через gui-core, отдаёт его на framebuffer (кадровый буфер), а /system/apps/display — обычный процесс. Он крутит цикл present(), уступает CPU между кадрами и сообщает PID 1 о готовности. Ввод (PS/2 мышь и клавиатура) приходит через syscall input. Координаты курсора и события клавиш обрабатываются в системном слое.
Тема рабочего стола, login‑экран, иконки, стартовое меню, анимации рендерятся из gui-core и проверяются по fingerprint (отпечатку) кадра.
Пакеты, подписи и установка приложений
Пакет здесь устроен сложнее zip‑архива с бинарником. В текущей реализации есть:
content‑addressed store: пакет идентифицируется хешем;
обязательная проверка подписи ed25519 по доверенным ключам;
opkg— CLI (command‑line interface),opkgd— демон/API (application programming interface),opkg-installer— интеграция с установкой;Program Manager — GUI (graphical user interface) и типизированные bridge‑вызовы;
safety gates для записи на диск: preflight, подтверждение, запрет системного диска, журнал установки;
audit bundle: отчёт установки, хеши, подпись манифеста и проверка подписи.
Для госсектора и промышленности обновление и установка ПО важная часть для безопасности. Если пакет можно подменить, capability‑модель не спасёт. Подпись здесь — условие установки: пакет без валидной подписи не попадает в систему.
Доказательная приёмка
Мы ввели доказательную приёмку (dev/trace):
Закрытая схема.
spec_id(идентификатор инварианта) — только из whitelistdev/trace/schema/trace_schema.yaml. Неизвестныйspec_idдаётschema_violation.Один примитив.
TraceContext::assert_invariant(spec_id, condition, payload)— единственный способ выдатьok. Публичной функцииemit_evidenceнет и не должно появиться.Два канала.
evidence.jsonl(доказательства) — append‑only, hash‑chain (цепочка хешей), закрытая схема.evidence.diagnostic.jsonl— свободный лог для отладки. Верификатор читает только evidence.Верификатор.
trace::verdictвозвращаетProof(доказательство). Порядок проверок: whitelist, hash‑chain, режим, схема payload, expected payload.Негативный контроль. Mutation‑тесты (тесты с намеренным изменением кода) ломают инвариант, переписывают лог, подсовывают неверный payload и неизвестный
spec_id. Верификатор обязан поймать каждое нарушение.
Выглядит это примерно так:
let ctx = TraceContext::new(TraceSchema::bundled().arc(), ".trace", run_id, "opkg")?; opkg::install_package_traced(&root, &package_dir, Some(&ctx))?; // внутри install_package_traced: ctx.assert_invariant( "spec.opkg.install.committed_after_signature", signature_verified && committed, json!({ "package": manifest.name, "version": manifest.version, "key_id": verified_key_id, "payload_hash": payload_hash, }), );
Проверка запрашивает доказательство:
let entries = ctx.read_evidence()?; let proof = verdict(&entries, &schema, spec_id, Some(&expected_payload), None); assert!(proof.accepted(schema.get(spec_id).unwrap()));
Что это даёт
В whitelist сейчас 72 инварианта. Есть положительные и отрицательные:
Инвариант |
Что доказывает |
|---|---|
|
оба GPT‑заголовка декодируются, CRC32 (контрольная сумма) сходятся, разделы не пересекаются |
|
запись сохранилась после сброса |
|
данные покинули кеш и дошли до носителя |
|
установщик не пишет на USB, с которого загрузился |
|
PID 1 запущен |
|
сообщение неверного типа не доставляется |
|
пароль не хранится в открытом виде |
|
рабочий стол не появляется без валидной сессии |
Отрицательные инварианты — отдельная ценность. Они доказывают, что система не делает лишнего: не пишет на загрузочный носитель, не логинит без проверенных учётных данных, не отдаёт рабочий стол без сессии, не принимает пакет без подписи.
Зачем это аудитору
Сертификация и аудит любят вопрос: «чем подтвердите, что свойство выполняется?» Обычный ответ — «у нас есть тесты». Хороший ответ — evidence за конкретный прогон, провязка с payload, hash‑chain, негативный контроль, который ловит подделку.
Отсутствие всех багов trace доказывает выполнение заявленных инвариантов при конкретном прогоне. Это проверяемый и воспроизводимый результат.
Лицензия: GPL-2.0 вместо GPL-3 и коммерческой
В первой статье была GPL-3 с коммерческой лицензией. Плюс CLA. После обсуждения я это изменил.
Причины:
Совместимость с экосистемой Linux. GPL-2.0-only — лицензия ядра Linux. Для ОС, которая хочет жить рядом с Linux‑драйверами и утилитами, это практичнее GPL-3.
Никакого CLA. CLA — барьер для контрибьюторов и источник юридической двусмысленности. Теперь вклад оформляется через DCO:
git commit -s, авторские права остаются у автора, проект получает право распространять вклад под GPL-2.0.Отказ от двойного лицензирования. Схема «community под GPL, коммерческие пользователи платят за закрытость» на ранней стадии усложняет вклад, аудит, переговоры и сопровождение. Для проекта такого размера это преждевременно.
Copyleft (сохранение свободной лицензии при распространении) остаётся. GPL-2.0 требует публиковать изменения при распространении. Взять ядро, добавить тысячу патчей под свой SoC и уйти в закрытую ветку не получится.
В COPYING есть примечание о системных вызовах, как в Linux. Пользовательские программы, которые обращаются к ядру через обычные syscall, не считаются производными произведениями. Производителям это важно: userspace‑приложения и сервисы могут иметь свою лицензию.
Репозиторий размещён только на GitVerse. В первой статье была ссылка на GitHub; теперь её нет. Для проекта, который строит независимый контур разработки, странно делать основной площадкой внешний сервис. GitVerse — российская платформа, и это согласуется с курсом на независимость инфраструктуры.
Что значит «национальная ОС»
Наклейка на логотипе ничего не значит. Национальная ОС — это способность собрать, проверить, обновить и сопровождать каждый слой без внешнего разрешения. Вот что уже сделано или запланировано под этот сценарий.
Собственный стек. Свой загрузчик, свой установщик, своя разметка диска, своя ФС, свой формат исполняемых файлов, свой пакетный формат, своя модель доказательств. Набор фундаментальных решений здесь другой, чем у Linux‑дистрибутива.
Проверяемость. Минимальный TCB (Trusted Computing Base, доверенная вычислительная база), capability‑модель без глобального root, подписанные пакеты, evidence по инвариантам. Аудитору можно показать не только код, но и артефакты прогонов.
Независимость инфраструктуры. Код, документация, репозиторий и обсуждения на российской платформе. Документация на русском, сообщество русскоязычное. Международное участие при этом возможно.
Потенциал сертификации. Реестр российского ПО, требования ФСТЭК (Федеральная служба по техническому и экспортному контролю), защита КИИ, аттестация объектов КИИ — это процесс, не галочка. Чтобы в него заходить, нужна архитектура, которую можно проверять. Мы строим её заранее.
Платформенная стратегия. Сейчас x86_64 UEFI. Дальше — исследование переноса на российские архитектуры. «Завтра на Эльбрусе» я не обещаю: сначала ring-3, preemption, стабильность и валидация на текущем железе.
Продуктовая рамка. Сегодня это технологическая база, не коробочный продукт. Траектория: базовая открытая ОС, сертифицированная сборка для госсектора и КИИ, поддержка промышленных заказчиков, обучение и документация.
Спасибо, что дочитали. Вопросы, критика, идеи и pull request’ы — приветствуются.
dorne
Это просто отличная идея! Давайте напишем ОС для:
Доверенной рабочей среды для госсектора и КИИ
Промышленности
На языке, имеющем единственную реализацию компилятора, поддерживать который способны всего несколько человек в мире, разработку и внедрение которого спонсирует АНБ?
Это просто гениально!
ANTON62 Автор
Справедливое замечание, такие риски есть, но Rust разрабатывается сообществом и Rust Foundation (AWS, Google, Microsoft, Mozilla, Huawei и др.) и там порядка 70 человек в команде.
АНБ рекомендует использовать этот язык как безопасный, это неприятно, но факт.
Кроме rustc есть gccrs (в составе GCC) и mrustc. Да они в разработке, но компилятор получается не единственный.
По специалистам – ИИ очень сильно снижает порог входа, так что и у нас вполне могут появится спецы разбирающиеся в тонкостях компилятора.
А так так да, комментарий правильный, но немного преувеличенный.