กำลังดำเนินการ dm-verity

Android 4.4 และสูงกว่ารองรับ Verified Boot ผ่านคุณลักษณะเคอร์เนลอุปกรณ์ mapper-verity (dm-verity) ที่เป็นตัวเลือก ซึ่งให้การตรวจสอบความสมบูรณ์ของอุปกรณ์บล็อกอย่างโปร่งใส dm-verity ช่วยป้องกันรูทคิทถาวรที่สามารถยึดสิทธิ์รูทและอุปกรณ์ที่บุกรุกได้ คุณลักษณะนี้ช่วยให้ผู้ใช้ Android มั่นใจได้ว่าเมื่อบูตอุปกรณ์ อุปกรณ์จะอยู่ในสถานะเดียวกับที่ใช้ล่าสุด

แอปพลิเคชันที่อาจเป็นอันตราย (PHA) ที่มีสิทธิ์รูทสามารถซ่อนจากโปรแกรมตรวจจับและปิดบังตัวเองได้ ซอฟต์แวร์การรูทสามารถทำได้เพราะมักจะได้รับสิทธิพิเศษมากกว่าตัวตรวจจับ ทำให้ซอฟต์แวร์สามารถ "โกหก" กับโปรแกรมตรวจจับได้

คุณสมบัติ dm-verity ช่วยให้คุณดูอุปกรณ์บล็อก ซึ่งเป็นเลเยอร์พื้นที่เก็บข้อมูลพื้นฐานของระบบไฟล์ และพิจารณาว่าอุปกรณ์นั้นตรงกับการกำหนดค่าที่คาดไว้หรือไม่ ทำสิ่งนี้โดยใช้แผนผังแฮชเข้ารหัส สำหรับทุกบล็อก (โดยทั่วไปคือ 4k) จะมีแฮช SHA256

เนื่องจากค่าแฮชถูกจัดเก็บไว้ในทรีของเพจ เฉพาะแฮช "รูท" ระดับบนสุดเท่านั้นที่ต้องเชื่อถือได้ในการตรวจสอบส่วนที่เหลือของทรี ความสามารถในการแก้ไขบล็อกใด ๆ จะเทียบเท่ากับการทำลายแฮชการเข้ารหัส ดูไดอะแกรมต่อไปนี้เพื่ออธิบายโครงสร้างนี้

dm-verity-แฮชตาราง

รูปที่ 1 ตารางแฮช dm-verity

คีย์สาธารณะรวมอยู่ในพาร์ติชันสำหรับเริ่มระบบ ซึ่งผู้ผลิตอุปกรณ์จะต้องตรวจสอบจากภายนอก คีย์นั้นใช้เพื่อตรวจสอบลายเซ็นสำหรับแฮชนั้น และยืนยันว่าพาร์ติชันระบบของอุปกรณ์ได้รับการปกป้องและไม่มีการเปลี่ยนแปลง

การดำเนินการ

การป้องกัน dm-verity อยู่ในเคอร์เนล ดังนั้นหากการรูทซอฟต์แวร์ทำให้ระบบเสียหายก่อนที่เคอร์เนลจะเกิดขึ้น ซอฟต์แวร์จะรักษาการเข้าถึงนั้นไว้ เพื่อลดความเสี่ยงนี้ ผู้ผลิตส่วนใหญ่จะตรวจสอบเคอร์เนลโดยใช้คีย์ที่เขียนลงในอุปกรณ์ คีย์นั้นไม่สามารถเปลี่ยนแปลงได้เมื่ออุปกรณ์ออกจากโรงงาน

ผู้ผลิตใช้คีย์นั้นเพื่อตรวจสอบลายเซ็นบน bootloader ระดับแรก ซึ่งจะยืนยันลายเซ็นในระดับต่อๆ ไป แอปพลิเคชัน bootloader และเคอร์เนลในที่สุด ผู้ผลิตแต่ละรายที่ต้องการใช้ประโยชน์จาก การบู๊ตที่ผ่านการตรวจสอบแล้ว ควรมีวิธีการตรวจสอบความสมบูรณ์ของเคอร์เนล สมมติว่าเคอร์เนลได้รับการตรวจสอบแล้ว เคอร์เนลสามารถดูอุปกรณ์บล็อกและตรวจสอบได้ในขณะที่ติดตั้ง

วิธีหนึ่งในการตรวจสอบอุปกรณ์บล็อกคือการแฮชเนื้อหาโดยตรงและเปรียบเทียบกับค่าที่เก็บไว้ อย่างไรก็ตาม การพยายามตรวจสอบอุปกรณ์บล็อกทั้งหมดอาจใช้เวลานานขึ้นและใช้พลังงานของอุปกรณ์มาก อุปกรณ์จะใช้เวลานานในการบู๊ตและจากนั้นจะสิ้นเปลืองพลังงานอย่างมากก่อนใช้งาน

แต่ dm-verity จะตรวจสอบบล็อกทีละบล็อกและเฉพาะเมื่อมีการเข้าถึงแต่ละบล็อกเท่านั้น เมื่ออ่านในหน่วยความจำ บล็อกจะถูกแฮชแบบขนาน จากนั้นแฮชจะถูกตรวจสอบขึ้นไปบนต้นไม้ และเนื่องจากการอ่านบล็อกเป็นการดำเนินการที่มีราคาแพง ดังนั้นเวลาแฝงที่นำมาใช้โดยการตรวจสอบระดับบล็อกนี้จึงค่อนข้างน้อย

หากการตรวจสอบล้มเหลว อุปกรณ์จะสร้างข้อผิดพลาด I/O ซึ่งระบุว่าบล็อกไม่สามารถอ่านได้ ดูเหมือนว่าระบบไฟล์จะเสียหายตามที่คาดไว้

แอปพลิเคชันอาจเลือกที่จะดำเนินการต่อโดยไม่มีข้อมูลผลลัพธ์ เช่น เมื่อผลลัพธ์เหล่านั้นไม่จำเป็นสำหรับฟังก์ชันหลักของแอปพลิเคชัน อย่างไรก็ตาม หากแอปพลิเคชันไม่สามารถดำเนินการต่อได้หากไม่มีข้อมูล ก็จะล้มเหลว

ส่งต่อการแก้ไขข้อผิดพลาด

Android 7.0 และสูงกว่าปรับปรุงความทนทานของ dm-verity ด้วยการแก้ไขข้อผิดพลาดไปข้างหน้า (FEC) การใช้งาน AOSP เริ่มต้นด้วยรหัสแก้ไขข้อผิดพลาดทั่วไป ของ Reed-Solomon และใช้เทคนิคที่เรียกว่าการแทรกสลับเพื่อลดพื้นที่ว่างและเพิ่มจำนวนบล็อกที่เสียหายซึ่งสามารถกู้คืนได้ สำหรับรายละเอียดเพิ่มเติมเกี่ยวกับ FEC โปรดดู Strictly Verified Boot with Error Correction

การดำเนินการ

สรุป

  1. สร้างอิมเมจระบบ ext4
  2. สร้างแผนผังแฮช สำหรับรูปภาพนั้น
  3. สร้างตาราง dm-verity สำหรับแผนผังแฮชนั้น
  4. เซ็นชื่อตาราง dm-verity เพื่อสร้างลายเซ็นตาราง
  5. รวมลายเซ็นของตาราง และตาราง dm-verity ไว้ในข้อมูลเมตาของ verity
  6. เชื่อมต่ออิมเมจระบบ ข้อมูลเมตาของความจริง และแผนผังแฮช

ดูThe Chromium Projects - Verified Boot สำหรับคำอธิบายโดยละเอียดของแผนผังแฮชและตาราง dm-verity

การสร้างต้นไม้แฮช

ดังที่อธิบายไว้ในบทนำ ต้นไม้แฮชเป็นองค์ประกอบสำคัญของ dm-verity เครื่องมือ cryptsetup จะสร้างแผนผังแฮชให้คุณ อีกวิธีหนึ่งคือกำหนดที่เข้ากันได้ที่นี่:

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

ในการสร้างแฮช อิมเมจระบบจะถูกแบ่งที่เลเยอร์ 0 เป็น 4k บล็อก แต่ละอันกำหนดแฮช SHA256 เลเยอร์ 1 เกิดจากการรวมแฮช SHA256 เหล่านั้นเป็นบล็อก 4k เท่านั้น ส่งผลให้รูปภาพมีขนาดเล็กลงมาก เลเยอร์ 2 ถูกสร้างขึ้นเหมือนกันโดยมีแฮช SHA256 ของเลเยอร์ 1

สิ่งนี้ทำจนกว่าแฮช SHA256 ของเลเยอร์ก่อนหน้าจะพอดีกับบล็อกเดียว เมื่อได้รับ SHA256 ของบล็อกนั้น คุณก็จะได้รูทแฮชของต้นไม้

ขนาดของแผนผังแฮช (และการใช้พื้นที่ดิสก์ที่เกี่ยวข้อง) จะแตกต่างกันไปตามขนาดของพาร์ติชันที่ตรวจสอบแล้ว ในทางปฏิบัติ ขนาดของ hash tree มักจะมีขนาดเล็ก โดยมักจะน้อยกว่า 30 MB

หากคุณมีบล็อกในเลเยอร์ที่ไม่ได้ถูกเติมเต็มตามธรรมชาติด้วยแฮชของเลเยอร์ก่อนหน้า คุณควรรองบล็อกด้วยเลขศูนย์เพื่อให้ได้ 4k ที่คาดไว้ ซึ่งช่วยให้คุณทราบได้ว่าต้นไม้แฮชไม่ได้ถูกลบออก และเติมข้อมูลเปล่าแทน

ในการสร้างแผนผังแฮช ให้เชื่อมแฮชเลเยอร์ 2 เข้ากับแฮชสำหรับเลเยอร์ 1 เชื่อมแฮชเลเยอร์ 3 เข้ากับแฮชของเลเยอร์ 2 และอื่น ๆ เขียนทั้งหมดนี้ลงดิสก์ โปรดทราบว่าสิ่งนี้ไม่ได้อ้างอิงเลเยอร์ 0 ของรูทแฮช

สรุป อัลกอริทึมทั่วไปในการสร้างแผนผังแฮชมีดังนี้:

  1. เลือกเกลือแบบสุ่ม (การเข้ารหัสเลขฐานสิบหก)
  2. แยกอิมเมจระบบของคุณออกเป็นบล็อก 4k
  3. สำหรับแต่ละบล็อก รับแฮช SHA256 (เค็ม)
  4. เชื่อมต่อแฮชเหล่านี้เพื่อสร้างระดับ
  5. เลื่อนระดับด้วย 0 ถึงขอบเขตบล็อก 4k
  6. เชื่อมต่อระดับกับแผนผังแฮชของคุณ
  7. ทำซ้ำขั้นตอนที่ 2-6 โดยใช้ระดับก่อนหน้าเป็นแหล่งที่มาสำหรับถัดไปจนกว่าคุณจะมีแฮชเดียว

ผลลัพธ์คือแฮชเดียวซึ่งเป็นรูทแฮชของคุณ สิ่งนี้และเกลือของคุณถูกใช้ระหว่างการสร้างตารางการแมป dm-verity

สร้างตารางการแมป dm-verity

สร้างตารางการแมป dm-verity ซึ่งระบุอุปกรณ์บล็อก (หรือเป้าหมาย) สำหรับเคอร์เนลและตำแหน่งของแผนผังแฮช (ซึ่งเป็นค่าเดียวกัน) การแมปนี้ใช้สำหรับการสร้างและการบูท fstab ตารางยังระบุขนาดของบล็อกและ hash_start ซึ่งเป็นตำแหน่งเริ่มต้นของแผนผังแฮช (โดยเฉพาะอย่างยิ่ง หมายเลขบล็อกจากจุดเริ่มต้นของรูปภาพ)

ดู cryptsetup สำหรับคำอธิบายโดยละเอียดของช่องตารางการแมปเป้าหมาย verity

การลงนามในตาราง dm-verity

ลงนามในตาราง dm-verity เพื่อสร้างลายเซ็นตาราง เมื่อตรวจสอบพาร์ติชัน ลายเซ็นตารางจะได้รับการตรวจสอบก่อน สิ่งนี้ทำกับคีย์บนอิมเมจสำหรับบูตของคุณในตำแหน่งที่แน่นอน โดยทั่วไปแล้วคีย์จะรวมอยู่ในระบบการสร้างของผู้ผลิตสำหรับการรวมโดยอัตโนมัติบนอุปกรณ์ในตำแหน่งคงที่

ในการตรวจสอบพาร์ติชันด้วยลายเซ็นและคีย์ผสมนี้:

  1. เพิ่มคีย์ RSA-2048 ในรูปแบบที่เข้ากันได้กับ libmincrypt ไปยังพาร์ติชัน /boot ที่ /verity_key ระบุตำแหน่งของคีย์ที่ใช้ในการตรวจสอบแผนผังแฮช
  2. ใน fstab สำหรับรายการที่เกี่ยวข้อง ให้เพิ่ม verify ไปยังแฟล็ก fs_mgr

การรวมลายเซ็นตารางเข้ากับข้อมูลเมตา

รวมลายเซ็นของตารางและตาราง dm-verity ไว้ในข้อมูลเมตาของ verity ข้อมูลเมตาทั้งบล็อกได้รับการกำหนดเวอร์ชัน ดังนั้นอาจมีการขยาย เช่น เพิ่มลายเซ็นประเภทที่สองหรือเปลี่ยนลำดับบางอย่าง

ในการตรวจสอบสุขภาพจิต หมายเลขอาคมจะเชื่อมโยงกับชุดข้อมูลเมตาของตารางแต่ละชุดที่ช่วยระบุตาราง เนื่องจากความยาวจะรวมอยู่ในส่วนหัวของอิมเมจระบบ ext4 วิธีนี้จึงเป็นวิธีการค้นหาข้อมูลเมตาโดยไม่ต้องรู้เนื้อหาของข้อมูล

สิ่งนี้ทำให้แน่ใจว่าคุณไม่ได้เลือกที่จะตรวจสอบพาร์ติชันที่ไม่ได้รับการยืนยัน ถ้าเป็นเช่นนั้น การไม่มีหมายเลขวิเศษนี้จะหยุดกระบวนการตรวจสอบ หมายเลขนี้คล้ายกับ:
0xb001b001

ค่าไบต์เป็นเลขฐานสิบหกคือ:

  • ไบต์แรก = b0
  • ไบต์ที่สอง = 01
  • ไบต์ที่สาม = b0
  • ไบต์ที่สี่ = 01

ไดอะแกรมต่อไปนี้แสดงรายละเอียดของข้อมูลเมตาของความจริง:

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

และตารางนี้อธิบายเขตข้อมูลเมตาเหล่านั้น

ตารางที่ 1. ฟิลด์ข้อมูลเมตาของ Verity

สนาม วัตถุประสงค์ ขนาด ค่า
หมายเลขมายากล ใช้โดย fs_mgr เป็นการตรวจสุขภาพ 4 ไบต์ 0xb001b001
รุ่น ใช้เพื่อกำหนดเวอร์ชันของบล็อกข้อมูลเมตา 4 ไบต์ ปัจจุบัน 0
ลายเซ็น ลายเซ็นของตารางในรูปแบบเบาะ PKCS1.5 256 ไบต์
ความยาวของโต๊ะ ความยาวของตาราง dm-verity หน่วยเป็นไบต์ 4 ไบต์
โต๊ะ ตาราง dm-verity ที่อธิบายไว้ก่อนหน้านี้ ไบต์ความยาวตาราง
การขยายความ โครงสร้างนี้มีความยาว 0 ถึง 32k 0

การเพิ่มประสิทธิภาพ dm-verity

เพื่อให้ได้ประสิทธิภาพที่ดีที่สุดจาก dm-verity คุณควร:

  • ในเคอร์เนล ให้เปิด NEON SHA-2 สำหรับ ARMv7 และส่วนขยาย SHA-2 สำหรับ ARMv8
  • ทดลองกับการตั้งค่าแบบอ่านล่วงหน้าและ prefetch_cluster ต่างๆ เพื่อค้นหาการกำหนดค่าที่ดีที่สุดสำหรับอุปกรณ์ของคุณ