Triển khai dm-verity

Android 4.4 trở lên hỗ trợ Khởi động được xác minh thông qua tính năng kernel device-mapper-verity (dm-verity) tùy chọn, cung cấp khả năng kiểm tra tính toàn vẹn minh bạch của các thiết bị khối. dm-verity giúp ngăn chặn các rootkit dai dẳng có thể nắm giữ các đặc quyền của root và xâm phạm thiết bị. Tính năng này giúp người dùng Android chắc chắn rằng khi khởi động thiết bị vẫn ở trạng thái giống như khi sử dụng lần cuối.

Các ứng dụng có khả năng gây hại (PHA) có quyền root có thể ẩn khỏi các chương trình phát hiện và nếu không sẽ tự che giấu. Phần mềm root có thể làm được điều này vì nó thường có nhiều đặc quyền hơn các trình phát hiện, cho phép phần mềm "nói dối" với các chương trình phát hiện.

Tính năng dm-verity cho phép bạn xem xét một thiết bị khối, lớp lưu trữ cơ bản của hệ thống tệp và xác định xem nó có phù hợp với cấu hình dự kiến ​​hay không. Nó thực hiện điều này bằng cách sử dụng cây băm mật mã. Đối với mỗi khối (thường là 4k), có một hàm băm SHA256.

Bởi vì các giá trị băm được lưu trữ trong một cây các trang, nên chỉ có hàm băm "gốc" cấp cao nhất mới được tin cậy để xác minh phần còn lại của cây. Khả năng sửa đổi bất kỳ khối nào sẽ tương đương với việc phá vỡ hàm băm mật mã. Xem sơ đồ sau để mô tả cấu trúc này.

dm-verity-hash-table

Hình 1. Bảng băm dm-verity

Một khóa chung được bao gồm trong phân vùng khởi động, khóa này phải được nhà sản xuất thiết bị xác minh bên ngoài. Khóa đó được sử dụng để xác minh chữ ký cho hàm băm đó và xác nhận phân vùng hệ thống của thiết bị được bảo vệ và không thay đổi.

Hoạt động

bảo vệ dm-verity nằm trong kernel. Vì vậy, nếu phần mềm root xâm phạm hệ thống trước khi kernel xuất hiện, nó sẽ giữ lại quyền truy cập đó. Để giảm thiểu rủi ro này, hầu hết các nhà sản xuất xác minh kernel bằng cách sử dụng khóa được ghi vào thiết bị. Khóa đó không thể thay đổi sau khi thiết bị rời khỏi nhà máy.

Các nhà sản xuất sử dụng khóa đó để xác minh chữ ký trên bộ tải khởi động cấp đầu tiên, từ đó xác minh chữ ký ở các cấp tiếp theo, bộ tải khởi động ứng dụng và cuối cùng là nhân. Mỗi nhà sản xuất muốn tận dụng khả năng khởi động đã xác minh nên có một phương pháp để xác minh tính toàn vẹn của nhân. Giả sử kernel đã được xác minh, kernel có thể xem xét một thiết bị khối và xác minh nó khi nó được gắn kết.

Một cách để xác minh thiết bị khối là băm trực tiếp nội dung của nó và so sánh chúng với giá trị được lưu trữ. Tuy nhiên, việc cố gắng xác minh toàn bộ thiết bị khối có thể mất nhiều thời gian và tiêu tốn nhiều năng lượng của thiết bị. Các thiết bị sẽ mất nhiều thời gian để khởi động và sau đó sẽ bị cạn kiệt đáng kể trước khi sử dụng.

Thay vào đó, dm-verity xác minh các khối riêng lẻ và chỉ khi mỗi khối được truy cập. Khi được đọc vào bộ nhớ, khối được băm song song. Hàm băm sau đó được xác minh trên cây. Và vì việc đọc khối là một hoạt động tốn kém như vậy nên độ trễ do xác minh cấp khối này đưa ra là tương đối nhỏ.

Nếu xác minh không thành công, thiết bị sẽ tạo ra lỗi I/O cho biết khối không thể đọc được. Nó sẽ xuất hiện như thể hệ thống tập tin đã bị hỏng, như mong đợi.

Các ứng dụng có thể chọn tiếp tục mà không có dữ liệu kết quả, chẳng hạn như khi những kết quả đó không bắt buộc đối với chức năng chính của ứng dụng. Tuy nhiên, nếu ứng dụng không thể tiếp tục mà không có dữ liệu, nó sẽ bị lỗi.

Chuyển tiếp sửa lỗi

Android 7.0 trở lên cải thiện độ bền của dm-verity với tính năng sửa lỗi chuyển tiếp (FEC). Việc triển khai AOSP bắt đầu với mã sửa lỗi Reed-Solomon phổ biến và áp dụng một kỹ thuật gọi là xen kẽ để giảm chi phí không gian và tăng số lượng khối bị hỏng có thể được khôi phục. Để biết thêm chi tiết về FEC, hãy xem Khởi động được xác minh được thực thi nghiêm ngặt với sửa lỗi .

Thực hiện

Bản tóm tắt

  1. Tạo một hình ảnh hệ thống ext4.
  2. Tạo một cây băm cho hình ảnh đó.
  3. Xây dựng bảng dm-verity cho cây băm đó.
  4. Ký bảng dm-verity đó để tạo chữ ký bảng.
  5. Kết hợp chữ ký bảng và bảng dm-verity thành siêu dữ liệu xác thực.
  6. Ghép nối hình ảnh hệ thống, siêu dữ liệu xác thực và cây băm.

XemDự án Chromium - Khởi động đã xác minh để biết mô tả chi tiết về cây băm và bảng dm-verity.

Tạo cây băm

Như được mô tả trong phần giới thiệu, cây băm là không thể thiếu đối với dm-verity. Công cụ cryptsetup sẽ tạo cây băm cho bạn. Ngoài ra, một cái tương thích được định nghĩa ở đây:

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

Để tạo hàm băm, hình ảnh hệ thống được chia ở lớp 0 thành 4k khối, mỗi khối được gán một hàm băm SHA256. Lớp 1 được hình thành bằng cách chỉ kết hợp các hàm băm SHA256 đó thành các khối 4k, dẫn đến hình ảnh nhỏ hơn nhiều. Lớp 2 được hình thành giống hệt nhau, với hàm băm SHA256 của Lớp 1.

Điều này được thực hiện cho đến khi các giá trị băm SHA256 của lớp trước đó có thể vừa với một khối. Khi nhận được SHA256 của khối đó, bạn có hàm băm gốc của cây.

Kích thước của cây băm (và mức sử dụng dung lượng ổ đĩa tương ứng) thay đổi theo kích thước của phân vùng đã xác minh. Trong thực tế, kích thước của cây băm có xu hướng nhỏ, thường dưới 30 MB.

Nếu bạn có một khối trong một lớp không được lấp đầy hoàn toàn một cách tự nhiên bởi các giá trị băm của lớp trước đó, bạn nên đệm nó bằng các số 0 để đạt được 4k như mong đợi. Điều này cho phép bạn biết cây băm chưa bị xóa và thay vào đó được hoàn thành với dữ liệu trống.

Để tạo cây băm, hãy nối các giá trị băm của lớp 2 với các giá trị băm của lớp 1, các giá trị băm của lớp 3 với các giá trị băm của lớp 2, v.v. Viết tất cả những thứ này ra đĩa. Lưu ý rằng điều này không tham chiếu lớp 0 của hàm băm gốc.

Tóm lại, thuật toán chung để xây dựng cây băm như sau:

  1. Chọn một loại muối ngẫu nhiên (mã hóa thập lục phân).
  2. Giải phóng hình ảnh hệ thống của bạn thành các khối 4k.
  3. Đối với mỗi khối, lấy hàm băm SHA256 (có muối) của nó.
  4. Nối các giá trị băm này để tạo thành một cấp độ
  5. Đệm mức bằng 0 đến ranh giới khối 4k.
  6. Nối cấp độ với cây băm của bạn.
  7. Lặp lại các bước 2-6 bằng cách sử dụng cấp độ trước đó làm nguồn cho cấp độ tiếp theo cho đến khi bạn chỉ có một hàm băm duy nhất.

Kết quả của việc này là một hàm băm duy nhất, là hàm băm gốc của bạn. Điều này và muối của bạn được sử dụng trong quá trình xây dựng bảng ánh xạ dm-verity của bạn.

Xây dựng bảng ánh xạ dm-verity

Xây dựng bảng ánh xạ dm-verity, bảng này xác định thiết bị khối (hoặc đích) cho nhân và vị trí của cây băm (có cùng giá trị). Ánh xạ này được sử dụng để tạo và khởi động fstab . Bảng cũng xác định kích thước của các khối và hash_start, vị trí bắt đầu của cây băm (cụ thể là số khối của nó từ đầu hình ảnh).

Xem cryptsetup để biết mô tả chi tiết về các trường bảng ánh xạ mục tiêu xác thực.

Ký tên vào bảng dm-verity

Ký bảng dm-verity để tạo chữ ký bảng. Khi xác minh một phân vùng, chữ ký bảng được xác thực trước. Điều này được thực hiện đối với một phím trên hình ảnh khởi động của bạn ở một vị trí cố định. Các khóa thường được bao gồm trong hệ thống xây dựng của nhà sản xuất để tự động đưa vào thiết bị ở một vị trí cố định.

Để xác minh phân vùng bằng chữ ký và tổ hợp phím này:

  1. Thêm khóa RSA-2048 ở định dạng tương thích với libmincrypt vào phân vùng /boot tại /verity_key . Xác định vị trí của khóa được sử dụng để xác minh cây băm.
  2. Trong fstab cho mục nhập có liên quan, hãy thêm verify vào các cờ fs_mgr .

Kết hợp chữ ký bảng vào siêu dữ liệu

Kết hợp chữ ký bảng và bảng dm-verity thành siêu dữ liệu xác thực. Toàn bộ khối siêu dữ liệu được tạo phiên bản để nó có thể được mở rộng, chẳng hạn như thêm loại chữ ký thứ hai hoặc thay đổi một số thứ tự.

Để kiểm tra tính chính xác, một số ma thuật được liên kết với mỗi bộ siêu dữ liệu bảng giúp xác định bảng. Vì độ dài được bao gồm trong tiêu đề hình ảnh hệ thống ext4, điều này cung cấp một cách để tìm kiếm siêu dữ liệu mà không cần biết chính nội dung của dữ liệu.

Điều này đảm bảo rằng bạn đã không chọn xác minh một phân vùng chưa được xác minh. Nếu vậy, việc không có số ma thuật này sẽ tạm dừng quá trình xác minh. Con số này giống như:
0xb001b001

Các giá trị byte trong hex là:

  • byte đầu tiên = b0
  • byte thứ hai = 01
  • byte thứ ba = b0
  • byte thứ tư = 01

Sơ đồ sau đây mô tả phân tích siêu dữ liệu xác thực:

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

Và bảng này mô tả các trường siêu dữ liệu đó.

Bảng 1. Các trường siêu dữ liệu xác thực

Cánh đồng Mục đích Kích cỡ Giá trị
con số kỳ diệu được sử dụng bởi fs_mgr để kiểm tra độ tỉnh táo 4 byte 0xb001b001
phiên bản được sử dụng để phiên bản khối siêu dữ liệu 4 byte hiện tại 0
chữ ký chữ ký của bảng ở dạng đệm PKCS1.5 256 byte
chiều dài bàn độ dài của bảng dm-verity tính bằng byte 4 byte
bàn bảng dm-verity được mô tả trước đó byte chiều dài bảng
đệm cấu trúc này có độ dài từ 0 đến 32k 0

Tối ưu hóa dm-verity

Để có được hiệu suất tốt nhất từ ​​dm-verity, bạn nên:

  • Trong kernel, bật NEON SHA-2 cho ARMv7 và phần mở rộng SHA-2 cho ARMv8.
  • Thử nghiệm với các cài đặt đọc trước và tìm nạp trước khác nhau để tìm ra cấu hình tốt nhất cho thiết bị của bạn.