Wdróż DM-Vity

Android 4.4 i nowsze wersje obsługują weryfikację podczas uruchamiania dzięki opcjonalnej funkcji jądra device-mapper-verity (dm-verity), która zapewnia przejrzyste sprawdzanie integralności urządzeń blokowych. Funkcja dm-verity pomaga zapobiegać trwałym rootkitom, które mogą zachować uprawnienia roota i zaatakować urządzenia. Ta funkcja pomaga użytkownikom Androida mieć pewność, że po uruchomieniu urządzenie jest w tym samym stanie, w jakim było używane ostatnio.

Potencjalnie szkodliwe aplikacje z przywilejami roota mogą ukrywać się przed programami wykrywającymi i w inny sposób maskować swoją obecność. Oprogramowanie do roota może Dzieje się tak, ponieważ często mają one większe uprawnienia niż detektory, oprogramowanie „kłamstwa” programy wykrywające.

Funkcja dm-verity umożliwia sprawdzenie urządzenia blokowego, czyli podstawowej warstwy pamięci masowej systemu plików, i określenie, czy odpowiada ona oczekiwanej konfiguracji. Służy do tego kryptograficzne drzewo haszujące. Dla każdego bloku (zwykle 4k), jest dostępny hasz SHA256.

Ponieważ wartości hash są przechowywane w drzewie stron, tylko tagi najwyższego poziomu „root” hasz musi być zaufany w celu weryfikacji reszty drzewa. Możliwość modyfikowania dowolnego bloku byłaby równoznaczna z przełamaniem hasza kryptograficznego. Poniższy schemat przedstawia tę strukturę.

tabela z haszowaniem-dm-werity

Rysunek 1. Tabela haszy dm-verity

partycja rozruchowa zawiera klucz publiczny, który musi zostać zweryfikowany. przez producenta urządzenia. Ten klucz jest używany do weryfikacji podpisu dla tego hasza i potwierdzić, że partycja systemowa urządzenia jest chroniona bez zmian.

Operacja

W jądrze działa ochrona dm-verity. Jeśli więc oprogramowanie roota zaatakuje systemu, zanim pojawi się jądro, zachowa dostęp. Aby temu zaradzić większość producentów weryfikuje jądro za pomocą klucza wypalonego w urządzeniu. Klucza nie można zmienić, gdy urządzenie opuści fabrykę.

Producenci używają tego klucza do weryfikacji podpisu w pierwszym bootloaderze, który z kolei weryfikuje podpis na kolejnych poziomach, w bootloaderze aplikacji i ostatecznie w rdzeniu. Każdy producent, który chce korzystać z weryfikowanego uruchamiania, powinien mieć metodę weryfikacji integralności jądra. Jeśli jądro zostało zweryfikowane, może sprawdzać urządzenie blokowe i sprawdź, czy został zamontowany.

Jednym ze sposobów weryfikacji urządzenia blokowego jest bezpośrednie zaszyfrowanie jego zawartości i porównanie do wartości przedpłaconej. Próba zweryfikowania całego urządzenia blokowego może jednak zająć dużo czasu i wymagać znacznego zużycia energii. Urządzenia potrzebowałyby dużo czasu na uruchomienie, a potem byłyby bardzo rozładowane.

Zamiast tego dm-verity weryfikuje bloki pojedynczo i tylko wtedy, gdy każdy z nich jest dostępny. Podczas odczytu do pamięci blok jest równolegle szyfrowany. Następnie skrót jest weryfikowany w drzewie. Ponieważ odczyt bloku jest tak kosztowną operacją, opóźnienie spowodowane weryfikacją na poziomie bloku jest stosunkowo niewielkie.

Jeśli weryfikacja się nie powiedzie, urządzenie wygeneruje błąd wejścia-wyjścia, który wskazuje blok. nie może zostać odczytana. Wygląda na to, że system plików jest uszkodzony. nie jest oczekiwany.

Aplikacje mogą działać bez danych wynikowych, np. gdy te wyniki nie są wymagane do realizacji głównej funkcji aplikacji. Jeśli jednak aplikacja nie może działać bez tych danych, nie uda się to.

Przekaż dalej korektę błędu

Android 7.0 i nowsze wersje zwiększają odporność dm-verity dzięki korekcie błędów w przód (FEC). Implementacja AOSP zaczyna się od wspólnego kodu korygującego błędy Reed-Solomon i zawiera technikę zwaną przeplataniem, która pozwala zmniejszyć ilość zajmowanego miejsca i zwiększyć liczbę uszkodzonych bloków, które można odzyskać. Więcej informacji o FEC znajdziesz na stronie ściśle wymuszana weryfikacja podczas uruchamiania z korektą błędów;

Implementacja

Podsumowanie

  1. Wygeneruj obraz systemu ext4.
  2. Wygeneruj drzewo haszowania dla tego obrazu.
  3. Utwórz tabelę dm-verity dla tego drzewa haszowania.
  4. Podpisz tabelę dm-verity, aby wygenerować tabelę. podpis.
  5. Łączenie w pakiety podpisu tabeli i tabeli dm-verity do metadanych prawdziwości.
  6. Połącz obraz systemu, metadane weryfikacji i drzewo haszowania.

Szczegółowe informacje o drzewie haszy i tabeli dm-verity znajdziesz w artykule The Chromium Projects – Verified Boot.

Generowanie drzewa haszy

Jak wspomniano we wstępie, drzewo haszowania jest nieodłącznym elementem dm-verity. narzędzie cryptsetup tworzy drzewo haszujące. Zgodny jest też tutaj zdefiniowany:

<your block device name> <your block device name> <block size> <block size> <image size in blocks> <image size in blocks + 8> <root hash> <salt>

Aby utworzyć hasz, obraz systemu w warstwie 0 jest dzielony na 4 tys. bloków, z których każdy ma przypisany hasz SHA256. Warstwa 1 jest tworzona przez złączenie tylko tych skrótów SHA-256 w bloki 4 kB, co powoduje powstanie znacznie mniejszego obrazu. Powstała warstwa 2 z zaszyfrowanymi SHA256 warstwy 1.

Jest to możliwe, dopóki hasze SHA256 poprzedniej warstwy nie zmieszczą się w jednym miejscu. blokować. Po otrzymaniu skrótu SHA256 tego bloku otrzymasz hasz główny drzewa.

Rozmiar drzewa haszowania (i odpowiednia ilość miejsca na dysku) zmienia się wraz z rozmiarem weryfikowanej partycji. W praktyce rozmiar drzew hashowania jest zazwyczaj niewielki, często poniżej 30 MB.

Jeśli masz blok w warstwie, który nie jest całkowicie wypełniony przez hasze poprzedniej warstwy, musisz go uzupełnić zerami, aby uzyskać oczekiwane 4 K. Dzięki temu będziesz wiedzieć, że drzewo skrótu nie zostało usunięte i jest uzupełniono o puste dane.

Aby wygenerować drzewo skrótów, należy złączyć skróty warstwy 2 z skrótami warstwy 1, skróty warstwy 3 z skrótami warstwy 2 itd. Napisz wszystko na dysk. Zwróć uwagę, że nie odnosi się to do warstwy 0 skrótu głównego.

Podsumujmy, jak wygląda ogólny algorytm tworzenia drzewa haszy:

  1. Wybierz losową sól (kodowanie szesnastkowe).
  2. Rozdziel obraz systemu na bloki 4K.
  3. Dla każdego bloku uzyskaj jego (zasolony) identyfikator SHA256.
  4. Połącz te hasze, aby utworzyć poziom
  5. Uzupełnij poziom 0 do granicy bloku 4K.
  6. Połącz poziom z drzewem haszowania.
  7. Powtarzaj kroki 2–6, używając poprzedniego poziomu jako źródła dla następnego, aż będziesz mieć tylko jeden ciąg znaków.

Wynikiem jest pojedynczy ciąg znaków, czyli tzw. root hash. Te wartości i sól są używane podczas tworzenia tabeli mapowania dm-verity.

Tworzenie tabeli mapowania dm-verity

Utwórz tabelę mapowania dm-verity, która identyfikuje urządzenie blokowe (lub docelowe) dla jądra i lokalizacji drzewa haszy (które ma tę samą wartość). Ten mapowanie jest używane do generowania i uruchamiania fstab. Tabela zawiera też informacje o rozmiarze bloków i wartości hash_start, czyli początkowej lokalizacji drzewa haszowania (a precyzyjniej numer bloku od początku obrazu).

Zobacz konfigurację kryptografii dla szczegółowy opis pól tabeli mapowania wartości docelowej

Podpisz tabelę dm-verity

Podpisz tabelę dm-verity, aby wygenerować podpis tabeli. Podczas weryfikacji partycjonowanie, podpis tabeli jest najpierw weryfikowany. Jest to wykonywane w przypadku klucza na obraz rozruchowy w stałym miejscu. Klucze są zwykle uwzględniane w systemach kompilacji producentów w celu automatycznego uwzględniania ich na urządzeniach w stałym miejscu.

Aby zweryfikować partycję za pomocą tej kombinacji podpisu i klucza:

  1. Dodaj klucz RSA-2048 w formacie zgodnym z libmincrypt /boot partycja o /verity_key. Określ lokalizację klucza używanego do weryfikacji drzewa haszowania.
  2. W obszarze fstab odpowiedniego wpisu dodaj verify do flag fs_mgr.

Umieszczanie sygnatury tabeli w metadanych

Połącz podpis tabeli i tabelę dm-verity z metadanymi verity. Całość blok metadanych jest objęty wersjami, więc można go rozszerzyć, na przykład dodać dodać podpis lub zmienić kolejność.

W ramach kontroli z każdym zestawem metadanych tabeli kojarzona jest magiczna liczba i łatwiej zidentyfikować tabelę. Długość jest zawarta w nagłówku obrazu systemu ext4, co umożliwia wyszukiwanie metadanych bez znajomości zawartości samych danych.

Dzięki temu możesz się upewnić, że nie została wybrana opcja weryfikacji niezweryfikowanej partycji. Jeśli tak, brak tego magicznego numeru spowoduje przerwanie procesu weryfikacji. Ta liczba jest podobna do 0xb001b001.

Wartości bajtów w szeszxie:

  • pierwszy bajt = b0
  • drugi bajt = 01
  • trzeci bajt = b0
  • czwarty bajt = 01

Ten diagram przedstawia podział metadanych weryfikacji:

<magic number>|<version>|<signature>|<table length>|<table>|<padding>
\-------------------------------------------------------------------/
\----------------------------------------------------------/   |
                            |                                  |
                            |                                 32K
                       block content

W tej tabeli znajdziesz opis tych pól metadanych.

Tabela 1. Pola metadanych Verity

Pole Cel Rozmiar Wartość
magiczna liczba używany przez fs_mgr jako kontrola poprawności 4 bajty 0xb001b001
Wersja używane do wersji bloku metadanych 4 bajty obecnie 0
podpis podpis tabeli w formie dopełnionej PKCS1.5 256 bajtów
długość tabeli długość tabeli dm-verity w bajtach 4 bajty
stół opisana wcześniej tabela dm-verity bajty długości tabeli
padding ta struktura jest wypełniona zerami o długości 32 tys. 0

Optymalizuj dm-weryfikację

Aby uzyskać najlepszą wydajność dm-verity, wykonaj te czynności:

  • W jądrze włącz NEON SHA-2 dla ARMv7 i SHA-2 dla architektur ARMv8.
  • Eksperymentuj z różnymi ustawieniami funkcji odczytu wstępnego i prefetch_cluster, aby znaleźć najlepszą konfigurację dla swojego urządzenia.