Menerapkan dm-verity

Android 4.4 dan yang lebih tinggi mendukung Booting Terverifikasi melalui fitur kernel device-mapper-verity (dm-verity) opsional, yang memberikan pemeriksaan integritas transparan pada perangkat blok. dm-verity membantu mencegah rootkit persisten yang dapat mempertahankan hak istimewa root dan membahayakan perangkat. Fitur ini membantu pengguna Android memastikan bahwa saat mem-booting perangkat, perangkat tersebut berada dalam status yang sama seperti saat terakhir kali digunakan.

Aplikasi yang Berpotensi Berbahaya (PHA) dengan hak istimewa root dapat bersembunyi dari program deteksi dan menyamarkan dirinya sendiri. Software rooting dapat melakukannya karena sering kali memiliki lebih banyak hak istimewa daripada detektor, sehingga memungkinkan software untuk "berbohong" kepada program deteksi.

Fitur dm-verity memungkinkan Anda melihat perangkat blok, lapisan penyimpanan yang mendasari sistem file, dan menentukan apakah perangkat tersebut cocok dengan konfigurasi yang diharapkan. Hal ini dilakukan menggunakan hierarki hash kriptografis. Untuk setiap blok (biasanya 4k), ada hash SHA256.

Karena nilai hash disimpan dalam hierarki halaman, hanya hash "root" tingkat teratas yang harus dipercaya untuk memverifikasi bagian hierarki lainnya. Kemampuan untuk mengubah blok apa pun akan setara dengan memecahkan hash kriptografis. Lihat diagram berikut untuk mengetahui penggambaran struktur ini.

dm-verity-hash-table

Gambar 1. Tabel hash dm-verity

Kunci publik disertakan di partisi booting, yang harus diverifikasi secara eksternal oleh produsen perangkat. Kunci tersebut digunakan untuk memverifikasi tanda tangan untuk hash tersebut dan mengonfirmasi bahwa partisi sistem perangkat dilindungi dan tidak berubah.

Operasi

Perlindungan dm-verity berada di kernel. Jadi, jika software rooting membahayakan sistem sebelum kernel muncul, software tersebut akan mempertahankan akses tersebut. Untuk mengurangi risiko ini, sebagian besar produsen memverifikasi kernel menggunakan kunci yang di-burn ke dalam perangkat. Kunci tersebut tidak dapat diubah setelah perangkat keluar dari pabrik.

Produsen menggunakan kunci tersebut untuk memverifikasi tanda tangan di bootloader level pertama, yang pada akhirnya memverifikasi tanda tangan di level berikutnya, bootloader aplikasi, dan akhirnya kernel. Setiap produsen yang ingin memanfaatkan boot terverifikasi harus memiliki metode untuk memverifikasi integritas kernel. Dengan asumsi kernel telah diverifikasi, kernel dapat melihat perangkat blok dan memverifikasinya saat dipasang.

Salah satu cara memverifikasi perangkat blok adalah dengan langsung melakukan hashing pada kontennya dan membandingkannya dengan nilai yang disimpan. Namun, upaya untuk memverifikasi seluruh perangkat blok dapat memerlukan waktu yang lama dan menghabiskan banyak daya perangkat. Perangkat akan memerlukan waktu yang lama untuk melakukan booting, lalu baterainya akan habis secara signifikan sebelum digunakan.

Sebagai gantinya, dm-verity memverifikasi blok satu per satu dan hanya saat setiap blok diakses. Saat dibaca ke dalam memori, blok di-hash secara paralel. Hash kemudian diverifikasi ke atas hierarki. Selain itu, karena membaca blok adalah operasi yang sangat mahal, latensi yang diperkenalkan oleh verifikasi tingkat blok ini relatif nominal.

Jika verifikasi gagal, perangkat akan menghasilkan error I/O yang menunjukkan blok tidak dapat dibaca. Sepertinya sistem file telah rusak, seperti 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, aplikasi akan gagal.

Forward error correction

Android 7.0 dan yang lebih baru meningkatkan keandalan dm-verity dengan forward error correction (FEC). Penerapan AOSP dimulai dengan kode perbaikan error Reed-Solomon umum dan menerapkan teknik yang disebut interleaving untuk mengurangi overhead ruang dan meningkatkan jumlah blok yang rusak yang dapat dipulihkan. Untuk mengetahui detail selengkapnya tentang FEC, lihat Booting Terverifikasi yang Diberlakukan 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 tanda tangan tabel.
  5. Gabungkan tanda tangan tabel dan tabel dm-verity ke dalam metadata verity.
  6. Gabungkan image sistem, metadata verity, dan hierarki hash.

Lihat Project Chromium - Verified Boot untuk deskripsi mendetail tentang hierarki hash dan tabel dm-verity.

Membuat hierarki hash

Seperti yang dijelaskan dalam pengantar, hierarki hash merupakan bagian integral dari dm-verity. Alat cryptsetup akan membuat hierarki hash 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 hash, image sistem dibagi di lapisan 0 menjadi blok 4k, yang masing-masing diberi hash SHA256. Lapisan 1 dibentuk dengan menggabungkan hash SHA256 tersebut menjadi blok 4k, sehingga menghasilkan gambar yang jauh lebih kecil. Lapisan 2 dibentuk secara identik, dengan hash SHA256 Lapisan 1.

Hal ini dilakukan hingga hash SHA256 dari lapisan sebelumnya dapat muat dalam satu blok. Saat mendapatkan SHA256 blok tersebut, Anda memiliki hash root hierarki.

Ukuran hierarki hash (dan penggunaan ruang disk yang sesuai) bervariasi dengan ukuran partisi yang diverifikasi. Dalam praktiknya, ukuran hierarki hash cenderung kecil, sering kali kurang dari 30 MB.

Jika Anda memiliki blok di lapisan yang tidak terisi sepenuhnya secara alami oleh hash lapisan sebelumnya, Anda harus mengisinya dengan nol untuk mencapai 4k yang diharapkan. Hal ini memungkinkan Anda mengetahui bahwa hierarki hash belum dihapus dan sebagai gantinya diisi dengan data kosong.

Untuk membuat hierarki hash, gabungkan hash lapisan 2 ke hash untuk lapisan 1, hash lapisan 3 ke hash lapisan 2, dan seterusnya. Tulis semua ini ke disk. Perhatikan bahwa ini tidak mereferensikan lapisan 0 hash root.

Sebagai rangkuman, algoritma umum untuk membuat hierarki hash adalah sebagai berikut:

  1. Pilih salt acak (encoding heksadesimal).
  2. Hapus spasi image sistem Anda menjadi blok 4k.
  3. Untuk setiap blok, dapatkan hash SHA256 (dengan garam).
  4. Gabungkan hash ini untuk membentuk level
  5. Isi level dengan 0 ke batas blok 4k.
  6. Gabungkan level ke hierarki hash Anda.
  7. Ulangi langkah 2-6 menggunakan level sebelumnya sebagai sumber untuk level berikutnya hingga Anda hanya memiliki satu hash.

Hasilnya adalah satu hash, yang merupakan hash root Anda. Hal ini dan salt Anda digunakan selama pembuatan tabel pemetaan dm-verity.

Membuat tabel pemetaan dm-verity

Buat tabel pemetaan dm-verity, yang mengidentifikasi perangkat blok (atau target) untuk kernel dan lokasi hierarki hash (yang merupakan nilai yang sama). Pemetaan ini digunakan untuk pembuatan dan booting fstab. Tabel ini juga mengidentifikasi ukuran blok dan hash_start, lokasi awal hierarki hash (khususnya, nomor bloknya dari awal gambar).

Lihat cryptsetup untuk deskripsi mendetail tentang kolom tabel pemetaan target verity.

Menandatangani tabel dm-verity

Tanda tangani tabel dm-verity untuk menghasilkan tanda tangan tabel. Saat memverifikasi partisi, tanda tangan tabel akan divalidasi terlebih dahulu. Hal ini dilakukan terhadap kunci di image booting Anda di lokasi tetap. Kunci biasanya disertakan dalam sistem build produsen untuk penyertaan otomatis di perangkat di lokasi tetap.

Untuk memverifikasi partisi dengan kombinasi kunci dan tanda tangan ini:

  1. Tambahkan kunci RSA-2048 dalam format yang kompatibel dengan libmincrypt ke partisi /boot di /verity_key. Identifikasi lokasi kunci yang digunakan untuk memverifikasi hash tree.
  2. Di fstab untuk entri yang relevan, tambahkan verify ke flag fs_mgr.

Memaketkan tanda tangan tabel ke dalam metadata

Gabungkan tanda tangan tabel dan tabel dm-verity ke dalam metadata verity. Seluruh blok metadata diberi versi sehingga dapat diperluas, seperti menambahkan jenis tanda tangan kedua atau mengubah beberapa urutan.

Sebagai pemeriksaan keandalan, angka ajaib dikaitkan dengan setiap kumpulan metadata tabel yang membantu mengidentifikasi tabel. Karena panjangnya disertakan dalam header image sistem ext4, hal ini memberikan cara untuk menelusuri metadata tanpa mengetahui konten data itu sendiri.

Hal ini memastikan Anda belum memilih untuk memverifikasi partisi yang belum diverifikasi. Jika demikian, tidak adanya angka ajaib ini akan menghentikan proses verifikasi. Angka ini menyerupai 0xb001b001.

Nilai byte dalam hex adalah:

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

Diagram berikut menggambarkan pengelompokan metadata verity:

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

Dan tabel ini menjelaskan kolom metadata tersebut.

Tabel 1. Memverifikasi kolom metadata

Kolom Tujuan Ukuran Nilai
angka ajaib digunakan oleh fs_mgr sebagai pemeriksaan keandalan 4 byte 0xb001b001
version digunakan untuk membuat versi blok metadata 4 byte saat ini 0
tanda tangan tanda tangan tabel dalam bentuk padding PKCS1.5 256 byte
panjang tabel panjang tabel dm-verity dalam byte 4 byte
meja tabel dm-verity yang dijelaskan sebelumnya byte panjang tabel
padding struktur ini ditambahkan 0 hingga panjangnya 32 ribu 0

Mengoptimalkan dm-verity

Untuk mendapatkan performa terbaik dari dm-verity, Anda harus:

  • Di kernel, aktifkan NEON SHA-2 untuk ARMv7 dan ekstensi SHA-2 untuk ARMv8.
  • Bereksperimenlah dengan berbagai setelan read-ahead dan prefetch_cluster untuk menemukan konfigurasi terbaik bagi perangkat Anda.