Menerapkan dm-verity

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

Aplikasi yang Berpotensi Membahayakan (PHA) dengan hak akses root dapat bersembunyi dari program deteksi dan sebaliknya menutupi dirinya sendiri. Perangkat lunak rooting dapat melakukan hal ini karena seringkali lebih diistimewakan daripada detektor, sehingga memungkinkan perangkat lunak untuk "berbohong" kepada program pendeteksi.

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 dengan menggunakan pohon hash kriptografi. Untuk setiap blok (biasanya 4k), ada hash SHA256.

Karena nilai hash disimpan dalam pohon halaman, hanya hash "root" tingkat atas yang harus dipercaya untuk memverifikasi sisa pohon. Kemampuan untuk memodifikasi blok mana pun sama dengan memecahkan hash kriptografi. Lihat diagram berikut untuk gambaran struktur ini.

dm-verity-hash-tabel

Gambar 1. tabel hash dm-verity

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

Operasi

perlindungan dm-verity ada di kernel. Jadi jika perangkat lunak rooting membahayakan sistem sebelum kernel muncul, akses tersebut akan tetap dipertahankan. Untuk mengurangi risiko ini, sebagian besar produsen memverifikasi kernel menggunakan kunci yang dimasukkan ke dalam perangkat. Kunci tersebut tidak dapat diubah setelah perangkat meninggalkan pabrik.

Produsen menggunakan kunci tersebut untuk memverifikasi tanda tangan pada bootloader tingkat pertama, yang pada gilirannya memverifikasi tanda tangan pada tingkat berikutnya, bootloader aplikasi, dan akhirnya kernel. Setiap pabrikan 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 sudah terpasang.

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

Sebaliknya, dm-verity memverifikasi blok secara individual dan hanya ketika masing-masing blok diakses. Saat dibaca ke dalam memori, blok tersebut di-hash secara paralel. Hash tersebut kemudian diverifikasi di pohon. Dan karena membaca blok adalah operasi yang mahal, latensi yang ditimbulkan oleh verifikasi tingkat blok ini relatif kecil.

Jika verifikasi gagal, perangkat menghasilkan kesalahan I/O yang menunjukkan blok tidak dapat dibaca. Tampaknya sistem file telah rusak, seperti yang diharapkan.

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

Koreksi kesalahan ke depan

Android 7.0 dan lebih tinggi meningkatkan ketahanan dm-verity dengan koreksi kesalahan maju (FEC). Implementasi AOSP dimulai dengan kode koreksi kesalahan Reed-Solomon yang umum dan menerapkan teknik yang disebut interleaving untuk mengurangi overhead ruang dan meningkatkan jumlah blok rusak yang dapat dipulihkan. Untuk detail selengkapnya tentang FEC, lihat Boot Terverifikasi yang Ditegakkan Secara Ketat dengan Koreksi Kesalahan .

Penerapan

Ringkasan

  1. Hasilkan gambar sistem ext4.
  2. Hasilkan pohon hash untuk gambar itu.
  3. Buat tabel dm-verity untuk pohon 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 citra sistem, metadata kebenaran, dan pohon hash.

Lihat Proyek Chromium - Boot Terverifikasi untuk penjelasan rinci tentang pohon hash dan tabel dm-verity.

Menghasilkan pohon hash

Seperti yang dijelaskan dalam pendahuluan, pohon hash merupakan bagian integral dari dm-verity. Alat cryptsetup akan menghasilkan pohon hash untuk Anda. Alternatifnya, 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, citra sistem dipecah pada lapisan 0 menjadi 4k blok, masing-masing diberi hash SHA256. Lapisan 1 dibentuk dengan menggabungkan hanya hash SHA256 tersebut ke dalam blok 4k, sehingga menghasilkan gambar yang jauh lebih kecil. Layer 2 dibentuk secara identik, dengan hash SHA256 dari Layer 1.

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

Ukuran pohon hash (dan penggunaan ruang disk yang sesuai) bervariasi menurut ukuran partisi yang diverifikasi. Dalam praktiknya, ukuran pohon hash cenderung kecil, seringkali kurang dari 30 MB.

Jika Anda memiliki blok di lapisan yang tidak terisi penuh secara alami oleh hash dari lapisan sebelumnya, Anda harus mengisinya dengan nol untuk mencapai 4k yang diharapkan. Hal ini memungkinkan Anda mengetahui bahwa pohon hash belum dihapus dan malah dilengkapi dengan data kosong.

Untuk menghasilkan pohon hash, gabungkan hash lapisan 2 ke hash lapisan 1, hash lapisan 3 ke hash lapisan 2, dan seterusnya. Tulis semua ini ke disk. Perhatikan bahwa ini tidak mereferensikan lapisan 0 dari hash root.

Singkatnya, algoritma umum untuk membangun pohon hash adalah sebagai berikut:

  1. Pilih garam acak (pengkodean heksadesimal).
  2. Pisahkan citra sistem Anda menjadi blok 4k.
  3. Untuk setiap blok, dapatkan hash SHA256 (asin).
  4. Gabungkan hash ini untuk membentuk level
  5. Padukan level dengan 0 hingga batas blok 4k.
  6. Gabungkan level ke pohon 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, yaitu hash root Anda. Ini dan garam Anda digunakan selama pembuatan tabel pemetaan dm-verity Anda.

Membangun tabel pemetaan dm-verity

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

Lihat cryptsetup untuk penjelasan rinci tentang bidang tabel pemetaan target kebenaran.

Menandatangani tabel dm-verity

Tanda tangani tabel dm-verity untuk menghasilkan tanda tangan tabel. Saat memverifikasi partisi, tanda tangan tabel divalidasi terlebih dahulu. Ini dilakukan terhadap kunci pada image boot Anda di lokasi tetap. Kunci biasanya disertakan dalam sistem build pabrikan untuk penyertaan otomatis pada perangkat di lokasi tetap.

Untuk memverifikasi partisi dengan tanda tangan dan kombinasi kunci 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 pohon hash.
  2. Di fstab untuk entri yang relevan, tambahkan verify ke flag fs_mgr .

Menggabungkan 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 kewarasan, angka ajaib dikaitkan dengan setiap kumpulan metadata tabel yang membantu mengidentifikasi tabel. Karena panjangnya disertakan dalam header gambar sistem ext4, ini menyediakan cara untuk mencari metadata tanpa mengetahui konten data itu sendiri.

Ini memastikan Anda tidak memilih untuk memverifikasi partisi yang belum diverifikasi. Jika ya, 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 rincian metadata kebenaran:

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

Dan tabel ini menjelaskan bidang metadata tersebut.

Tabel 1. Bidang metadata kebenaran

Bidang Tujuan Ukuran Nilai
angka ajaib digunakan oleh fs_mgr sebagai pemeriksaan kewarasan 4 byte 0xb001b001
Versi: kapan digunakan untuk membuat versi blok metadata 4 byte saat ini 0
tanda tangan tanda tangan tabel dalam bentuk empuk PKCS1.5 256 byte
panjang meja panjang tabel dm-verity dalam byte 4 byte
meja tabel dm-verity yang dijelaskan sebelumnya byte panjang tabel
lapisan struktur ini memiliki bantalan 0 hingga panjang 32k 0

Mengoptimalkan kebenaran dm

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

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