Чей это компьютер? Ваш, или…

Опубликовано 2026-09-19
Чей это компьютер? Ваш, или…
Серия: Чей это компьютер?Часть 1 из 8

Вводная статья серии. Мы написали ОС с нуля на Rust и запустили её на серийном планшете Samsung Galaxy Tab S6 (Snapdragon 855). Ниже — не про Rust и не про планшет. Про то, кто ещё живёт в этом устройстве, какие у каждого права, и почему наша ОС — далеко не самый привилегированный жилец. Остальные статьи серии — про то, как мы это узнавали, по одному открытию за раз.


1. Наивная картина

Когда пишешь ОС для микроконтроллера, картина простая: есть процессор, есть память, есть периферия. Ты — единственный код, который исполняется. Что ты не написал, того нет. Все привилегии — твои, вся ответственность — тоже.

Мы принесли эту картину на планшет. Загрузчик передаёт управление нашему образу на EL1, дальше — наша память, наш MMU, наши драйверы. Так казалось.

Понадобилось около десяти тихих перезагрузок всего чипа — без паники, без сообщения, без прерывания, — чтобы картина сменилась на честную: в этом устройстве живёт по меньшей мере восемь исполняющихся сущностей, семь из них написаны не нами, и почти каждая может нас убить, а мы — ни одну из них.

2. Жильцы

Вот они — от самого привилегированного к нам. Для каждого: где исполняется, чей код, что держит над нами, и как мы это узнали (обычно — сбросом).

ЖилецГдеЧей кодЧто держит над намиКак узнали
TrustZone (secure world, EL3)те же ядра, секретный режимQualcomm (+ Samsung)Загружает и проверяет подписи прошивок остальных жильцов (PAS). Ставит XPU‑заборы на память: наше чтение одного байта за забор — тихий сброс. Владеет регистрами модема (QDSP6SS): читать — bus error. Решает, кому принадлежит какой регион RAM (assign_mem). Свой лог зашифрован и чистится при сбросесбросы №1, №2, №9; каждая передача памяти модему идёт через него
Гипервизор (EL2)те же ядра, уровень выше нашегоSamsungВладеет SMMU (qcom,skip-init — глобальная конфигурация его): stage‑2 трансляция всех DMA‑мастеров — его, нам остаётся stage‑1. Ветирует запись S2CR типа bypass — она возвращается как fault. Пересылает наши smc в TrustZone. Его память hyp_memno-map: спекулятивное чтение процессора в неё — сброспопытка настроить SMMU для Wi‑Fi; сброс №10 (превентивно)
AOP (Always‑On Processor)отдельное ядро Cortex‑M внутри SoCQualcommУправляет питанием и тактами через RPMh: каждая рельса — голос по имени из базы команд (cmd-db), которую он же хранит. Копия базы в его message‑RAM закрыта: чтение — остановка процессора. Без его load_state modem on модем не грузится, без такта qdss — Wi‑Fi не стартует. Наш неверный голос vote(0) за cx.lvl обесточил цифровую логику всего SoCсброс №3, сброс №8
S‑Boot (загрузчик)до нас; остаётся в двух слотах на дискеSamsungРешает, что вообще загрузится: boot или recovery, по байту причины перезагрузки в PMIC. Выбирает дерево устройств по msm-id, входит на EL1 «где хочет» (наш образ — PIE). Оставляет после себя голоса за рельсы от имени APPS и framebuffer с логотипом, который мы захватываем как дисплей. Умирающий recovery больше не грузит — самэксперимент с причиной recovery, который привёл в Download mode
Модем (MPSS, Hexagon)отдельный DSP, 160 МиБ carve‑outQualcomm, 80 МБ подписанной прошивкиВнутри — три домена: сотовый, GNSS, WLAN. Требует от нас четыре сервера (rmtfs, tqftp, pd‑mapper, memshare), общую память SMEM, очереди GLINK/QRTR/QMI. Без EFS умирает через 40 с; на отказ открыть fsg — через 23 мс. Собственное радио, собственный uplinkсбросы №4, №5, №6, №7; вся стадия 3–4 Wi‑Fi
Copy engines WLAN12 DMA‑каналов в WCSSисполняют дескрипторы, которые пишет прошивка модемаDMA в физическую память — поток 0x640 идёт через SMMU без stage‑1 трансляции. Единственный забор — гипервизор и XPU, не нашианализ SMMU; docs/wifi-threat-model.md
Дисплейный контроллер (MDSS)DMA‑мастер, поток 0x800железо + настройка загрузчикаСканирует память framebuffer’а через ту же SMMU. Мы не поднимали дисплей — мы подменили содержимое того, что он уже показывалmilestone 0: полосы и циклы цветов, по которым угадали stride и порядок байт
PMIC (PM8150) по SPMIотдельная микросхемаQualcommПричины перезагрузки (PON), байт для загрузчика, и SDAM — единственная энергонезависимая память, куда мы можем записать слово перед опасным шагом и прочитать после сброса. Наш единственный свидетельметодика тихих сбросов
Мы (EL1)ядра APPS, куча ~85 МиБ между образом и первым резервомнаш RustГолосуем за рельсы (по разрешению AOP), просим TrustZone загрузить модем, обслуживаем модем, программируем stage‑1 SMMU (пока нет), пишем слово в SDAM. Второе ядро — наш watchdog, который называет шаг, на котором повисло первое

Читать таблицу нужно так: выше нас — трое (TrustZone, гипервизор, AOP), рядом — двое с DMA в нашу память (модем через copy engines, дисплей), и до нас — один, который решает, будем ли мы вообще. Все семеро — чужой код.

2a. Карта связей

Та же таблица — как граф. Это общая схема всей серии: каждая частная статья показывает свой фрагмент этой же схемы, теми же именами узлов.

Схема: Чей это компьютер? Ваш, или…

Как читать: красное — чужой код; зелёное — наш; синее — память, за которую идёт спор; пунктир — «может, если захочет» (сброс, чтение, DMA мимо окна). Все стрелки из нашего блока — просьбы, голоса, ответы и трансляция; все стрелки в него — власть.

3. Что значит «владеть»

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

Прочитать нашу памятьЗаписать в неёОбесточить/сброситьРешить, загрузимся ли мыЧто можем мы
TrustZoneвсювсюда (XPU → сброс)косвенно (проверяет подписи)просить (smc)
Гипервизорвсювсюданетпросить (через него идут smc); принимать его вето
AOPнетнетда (питание всего SoC)нетголосовать по его правилам
S‑Bootдо насдо наснетдаоставить байт причины в PMIC
Модем через CEвсю (bypass)всю (bypass)косвенно (сброс через TZ на отказ)нетобслуживать, изолируя прозрачно; запереть stage‑1
Модем сам по себесвои регионы + SMEMто женетнетвалидировать всё, что он написал
Дисплейframebufferнетнетнетрисовать в нужное место
PMICнетнетпо командехранит байт для S‑Bootписать слово‑свидетель

Обратите внимание на асимметрию: в столбце «что можем мы» — только просить, голосовать, обслуживать, валидировать и запирать. Ни одного «запретить», ни одного «проверить их код». Это нормально для современного SoC. Ненормально — не знать об этом.

4. Три открытия, из которых выросла серия

4.1 Чип наказывает не ошибкой, а сбросом

На микроконтроллере ошибка — это HardFault с адресом в регистре. Здесь ошибка перед забором TrustZone — это перезагрузка из secure world, неотличимая от штатной SYSTEM_RESET: регистры причины в PMIC чисты, лог TrustZone зашифрован, прерывания нет. Единственный способ узнать, на каком шаге умерли, — записать слово о шаге в энергонезависимую память до шага и прочитать после. Так появился «свидетель» в SDAM, и так десяток сбросов был превращён в таблицу «симптом → причина → доказательство → фикс».

Сброс без свидетелей

4.2 Карта памяти — это граница безопасности

Один кэшируемый мегабайт в окне, которое мы одолжили модему, стоил сброса: модем прочитал через наш кэш пустые заголовки своей файловой системы, «восстановил» её и упал. Спекулятивное чтение процессора в память гипервизора — сброс. Метаданные для TrustZone в куче, которую мы потом переиспользовали, — сброс через шесть секунд «в простое». Отсюда инварианты, проверяемые компилятором: всё разделяемое — некэшируемое, всё чужое — Device, каждое окно — на границе 2 МиБ.

Мегабайт, который убил модем

4.3 Радио — не периферия, а жилец

Самое большое открытие. На макетке STM32 + ESP32 Wi‑Fi был модулем за UART‑ом: 950 строк драйвера, провод, текстовый протокол. На планшете «то же самое» заняло 32 000 строк, потому что Wi‑Fi‑прошивка исполняется на процессоре сотового модема, требует от хоста файлы, диск, память и IPC, и ходит в нашу RAM по физическим адресам. Это касается не одного планшета: каждого Android на Snapdragon, ноутбуков с Wi‑Fi Qualcomm под Windows, iPhone с модемом Qualcomm.

Паразит в планшете — центральная статья: анатомия, модель угроз, Android/Windows/Apple/ESP32, что открывается спецслужбам, как проверить своё устройство.

Из неё выросли четыре частных:

5. Что из этого стало правилами ОС

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

  1. Ничего не читать без запроса. Первый smc и первое чтение SMEM — только когда агент спросил. Загрузка не должна повиснуть на вопросе, который никто не задавал.
  2. Каждый шаг, который может повиснуть или убить, — помечен. Вызов в secure world, первое чтение общей памяти, каждый шаг рукопожатия с модемом — под меткой, которую читает watchdog‑ядро или следующая загрузка из SDAM. Ответ «повисло на scm detect» или «сброс на wlfw fw_ready wait» — вместо «умерло».
  3. Карта памяти — константы с const‑проверками. Окна 2 МиБ, всё разделяемое некэшируемое, все no‑map — Device, метаданные для TrustZone — в своём окне вне кучи.
  4. Всё, что написала другая сторона, — недоверенный ввод. База FIFO, смещение элемента, длина, адрес в QMI, адрес буфера в HTT — проверяется против окна до разыменования. Парсеры — safe Rust: баг — паника, не запись мимо буфера.
  5. Прозрачная изоляция. Модему отвечают на всё, что он спросит, — формально правильно, по сути пусто: тень вместо диска, scratch в RAM вместо файлов, именованные регионы вместо произвольных, NOT_SUPPORTED вместо молчания.
  6. Голосовать, не приказывать. Рельсы и такты — голоса с полом, не абсолютные значения: наш голос — один из нескольких, и загрузчик уже оставил свой.
  7. Честный список «не можем». Модель угроз, в которой всё закрыто, — не модель угроз. Гипервизор, XPU, прошивка модема, эфир и сотовый uplink — не наши; это записано, а не спрятано.

6. Что дальше

7. Порядок чтения

Если читать одно — Паразит в планшете. Если читать всё — в таком порядке:

  1. Эта статья — карта жильцов.
  2. Сброс без свидетелей — метод, без которого не было бы остального.
  3. Мегабайт, который убил модем — карта памяти как граница.
  4. Паразит в планшете — радио как жилец.
  5. 23 миллисекунды, чтобы солгать — как жилец проверяет хозяина.
  6. Гипервизор сказал «нет» — кто владеет SMMU.
  7. Пароль у нас, ключ у модема — где граница WPA.
  8. Доверяй проводу? — где граница конфиденциальности.

Технические первоисточники — docs/wifi-sm8150.md (железо, карта памяти, все сбросы с причинами, методика) и docs/wifi-threat-model.md (модель угроз по каналам, остаточные возможности, сравнение с Linux).


Ответ на вопрос из заголовка: компьютер — того, кто держит ключи, владеет заборами и решает, что загрузится. На планшете это TrustZone, гипервизор, AOP и загрузчик — Qualcomm и Samsung. Мы — жилец на EL1, который научился не наступать на заборы, обслуживать соседа с DMA так, чтобы он ничего не получил, и честно записывать, до чего не дотягивается. Это меньше, чем хотелось. Это больше, чем есть у любой ОС, которая об этом не знает.

Часть 1 из 8
  1. 1Чей это компьютер? Ваш, или…
  2. 2Сброс без свидетелей
  3. 3Мегабайт, который убил модем
  4. 4Паразит в планшете
  5. 523 миллисекунды, чтобы солгать
  6. 6Гипервизор сказал «нет»
  7. 7Пароль у нас, ключ у модема
  8. 8Доверяй проводу?

Продукты из статьи

0xd-ossecurityembeddedsnapdragon
Попробовать