Menerapkan dm-verity

Android 4.4 dan yang lebih tinggi mendukung Booting Terverifikasi melalui fitur kernel device-mapper-verity (dm-verity), yang memberikan pemeriksaan integritas perangkat blok. dm-verity membantu mencegah rootkit persisten yang dapat memiliki hak istimewa {i>root<i} dan menyusupi perangkat. Ini membantu pengguna Android memastikan bahwa saat {i>booting<i} perangkat, perangkat itu berada di tempat yang sama seperti saat terakhir kali digunakan.

Aplikasi yang Berpotensi Membahayakan (PHA) dengan hak istimewa root dapat disembunyikan dari program deteksi dan menyamarkan diri mereka sendiri. Perangkat lunak {i>rooting<i} dapat melakukan ini karena sering kali lebih istimewa daripada detektor, yang memungkinkan perangkat lunak untuk "berbohong" ke program deteksi.

Fitur dm-verity memungkinkan Anda melihat perangkat blok, penyimpanan yang mendasarinya, sistem file, dan menentukan apakah sesuai dengan yang diharapkan konfigurasi Anda. Hal ini dilakukan dengan menggunakan pohon {i>hash<i} kriptografi. Untuk setiap blok (biasanya 4k), ada {i>hash<i} SHA256.

Karena nilai {i>hash<i} disimpan di hierarki halaman, hanya {i>hash<i} tingkat atas "akar" {i>hash <i}harus dipercaya untuk memverifikasi bagian pohon yang lain. Kemampuan untuk memodifikasi blok mana pun akan setara dengan merusak {i>hash<i} kriptografi. Lihat diagram berikut untuk gambaran struktur ini.

tabel hash dm-verity

Gambar 1. Tabel hash dm-verity

Kunci publik disertakan pada partisi {i>boot<i}, yang harus diverifikasi secara eksternal oleh produsen perangkat. Kunci tersebut digunakan untuk memverifikasi tanda tangan untuk {i>hash<i} itu dan mengkonfirmasi bahwa partisi sistem perangkat telah dilindungi dan tidak berubah.

Operasi

Perlindungan dm-verity ada di {i>kernel<i}. Jadi, jika perangkat lunak {i>rooting<i} menyusupi jaringan sebelum {i>kernel<i} muncul, ia akan mempertahankan akses itu. Untuk memitigasi hal ini sebagian besar produsen memverifikasi {i>kernel<i} menggunakan kunci yang dibakar ke dalam perangkat. Kunci tersebut tidak dapat diubah setelah perangkat keluar dari pabrik.

Produsen menggunakan kunci tersebut untuk memverifikasi tanda tangan di level pertama yang pada gilirannya memverifikasi tanda tangan pada level berikutnya, {i>bootloader<i} aplikasi dan akhirnya {i>kernel<i}. Setiap produsen ingin memanfaatkan analisis terverifikasi booting harus memiliki metode untuk memverifikasi integritas kernel. Dengan asumsi bahwa {i>kernel<i} telah diverifikasi, {i>kernel<i} dapat melihat perangkat blok dan memverifikasinya saat terpasang.

Salah satu cara memverifikasi perangkat blok adalah dengan langsung {i>hash<i} isinya dan membandingkannya mereka ke nilai yang tersimpan. Tetapi, mencoba memverifikasi seluruh perangkat blok dapat memakan waktu lama dan menghabiskan banyak daya perangkat. Perangkat akan memerlukan lama untuk {i>booting<i}, dan kemudian terkuras secara signifikan sebelum digunakan.

Sebaliknya, dm-verity memverifikasi blok satu per satu dan hanya ketika masing-masing blok diakses. Saat dibaca ke memori, blok akan di-hash secara paralel. {i>Hash <i}nya adalah kemudian memverifikasi pohonnya. Dan karena membaca blok itu sangat mahal, , latensi yang disebabkan oleh verifikasi tingkat blok ini adalah relatif nominal.

Jika verifikasi gagal, perangkat akan membuat error I/O yang menunjukkan pemblokiran tidak dapat dibaca. Sistem file akan tampak seperti telah rusak yang diharapkan.

Aplikasi dapat memilih untuk melanjutkan tanpa data yang dihasilkan, seperti saat hasil tersebut tidak diperlukan untuk fungsi utama aplikasi. Namun, jika aplikasi tidak dapat dilanjutkan tanpa data, maka aplikasi akan gagal.

Teruskan koreksi error

Android 7.0 dan yang lebih tinggi meningkatkan keandalan dm-verity dengan error maju koreksi (FEC). Implementasi AOSP dimulai dengan kode koreksi error Reed-Solomon dan menerapkan teknik yang disebut interleaving untuk mengurangi overhead ruang dan meningkatkan jumlah blok rusak yang dapat dipulihkan. Untuk mengetahui detail selengkapnya tentang FEC, lihat Booting Terverifikasi yang Diterapkan Secara Ketat dengan Koreksi Error.

Implementasi

Ringkasan

  1. Buat image sistem ext4.
  2. Buat hierarki hash untuk gambar tersebut.
  3. Buat tabel dm-verity untuk hierarki hash tersebut.
  4. Tanda tangani tabel dm-verity tersebut untuk menghasilkan tabel tanda tangan.
  5. Memaketkan tanda tangan tabel dan tabel dm-verity ke dalam {i>metadata <i}benar.
  6. Menggabungkan image sistem, metadata verifikasi, dan hierarki hash.

Lihat Project Chromium - Booting Terverifikasi untuk deskripsi terperinci tentang pohon {i>hash<i} dan tabel {i>dm-verity<i}.

Membuat hierarki hash

Seperti yang dijelaskan di pendahuluan, hierarki hash adalah bagian integral dari dm-verity. Tujuan alat cryptsetup akan membuatkan pohon {i>hash <i}untuk Anda. Atau, yang kompatibel ditentukan di sini:

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

Untuk membentuk {i>hash<i}, {i>image<i} sistem dibagi pada lapisan 0 menjadi blok 4k, masing-masing diberi {i>hash<i} SHA256. Lapisan 1 dibentuk dengan hanya menggabungkan hash SHA256 tersebut menjadi blok 4k, yang menghasilkan gambar yang jauh lebih kecil. Lapisan 2 terbentuk secara identik, dengan {i>hash<i} SHA256 di Lapisan 1.

Hal ini dilakukan sampai {i>hash<i} SHA256 dari lapisan sebelumnya dapat ditampung dalam satu diblokir. Saat mendapatkan SHA256 dari blok tersebut, Anda memiliki hash root hierarki.

Ukuran hierarki hash (dan penggunaan kapasitas {i>disk<i} yang sesuai) bervariasi menurut ukuran partisi yang diverifikasi. Dalam praktiknya, ukuran pohon {i>hash<i} cenderung kecil, biasanya kurang dari 30 MB.

Jika Anda memiliki sebuah blok di lapisan yang tidak sepenuhnya terisi secara alami oleh {i>hash <i}dari lapisan sebelumnya, Anda harus melapisinya dengan angka nol untuk mencapai 4k yang diharapkan. Hal ini memungkinkan Anda untuk mengetahui bahwa pohon {i>hash<i} belum dihapus dan alih-alih diisi dengan data kosong.

Untuk menghasilkan hierarki hash, gabungkan hash lapisan 2 ke hash untuk lapisan 1, lapisan 3 {i>hash<i} ke lapisan 2, dan seterusnya. Tulis semua ini ke {i>disk<i}. Perhatikan bahwa ini tidak mereferensikan lapisan 0 dari hash root.

Sebagai rangkuman, algoritma umum untuk menyusun pohon {i>hash<i} adalah sebagai berikut:

  1. Pilih salt acak (encoding heksadesimal).
  2. Uraikan image sistem Anda menjadi blok 4k.
  3. Untuk setiap blok, dapatkan hash SHA256 (asin).
  4. Gabungkan hash ini untuk membentuk level
  5. Tambahkan level dengan 0 hingga batas blok 4k.
  6. Gabungkan tingkat ke hierarki hash Anda.
  7. Ulangi langkah 2-6 menggunakan level sebelumnya sebagai sumber untuk level berikutnya hingga Anda hanya memiliki satu {i>hash<i}.

Hasilnya adalah hash tunggal, yang merupakan hash root Anda. Ini dan salt Anda digunakan selama pembangunan tabel pemetaan dm-veritas Anda.

Membuat tabel pemetaan dm-verity

Bangun tabel pemetaan dm-verity, yang mengidentifikasi perangkat blok (atau target) untuk {i>kernel<i} dan lokasi {i>hash tree<i} (yang merupakan nilai yang sama.) Ini pemetaan digunakan untuk pembuatan dan booting fstab. Tabel tersebut juga mengidentifikasi ukuran blok dan {i>hash_start<i}, lokasi awal hierarki {i>hash<i} (khususnya, nomor bloknya dari awal gambar).

Lihat cryptsetup untuk deskripsi terperinci tentang {i>field<i} tabel pemetaan target kebenaran.

Menandatangani tabel verifikasi dm

Tanda tangani tabel dm-verity untuk menghasilkan tanda tangan tabel. Saat memverifikasi , tanda tangan tabel divalidasi terlebih dahulu. Hal ini dilakukan terhadap kunci di image {i>booting<i} Anda di lokasi yang tetap. Kunci biasanya tercakup dalam produsen membangun sistem untuk penyertaan otomatis pada perangkat dalam lokasi HTTP/HTTPS.

Untuk memverifikasi partisi dengan kombinasi tanda tangan dan tombol ini:

  1. Tambahkan kunci RSA-2048 dalam format yang kompatibel dengan libmincrypt ke Partisi /boot pukul /verity_key. Mengidentifikasi lokasi kunci yang digunakan untuk memverifikasi {i>hash tree<i}.
  2. Di fstab untuk entri yang relevan, tambahkan verify ke tanda fs_mgr.

Membundel tanda tangan tabel ke dalam metadata

Gabungkan tanda tangan tabel dan tabel dm-verity ke dalam metadata verifikasi. Seluruh blok metadata memiliki beberapa versi sehingga dapat diperpanjang, seperti menambahkan tanda tangan atau mengubah urutannya.

Sebagai pemeriksaan kesehatan, angka ajaib dikaitkan dengan setiap set metadata tabel yang membantu mengidentifikasi tabel. Karena panjangnya termasuk dalam sistem ext4 gambar, menyediakan cara untuk mencari metadata tanpa mengetahui isi dari data itu sendiri.

Hal ini memastikan Anda tidak memilih untuk memverifikasi partisi yang belum diverifikasi. Jika demikian, ketiadaan angka ajaib ini akan menghentikan proses verifikasi. Nomor ini menyerupai:
{i>0xb001b001<i}

Nilai byte dalam heksadesimal adalah:

  • byte pertama = b0
  • byte kedua = 01
  • byte ketiga = b0
  • byte keempat = 01

Diagram berikut menggambarkan perincian metadata verifikasi:

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

Dan tabel ini menjelaskan kolom metadata tersebut.

Tabel 1. Kolom metadata Verity

Kolom Tujuan Ukuran Nilai
angka ajaib digunakan oleh fs_mgr sebagai pemeriksaan kesehatan 4 byte {i>0xb001b001<i}
version digunakan untuk membuat versi blok metadata 4 byte saat ini 0
tanda tangan tanda tangan tabel dalam formulir dengan padding PKCS1.5 256 byte
panjang tabel panjang tabel dm-verity dalam byte 4 byte
meja tabel {i>dm-verity<i} yang dijelaskan sebelumnya byte panjang tabel
padding struktur ini diberi padding 0 hingga panjang 32k 0

Mengoptimalkan tingkat dm

Untuk mendapatkan performa terbaik dari verifikasi dm, Anda harus:

  • Di kernel, aktifkan SHA-2 neon untuk ARMv7 dan SHA-2 ekstensi untuk ARMv8.
  • Bereksperimen dengan berbagai read-ahead dan fetch_cluster khusus untuk menemukan konfigurasi terbaik bagi perangkat Anda.