În cadrul eforturilor de întărire a securității componentelor software critice ale platformei Android, compania Google a rescris firmware-ul pvmfm în limbajul Rust, utilizat pentru gestionarea funcționării mașinilor virtuale lansate de hipervizorul pVM din cadrul Android Virtualization Framework. Anterior, firmware-ul era scris în limbajul C și implementat deasupra bootloader-ului U-Boot, în codul căruia au fost identificate anterior vulnerabilități cauzate de probleme legate de gestionarea memoriei.
Firmware-ul rescris în Rust este inclus în Android 14, iar bibliotecile universale create în timpul dezvoltării firmware-ului sunt organizate sub formă de pachete crate și transmise comunității Rust. De exemplu, a fost publicat pachetul smccc pentru suportul interfețelor ARM PSCI (Power State Coordination Interface) și apelurilor SMCCC (SMC Calling Convention), precum și pachetul aarch64-paging pentru manipularea tabelilor de pagini ale memoriei. De asemenea, a fost efectuată o muncă de corectare a erorilor și extindere a funcționalităților pachetului existent virtio-drivers cu implementarea driverelor VirtIO. Pe lângă platforma Android, aceste pachete sunt utilizate în proiectul Oak, care dezvoltă componente pentru transmiterea, stocarea și procesarea datelor în medii securizate (TEE, Trusted Execution Environment).
Hipervizorul pVM preia controlul într-o etapă timpurie a încărcării și asigură o izolare completă a memoriei mașini virtuale și a mediului gazdă, fără a permite sistemului gazdă să acceseze mașinile virtuale protejate în care se efectuează procesarea datelor confidențiale. Firmware-ul pvmfm (Protected Virtual Machine Firmware) preia controlul imediat după lansarea mașinii virtuale, efectuează verificarea mediului format și ia decizia de a întrerupe în mod de urgență încărcarea în cazul detectării unor probleme cu integritatea sau generează un certificat de încărcare pentru sistemul gazdă în cazul confirmării lanțului de încredere.
Reimplementarea în limbajul Rust permite o conformare mai simplă și mai sigură a „regulii celor două”, aplicată de Google pentru menținerea securității componentelor de sistem Android. Conform acestei reguli, orice cod adăugat trebuie să se încadreze în maximum două din trei condiții: lucrul cu date de intrare nevalidate, utilizarea unui limbaj de programare nesigur (C/C++) și executarea cu privilegii înalte. Din această regulă reiese că codul pentru procesarea datelor externe trebuie fie să fie restricționat la privilegii minime (izolat), fie să fie scris într-un limbaj de programare sigur. Potrivit statisticilor Google, aproximativ 70% din toate vulnerabilitățile periculoase identificate în Android sunt cauzate de erori în gestionarea memoriei.
Rust se concentrează pe gestionarea sigură a memoriei și permite reducerea riscurilor de apariție a vulnerabilităților cauzate de probleme precum accesarea unui spațiu de memorie după eliberare și depășirea limitelor buffer-ului. Gestionarea sigură a memoriei este asigurată în Rust în timpul compilării prin verificarea referințelor, urmărirea deținerii obiectelor și gestionarea duratei de viață a obiectelor (zona de vizibilitate), precum și prin evaluarea corectitudinii accesului la memorie în timpul execuției codului. Rust oferă, de asemenea, mecanisme pentru protecția împotriva suprascrierilor de tip integer, necesită inițializarea obligatorie a valorilor variabilelor înainte de utilizare, gestionează mai bine erorile în biblioteca standard, aplică conceptul de referințe și variabile nemodificabile (immutable) în mod implicit și oferă o tipizare statică puternică pentru minimizarea erorilor logice.
Printre dificultățile întâmpinate în procesul de dezvoltare a componentelor de nivel scăzut în limbajul Rust, cum ar fi driverele, se menționează necesitatea lucrului cu pointere brute în modul unsafe, deoarece Rust este conceput având în vedere utilizarea memoriei alocate în program, iar în codul care funcționează fără straturi deasupra hardware-ului, trebuie să se acceseze memoria partajată și MMIO. În prezent, capacitățile Rust de a gestiona pointere brute lasă mult de dorit, dar situația ar trebui să se schimbe după stabilizarea suportului pentru macro-comenzile offset_of, slice_ptr_get și slice_ptr_len.
Printre dezavantaje se evidențiază necesitatea unui sintax mai bun pentru accesul la câmpurile structurilor și indexurile array-urilor prin pointeri nudi, fără a crea referințe, dar și limitările în crearea unor învăluiri sigure pentru operațiuni unsafe, care pot provoca comportamente nedefinite și nu pot fi verificate de compilator. De exemplu, nu se pot crea astfel de învăluiri pentru operațiunile cu tabele de pagini de memorie, deoarece mapping-ul paginilor într-o parte a programului poate afecta alte părți.
În ceea ce privește dimensiunea codului rezultat, vechea variantă a firmware-ului pVM ocupa 220 kB, iar noua variantă - 460 kB, însă în varianta rescrisă au fost adăugate noi funcționalități, datorită cărora s-au putut elimina unele dintre celelalte componente utilizate la încărcare. Ca urmare, dimensiunea totală a tuturor componentelor de încărcare vechi și noi s-a dovedit a fi comparabilă. Se menționează că atunci când dimensiunea este mai importantă decât performanța, rezultate comparabile cu cele ale limbajului C pot fi obținute activând în compilator moduri suplimentare de optimizare pe baza dimensiunii, eliminând dependențele inutile și nefolosind instrumentele de formatare a șirurilor.
Se menționează, de asemenea, continuarea muncii la implementarea capacității de a rula aplicații de încredere scrise în limbajul Rust (Trusted Application) în sistemul de operare Trusty, care oferă un mediu TEE (Trusted Execution Environment) pentru Android, rulând în paralel cu Android pe același procesor într-un mediu izolat. Trusty este utilizat în dispozitivele Pixel și deja folosește Rust în biblioteci și componentele de sistem (nucleul rămâne în C).
Sursa: opennet.ro
