Android มีการใช้งานอ้างอิงสำหรับคอมโพเนนต์ทั้งหมดที่จำเป็นในการใช้งานเฟรมเวิร์กการจำลองการทำงานแบบเสมือนของ Android ปัจจุบันการใช้งานนี้จำกัดไว้ที่ ARM64 หน้านี้จะอธิบายถึงสถาปัตยกรรมเฟรมเวิร์ก
ฉากหลัง
สถาปัตยกรรม Arm อนุญาตให้มีระดับข้อยกเว้นได้สูงสุด 4 ระดับ โดยระดับข้อยกเว้น 0 (EL0) มีสิทธิ์น้อยที่สุด และระดับข้อยกเว้น 3 (EL3) มีสิทธิ์มากที่สุด ส่วนที่มีขนาดใหญ่ที่สุดของ Codebase ของ Android (คอมโพเนนต์พื้นที่ผู้ใช้ทั้งหมด) จะทำงานที่ EL0 ส่วนที่เหลือของสิ่งที่โดยทั่วไปเรียกว่า "Android" คือเคอร์เนลของ Linux ซึ่งทำงานที่ EL1
เลเยอร์ EL2 ช่วยให้สามารถนํา Hypervisor มาใช้แยกหน่วยความจําและอุปกรณ์ออกเป็น pVM แต่ละรายการที่ EL1/EL0 พร้อมการรับประกันความลับและความสมบูรณ์ที่เข้มงวด
ไฮเปอร์ไวเซอร์
เครื่องเสมือนที่ใช้เคอร์เนลที่ได้รับการปกป้อง (pKVM) สร้างขึ้นจากไฮเปอร์วิซอร์ KVM ของ Linux ซึ่งได้รับการขยายความสามารถให้จำกัดการเข้าถึงเพย์โหลดที่ทำงานอยู่ในเครื่องเสมือนที่ติดตั้งใช้งานซึ่งทําเครื่องหมายว่า "ได้รับการปกป้อง" ณ เวลาที่สร้างขึ้น
KVM/arm64 รองรับโหมดการดําเนินการที่แตกต่างกัน ทั้งนี้ขึ้นอยู่กับความพร้อมใช้งานของฟีเจอร์บางอย่างของ CPU เช่น Virtualization Host Extensions (VHE) (ARMv8.1 ขึ้นไป) ในโหมดใดโหมดหนึ่ง หรือที่รู้จักกันโดยทั่วไปว่าโหมดที่ไม่ใช่ VHE รหัส Hypervisor จะแยกออกจากอิมเมจเคอร์เนลระหว่างการเปิดเครื่องและติดตั้งที่ EL2 ในขณะที่เคอร์เนลเองจะทำงานที่ EL1 แม้ว่าจะเป็นส่วนหนึ่งของโค้ดเบส Linux แต่คอมโพเนนต์ EL2 ของ KVM เป็นคอมโพเนนต์ขนาดเล็กที่รับผิดชอบการสลับระหว่าง EL1 หลายรายการ คอมโพเนนต์ไฮเปอร์วิซอร์จะคอมไพล์ด้วย Linux แต่อยู่ในส่วนหน่วยความจำเฉพาะแยกต่างหากของvmlinux
ไฟล์ภาพ pKVM ใช้ประโยชน์จากการออกแบบนี้โดยการขยายโค้ดไฮเปอร์วิซอร์ด้วยฟีเจอร์ใหม่ๆ ซึ่งช่วยให้สามารถจำกัดเคอร์เนลโฮสต์ Android และพื้นที่ผู้ใช้ รวมถึงจำกัดการเข้าถึงหน่วยความจำของผู้ใช้และไฮเปอร์วิซอร์ของโฮสต์
โมดูลผู้ให้บริการ pKVM
โมดูลผู้ให้บริการ pKVM คือโมดูลเฉพาะฮาร์ดแวร์ที่มีฟังก์ชันเฉพาะอุปกรณ์ เช่น โปรแกรมควบคุมหน่วยจัดการหน่วยความจำอินพุต-เอาต์พุต (IOMMU) โมดูลเหล่านี้ช่วยให้คุณพอร์ตฟีเจอร์ด้านความปลอดภัยที่ต้องใช้สิทธิ์เข้าถึงระดับ 2 (EL2) ไปยัง pKVM ได้
ดูวิธีติดตั้งใช้งานและโหลดโมดูลผู้ให้บริการ pKVM ได้ที่หัวข้อติดตั้งใช้งานโมดูลผู้ให้บริการ pKVM
ขั้นตอนการเปิดเครื่อง
รูปต่อไปนี้แสดงขั้นตอนการเปิดเครื่อง pKVM
- บูตโหลดเดอร์จะเข้าสู่เคอร์เนลทั่วไปที่ EL2
- เคอร์เนลทั่วไปจะตรวจพบว่ากำลังทำงานที่ EL2 และยกเลิกสิทธิ์ตัวเองเป็น EL1 ขณะที่ pKVM และโมดูลต่างๆ ยังคงทำงานที่ EL2 นอกจากนี้ ระบบจะโหลดโมดูลของผู้ให้บริการ pKVM ในขณะนี้ด้วย
- เคอร์เนลทั่วไปจะบูตตามปกติ โหลดไดรเวอร์อุปกรณ์ที่จำเป็นทั้งหมดจนกว่าจะถึงพื้นที่ผู้ใช้ ณ จุดนี้ pKVM พร้อมใช้งานแล้ว และจะจัดการตารางหน้าระยะที่ 2
กระบวนการบูตจะเชื่อถือ Bootloader เพื่อรักษาความสมบูรณ์ของภาพเคอร์เนลในช่วงบูตตอนต้นเท่านั้น เมื่อเคอร์เนลถูกยกเลิก ไฮเปอร์ไวเซอร์ก็จะไม่เชื่อถือเคอร์เนลอีกต่อไป ซึ่งจะรับผิดชอบในการปกป้องตัวเองแม้ว่าเคอร์เนลจะถูกบุกรุกก็ตาม
การมีเคอร์เนล Android และไฮเปอร์วิซอร์ในรูปภาพไบนารีเดียวกันช่วยให้อินเทอร์เฟซการสื่อสารระหว่างทั้งสองทำงานร่วมกันได้อย่างแนบแน่น การเชื่อมโยงที่แน่นหนานี้รับประกันการอัปเดตแบบอะตอมสำหรับคอมโพเนนต์ 2 รายการ ซึ่งทำให้ไม่ต้องทำให้อินเทอร์เฟซระหว่างคอมโพเนนต์ทั้งสองมีเสถียรภาพอยู่เสมอ และมีความยืดหยุ่นอย่างมากโดยไม่ทำให้การบำรุงรักษาในระยะยาวเสียไป การเชื่อมโยงที่แน่นแฟ้นยังช่วยให้เพิ่มประสิทธิภาพได้เมื่อคอมโพเนนต์ทั้ง 2 รายการทำงานร่วมกันได้โดยไม่ส่งผลกระทบต่อการรับประกันความปลอดภัยที่ไฮเปอร์วิซอร์มอบให้
นอกจากนี้ การใช้ GKI ในระบบนิเวศ Android ยังช่วยให้สามารถติดตั้งใช้งานไฮเปอร์วิซอร์ pKVM ในอุปกรณ์ Android ในรูปแบบไบนารีเดียวกันกับเคอร์เนลได้โดยอัตโนมัติ
การป้องกันการเข้าถึงหน่วยความจำของ CPU
สถาปัตยกรรม Arm ระบุหน่วยจัดการหน่วยความจำ (MMU) ที่แบ่งออกเป็น 2 ระยะอิสระ ซึ่งทั้ง 2 ระยะสามารถใช้เพื่อใช้การเปลี่ยนที่อยู่และการควบคุมการเข้าถึงส่วนต่างๆ ของหน่วยความจำ ระยะที่ 1 MMU จะถูกควบคุมโดย EL1 และอนุญาตการแปลที่อยู่ระดับแรก Linux ใช้ MMU ระยะที่ 1 เพื่อจัดการพื้นที่ที่อยู่เสมือนที่จัดสรรให้กับแต่ละกระบวนการใน Userspace และพื้นที่ที่อยู่เสมือนของตนเอง
MMU ระยะที่ 2 ควบคุมโดย EL2 และเปิดใช้การแปลที่อยู่ครั้งที่ 2 ในที่อยู่เอาต์พุตของ MMU ระยะที่ 1 ซึ่งส่งผลให้เกิดที่อยู่จริง (PA) ไฮเปอร์วิซอร์สามารถใช้การแปลระดับ 2 เพื่อควบคุมและแปลการเข้าถึงหน่วยความจำจาก VM ทั้งหมดที่ไม่ใช่ระบบปฏิบัติการหลัก ดังที่แสดงในรูปที่ 2 เมื่อเปิดใช้การแปลทั้ง 2 ระยะ ที่อยู่เอาต์พุตของระยะที่ 1 จะเรียกว่าที่อยู่จริงระดับกลาง (IPA) หมายเหตุ: ระบบจะแปลที่อยู่เสมือน (VA) เป็น IPA แล้วจึงแปลเป็น PA
ที่ผ่านมา KVM จะทำงานโดยเปิดใช้การแปลระยะที่ 2 ขณะเรียกใช้ระบบปฏิบัติการแบบแขก และปิดใช้ระยะที่ 2 ขณะเรียกใช้เคอร์เนล Linux ของโฮสต์ สถาปัตยกรรมนี้ช่วยให้การเข้าถึงหน่วยความจำจาก MMU ระยะที่ 1 ของโฮสต์ผ่าน MMU ระยะที่ 2 ได้ จึงช่วยให้เข้าถึงหน้าหน่วยความจำของผู้มาเยือนจากโฮสต์ได้แบบไม่จำกัด ในทางกลับกัน pKVM จะเปิดใช้การป้องกันระยะที่ 2 แม้ในบริบทของโฮสต์ และกำหนดให้ไฮเปอร์วิซอร์เป็นผู้รับผิดชอบในการปกป้องหน้าหน่วยความจำของผู้ใช้แทนโฮสต์
KVM ใช้ประโยชน์จากการแปลที่อยู่ในระยะที่ 2 อย่างเต็มที่เพื่อใช้การแมป IPA/PA ที่ซับซ้อนสำหรับแขก ซึ่งสร้างภาพลวงว่าแขกมีหน่วยความจำต่อเนื่องกัน แม้ว่าจะมีการจัดสรรหน่วยความจำแบบกระจัดกระจายก็ตาม อย่างไรก็ตาม การใช้ MMU ระยะที่ 2 สำหรับโฮสต์จะจำกัดไว้ที่การควบคุมการเข้าถึงเท่านั้น ระยะที่ 2 ของโฮสต์จะได้รับการแมปข้อมูลประจำตัวเพื่อให้หน่วยความจำที่ต่อเนื่องกันในพื้นที่ IPA ของโฮสต์ต่อเนื่องกันในพื้นที่ PA สถาปัตยกรรมนี้ช่วยให้ใช้การแมปขนาดใหญ่ในตารางหน้าเว็บได้ จึงช่วยลดภาระของบัฟเฟอร์การมองข้ามการแปล (TLB) เนื่องจาก PA สามารถจัดทำดัชนีการจับคู่ข้อมูลประจำตัวได้ ระบบจึงใช้ระยะที่ 2 ของโฮสต์เพื่อติดตามการเป็นเจ้าของหน้าเว็บโดยตรงในตารางหน้าเว็บด้วย
การป้องกันการเข้าถึงหน่วยความจำโดยตรง (DMA)
ดังที่อธิบายไว้ก่อนหน้านี้ การยกเลิกการแมปหน้าเว็บของแขกจากโฮสต์ Linux ในตารางหน้าของ CPU เป็นขั้นตอนที่จำเป็นแต่ไม่เพียงพอต่อการปกป้องหน่วยความจำของแขก นอกจากนี้ pKVM ยังต้องป้องกันไม่ให้อุปกรณ์ที่รองรับ DMA ภายใต้การควบคุมของเคอร์เนลของโฮสต์เข้าถึงหน่วยความจำ และป้องกันไม่ให้โฮสต์ที่เป็นอันตรายทำการโจมตี DMA pKVM ต้องใช้ฮาร์ดแวร์หน่วยจัดการหน่วยความจำอินพุต-เอาต์พุต (IOMMU) สำหรับอุปกรณ์ทุกเครื่องที่รองรับ DMA ในระบบเพื่อป้องกันไม่ให้อุปกรณ์ดังกล่าวเข้าถึงหน่วยความจำของผู้ใช้ตามที่แสดงในรูปภาพ 3
อย่างน้อยที่สุด ฮาร์ดแวร์ IOMMU จะมีวิธีให้สิทธิ์และเพิกถอนสิทธิ์การอ่าน/เขียนสำหรับอุปกรณ์ไปยังหน่วยความจำหลักในระดับรายละเอียดหน้า อย่างไรก็ตาม ฮาร์ดแวร์ IOMMU นี้จะจํากัดการใช้อุปกรณ์ใน pVM เนื่องจากถือว่ามีการกำหนดค่าระยะที่ 2 ที่มีการแมปข้อมูลประจำตัว
เพื่อให้มีการแยกระหว่างเครื่องเสมือน ธุรกรรมหน่วยความจำที่สร้างขึ้นในนามของเอนทิตีต่างๆ จะต้องสามารถแยกแยะได้ด้วย IOMMU เพื่อให้ใช้ชุดตารางหน้าที่เหมาะสมในการแปลได้
นอกจากนี้ การลดจำนวนโค้ดเฉพาะ SoC ที่ EL2 เป็นกลยุทธ์หลักในการลดฐานการคำนวณที่เชื่อถือได้ (TCB) โดยรวมของ pKVM และขัดแย้งกับการรวมไดรเวอร์ IOMMU ในไฮเปอร์วิซอร์ เพื่อลดปัญหานี้ โฮสต์ที่ EL1 จะรับผิดชอบงานการจัดการ IOMMU เสริม เช่น การจัดการพลังงาน การจัดเตรียม และการจัดการการขัดจังหวะตามความเหมาะสม
อย่างไรก็ตาม การกำหนดให้โฮสต์ควบคุมสถานะของอุปกรณ์จะเพิ่มข้อกำหนดเพิ่มเติมในอินเทอร์เฟซการเขียนโปรแกรมของฮาร์ดแวร์ IOMMU เพื่อให้มั่นใจว่าการตรวจสอบสิทธิ์จะไม่สามารถข้ามผ่านด้วยวิธีอื่น เช่น หลังจากการรีเซ็ตอุปกรณ์
IOMMU มาตรฐานและรองรับอุปกรณ์ Arm ซึ่งมีทั้งการแยกและการกำหนดโดยตรงได้ก็คือสถาปัตยกรรม Arm System Memory Management Unit (SMMU) สถาปัตยกรรมนี้เป็นโซลูชันอ้างอิงที่แนะนำ
ความเป็นเจ้าของหน่วยความจำ
เมื่อเปิดเครื่อง จะถือว่าหน่วยความจำที่ไม่ใช่ Hypervisor ทั้งหมดเป็นของโฮสต์และไฮเปอร์ไวเซอร์จะติดตามหน่วยความจำดังกล่าว เมื่อสร้าง pVM โฮสต์จะบริจาคหน้าหน่วยความจำเพื่อให้ระบบบูตได้ และไฮเปอร์วิซอร์จะเปลี่ยนความเป็นเจ้าของหน้าเหล่านั้นจากโฮสต์ไปยัง pVM ดังนั้น ไฮเปอร์วิซอร์จึงกำหนดข้อจำกัดการควบคุมการเข้าถึงในตารางหน้าเว็บระยะที่ 2 ของโฮสต์เพื่อป้องกันไม่ให้ผู้ใช้เข้าถึงหน้าเว็บดังกล่าวอีกครั้ง ซึ่งจะรักษาความลับของผู้มาเยือน
การสื่อสารระหว่างผู้จัดการประชุมและผู้เข้าร่วมเกิดขึ้นได้ด้วยการแชร์หน่วยความจำที่มีการควบคุมระหว่างผู้เข้าร่วม ผู้มาเยือนได้รับอนุญาตให้แชร์หน้าเว็บบางส่วนกลับไปกับโฮสต์ได้โดยใช้ Hypercall ซึ่งจะสั่งให้ไฮเปอร์วิซอร์แมปหน้าเว็บเหล่านั้นใหม่ในตารางหน้าเว็บระยะที่ 2 ของโฮสต์ ในทำนองเดียวกัน การสื่อสารของโฮสต์กับ TrustZone ก็เกิดขึ้นได้ด้วยการแชร์หน่วยความจำและ/หรือการให้ยืม ซึ่งทั้งหมดนี้จะมีการตรวจสอบและควบคุมอย่างใกล้ชิดโดย pKVM โดยใช้ข้อมูลจำเพาะของเฟรมเวิร์กเฟิร์มแวร์สำหรับ Arm (FF-A)
เนื่องจากข้อกำหนดด้านหน่วยความจำของ pVM อาจเปลี่ยนแปลงได้เมื่อเวลาผ่านไป ระบบจึงมี Hypercall ไว้ให้ ซึ่งช่วยให้สามารถส่งคืนการเป็นเจ้าของหน้าเว็บที่ระบุซึ่งเป็นของ Caller กลับไปให้โฮสต์ได้ ในทางปฏิบัติ ระบบจะใช้ Hypercall นี้กับโปรโตคอลบอลลูน virtio เพื่ออนุญาตให้ VMM ขอหน่วยความจำคืนจาก pVM และเพื่อให้ pVM แจ้ง VMM เกี่ยวกับหน้าที่ปล่อย
ไฮเปอร์วิซอร์มีหน้าที่ติดตามการเป็นเจ้าของหน้าหน่วยความจำทั้งหมดในระบบ และติดตามว่ามีการแชร์หรือให้ยืมหน้าหน่วยความจำแก่บุคคลอื่นหรือไม่ การติดตามสถานะส่วนใหญ่นี้ทำโดยใช้ข้อมูลเมตาที่แนบมากับตารางหน้าระยะที่ 2 ของโฮสต์และผู้มาเยือน โดยใช้บิตที่สงวนไว้ในรายการตารางหน้า (PTE) ซึ่งสงวนไว้สําหรับการใช้งานซอฟต์แวร์ตามที่ชื่อบอกไว้
โฮสต์ต้องตรวจสอบว่าไม่ได้พยายามเข้าถึงหน้าที่ไฮเปอร์วิซอร์ทำให้เข้าถึงไม่ได้ การเข้าถึงโฮสต์ที่ไม่ถูกต้องทำให้ Hypervisor แทรกข้อยกเว้นแบบซิงโครนัสลงในโฮสต์ ซึ่งอาจส่งผลให้งาน Userspace ที่รับผิดชอบได้รับสัญญาณ SEGV หรือทำให้เคอร์เนลขัดข้อง เพื่อป้องกันไม่ให้เข้าถึงโดยไม่ตั้งใจ เคอร์เนลของโฮสต์จะกำหนดให้หน้าเว็บที่บริจาคแก่ผู้มาเยือนไม่มีสิทธิ์สลับหรือผสาน
การจัดการการขัดจังหวะและตัวจับเวลา
การขัดจังหวะเป็นส่วนสําคัญของวิธีที่ผู้ใช้แบบไม่ระบุตัวตนโต้ตอบกับอุปกรณ์และการสื่อสารระหว่าง CPU โดยที่การขัดจังหวะระหว่างโปรเซสเซอร์ (IPI) เป็นกลไกการสื่อสารหลัก รูปแบบ KVM คือการมอบสิทธิ์การจัดการการขัดจังหวะเสมือนทั้งหมดให้กับโฮสต์ใน EL1 ซึ่งจะทํางานเป็นส่วนที่ไม่น่าเชื่อถือของไฮเปอร์วิซอร์
pKVM มีการจําลอง Generic Interrupt Controller เวอร์ชัน 3 (GICv3) แบบเต็มโดยอิงตามโค้ด KVM ที่มีอยู่ ระบบจะจัดการตัวจับเวลาและ IPI โดยเป็นส่วนหนึ่งของโค้ดการจำลองที่ไม่น่าเชื่อถือนี้
การรองรับ GICv3
อินเทอร์เฟซระหว่าง EL1 กับ EL2 ต้องทำให้โฮสต์ EL1 เห็นสถานะการขัดจังหวะทั้งหมด รวมถึงสำเนารีจิสเตอร์ไฮเปอร์วิซอร์ที่เกี่ยวข้องกับการขัดจังหวะ โดยปกติระดับการเข้าถึงนี้จะทำได้โดยใช้เขตหน่วยความจำที่ใช้ร่วมกัน ซึ่งก็คือ 1 ครั้งต่อ CPU เสมือน (vCPU)
รหัสการสนับสนุนรันไทม์ของการลงทะเบียนของระบบนั้นสามารถทำให้ง่ายขึ้นเพื่อสนับสนุนเฉพาะการดักรับการลงทะเบียนที่ซอฟต์แวร์สร้างการหยุดชะงัก (SGIR) และปิดใช้งานการหยุดชะงัก ลงทะเบียน (DIR) สถาปัตยกรรมกำหนดว่าอุปกรณ์เหล่านี้จะลงทะเบียนการดักจับ EL2 เสมอ ในขณะที่กับดักอื่นๆ มีประโยชน์ในการบรรเทาข้อผิดพลาดเท่านั้น ส่วนที่เหลือจะจัดการในฮาร์ดแวร์
ในด้าน MMIO ทุกอย่างจะจำลองที่ EL1 และนำโครงสร้างพื้นฐานปัจจุบันทั้งหมดใน KVM มาใช้ซ้ำ สุดท้าย รอการรบกวน (WFI) จะส่งต่อไปยัง EL1 เสมอ เนื่องจากนี่เป็นหนึ่งในวิธีพื้นฐานที่ KVM ใช้ในการกำหนดเวลาพื้นฐาน
การรองรับตัวจับเวลา
ค่าตัวเปรียบเทียบสำหรับตัวจับเวลาเสมือนต้องแสดงต่อ EL1 ในการทํางาน WFI แต่ละครั้งเพื่อให้ EL1 สามารถแทรกการขัดจังหวะตัวจับเวลาได้ขณะที่ vCPU ถูกบล็อก ตัวจับเวลาจริงได้รับการจําลองทั้งหมด และส่งต่อกับดักลวงทั้งหมดไปยัง EL1
การจัดการ MMIO
หากต้องการสื่อสารกับเครื่องมือตรวจสอบเครื่องเสมือน (VMM) และทำการจําลอง GIC ต้องมีการส่งต่อกับดักของ MMIO กลับไปที่โฮสต์ใน EL1 เพื่อคัดแยกปัญหาเพิ่มเติม pKVMต้องใช้สิ่งต่อไปนี้
- IPA และขนาดของการเข้าถึง
- ข้อมูลในกรณีที่มีการเขียน
- Endianness ของ CPU ณ จุดที่มีการวางกับดักแฮ็ก
นอกจากนี้ กับดักที่มีรีจิสเตอร์วัตถุประสงค์ทั่วไป (GPR) เป็นแหล่งที่มา/ปลายทางจะได้รับการรีเลย์โดยใช้รีจิสเตอร์จำลองการโอนแบบนามธรรม
อินเทอร์เฟซของผู้มาเยือน
ผู้เข้าร่วมสามารถสื่อสารกับผู้เข้าร่วมที่มีการป้องกันโดยใช้ไฮเปอร์คอลและการเข้าถึงหน่วยความจำในภูมิภาคที่ดักไว้ Hypercall จะแสดงตามมาตรฐาน SMCCC โดยมีช่วงที่กำหนดไว้สำหรับการกำหนดค่าผู้ให้บริการโดย KVM Hypercall ต่อไปนี้มีความสำคัญอย่างยิ่งสำหรับผู้เข้าร่วม pKVM
ไฮเปอร์คอลทั่วไป
- PSCI มีกลไกมาตรฐานสำหรับผู้เข้าร่วมในการควบคุมวงจรการใช้งานของ vCPU ซึ่งรวมถึงการออนไลน์ การทำเป็นออฟไลน์ และการปิดระบบ
- TRNG มีกลไกมาตรฐานสำหรับผู้เข้าร่วมในการขอเอนโทรปีจาก pKVM ซึ่งส่งต่อการเรียกไปยัง EL3 กลไกนี้จะมีประโยชน์อย่างยิ่งในกรณีที่ไม่สามารถเชื่อถือโฮสต์ให้ใช้การจำลองฮาร์ดแวร์แบบสุ่ม (RNG)
ไฮเปอร์คอลของ pKVM
- การแชร์ความทรงจำกับผู้จัด ในตอนแรก โฮสต์จะเข้าถึงหน่วยความจำทั้งหมดของผู้มาเยือนไม่ได้ แต่การเข้าถึงของโฮสต์จําเป็นต่อการสื่อสารที่ใช้หน่วยความจําร่วมกันและสำหรับอุปกรณ์แบบพาราเวอร์ชวลไลเซชันซึ่งอาศัยบัฟเฟอร์ที่ใช้ร่วมกัน Hypercall สำหรับการแชร์และการเลิกแชร์หน้าเว็บกับผู้โฮสต์ช่วยให้ผู้เข้าร่วมตัดสินใจได้ว่าจะอนุญาตให้ Android ส่วนใดเข้าถึงหน่วยความจำได้บ้างโดยไม่ต้องใช้การจับมือ
- การส่งคืนหน่วยความจำไปยังโฮสต์ โดยปกติแล้ว หน่วยความจำทั้งหมดของแขกจะเป็นของแขกจนกว่าหน่วยความจำดังกล่าวจะถูกทำลาย สถานะนี้อาจไม่เพียงพอสำหรับ VM ที่มีอายุการใช้งานยาวนานซึ่งมีข้อกำหนดด้านหน่วยความจำซึ่งจะเปลี่ยนแปลงไปตามเวลา Hypercall
relinquish
ช่วยให้ผู้มาเยือนโอนการเป็นเจ้าของหน้าเว็บกลับไปยังโฮสต์ได้อย่างชัดเจนโดยไม่ต้องสิ้นสุดสถานะผู้มาเยือน - การดักรับการเข้าถึงหน่วยความจำสำหรับโฮสต์ โดยทั่วไปแล้ว หากผู้เข้าร่วม KVM เข้าถึงที่อยู่ที่ไม่ตรงกับรีจินัลหน่วยความจำที่ถูกต้อง เทรดของ vCPU จะออกจากโฮสต์ และโดยทั่วไปแล้วการเข้าถึงจะใช้สำหรับ MMIO และ VMM จะจำลองในยูสเซอร์สเปซ pKVM ต้องแสดงรายละเอียดเกี่ยวกับคำสั่งที่ทำให้เกิดข้อผิดพลาด เช่น ที่อยู่ พารามิเตอร์การลงทะเบียน และเนื้อหาที่อาจส่งกลับไปยังโฮสต์ เพื่อให้จัดการได้ง่ายขึ้น ซึ่งอาจเปิดเผยข้อมูลที่ละเอียดอ่อนจากแขกที่ได้รับการปกป้องโดยไม่ตั้งใจหากไม่คาดการณ์ไว้ pKVM จะแก้ปัญหานี้โดยถือว่าข้อผิดพลาดเหล่านี้ร้ายแรง เว้นแต่แขกจะเคยออก Hypercall เพื่อระบุว่าช่วง IPA ที่ทำให้เกิดข้อผิดพลาดเป็นช่วงที่อนุญาตให้มีการเข้าถึงเพื่อส่งกลับไปยังโฮสต์ โซลูชันนี้เรียกว่าMMIO guard
อุปกรณ์ I/O เสมือน (virtio)
Virtio เป็นมาตรฐานที่ได้รับความนิยม พกพาได้ และมีประสิทธิภาพสำหรับการใช้งานและการโต้ตอบกับอุปกรณ์แบบพาราเวอร์ชวล อุปกรณ์ส่วนใหญ่ที่แสดงต่อผู้ใช้ที่ได้รับการปกป้องจะใช้ virtio Virtio ยังรองรับการใช้งาน vsock ที่ใช้สำหรับการสื่อสารระหว่างผู้ใช้ชั่วคราวที่ได้รับการปกป้องกับส่วนที่เหลือของ Android ด้วย
โดยปกติแล้ว VMM จะติดตั้งใช้งานอุปกรณ์ Virtio ในพื้นที่ผู้ใช้ของโฮสต์ ซึ่งจะขัดจังหวะการเข้าถึงหน่วยความจำที่ถูกกักเก็บไว้จากแขกไปยังอินเทอร์เฟซ MMIO ของอุปกรณ์ Virtio และจำลองลักษณะการทำงานที่คาดไว้ การเข้าถึง MMIO ค่อนข้างมีค่าใช้จ่ายสูงเนื่องจากการเข้าถึงอุปกรณ์แต่ละครั้งต้องส่งข้อมูลไป-กลับไปยัง VMM และกลับ ดังนั้นการโอนข้อมูลจริงส่วนใหญ่ระหว่างอุปกรณ์กับแขกจะเกิดขึ้นโดยใช้ชุด virtqueue ในหน่วยความจำ สมมติฐานหลักของ VMWare Virtio คือโฮสต์สามารถเข้าถึงหน่วยความจำของผู้มาเยือนได้ตามต้องการ สมมติฐานนี้เห็นได้ชัดในการออกแบบ virtqueue ซึ่งอาจมีตัวชี้ไปยังบัฟเฟอร์ในระบบปฏิบัติการที่จำลองอุปกรณ์มีไว้เพื่อเข้าถึงโดยตรง
แม้ว่าอาจมีการใช้ Hypercall การแชร์หน่วยความจำที่อธิบายก่อนหน้านี้เพื่อแชร์บัฟเฟอร์ข้อมูล Virtio จากผู้มาเยือนไปยังโฮสต์ แต่การแชร์นี้ต้องดำเนินการที่ความละเอียดของหน้าเว็บและอาจแสดงข้อมูลมากกว่าที่กำหนดหากขนาดบัฟเฟอร์น้อยกว่าของหน้าเว็บ แต่ระบบจะกำหนดค่าให้แขกจัดสรรทั้งคิวเสมือนและบัฟเฟอร์ข้อมูลที่เกี่ยวข้องจากกรอบเวลาคงที่ของหน่วยความจำที่ใช้ร่วมกัน โดยระบบจะคัดลอกข้อมูล (ส่งต่อ) ไปยังและจากกรอบเวลาตามที่จำเป็น
การโต้ตอบกับ TrustZone
แม้ว่าผู้เข้าร่วมจะโต้ตอบกับ TrustZone โดยตรงไม่ได้ แต่ผู้จัดต้องยังคงออกการเรียก SMC ไปยังโลกที่ปลอดภัยได้ การเรียกเหล่านี้สามารถระบุบัฟเฟอร์หน่วยความจำที่ระบุที่อยู่จริงซึ่งโฮสต์เข้าถึงไม่ได้ เนื่องจากโดยทั่วไปซอฟต์แวร์ที่ปลอดภัยจะไม่ทราบว่าบัฟเฟอร์เข้าถึงได้ โฮสต์ที่เป็นอันตรายจึงอาจใช้บัฟเฟอร์นี้เพื่อทำการโจมตีด้วยการเปลี่ยนเส้นทางข้อมูล (คล้ายกับการโจมตี DMA) pKVM จะป้องกันไม่ให้มีการโจมตีดังกล่าวด้วยการดักจับ SMC ทั้งหมดของโฮสต์ที่เรียกใช้ EL2 และทำหน้าที่เป็นพร็อกซีระหว่างโฮสต์กับจอภาพที่มีความปลอดภัยที่ EL3
การเรียก PSCI จากโฮสต์จะส่งต่อไปยังเฟิร์มแวร์ EL3 โดยมีการแก้ไขเพียงเล็กน้อย กล่าวโดยละเอียดคือ ระบบจะเขียนจุดแรกเข้าของ CPU ที่ออนไลน์หรือกลับมาทำงานต่อหลังจากหยุดชั่วคราวใหม่เพื่อให้ติดตั้งตารางหน้าระยะที่ 2 ที่ EL2 ก่อนที่จะกลับไปที่โฮสต์ที่ EL1 ในระหว่างการบูท pKVM จะบังคับใช้การป้องกันนี้
สถาปัตยกรรมนี้อาศัย SoC ที่รองรับ PSCI โดยควรใช้ TF-A เวอร์ชันล่าสุดเป็นเฟิร์มแวร์ EL3
เฟรมเวิร์กเฟิร์มแวร์สำหรับ Arm (FF-A) กำหนดมาตรฐานการโต้ตอบระหว่างโลกปกติและโลกที่ปลอดภัย โดยเฉพาะอย่างยิ่งเมื่อมีไฮเปอร์วิซอร์ที่ปลอดภัย ส่วนสําคัญของข้อกําหนดจะกําหนดกลไกการแชร์หน่วยความจํากับโลกที่ปลอดภัย โดยใช้ทั้งรูปแบบข้อความทั่วไปและรูปแบบสิทธิ์ที่กําหนดไว้อย่างชัดเจนสําหรับหน้าเว็บที่เกี่ยวข้อง pKVM จะทำหน้าที่เป็นพร็อกซีสำหรับข้อความ FF-A เพื่อให้แน่ใจว่าโฮสต์ไม่ได้พยายามแชร์หน่วยความจํากับฝั่งที่ปลอดภัยซึ่งไม่มีสิทธิ์เพียงพอ
สถาปัตยกรรมนี้อาศัยซอฟต์แวร์โลกที่ปลอดภัยซึ่งบังคับใช้โมเดลการเข้าถึงหน่วยความจำเพื่อดูแลให้แอปที่เชื่อถือได้และซอฟต์แวร์อื่นๆ ที่ทำงานในโลกที่ปลอดภัยเข้าถึงหน่วยความจำได้ต่อเมื่อเจ้าของอย่างปลอดภัยเป็นเอกสิทธิ์ของโลกที่ปลอดภัยหรือมีการแชร์กับแอปดังกล่าวอย่างชัดเจนโดยใช้ FF-A ในระบบที่มี S-EL2 การบังคับใช้รูปแบบการเข้าถึงหน่วยความจำควรทำโดย Secure Partition Manager Core (SPMC) เช่น Hafnium ซึ่งดูแลตารางหน้าระยะที่ 2 สำหรับโลกที่ปลอดภัย ในระบบที่ไม่มี S-EL2 TEE สามารถบังคับใช้รูปแบบการเข้าถึงหน่วยความจำผ่านตารางหน้าระยะที่ 1 แทน
หากการเรียก SMC ไปยัง EL2 ไม่ใช่การเรียก PSCI หรือข้อความที่กำหนดไว้ FF-A ระบบจะส่งต่อ SMC ที่ไม่มีการจัดการไปยัง EL3 สมมติฐานคือเฟิร์มแวร์ที่ปลอดภัย (ต้องเชื่อถือได้) สามารถจัดการ SMC ที่ไม่ได้รับการจัดการได้อย่างปลอดภัย เนื่องจากเฟิร์มแวร์เข้าใจถึงข้อควรระวังที่จำเป็นในการรักษาการแยก pVM
เครื่องมือตรวจสอบเครื่องเสมือน
crosvm คือเครื่องมือตรวจสอบเครื่องเสมือน (VMM) ซึ่งเรียกใช้เครื่องเสมือนผ่านอินเทอร์เฟซ KVM ของ Linux สิ่งที่ทำให้ crosvm โดดเด่นคือความมุ่งเน้นด้านความปลอดภัยด้วยการใช้ภาษาโปรแกรม Rust และ Sandbox รอบๆ อุปกรณ์เสมือนเพื่อปกป้องเคอร์เนลของโฮสต์ ดูข้อมูลเพิ่มเติมเกี่ยวกับ crosvm ได้ในเอกสารประกอบอย่างเป็นทางการที่นี่
ตัวระบุไฟล์และ ioctl
KVM จะแสดงอุปกรณ์อักขระ /dev/kvm
ไปยังพื้นที่ผู้ใช้ด้วย ioctl ต่างๆ ที่ประกอบกันเป็น KVM API ซึ่งแบ่งออกเป็นหมวดหมู่ต่อไปนี้
- ioctls ของระบบและตั้งค่าแอตทริบิวต์ส่วนกลางที่มีผลต่อระบบย่อย KVM ทั้งหมดและสร้าง pVM
- ioctl ของ VM จะค้นหาและตั้งค่าแอตทริบิวต์ที่สร้าง CPU (vCPU) และอุปกรณ์เสมือน รวมถึงส่งผลต่อ pVM ทั้งหมด เช่น เลย์เอาต์หน่วยความจำ และจำนวน CPU (vCPU) และอุปกรณ์เสมือน
- ioctl ของ vCPU จะค้นหาและตั้งค่าแอตทริบิวต์ที่ควบคุมการทํางานของ CPU เสมือนตัวเดียว
- Device ioctls จะค้นหาและตั้งค่าแอตทริบิวต์ที่ควบคุมการทํางานของอุปกรณ์เสมือนเครื่องเดียว
กระบวนการ crosvm แต่ละรายการจะเรียกใช้เครื่องเสมือนเพียง 1 อินสแตนซ์เท่านั้น กระบวนการนี้ใช้ Ioctl ของระบบ KVM_CREATE_VM
เพื่อสร้างข้อบ่งชี้ไฟล์ VM ที่ใช้ออก ioctl ของ pVM ได้ ioctl KVM_CREATE_VCPU
หรือ KVM_CREATE_DEVICE
ใน FD ของ VM จะสร้าง vCPU/อุปกรณ์และแสดงผลตัวระบุไฟล์ที่ชี้ไปยังทรัพยากรใหม่ ioctl ใน vCPU หรือ FD ของอุปกรณ์สามารถใช้เพื่อควบคุมอุปกรณ์ที่สร้างขึ้นโดยใช้ ioctl ใน FD ของ VM สำหรับ vCPU การดำเนินการนี้รวมถึงงานสำคัญๆ ของการทำงานโค้ดผู้มาเยือน
ในทางภายใน crosvm จะลงทะเบียนตัวระบุไฟล์ของ VM กับเคอร์เนลโดยใช้อินเทอร์เฟซ epoll
ที่ทริกเกอร์เมื่อขอบ จากนั้นเคอร์เนลจะแจ้งให้ crosvm ทราบทุกครั้งที่มีเหตุการณ์ใหม่รอดำเนินการในตัวระบุไฟล์
pKVM เพิ่มความสามารถใหม่ KVM_CAP_ARM_PROTECTED_VM
ซึ่งสามารถใช้เพื่อรับข้อมูลเกี่ยวกับสภาพแวดล้อม pVM และตั้งค่าโหมดที่ได้รับการป้องกันสำหรับ VM ได้ crosvm จะใช้ความสามารถนี้ในระหว่างการสร้าง pVM หากมีการส่งผ่าน Flag --protected-vm
เพื่อค้นหาและจองหน่วยความจำในปริมาณที่เหมาะสมสำหรับเฟิร์มแวร์ pVM จากนั้นจึงเปิดใช้โหมดที่ได้รับการป้องกัน
การจัดสรรหน่วยความจำ
ภาระหน้าที่หลักอย่างหนึ่งของ VMM คือการจัดสรรหน่วยความจำของ VM และจัดการเลย์เอาต์หน่วยความจำ crosvm สร้างเลย์เอาต์หน่วยความจำแบบคงที่ตามที่อธิบายไว้คร่าวๆ ในตารางด้านล่าง
FDT ในโหมดปกติ | PHYS_MEMORY_END - 0x200000
|
พื้นที่ว่าง | ...
|
แรมดิสก์ | ALIGN_UP(KERNEL_END, 0x1000000)
|
เคอร์เนล | 0x80080000
|
Bootloader | 0x80200000
|
FDT ในโหมด BIOS | 0x80000000
|
ฐานหน่วยความจำทางกายภาพ | 0x80000000
|
เฟิร์มแวร์ pVM | 0x7FE00000
|
หน่วยความจำอุปกรณ์ | 0x10000 - 0x40000000
|
ระบบจะจัดสรรหน่วยความจําจริงด้วย mmap
และบริจาคหน่วยความจําให้กับ VM เพื่อป้อนข้อมูลในภูมิภาคหน่วยความจําที่เรียกว่า memslots ด้วย ioctl KVM_SET_USER_MEMORY_REGION
ดังนั้น หน่วยความจำ pVM ของผู้เข้าร่วมทั้งหมดจะได้รับการระบุแหล่งที่มาเป็นอินสแตนซ์ crosvm ที่จัดการอินสแตนซ์ดังกล่าว และอาจส่งผลให้การประมวลผลสิ้นสุดลง (ยกเลิก VM) หากโฮสต์เริ่มใช้หน่วยความจำที่ว่างอยู่จนหมด เมื่อหยุด VM ฮไฮเปอร์วิซอร์จะล้างหน่วยความจําโดยอัตโนมัติและส่งคืนไปยังเคอร์เนลของโฮสต์
ใน KVM ปกติ VMM จะยังคงเข้าถึงหน่วยความจำทั้งหมดของผู้มาเยือนได้ เมื่อใช้ pKVM ระบบจะยกเลิกการแมปหน่วยความจำของแขกจากพื้นที่ที่อยู่จริงของโฮสต์เมื่อบริจาคหน่วยความจำให้กับแขก ข้อยกเว้นเพียงอย่างเดียวคือหน่วยความจำที่ผู้มาเยือนแชร์กลับไปอย่างชัดเจน เช่น สำหรับอุปกรณ์ Virtio
ระบบจะไม่แมปภูมิภาค MMIO ในพื้นที่ที่อยู่ของผู้มาเยือน การเข้าถึงภูมิภาคเหล่านี้โดยผู้เข้าร่วมจะถูกบล็อกไว้และส่งผลให้เกิดเหตุการณ์ I/O ใน FD ของ VM กลไกนี้ใช้เพื่อติดตั้งใช้งานอุปกรณ์เสมือน ในโหมดที่ได้รับการป้องกัน ผู้มาเยือนต้องรับทราบว่ามีการใช้พื้นที่ที่อยู่ของโฮสต์สำหรับ MMIO โดยใช้ Hypercall เพื่อลดความเสี่ยงที่ข้อมูลจะรั่วไหลโดยไม่ตั้งใจ
การตั้งเวลา
CPU เสมือนแต่ละตัวจะแสดงด้วยเธรด POSIX และกำหนดเวลาโดยตัวจัดตารางเวลา Linux ของโฮสต์ เทรดเรียก KVM_RUN
ioctl ใน FD ของ vCPU ซึ่งส่งผลให้ Hypervisor เปลี่ยนไปใช้บริบท vCPU ของแขก ตัวจัดตารางเวลาของโฮสต์จะพิจารณาเวลาที่ใช้ในบริบทของผู้ใช้ชั่วคราวเป็นเวลาที่ใช้ในการใช้เธรด vCPU ที่เกี่ยวข้อง KVM_RUN
จะแสดงผลเมื่อมีเหตุการณ์ที่ VMM ต้องจัดการ เช่น I/O, การสิ้นสุดการขัดจังหวะ หรือ vCPU หยุดทำงาน VMM จะจัดการเหตุการณ์และเรียก KVM_RUN
อีกครั้ง
ในระหว่าง KVM_RUN
เทรดยังคงถูกตัดสิทธิ์โดยตัวจัดตารางเวลาของโฮสต์ได้ ยกเว้นการเรียกใช้โค้ดไฮเปอร์วิซอร์ EL2 ซึ่งไม่สามารถตัดสิทธิ์ได้ pVM ของผู้เข้าร่วมเองไม่มีกลไกในการควบคุมพฤติกรรมนี้
เนื่องจากเธรด vCPU ทั้งหมดได้รับการกำหนดเวลาไว้เหมือนกับงานอื่นๆ ใน Userspace จึงอยู่ภายใต้กลไก QoS มาตรฐานทั้งหมด กล่าวโดยละเอียดคือ คุณสามารถปรับแต่งแต่ละเธรด vCPU ให้เหมาะกับ CPU จริง วางไว้ใน cpuset เพิ่มหรือจำกัดโดยใช้การจำกัดการใช้งาน เปลี่ยนนโยบายลําดับความสําคัญ/การจัดตารางเวลา และอื่นๆ
อุปกรณ์เสมือน
crosvm รองรับอุปกรณ์หลายรุ่น ซึ่งรวมถึงอุปกรณ์ต่อไปนี้
- virtio-blk สำหรับอิมเมจดิสก์คอมโพสิต อ่านอย่างเดียวหรืออ่านอย่างเดียว
- vhost-vsock สำหรับการสื่อสารกับโฮสต์
- virtio-pci เป็นพาหนะ virtio
- นาฬิกาเรียลไทม์ pl030 (RTC)
- 16550a UART สําหรับการสื่อสารแบบอนุกรม
เฟิร์มแวร์ pVM
เฟิร์มแวร์ pVM (pvmfw) คือโค้ดแรกที่ pVM เรียกใช้ ซึ่งคล้ายกับบูต ROM ของอุปกรณ์จริง เป้าหมายหลักของ pvmfw คือการสร้างบูตเพื่อบูตอย่างปลอดภัยและดึงข้อมูลลับที่ไม่ซ้ำกันของ pVM โดย pvmfw ไม่ได้จำกัดให้ใช้กับระบบปฏิบัติการใดระบบปฏิบัติการหนึ่งโดยเฉพาะ เช่น Microdroid ตราบใดที่ crosvm รองรับระบบปฏิบัติการนั้นและได้ลงนามอย่างถูกต้อง
ระบบจะจัดเก็บไบนารี pvmfw ไว้ในพาร์ติชันแฟลชที่มีชื่อเดียวกันและอัปเดตโดยใช้ OTA
การบูตอุปกรณ์
ระบบจะเพิ่มลำดับขั้นตอนต่อไปนี้ลงในกระบวนการบูตของอุปกรณ์ที่เปิดใช้ pKVM
- บูตโหลดเดอร์ Android (ABL) จะโหลด pvmfw จากพาร์ติชันลงในหน่วยความจำและตรวจสอบอิมเมจ
- ABL จะได้รับข้อมูลลับของ Device Identifier Composition Engine (DICE) (ตัวระบุอุปกรณ์แบบผสม (CDI) และเชนใบรับรอง DICE) จากรูทแห่งการเชื่อถือ
- ABL จะดึงข้อมูล CDI ที่จำเป็นสำหรับ pvmfw และเพิ่มลงในไฟล์ pvmfw แบบไบนารี
- ABL จะเพิ่มโหนดภูมิภาคหน่วยความจำ
linux,pkvm-guest-firmware-memory
ที่สงวนไว้ไปยัง DT ซึ่งอธิบายตำแหน่งและขนาดของไบนารี pvmfw และข้อมูลลับที่ได้มาจากขั้นตอนก่อนหน้า - ABL จะส่งการควบคุมไปยัง Linux และ Linux จะเริ่มต้น pKVM
- pKVM จะยกเลิกการแมปพื้นที่หน่วยความจำ pvmfw จากตารางหน้าระยะที่ 2 ของโฮสต์ และปกป้องพื้นที่หน่วยความจำดังกล่าวจากโฮสต์ (และผู้เข้าร่วม) ตลอดช่วงเวลาที่อุปกรณ์ทำงาน
หลังจากบูตอุปกรณ์แล้ว ระบบจะบูต Microdroid ตามขั้นตอนในส่วนลําดับการบูตของเอกสาร Microdroid
การบูต pVM
เมื่อสร้าง pVM แล้ว crosvm (หรือ VMM อื่น) จะต้องสร้าง memslot ที่ใหญ่พอเพื่อให้ Hypervisor ใส่ข้อมูลไฟล์อิมเมจ pvmfw นอกจากนี้ VMM ยังถูกจํากัดในรายการรีจิสทร์ที่กําหนดค่าเริ่มต้นได้ (x0-x14 สําหรับ vCPU หลัก และไม่มีสําหรับ vCPU รอง) รีจิสเตอร์ที่เหลือจะสงวนไว้และเป็นส่วนหนึ่งของ ABI ของไฮเปอร์วิซอร์-pvmfw
เมื่อเรียกใช้ pVM ไฮเปอร์วิซอร์จะส่งการควบคุม vCPU หลักให้กับ pvmfw ก่อน เฟิร์มแวร์คาดว่า crosvm จะต้องโหลดเคอร์เนลที่ลงชื่อ AVB ซึ่งอาจเป็น Bootloader หรือรูปภาพอื่น และ FDT ที่ไม่ได้ลงชื่อไปยังหน่วยความจำในออฟเซ็ตที่ทราบ pvmfw จะตรวจสอบลายเซ็น AVB และถ้าสำเร็จ ก็จะสร้างแผนผังอุปกรณ์ที่เชื่อถือได้จาก FDT ที่ได้รับ แล้วล้างข้อมูลลับจากเพย์โหลด และ Branch ของ Branch จะตรวจสอบลายเซ็น AVB หากขั้นตอนการตรวจสอบใดขั้นตอนหนึ่งไม่สำเร็จ เฟิร์มแวร์จะส่ง Hypercall SYSTEM_RESET
ของ PSCI
ระหว่างการบูต ข้อมูลเกี่ยวกับอินสแตนซ์ pVM จะจัดเก็บไว้ในพาร์ติชัน (อุปกรณ์ virtio-blk) และเข้ารหัสด้วยข้อมูลลับของ pvmfw เพื่อให้แน่ใจว่าหลังจากการรีบูต ระบบจะจัดสรรข้อมูลลับให้กับอินสแตนซ์ที่ถูกต้อง