urMQTT v0.3.0: šifrovanie disku, boot, ktorý odmietne upravený obraz, a to, čo sme si sami pokazili
Čo sa stalo po treťom texte o urMQTT: šifrovanie disku v pokoji so zmeranou cenou, test, ktorý zmení jeden bajt v jadre a ukáže, že ho zavádzač odmietne, auditný balík s 889 zdôvodnenými miestami s unsafe, chyby, ktoré sme našli sami (a jedno tvrdenie, ktoré sme napísali nesprávne), a vydanie v0.3.0 so zoznamom toho, čo ešte nie je dokázané, vrátane červeného CI.

Tretí text, urMQTT po VPS, skončil zoznamom „Čo bude ďalej": verejný demo broker (D1), druhé kolo pre pomalý jediný tok, obyčajná cesta proti Mosquittu na VPS a „po vydaní" bare metal, IOMMU, Secure Boot a šifrovanie disku. Tento text hovorí, čo z toho je hotové, čo nie a čo sme medzitým našli. Šifrovanie disku a časť Secure Bootu sa nakoniec do vydania dostali, pretože ležali na ceste k auditu. Druhé kolo pre jediný tok a obyčajná cesta proti Mosquittu hotové nie sú.
Poznámka vopred ostáva rovnaká: projekt je pre-alpha, vydanie cieli na VPS s KVM a čísla merajú kód, testy a konkrétne pokusy, nie zrelosť v produkcii.
Ako to vyzeralo v čase
Od minulého textu (1. novembra o 20:41) do dneška (3. novembra o 02:43) pribudlo v hlavnej vetve 37 nových commitov, spolu 215. Ako predtým, projekt sa stavia s Claude Code (commity nesú Co-Authored-By: Claude) a tentoraz bežali paralelne tri vetvy (D1, H8, príprava vydania), takže poradie commitov nie je presne poradie práce. Čísla sú vypočítané rovnakou metódou ako v minulom texte (všetky súbory .rs mimo vendor/ a fuzz/, funkcie #[test], nadpisy ## ADR- v docs/DECISIONS.md) a overené na starom commite, ktorý dáva rovnaké čísla ako vtedy.
| Okamih | Commit | Čas | Riadkov Rustu | Testov | ADR | Commitov |
|---|---|---|---|---|---|---|
| minulý text | d21e3ec | 1. 11., 20:41 | 112 408 | 926 | 126 | 178 |
| dnes | f1a7fbc | 3. 11., 02:43 | 115 148 | 962 | 133 | 215 |
Rast kódu je skromný (+2 740 riadkov, +36 testov), pretože tentoraz nebolo veľa nového kódu: väčšinu práce tvoria testy, skripty, dokumentácia a kontroly. Skripty a JavaScript sa do počtu riadkov nezapočítavajú.
Šifrovanie disku v pokoji (S7)
Čo sme plánovali. Voliteľné šifrovanie dátovej partície, v predvolenom stave vypnuté, so zmeranou cenou. Čo sme postavili (ADR-240):
- Vrstva pod diskom.
CryptDevobaľuje blokové zariadenie podDisk, takže rozloženie, tabuľka veľkostí, SQLite, telemetria a zálohy pracujú s čistým textom a o šifrovaní nevedia. Algoritmus je AES-256-XTS (IEEE 1619), jeden sektor s 512 bajtmi na dátovú jednotku, nie blok s 4 KiB, ako počítal plán: úložisko zapisuje po sektoroch a jednotka 4 KiB by každý zápis 512 bajtov premenila na čítanie-úpravu-zápis, ktorý môže výpadok prúdu prerušiť napoly. - Superblok ostáva otvorený. Dva sloty superbloku nesú príznak a kontrolu kľúča (HMAC-SHA-256 zo štítku a UUID disku), nikdy kľúč. Všetko ostatné v partícii je šifrované. Sektor, ktorý je na médiu celý nulový, sa číta ako nula a nedešifruje sa, takže discard, nikdy nezapísaný priestor a zväčšovanie disku fungujú ako predtým.
- Konfigurácia.
storage.encryption = "aes-256-xts"astorage.disk_key(súbor so 64 bajtmi kľúča). Formát blobu sa stáva 4 iba keď je šifrovanie zapnuté, takže všetky ostatné obrazy sa naďalej spúšťajú na starších jadrách. Staršia čítačka neznámy príznak v superbloku odmietne. - Bez hardvérového AES: odmietnutie. Jadro odmietne
storage.encryptionna procesore bez inštrukcií AES (alebo keď ich[cpu] disablevypne), namiesto toho, aby potichu bežalo na pomalej softvérovej verzii. - Prevod je offline. Jadro pri štarte nikdy disk nešifruje ani nedešifruje. Robia to
urmqtt-disk encrypt,decryptarekeypri vypnutom VM: záznam o prevode sa zapisuje ako prvý a maže ako posledný (kým existuje, jadro disk odmieta), kúsky po 1 MiB sa najprv uložia do žurnálu na hostiteľovi, potom sa zapíše prevedená kópia a superblok sa prepína ako posledný. Vyskúšané výpadkom prúdu po každom jednotlivom zápise pri všetkých troch postupoch, čisto aj napoly zapísanom, so zahodenou aj zachovanou cache: po--resumevždy platný disk so všetkými dátami.
Zmerané. Priepustnosť XTS na jadro na Apple silicon (jeden MiB sektorov v slučke): 3 109 MB/s šifrovanie a 3 103 MB/s dešifrovanie s hardvérovým AES, oproti 252 a 258 MB/s v softvéri. Preto softvér nepovoľujeme. db-bench vo VM (aarch64, HVF, 5 000 vložení v 50 transakciách, päť behov každého variantu, striedavo):
| op/s, päť behov | medián | |
|---|---|---|
| šifrovanie vypnuté | 49 239, 47 401, 50 802, 53 417, 46 531 | 49 239 |
| šifrovanie zapnuté | 57 790, 46 173, 45 939, 52 787, 49 632 | 49 632 |
Rozdiel mediánov je +0,8 % a rozptyl vnútri jedného variantu (46 000 až 58 000) je väčší, takže cena v tomto teste nie je merateľná. To je aj očakávané: celý beh db-bench zapíše asi 6 MB, čo je asi 2 ms AES, a commit čaká na flush, nie na šifru.
Diagnostická položka teraz popri AES-GCM zobrazuje aj AES-XTS (na HVF jadro nameria asi 800 MiB/s pre XTS oproti asi 560 MiB/s pre AES-GCM) a ukazuje, či je dostupný hardvérový AES.

Čo XTS nedáva. Nie je tu autentifikácia: upravený šifrovaný sektor sa dešifruje na šum v blokoch po 16 bajtov (CRC a čistič to nájdu) a ten, kto môže zapisovať na zväzok, môže medzi dvoma snímkami zameniť alebo vrátiť celé sektory. Chráni ukradnutý zväzok alebo snímku, nie ukradnuté ISO, pretože kľúč je v konfigurácii obrazu. Viditeľné zostáva: GPT, superblok, UUID a ktoré sektory boli kedy zapísané.
Čo sme pri tom našli vo vlastnej práci. Pri písaní kapitoly o kryptografii sme zistili dve veci. Krok násobenia tweaku v XTS mal vetvu závislú od bitu odvodeného z kľúča; teraz je bez vetvenia. A tvrdenie „overené podľa vektora 10 z IEEE 1619" pokrývalo iba prvý šifrovaný blok; teraz existuje aj naivná referenčná implementácia (aritmetika u128, blok po bloku), ktorá overuje celé sektory v oboch smeroch na 200 náhodných kľúčoch a sektoroch, a dokumentácia hovorí, čo bolo skutočne overené.
Boot, ktorý odmietne upravený obraz (H8)
Požiadavka z auditného zoznamu bola jednoduchá a doteraz neoverená: žiadny test neukázal, že sa upravené jadro nespustí. Pin hashu v limine.conf existoval, ale bez dôkazu.
- Test, ktorý mení bajt.
scripts/tamper.pyotočí jeden bit v každej kópii jadra (alebo konfiguračného modulu) vo vnútri zostaveného ISO alebo raw obrazu aSMOKE_ONLY=integrityukáže, že zavádzač odmietne: 24 kontrol prešlo, na aarch64 UEFI, x86_64 UEFI a x86_64 BIOS, s kontrolami, ktoré sa spúšťajú. Správa o odmietnutí sa číta zo sériového portu cez prepínač určený iba pre testy. Na BIOSe správa dorazí iba na obrazovku, takže tento test tvrdí iba to, že sa stroj nespustí. - Zapísaná konfigurácia zavádzača (ADR-250).
limine enroll-configfunguje naBOOTAA64.EFI,BOOTX64.EFIaj na stupni BIOS, takže sa odmietne aj upravenýlimine.conf(pridaná položka ponuky alebo argument).urmqtt-config pack --isoju zapíše znova. - Cesta Secure Bootu (ADR-251).
scripts/sign-loaders.sh(skúšobné kľúče, podpisovanie, overovanie, úložisko premenných OVMF),mkiso.sh --sb-keya skupinasecurebootna x86_64: podpísané ISO sa spustí a zostaví reprodukovateľne, zatiaľ čo nepodpísané, podpísané zlým kľúčom a upravené po podpise dostanúAccess Denied(10 kontrol prešlo). Limine aj pod Secure Bootom upravené jadro odmietne. - Pravidlá inštalačnej položky (ADR-253). Plán hovoril o jednom slove na príkazovom riadku,
install. Produkčné jadro v skutočnosti prijíma tri (install,live,diag) a zapisuje ibainstall. Test (9 kontrol) to spúšťa na troch strojoch s prázdnym diskom, ktorého hash sa nesmie zmeniť. - Tajnosť obrazu (ADR-252). Hlasné varovanie, keď sa produkčný obraz stavia mimo CI, a prehľadanie obrazu, logov zostavenia a sériových logov na bajty kľúčov v mnohých kódovaniach (11 kontrol).
- TPM, iba ADR-254. Čo by znamenalo zapečatiť kľúč servera do vTPM alebo TPM 2.0. Odporúčanie: nestavať pre vydanie zamerané na VPS. Neoverovali sme, ktorí poskytovatelia vTPM vôbec ponúkajú.
Čo to NEZNAMENÁ (zapísané ako H8-W1 až H8-W6 v AUDIT.md): nainštalovaný disk sa pod Secure Bootom nespustí, pretože jeho konfiguračný modul nemá hash (ADR-217); podpísané ISO sa nedá dodatočne konfigurovať (najprv konfigurovať, potom podpísať); cesta BIOS nemá podpis; nie je tu ochrana proti návratu k staršej verzii; na aarch64 firmvér tu Secure Boot nevynucuje, takže bol overený iba podpis zavádzača; neexistuje projektový kľúč, takže obrazy vydania nie sú pre Secure Boot podpísané; a žiadny fyzický stroj nebol vyskúšaný.
Auditný balík (H10)
docs/AUDIT.md je teraz balík, ktorý môže externý audítor použiť bez otázok: systém na jednej strane, základ, ktorému veríme (89 612 riadkov vlastného Rustu v obraze, 67 prilinkovaných cudzích balíkov), vstupy a ich parsery, matica ochrán s testami (aj ochrany bez testov), slabiny so stavom, tabuľka každej sieťovo dosiahnuteľnej slučky a alokácie s hranicou a testom, návod na zostavenie a testovanie, navrhnutý rozsah externého auditu v desiatich oblastiach a red-team zoznam s 31 útokmi a výsledkami. SECURITY.md má tabuľku STRIDE po komponentoch.
- Oprava prvého textu. V texte z 29. októbra stojí, že každý blok
unsafemá komentár// SAFETY:, ktorý kontroluje lint. To nebola pravda: lint (deny(unsafe_code)) iba obmedzuje, kde smieunsafebyť, a komentáre od H0 eviduje generovaný súpis, ktorý už vtedy našiel asi 30 miest bez zdôvodnenia a pri audite ich bolo 108 (lebo medzitým pribudli nové druhy miest, napríklad atribúty#[unsafe(no_mangle)]alink_section). Preto je to súpis, a nie lint, čo ich teraz drží na nule. - 889 miest
unsafe, každé s písomným zdôvodnením. Tých 108, ktoré ho nemali (hlavne#[unsafe(no_mangle)]alink_section, niekoľkounsafe fn), dostalo komentár (napísal ho AI agent, iba komentáre, vzorku som prešiel ja); generovaný súpis v CI zaznamená každé nové miesto bez zdôvodnenia. Zdôvodnenie je tvrdenie, ktoré treba preskúmať, nie dôkaz, a to je bod 5 navrhnutého rozsahu. - Päť otvorených nálezov ostáva otvorených, zapísané: nie je fuzzing parserov PCI a virtio, nie je test, ktorý zapisuje do stránkových tabuliek po ich uzamknutí, čas behu P-256, X25519 a Ed25519 nebol meraný, nie je fuzzing zámerne vytvorených súborov SQLite (obmedzené H6) a 53 zo 67 prilinkovaných balíkov sú výnimky
cargo-vet, nie audity.
Chyby, ktoré sme našli sami
- Tajomstvá TLS prevádzky sa nemazali (H0-W2, otvorené od prvého dňa auditu): tabuľka zachytených tajomstiev bola
Vec, ktorýremoveaswap_removepresúvali a nechávali po sebe kópie. Teraz je tabuľka po slotoch: slot sa maže na mieste, keď sa vezme, zahodí alebo vytlačí, nič sa nepresúva. - Vetva závislá od kľúča v XTS (vyššie).
log-slow-floodna x86_64 padal („log ring full"), aj na zdrojovom kóde v0.2.1. Príčinou nebola chyba, ale dimenzovanie testu: scenár nútil každé jadro na 25 ms, zatiaľ čo ADR-090 ho meral na 50 ms. Na x86_64 je COM1 port-I/O po bajte zachytené do pasce, jedno jadro zapisujúce do sinkov potrebuje asi 9 ms na riadok a tri jadrá na 25 ms žiadajú viac než sekundu práce za sekundu, takže sa kruhy plnia (zamýšľané pretečenie). Test teraz na x86_64 beží na 50 ms (prešiel, 30 z 30 v behu so základnými scenármi); na aarch64 ostáva 25 ms.- Zlúčenie vetiev pokazilo staré šablóny. Opätovný zápis konfigurácie v H8 vyžadoval koncovú značku v
limine.conf, ktorú šablóny pred H8 nemajú, takžeurmqtt-config pack --isoa stránka zostavovača odmietali každé vydanie pred H8, vrátane v0.2.x, ktoré stránka ponúka. Zachytili to testy zostavovača v prehliadači (4 zo 100 zlyhali), nie vlastný test H8. Opravené (šablóna bez značky sa konfiguruje ako predtým) a pridaný test, ktorý s pôvodnou chybou padá, keď sa oprava odstráni. - Naša dokumentácia nesprávne tvrdila, že x86_64 bolo overené iba v emulátore. X11 spustil produkčný obraz na skutočnom Contabo KVM VPS (4 vCPU AMD EPYC) s obojstranným TLS pod záťažou. Opravené všade: x86_64 bežalo na skutočnom KVM VPS pri commite H7 a v emulátore, ale kód pridaný po ňom (šifrovanie, integrita bootu) na KVM nebežal a na fyzickom hardvéri nebol vyskúšaný.
D1 a ponuka „vaša služba ako unikernel"
Verejný demo broker je postavený, ale nezverejnený: konfigurácia (live režim, ACL demo/{id}/#, obyčajné MQTT iba pre most), skript, ktorý vytvára zverejnenú skúšobnú CA a demo certifikáty, most WebSocket-na-TCP (iba štandardná knižnica Pythonu, obmedzenia spojení, rýchlosti a veľkosti, kontrola pôvodu), stránka „Vyskúšajte urMQTT naživo" s MQTT klientom v obyčajnom JavaScripte, runbook a model hrozieb. Testované na loopbacku a v QEMU (18 scenárov, 26 testov mosta). Netestované: skutočný VPS, DNS, Caddy, obraz kontajnera. Potrebuje samostatný VPS a výslovný súhlas s verejným vystavením.
Na webe je navyše zverejnená aj ponuka, Unikernel (15 jazykov, bez cien): úprava vašej služby tak, aby bežala ako unikernel (posúdenie realizovateľnosti, úprava, pilot, podpora), s urMQTT ako referenciou. Text výslovne uvádza obmedzenia dnešného základu: IPv4, TCP iba ako server, KVM, Rust prirodzený, C iba ako izolovaný worker.
Vydanie v0.3.0
Tag v0.3.0 bol nastavený 3. novembra na commit f1a7fbc a workflow vydania uspel. Vydanie je označené ako pre-release a obsahuje vývojové jadro pre aarch64, ISO a obraz, šablónu ISO (jadrá pre aarch64 a x86_64 a prázdnu konfiguráciu, ktorú urmqtt-config pack --iso a stránka zostavovača premenia na váš obraz), CycloneDX SBOM, SHA256SUMS a jeho podpis minisign a atestácie pôvodu SLSA. Overené po zverejnení, v prázdnom adresári: podpis SHA256SUMS platí, všetkých päť súborov zodpovedá kontrolným súčtom, obe atestácie (jadro a ISO s predikátom CycloneDX) prejdú, SBOM má 221 komponentov a šablóna sa konfiguruje (pack --iso znova zapíše šesť kópií zavádzača). Podpisový kľúč je stále skúšobný kľúč.
Poradie bolo dôležité a oplatí sa ho zapísať: stránka zostavovača bola aktualizovaná pred tagom (pozná formát 4 a všetky staršie šablóny) a až potom si zrkadlo na aldo.tech vydanie prevzalo. Zrkadlo ho uviedlo ako podpísané a overené (ok, formát konfigurácie 4, sha256 šablóny zhodný s tým v SHA256SUMS) a živá stránka ho ponúka ako predvolené vydanie a v prehliadači vytvorí ISO asi za 20 sekúnd. Poznámky k vydaniu hovoria aj to, čo sa píše zriedka: CI na GitHube nie je zelené (pozri nižšie), podpora je iba pre poslednú verziu (v0.2.1 a staršie končia) a audit vykonal sám projekt.
Na webe sme si pritom takmer sami uškodili: publikačný skript webu (publish.sh) robí rsync --delete a zrkadlo vydania patrí inému používateľovi, takže každá publikácia skončila chybou 23 (a pokazila by tlačidlo „Publikovať" v administrácii blogu). Opravené výnimkou pre /urmqtt/releases/. Podobný nález: deploy.sh s --delete maže stránku zostavovača z generátora, takže sa musí pred publikáciou vrátiť.
Čo ešte nie je dokázané
- CI na GitHube je červené. Nielen dnes: posledný beh úplného CI pred tagom mal sedem neúspešných jobov a behy spätne až do 31. októbra sú väčšinou červené. Zlyhali: lint (varovania shellcheck v skriptoch), TLS interop (všetky prípady wolfSSL), dodávateľský reťazec (zoznam výnimiek
vet-exemptions.mdnie je na Linuxe aktuálny), fuzz smoke (v tom jobe chýbajú vývojové certifikáty), sanitizery (LeakSanitizer hlási únik v testoch), testy na Linuxe aarch64 (jeden test nástroja padá s „Broken pipe") a jeden dôkaz Kani pre časové koleso (timer wheel) neprejde. Zatiaľ sme netriedili, čo z toho je prostredie a čo skutočná chyba; kým to neurobíme, netvrdíme, že vydanie prešlo CI. - Podpisový kľúč je skúšobný, a obrazy vydania sú vývojové so skúšobnými certifikátmi (okrem šablóny).
- Preklady stránok a tohto textu do ďalších 13 jazykov napísala AI a rodení hovoriaci ich nekontrolovali.
- Šifrovanie disku nebolo zmerané na x86_64 (ani na KVM, ani na fyzickom hardvéri) a nebola zmeraná ani priepustnosť telemetrie, ani čas štartu so šifrovaním. Na stránke zostavovača nie je (potrebuje dialóg pre kľúč).
- Nezávislý bezpečnostný audit neexistuje. Rozsah je napísaný; audítora nemáme.
- Secure Boot je čiastočný (vyššie), bez fyzického stroja.
- Bare metal, IOMMU, verejný demo broker: nehotové alebo nezverejnené.
Čo bude ďalej
- Roztriediť a opraviť CI (najprv prostredie, potom dôkaz Kani a test, ktorý padá na Linuxe aarch64), pretože vydanie bez zeleného CI nepovažujeme za hotové.
- Rozhodnutie o D1 (samostatný VPS, DNS, súhlas s verejným vystavením).
- Fuzzing parserov PCI a virtio a test uzamknutých stránkových tabuliek (H0-W9, H0-W10).
- Dialóg pre kľúč na stránke zostavovača, aby sa šifrovanie stalo dostupným bez príkazového riadka.
- Po vydaní: bare metal (X12 až X16) a IOMMU, v poradí, ktoré závisí od súpisu hardvéru testovacieho PC.
Kód je na github.com/zeljan-alduk/urMQTT; docs/PROGRESS.md ostáva jediným zdrojom pravdy o tom, čo skutočne funguje, docs/PERFORMANCE.md o tom, čo bolo zmerané, a docs/AUDIT.md o tom, čo ešte nie je dokázané. Pre-alpha, ako predtým; hlásenia chýb a bezpečnostné hlásenia podľa pokynov v SECURITY.md sú vítané.
Komentáre
Pravidlá komentovania