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-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 liên tục có thể giữ đặc quyền 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ị, thiết bị sẽ ở trạng thái giống như khi được 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à che giấu chúng. 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 máy dò, tạo điều kiện cho phần mềm "nói dối" các chương trình phát hiện.

Tính năng dm-verity cho phép bạn xem 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ó khớ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ó hàm băm SHA256.

Vì các giá trị băm được lưu trữ trong một cây trang nên chỉ có hàm băm "gốc" cấp cao nhất phả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-bảng

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

Khóa chung được bao gồm trên 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 tồn tại trong kernel. Vì vậy, nếu phần mềm root làm tổn hại đến 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 đều xác minh kernel bằng cách sử dụng khóa được ghi vào thiết bị. Phím đó không thể thay đổi 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à kernel. Mỗi nhà sản xuất muốn tận dụng khả năng khởi động đã được xác minh phải có một phương pháp để xác minh tính toàn vẹn của kernel. Giả sử hạt nhân đã được xác minh, hạt nhân có thể nhìn vào 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ị. Thiết bị sẽ mất nhiều thời gian để khởi động và sau đó 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 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 nên độ trễ do xác minh cấp khối này tạo 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.

Ứ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 cần thiết đố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 nếu không có dữ liệu thì nó sẽ bị lỗi.

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

Android 7.0 trở lên cải thiện độ mạnh mẽ 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 bằng 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 phục hồi. Để 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 hình ảnh hệ thống ext4.
  2. Tạo cây băm cho hình ảnh đó.
  3. Xây dựng bảng dm-verity cho cây băm đó.
  4. Ký vào bảng dm-verity đó để tạo chữ ký bảng.
  5. Kết hợp chữ ký bảng và bảng dm-verity vào 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.

Xem Dự án Chrome - Khởi động đã được 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ư đã mô tả trong phần giới thiệu, cây băm là một phần không thể thiếu của 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 xác định ở đâ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 thành hàm băm, hình ảnh hệ thống được chia ở lớp 0 thành các khối 4k, 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ỉ nối các giá trị 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 với hàm băm SHA256 của Lớp 1.

Việc này được thực hiện cho đến khi giá trị băm SHA256 của lớp trước có thể vừa với một khối duy nhất. Khi lấy 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 tùy theo kích thước của phân vùng được 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 ghép 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 điều này ra đĩa. Lưu ý rằng điều này không tham chiếu đến 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 nén 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, hãy lấy hàm băm SHA256 (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. Tăng 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òn 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 hạt 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ính từ đầu hình ảnh).

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

Ký bảng dm-verity

Ký vào bảng dm-verity để tạo chữ ký bảng. Khi xác minh một phân vùng, chữ ký bảng sẽ được xác thực trước tiên. Việc này được thực hiện dựa trên một phím trên ảnh khởi động của bạn ở một vị trí cố định. 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 dành cho mục nhập có liên quan, hãy thêm verify vào 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 vào siêu dữ liệu xác thực. Toàn bộ khối siêu dữ liệu được phiên bản hóa để có thể 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 độ chính xác, một số ma thuật được liên kết với từng bộ siêu dữ liệu của 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 nên đ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 nội dung của dữ liệu.

Điều này đảm bảo rằng bạn chưa chọn xác minh phân vùng chưa được xác minh. Nếu vậy, việc thiếu con số kỳ diệu này sẽ khiến quá trình xác minh bị dừng lại. 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ả chi tiết về 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 fs_mgr sử dụng để 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
phần đệm cấu trúc này có chiều dài 0 đệm đế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_cluster khác nhau để tìm cấu hình tốt nhất cho thiết bị của bạn.