Android มีการใช้งานอ้างอิงของส่วนประกอบทั้งหมดที่จำเป็นสำหรับการนำ Android Virtualization Framework ไปใช้ ขณะนี้การใช้งานนี้ถูก จำกัด ไว้ที่ ARM64 หน้านี้อธิบายสถาปัตยกรรมเฟรมเวิร์ก
พื้นหลัง
สถาปัตยกรรม Arm อนุญาตให้มีข้อยกเว้นได้ถึงสี่ระดับ โดยมีข้อยกเว้นระดับ 0 (EL0) เป็นสิทธิพิเศษน้อยที่สุด และระดับข้อยกเว้น 3 (EL3) มากที่สุด ส่วนที่ใหญ่ที่สุดของฐานรหัส Android (ส่วนประกอบ userspace ทั้งหมด) ทำงานที่ EL0 ส่วนที่เหลือของสิ่งที่เรียกกันทั่วไปว่า "Android" คือเคอร์เนล Linux ซึ่งทำงานที่ EL1
เลเยอร์ EL2 อนุญาตให้แนะนำไฮเปอร์ไวเซอร์ที่ช่วยให้สามารถแยกหน่วยความจำและอุปกรณ์ออกเป็น pVM แต่ละตัวที่ EL1/EL0 พร้อมการรับประกันความลับและความสมบูรณ์ที่เข้มงวด
ไฮเปอร์ไวเซอร์
เครื่องเสมือนที่ใช้เคอร์เนลที่ได้รับการป้องกัน (pKVM) สร้างขึ้นจาก ไฮเปอร์ไวเซอร์ Linux KVM ซึ่งได้รับการขยายด้วยความสามารถในการจำกัดการเข้าถึงเพย์โหลดที่ทำงานอยู่ในเครื่องเสมือนของแขกที่ทำเครื่องหมายว่า 'มีการป้องกัน' ในขณะที่สร้าง
KVM/arm64 รองรับโหมดการทำงานที่แตกต่างกันขึ้นอยู่กับความพร้อมใช้งานของคุณสมบัติ CPU บางอย่าง กล่าวคือ Virtualization Host Extensions (VHE) (ARMv8.1 และใหม่กว่า) ในโหมดใดโหมดหนึ่ง ซึ่งเรียกกันทั่วไปว่าโหมดที่ไม่ใช่ VHE รหัสไฮเปอร์ไวเซอร์จะถูกแยกออกจากเคอร์เนลอิมเมจระหว่างการบู๊ตและติดตั้งที่ EL2 ในขณะที่เคอร์เนลเองก็ทำงานที่ EL1 แม้ว่าจะเป็นส่วนหนึ่งของฐานรหัส Linux แต่องค์ประกอบ EL2 ของ KVM เป็นส่วนประกอบขนาดเล็กที่รับผิดชอบการสลับระหว่าง EL1 หลายตัว และควบคุมโดยเคอร์เนลของโฮสต์ทั้งหมด คอมโพเนนต์ไฮเปอร์ไวเซอร์ถูกคอมไพล์ด้วย Linux แต่อยู่ในส่วนหน่วยความจำเฉพาะที่แยกต่างหากของอิมเมจ vmlinux
pKVM ใช้ประโยชน์จากการออกแบบนี้โดยขยายรหัสไฮเปอร์ไวเซอร์ด้วยคุณสมบัติใหม่ ทำให้สามารถกำหนดข้อจำกัดบนเคอร์เนลโฮสต์ Android และพื้นที่ผู้ใช้ และจำกัดการเข้าถึงโฮสต์ไปยังหน่วยความจำของแขกและไฮเปอร์ไวเซอร์
ขั้นตอนการบูต
ขั้นตอนการบูต pKVM แสดงไว้ในรูปที่ 1 ขั้นตอนแรกมีไว้สำหรับ bootloader เพื่อเข้าสู่เคอร์เนล Linux ที่เปิดใช้งาน pKVM ที่ EL2 ในระหว่างการบูตในช่วงต้น เคอร์เนลตรวจพบว่ากำลังทำงานที่ EL2 ซึ่งทำให้ตัวเองสูญเสียสิทธิ์ไปที่ EL1 โดยทิ้ง pKVM ไว้ จากจุดนี้ไป เคอร์เนลของ Linux จะทำการบู๊ตตามปกติ โดยจะโหลดไดรเวอร์อุปกรณ์ที่จำเป็นทั้งหมด จนกว่าจะถึงพื้นที่ของผู้ใช้ ขั้นตอนเหล่านี้เกิดขึ้นขณะอยู่ภายใต้การควบคุมของ pKVM
ขั้นตอนการบูตเชื่อถือ bootloader เพื่อรักษาความสมบูรณ์ของเคอร์เนลอิมเมจเฉพาะในระหว่างการบู๊ตในช่วงต้นเท่านั้น เมื่อเคอร์เนลหมดสิทธิ์ ไฮเปอร์ไวเซอร์จะไม่ถือว่าเคอร์เนลนั้นเชื่อถือได้อีกต่อไป ซึ่งจะมีหน้าที่ในการป้องกันตัวเองแม้ว่าเคอร์เนลจะถูกบุกรุก
การมีเคอร์เนล Android และไฮเปอร์ไวเซอร์ในอิมเมจไบนารีเดียวกันช่วยให้มีอินเทอร์เฟซการสื่อสารที่เชื่อมโยงกันอย่างแน่นแฟ้นระหว่างกัน การมีเพศสัมพันธ์อย่างแน่นหนานี้รับประกันการอัปเดตอะตอมมิกของส่วนประกอบทั้งสอง ซึ่งหลีกเลี่ยงความจำเป็นในการรักษาส่วนต่อประสานระหว่างส่วนประกอบทั้งสองอย่างเสถียร และให้ความยืดหยุ่นอย่างมากโดยไม่กระทบต่อการบำรุงรักษาในระยะยาว การมีเพศสัมพันธ์อย่างแน่นหนายังช่วยให้สามารถเพิ่มประสิทธิภาพได้เมื่อส่วนประกอบทั้งสองสามารถทำงานร่วมกันได้โดยไม่กระทบต่อการรับประกันความปลอดภัยที่จัดทำโดยไฮเปอร์ไวเซอร์
นอกจากนี้ การนำ GKI มาใช้ในระบบนิเวศของ Android ยังทำให้ไฮเปอร์ไวเซอร์ pKVM ปรับใช้กับอุปกรณ์ Android ในไบนารีเดียวกันกับเคอร์เนลได้โดยอัตโนมัติ
การป้องกันการเข้าถึงหน่วยความจำ CPU
สถาปัตยกรรม Arm ระบุหน่วยการจัดการหน่วยความจำ (MMU) ที่แยกออกเป็นสองขั้นตอนอิสระ ซึ่งทั้งสองขั้นตอนสามารถใช้เพื่อดำเนินการแปลที่อยู่และควบคุมการเข้าถึงไปยังส่วนต่างๆ ของหน่วยความจำได้ MMU ระยะที่ 1 ถูกควบคุมโดย EL1 และอนุญาตให้มีการแปลที่อยู่ระดับแรก Linux ระยะที่ 1 ถูกใช้เพื่อจัดการพื้นที่ที่อยู่เสมือนที่จัดเตรียมให้กับแต่ละกระบวนการของ userspace และไปยังพื้นที่ที่อยู่เสมือนของตัวเอง
MMU ระยะที่ 2 ถูกควบคุมโดย EL2 และเปิดใช้งานการแปลที่อยู่ที่สองบนที่อยู่เอาต์พุตของ MMU ระยะที่ 1 ส่งผลให้เกิดที่อยู่จริง (PA) ไฮเปอร์ไวเซอร์สามารถใช้การแปลระยะที่ 2 เพื่อควบคุมและแปลการเข้าถึงหน่วยความจำจาก VM ของผู้เยี่ยมชมทั้งหมด ดังแสดงในรูปที่ 2 เมื่อเปิดใช้งานการแปลทั้งสองขั้นตอน ที่อยู่เอาต์พุตของระยะที่ 1 จะเรียกว่าที่อยู่ทางกายภาพระดับกลาง (IPA) หมายเหตุ: ที่อยู่เสมือน (VA) จะถูกแปลเป็น IPA แล้วจึงเปลี่ยนเป็น PA
ในอดีต KVM ทำงานโดยเปิดใช้การแปลระยะที่ 2 ขณะเรียกใช้แขกและปิดระยะที่ 2 ขณะเรียกใช้เคอร์เนล Linux ของโฮสต์ สถาปัตยกรรมนี้อนุญาตให้เข้าถึงหน่วยความจำจากโฮสต์สเตจ 1 MMU เพื่อผ่านด่าน 2 MMU ดังนั้นจึงอนุญาตให้เข้าถึงได้ไม่จำกัดจากโฮสต์ไปยังเพจหน่วยความจำของแขก ในทางกลับกัน pKVM เปิดใช้งานการป้องกันระยะที่ 2 แม้ในบริบทของโฮสต์ และทำให้ไฮเปอร์ไวเซอร์รับผิดชอบในการปกป้องหน้าหน่วยความจำของแขกแทนโฮสต์
KVM ใช้ประโยชน์จากการแปลที่อยู่ที่ขั้นตอนที่ 2 อย่างเต็มที่เพื่อนำการแมป IPA/PA ที่ซับซ้อนสำหรับแขกมาใช้งาน ซึ่งสร้างภาพลวงตาของหน่วยความจำที่อยู่ติดกันสำหรับแขกแม้ว่าจะมีการกระจายตัวทางกายภาพ อย่างไรก็ตาม การใช้ MMU ระยะที่ 2 สำหรับโฮสต์ถูกจำกัดให้ควบคุมการเข้าถึงเท่านั้น ระยะโฮสต์ 2 ถูกแม็พข้อมูลประจำตัว เพื่อให้แน่ใจว่าหน่วยความจำที่ต่อเนื่องกันในพื้นที่ IPA ของโฮสต์นั้นต่อเนื่องกันในพื้นที่ PA สถาปัตยกรรมนี้อนุญาตให้ใช้การแมปขนาดใหญ่ในตารางเพจ และลดแรงกดดันต่อการแปลบัฟเฟอร์ lookaside buffer (TLB) เนื่องจาก PA สามารถจัดทำดัชนีการแมปข้อมูลประจำตัวได้ ระยะโฮสต์ 2 จึงใช้เพื่อติดตามความเป็นเจ้าของเพจโดยตรงในตารางเพจ
การป้องกันการเข้าถึงหน่วยความจำโดยตรง (DMA)
ตามที่อธิบายไว้ก่อนหน้านี้ การยกเลิกการแมปหน้าผู้เยี่ยมชมจากโฮสต์ Linux ในตารางหน้า CPU เป็นขั้นตอนที่จำเป็นแต่ไม่เพียงพอสำหรับการปกป้องหน่วยความจำของแขก pKVM ยังต้องป้องกันการเข้าถึงหน่วยความจำที่ทำโดยอุปกรณ์ที่รองรับ DMA ภายใต้การควบคุมของเคอร์เนลของโฮสต์ และความเป็นไปได้ของการโจมตี DMA ที่เริ่มต้นโดยโฮสต์ที่เป็นอันตราย เพื่อป้องกันไม่ให้อุปกรณ์ดังกล่าวเข้าถึงหน่วยความจำของแขก pKVM ต้องใช้ฮาร์ดแวร์ Input-Output Memory Management Unit (IOMMU) สำหรับอุปกรณ์ที่รองรับ DMA ทุกเครื่องในระบบ ดังแสดงใน รูปที่ 3
อย่างน้อยที่สุด ฮาร์ดแวร์ IOMMU ให้วิธีการอนุญาตและเพิกถอนการเข้าถึงการอ่าน/เขียนสำหรับอุปกรณ์ไปยังหน่วยความจำกายภาพตามความละเอียดของหน้า อย่างไรก็ตาม ฮาร์ดแวร์ IOMMU นี้จำกัดการใช้อุปกรณ์ใน pVM เนื่องจากถือว่ามีการระบุตัวตนในระยะที่ 2
เพื่อให้แน่ใจว่ามีการแยกระหว่างเครื่องเสมือน ธุรกรรมหน่วยความจำที่สร้างขึ้นในนามของเอนทิตีที่แตกต่างกันจะต้องสามารถแยกแยะได้โดย IOMMU เพื่อให้สามารถใช้ชุดตารางหน้าที่เหมาะสมสำหรับการแปลได้
นอกจากนี้ การลดจำนวนโค้ดเฉพาะของ SoC ที่ EL2 ยังเป็นกลยุทธ์หลักในการลด Trusted Computing Base (TCB) โดยรวมของ pKVM และทำงานตรงข้ามกับการรวมไดรเวอร์ IOMMU ไว้ในไฮเปอร์ไวเซอร์ เพื่อลดปัญหานี้ โฮสต์ที่ EL1 รับผิดชอบงานการจัดการเสริม IOMMU เช่น การจัดการพลังงาน การเริ่มต้น และการจัดการขัดจังหวะ หากเหมาะสม
อย่างไรก็ตาม การให้โฮสต์ควบคุมสถานะอุปกรณ์จะกำหนดข้อกำหนดเพิ่มเติมบนอินเทอร์เฟซการเขียนโปรแกรมของฮาร์ดแวร์ IOMMU เพื่อให้แน่ใจว่าการตรวจสอบสิทธิ์จะไม่ถูกข้ามด้วยวิธีอื่น เช่น หลังจากการรีเซ็ตอุปกรณ์
IOMMU มาตรฐานและได้รับการสนับสนุนอย่างดีสำหรับอุปกรณ์ Arm ที่ทำให้ทั้งการแยกและการกำหนดโดยตรงเป็นไปได้คือสถาปัตยกรรม Arm System Memory Management Unit (SMMU) สถาปัตยกรรมนี้เป็นโซลูชันอ้างอิงที่แนะนำ
ความเป็นเจ้าของหน่วยความจำ
ในเวลาบูต หน่วยความจำที่ไม่ใช่ไฮเปอร์ไวเซอร์ทั้งหมดจะถือว่าโฮสต์เป็นเจ้าของ และไฮเปอร์ไวเซอร์ติดตามเช่นนั้น เมื่อ pVM เกิดขึ้น โฮสต์จะบริจาคเพจหน่วยความจำเพื่อให้บูตได้ และไฮเปอร์ไวเซอร์จะเปลี่ยนความเป็นเจ้าของเพจเหล่านั้นจากโฮสต์เป็น pVM ดังนั้นไฮเปอร์ไวเซอร์จึงวางข้อจำกัดการควบคุมการเข้าถึงไว้ในตารางหน้าที่ 2 ของโฮสต์เพื่อป้องกันไม่ให้เข้าถึงเพจอีกครั้ง โดยให้การรักษาความลับแก่แขก
การสื่อสารระหว่างโฮสต์และแขกสามารถทำได้โดยการควบคุมการแชร์หน่วยความจำระหว่างกัน ผู้เข้าร่วมได้รับอนุญาตให้แชร์บางหน้ากับโฮสต์โดยใช้ไฮเปอร์คอล ซึ่งแนะนำให้ไฮเปอร์ไวเซอร์ทำการแมปหน้าเหล่านั้นใหม่ในตารางเพจโฮสต์ระยะที่ 2 ในทำนองเดียวกัน การสื่อสารของโฮสต์กับ TrustZone เกิดขึ้นได้โดยการแชร์หน่วยความจำและ/หรือการดำเนินการให้ยืม ซึ่งทั้งหมดจะได้รับการตรวจสอบและควบคุมอย่างใกล้ชิดโดย pKVM โดยใช้ข้อกำหนด Firmware Framework for Arm (FF-A)
ไฮเปอร์ไวเซอร์มีหน้าที่ติดตามความเป็นเจ้าของเพจหน่วยความจำทั้งหมดในระบบ และไม่ว่าจะแชร์หรือให้เอนทิตีอื่นๆ การติดตามสถานะนี้ส่วนใหญ่ทำได้โดยใช้ข้อมูลเมตาที่แนบมากับตารางหน้า 2 หน้าของโฮสต์และแขก โดยใช้บิตที่สงวนไว้ในรายการตารางหน้า (PTE) ซึ่งสงวนไว้สำหรับการใช้ซอฟต์แวร์ ตามชื่อที่แนะนำ
โฮสต์ต้องตรวจสอบให้แน่ใจว่าไม่ได้พยายามเข้าถึงเพจที่ไฮเปอร์ไวเซอร์ไม่สามารถเข้าถึงได้ การเข้าถึงโฮสต์ที่ผิดกฎหมายทำให้เกิดข้อยกเว้นแบบซิงโครนัสที่จะฉีดเข้าไปในโฮสต์โดยไฮเปอร์ไวเซอร์ ซึ่งอาจส่งผลให้งานพื้นที่ผู้ใช้ที่รับผิดชอบได้รับสัญญาณ SEGV หรือเคอร์เนลของโฮสต์หยุดทำงาน เพื่อป้องกันการเข้าถึงโดยไม่ได้ตั้งใจ เพจที่บริจาคให้กับแขกจะไม่มีสิทธิ์ในการสลับหรือรวมโดยเคอร์เนลของโฮสต์
การจัดการขัดจังหวะและตัวจับเวลา
การขัดจังหวะเป็นส่วนสำคัญของวิธีที่แขกโต้ตอบกับอุปกรณ์และสำหรับการสื่อสารระหว่าง CPU โดยที่การขัดจังหวะระหว่างโปรเซสเซอร์ (IPI) เป็นกลไกการสื่อสารหลัก โมเดล KVM คือการมอบหมายการจัดการอินเตอร์รัปต์เสมือนทั้งหมดให้กับโฮสต์ใน EL1 ซึ่งสำหรับวัตถุประสงค์ดังกล่าวจะทำหน้าที่เป็นส่วนที่ไม่น่าเชื่อถือของไฮเปอร์ไวเซอร์
pKVM นำเสนอการจำลอง Generic Interrupt Controller เวอร์ชัน 3 (GICv3) เต็มรูปแบบตามรหัส KVM ที่มีอยู่ ตัวจับเวลาและ IPI ได้รับการจัดการโดยเป็นส่วนหนึ่งของรหัสจำลองที่ไม่น่าเชื่อถือนี้
รองรับ GICv3
อินเทอร์เฟซระหว่าง EL1 และ EL2 จะต้องตรวจสอบให้แน่ใจว่าโฮสต์ EL1 มองเห็นสถานะอินเตอร์รัปต์ทั้งหมด รวมถึงสำเนาของไฮเปอร์ไวเซอร์รีจิสเตอร์ที่เกี่ยวข้องกับอินเตอร์รัปต์ โดยทั่วไปการมองเห็นนี้ทำได้โดยใช้พื้นที่หน่วยความจำที่ใช้ร่วมกัน หนึ่งส่วนต่อ CPU เสมือน (vCPU)
รหัสสนับสนุนรันไทม์ของการลงทะเบียนระบบสามารถถูกทำให้ง่ายขึ้นเพื่อรองรับเฉพาะการลงทะเบียนการดักข้อมูลที่สร้างโดยซอฟต์แวร์ (SGIR) และปิดใช้งานการลงทะเบียน Interrupt Register (DIR) สถาปัตยกรรมกำหนดให้รีจิสเตอร์เหล่านี้ดักจับกับ EL2 เสมอ ในขณะที่กับดักอื่นๆ จนถึงตอนนี้ยังมีประโยชน์ในการลดข้อผิดพลาดเท่านั้น ทุกสิ่งทุกอย่างได้รับการจัดการในฮาร์ดแวร์
ในด้าน MMIO ทุกอย่างถูกจำลองที่ EL1 โดยนำโครงสร้างพื้นฐานปัจจุบันทั้งหมดใน KVM กลับมาใช้ใหม่ สุดท้าย Wait for Interrupt (WFI) จะส่งต่อไปยัง EL1 เสมอ เนื่องจากนี่เป็นหนึ่งในพื้นฐานการจัดกำหนดการพื้นฐานที่ KVM ใช้
รองรับตัวจับเวลา
ค่าตัวเปรียบเทียบสำหรับตัวจับเวลาเสมือนต้องเปิดเผยต่อ EL1 ในแต่ละ WFI ที่ดักจับ เพื่อให้ EL1 สามารถฉีดการขัดจังหวะของตัวจับเวลาในขณะที่ vCPU ถูกบล็อก ตัวจับเวลาทางกายภาพถูกจำลองทั้งหมด และกับดักทั้งหมดถูกส่งต่อไปยัง EL1
การจัดการ MMIO
ในการสื่อสารกับเครื่องตรวจสอบเครื่องเสมือน (VMM) และดำเนินการจำลอง GIC ต้องส่งกับดัก MMIO กลับไปยังโฮสต์ใน EL1 เพื่อไตร่ตรองเพิ่มเติม pKVM ต้องการสิ่งต่อไปนี้:
- IPA และขนาดของการเข้าถึง
- ข้อมูลกรณีเขียน
- Endianness ของ CPU ที่จุดดักจับ
นอกจากนี้ กับดักที่มีทะเบียนวัตถุประสงค์ทั่วไป (GPR) เป็นแหล่งที่มา/ปลายทางจะถูกส่งต่อโดยใช้การลงทะเบียนหลอกการถ่ายโอนนามธรรม
อินเทอร์เฟซสำหรับแขก
แขกสามารถสื่อสารกับแขกที่ได้รับการคุ้มครองโดยใช้ไฮเปอร์คอลและการเข้าถึงหน่วยความจำร่วมกันในพื้นที่ที่ติดอยู่ Hypercalls ถูกเปิดเผยตาม มาตรฐาน SMCCC โดยมีช่วงที่สงวนไว้สำหรับการจัดสรรผู้ขายโดย KVM ไฮเปอร์คอลต่อไปนี้มีความสำคัญเป็นพิเศษสำหรับแขก pKVM
ไฮเปอร์คอลทั่วไป
- PSCI มีกลไกมาตรฐานสำหรับแขกในการควบคุมวงจรชีวิตของ vCPU รวมถึงการออนไลน์ ออฟไลน์ และการปิดระบบ
- TRNG มีกลไกมาตรฐานสำหรับแขกในการขอเอนโทรปีจาก pKVM ซึ่งส่งต่อการเรียกไปยัง EL3 กลไกนี้มีประโยชน์อย่างยิ่งในกรณีที่โฮสต์ไม่สามารถเชื่อถือได้ในการทำเวอร์ชวลไลซ์เครื่องสร้างหมายเลขสุ่มของฮาร์ดแวร์ (RNG)
pKVM ไฮเปอร์คอล
- การแชร์หน่วยความจำกับโฮสต์ หน่วยความจำของผู้เยี่ยมชมทั้งหมดไม่สามารถเข้าถึงได้ในโฮสต์ในขั้นต้น แต่การเข้าถึงโฮสต์จำเป็นสำหรับการสื่อสารหน่วยความจำที่ใช้ร่วมกันและอุปกรณ์ paravirtualized ที่ใช้บัฟเฟอร์ที่ใช้ร่วมกัน Hypercalls สำหรับการแชร์และเลิกแชร์เพจกับโฮสต์ทำให้แขกสามารถเลือกได้ว่าส่วนใดของหน่วยความจำที่ Android ที่เหลือสามารถเข้าถึงได้โดยไม่จำเป็นต้องมีการจับมือกัน
- การดักจับการเข้าถึงหน่วยความจำไปยังโฮสต์ ตามเนื้อผ้า หากแขก KVM เข้าถึงที่อยู่ที่ไม่สอดคล้องกับภูมิภาคหน่วยความจำที่ถูกต้อง เธรด vCPU จะออกจากโฮสต์และโดยทั่วไปแล้วการเข้าถึงจะใช้สำหรับ MMIO และจำลองโดย VMM ในพื้นที่ผู้ใช้ เพื่ออำนวยความสะดวกในการจัดการนี้ pKVM จำเป็นต้องโฆษณารายละเอียดเกี่ยวกับคำสั่งที่ผิดพลาด เช่น ที่อยู่ พารามิเตอร์การลงทะเบียนและเนื้อหาอาจกลับไปยังโฮสต์ ซึ่งอาจเปิดเผยข้อมูลที่ละเอียดอ่อนโดยไม่ได้ตั้งใจจากแขกที่ได้รับการคุ้มครองหากไม่ได้คาดหมายว่าจะมีกับดัก pKVM แก้ปัญหานี้โดยถือว่าข้อผิดพลาดเหล่านี้เป็นอันตรายถึงชีวิต เว้นแต่แขกจะเคยออกไฮเปอร์คอลเพื่อระบุช่วง IPA ที่ผิดพลาดเป็นช่วงที่อนุญาตให้เข้าถึงเพื่อดักจับกลับไปยังโฮสต์ วิธีแก้ปัญหานี้เรียกว่าตัว ป้องกัน MMIO
อุปกรณ์ I/O เสมือน (virtio)
Virtio เป็นมาตรฐานที่ได้รับความนิยม พกพาได้ และเติบโตเต็มที่สำหรับการปรับใช้และโต้ตอบกับอุปกรณ์เสมือน อุปกรณ์ส่วนใหญ่ที่เปิดเผยต่อแขกที่ได้รับการคุ้มครองนั้นใช้งานโดยใช้เสมือน Virtio ยังสนับสนุนการใช้งาน vsock ที่ใช้สำหรับการสื่อสารระหว่างแขกที่ได้รับการป้องกันและส่วนอื่น ๆ ของ Android
โดยทั่วไปแล้วอุปกรณ์ Virtio จะถูกนำไปใช้ในพื้นที่ผู้ใช้ของโฮสต์โดย VMM ซึ่งขัดขวางการเข้าถึงหน่วยความจำที่ติดอยู่จากแขกไปยังอินเทอร์เฟซ MMIO ของอุปกรณ์ virtio และจำลองพฤติกรรมที่คาดไว้ การเข้าถึง MMIO ค่อนข้างแพง เนื่องจากการเข้าถึงอุปกรณ์แต่ละครั้งต้องใช้ VMM แบบไปกลับ ดังนั้นการถ่ายโอนข้อมูลจริงส่วนใหญ่ระหว่างอุปกรณ์และผู้เยี่ยมชมจึงเกิดขึ้นโดยใช้ชุดของ virtqueues ในหน่วยความจำ สมมติฐานที่สำคัญของ virtio คือโฮสต์สามารถเข้าถึงหน่วยความจำของแขกได้ตามใจชอบ ข้อสันนิษฐานนี้ชัดเจนในการออกแบบของ virtqueue ซึ่งอาจมีตัวชี้ไปยังบัฟเฟอร์ในแขกที่การจำลองอุปกรณ์มีจุดประสงค์เพื่อเข้าถึงโดยตรง
แม้ว่าไฮเปอร์คอลการแชร์หน่วยความจำที่อธิบายไว้ก่อนหน้านี้สามารถใช้เพื่อแชร์บัฟเฟอร์ข้อมูล virtio จากแขกไปยังโฮสต์ แต่การแชร์นี้จำเป็นต้องดำเนินการที่ความละเอียดของหน้าและอาจจบลงด้วยการเปิดเผยข้อมูลมากกว่าที่จำเป็นหากขนาดบัฟเฟอร์น้อยกว่าของเพจ . แต่แขกได้รับการกำหนดค่าให้จัดสรรทั้ง virtqueues และบัฟเฟอร์ข้อมูลที่เกี่ยวข้องจากหน้าต่างคงที่ของหน่วยความจำที่ใช้ร่วมกัน โดยข้อมูลจะถูกคัดลอก (ตีกลับ) ไปยังและจากหน้าต่างตามต้องการ
การโต้ตอบกับ TrustZone
แม้ว่าแขกจะไม่สามารถโต้ตอบกับ TrustZone ได้โดยตรง แต่โฮสต์จะต้องสามารถโทรออก SMC สู่โลกที่ปลอดภัยได้ การเรียกเหล่านี้สามารถระบุบัฟเฟอร์หน่วยความจำที่อยู่ทางกายภาพซึ่งไม่สามารถเข้าถึงโฮสต์ได้ เนื่องจากซอฟต์แวร์ความปลอดภัยโดยทั่วไปไม่ทราบถึงความสามารถในการเข้าถึงของบัฟเฟอร์ โฮสต์ที่เป็นอันตรายจึงสามารถใช้บัฟเฟอร์นี้เพื่อทำการโจมตีรองที่สับสนได้ (คล้ายกับการโจมตี DMA) เพื่อป้องกันการโจมตีดังกล่าว pKVM จะดักจับการเรียก SMC ของโฮสต์ทั้งหมดไปที่ EL2 และทำหน้าที่เป็นพร็อกซีระหว่างโฮสต์และมอนิเตอร์ที่ปลอดภัยที่ EL3
การเรียก PSCI จากโฮสต์จะถูกส่งต่อไปยังเฟิร์มแวร์ EL3 โดยมีการปรับเปลี่ยนเพียงเล็กน้อย โดยเฉพาะอย่างยิ่ง จุดเริ่มต้นสำหรับ CPU ที่กำลังออนไลน์หรือกลับมาทำงานอีกครั้งจากการหยุดชั่วคราว จะถูกเขียนใหม่เพื่อให้ตารางหน้าขั้นตอนที่ 2 ได้รับการติดตั้งที่ EL2 ก่อนกลับไปยังโฮสต์ที่ EL1 ในระหว่างการบูต การป้องกันนี้บังคับใช้โดย pKVM
สถาปัตยกรรมนี้อาศัย SoC ที่รองรับ PSCI โดยควรใช้ TF-A เวอร์ชันล่าสุดเป็นเฟิร์มแวร์ EL3
Firmware Framework for Arm (FF-A) กำหนดมาตรฐานการโต้ตอบระหว่างโลกปกติและโลกที่ปลอดภัย โดยเฉพาะอย่างยิ่งเมื่อมีไฮเปอร์ไวเซอร์ที่ปลอดภัย ส่วนสำคัญของข้อมูลจำเพาะกำหนดกลไกสำหรับการแบ่งปันหน่วยความจำกับโลกที่ปลอดภัย โดยใช้ทั้งรูปแบบข้อความทั่วไปและแบบจำลองการอนุญาตที่กำหนดไว้อย่างดีสำหรับเพจพื้นฐาน pKVM พร็อกซีข้อความ FF-A เพื่อให้แน่ใจว่าโฮสต์ไม่ได้พยายามแชร์หน่วยความจำกับฝั่งที่ปลอดภัยซึ่งไม่มีสิทธิ์เพียงพอ
สถาปัตยกรรมนี้อาศัยซอฟต์แวร์โลกที่ปลอดภัยซึ่งบังคับใช้รูปแบบการเข้าถึงหน่วยความจำ เพื่อให้แน่ใจว่าแอปที่เชื่อถือได้และซอฟต์แวร์อื่นๆ ที่ทำงานอยู่ในโลกที่ปลอดภัยจะสามารถเข้าถึงหน่วยความจำได้ก็ต่อเมื่อเป็นกรรมสิทธิ์ของโลกที่ปลอดภัยเท่านั้นหรือมีการแบ่งปันอย่างชัดเจนโดยใช้ FF -ก. ในระบบที่มี 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 และแซนด์บ็อกซ์รอบอุปกรณ์เสมือนเพื่อปกป้องเคอร์เนลของโฮสต์
ตัวอธิบายไฟล์และ ioctls
KVM เปิดเผยอุปกรณ์อักขระ /dev/kvm
ไปยัง userspace ด้วย ioctls ที่ประกอบขึ้นเป็น KVM API ioctls อยู่ในหมวดหมู่ต่อไปนี้:
- แบบสอบถาม ioctls ของระบบและตั้งค่าแอตทริบิวต์ส่วนกลางที่ส่งผลต่อระบบย่อย KVM ทั้งหมด และสร้าง pVM
- VM ioctls จะสืบค้นและตั้งค่าแอตทริบิวต์ที่สร้าง CPU เสมือน (vCPU) และอุปกรณ์ และส่งผลต่อ pVM ทั้งหมด เช่น การรวมเลย์เอาต์หน่วยความจำและจำนวน Virtual CPU (vCPU) และอุปกรณ์
- vCPU ioctls เคียวรีและตั้งค่าแอ็ตทริบิวต์ที่ควบคุมการทำงานของ CPU เสมือนตัวเดียว
- อุปกรณ์ ioctls สืบค้นและตั้งค่าแอตทริบิวต์ที่ควบคุมการทำงานของอุปกรณ์เสมือนเครื่องเดียว
แต่ละกระบวนการ crosvm จะรันอินสแตนซ์ของเครื่องเสมือนหนึ่งอินสแตนซ์เท่านั้น กระบวนการนี้ใช้ระบบ KVM_CREATE_VM
ioctl เพื่อสร้างตัวอธิบายไฟล์ VM ที่สามารถใช้เพื่อออก pVM ioctls KVM_CREATE_VCPU
หรือ KVM_CREATE_DEVICE
ioctl บน VM FD จะสร้าง vCPU/อุปกรณ์ และส่งคืน file descriptor ที่ชี้ไปยังทรัพยากรใหม่ ioctls บน vCPU หรือ FD อุปกรณ์สามารถใช้เพื่อควบคุมอุปกรณ์ที่สร้างขึ้นโดยใช้ ioctl บน VM FD สำหรับ vCPU นี่รวมถึงงานที่สำคัญของการรันโค้ดผู้เยี่ยมชม
ภายใน crosvm จะลงทะเบียน file descriptor ของ VM กับเคอร์เนลโดยใช้อินเทอร์เฟซ epoll
ที่ทริกเกอร์จากขอบ เคอร์เนลจะแจ้ง crosvm เมื่อใดก็ตามที่มีเหตุการณ์ใหม่ที่รอดำเนินการในตัวอธิบายไฟล์ใดๆ
pKVM เพิ่มความสามารถใหม่ KVM_CAP_ARM_PROTECTED_VM
ซึ่งสามารถใช้เพื่อรับข้อมูลเกี่ยวกับสภาพแวดล้อม pVM และตั้งค่าโหมดที่ได้รับการป้องกันสำหรับ VM crosvm ใช้สิ่งนี้ระหว่างการสร้าง pVM หากส่งแฟล็ก --protected --protected-vm
เพื่อสอบถามและจองหน่วยความจำในปริมาณที่เหมาะสมสำหรับเฟิร์มแวร์ pVM จากนั้นจึงเปิดใช้งานโหมดที่ได้รับการป้องกัน
การจัดสรรหน่วยความจำ
หนึ่งในความรับผิดชอบหลักของ VMM คือการจัดสรรหน่วยความจำของ VM และจัดการเลย์เอาต์หน่วยความจำ crosvm สร้าง เลย์เอาต์หน่วยความจำคงที่อธิบายอย่างหลวม ๆ ในตารางด้านล่าง
FDT ในโหมดปกติ | PHYS_MEMORY_END - 0x200000 |
ที่ว่าง | ... |
Ramdisk | ALIGN_UP(KERNEL_END, 0x1000000) |
เคอร์เนล | 0x80080000 |
Bootloader | 0x80200000 |
FDT ในโหมด BIOS | 0x80000000 |
ฐานหน่วยความจำกายภาพ | 0x80000000 |
เฟิร์มแวร์ pVM | 0x7FE00000 |
หน่วยความจำอุปกรณ์ | 0x10000 - 0x40000000 |
หน่วยความจำกายภาพได้รับการจัดสรรด้วย mmap
และหน่วยความจำจะบริจาคให้กับ VM เพื่อเติมพื้นที่หน่วยความจำที่เรียกว่า memslots ด้วย KVM_SET_USER_MEMORY_REGION
ioctl ดังนั้นหน่วยความจำ pVM ของแขกทั้งหมดจึงมาจากอินสแตนซ์ crosvm ที่จัดการ และอาจส่งผลให้กระบวนการถูกฆ่า (ยุติ VM) หากโฮสต์เริ่มหน่วยความจำว่างไม่เพียงพอ เมื่อ VM หยุดทำงาน ไฮเปอร์ไวเซอร์จะล้างหน่วยความจำโดยอัตโนมัติและส่งคืนไปยังเคอร์เนลของโฮสต์
ภายใต้ KVM ปกติ VMM จะคงการเข้าถึงหน่วยความจำของแขกทั้งหมด ด้วย pKVM หน่วยความจำของแขกจะไม่ถูกแมปจากพื้นที่ที่อยู่ทางกายภาพของโฮสต์เมื่อบริจาคให้กับแขก ข้อยกเว้นเพียงอย่างเดียวคือหน่วยความจำที่แขกแชร์อย่างชัดเจน เช่น สำหรับอุปกรณ์ virtio
ภูมิภาค MMIO ในพื้นที่ที่อยู่ของแขกไม่ได้ถูกแมป การเข้าถึงภูมิภาคเหล่านี้โดยแขกถูกดักไว้ และส่งผลให้เกิดเหตุการณ์ I/O บน VM FD กลไกนี้ใช้เพื่อติดตั้งอุปกรณ์เสมือน ในโหมดที่ได้รับการป้องกัน แขกต้องรับทราบว่าพื้นที่ของพื้นที่ที่อยู่นั้นใช้สำหรับ MMIO โดยใช้ไฮเปอร์คอล เพื่อลดความเสี่ยงของการรั่วไหลของข้อมูลโดยไม่ได้ตั้งใจ
การจัดตารางเวลา
CPU เสมือนแต่ละตัวจะแสดงโดยเธรด POSIX และกำหนดเวลาโดยตัวจัดกำหนดการ Linux ของโฮสต์ เธรดเรียก KVM_RUN
ioctl บน vCPU FD ส่งผลให้ไฮเปอร์ไวเซอร์เปลี่ยนเป็นบริบท vCPU ของแขก ตัวจัดกำหนดการโฮสต์จะพิจารณาเวลาที่ใช้ในบริบทของผู้เยี่ยมชมตามเวลาที่ใช้โดยเธรด vCPU ที่เกี่ยวข้อง KVM_RUN
ส่งคืนเมื่อมีเหตุการณ์ที่ต้องจัดการโดย VMM เช่น I/O การสิ้นสุดการขัดจังหวะ หรือ vCPU หยุดทำงาน VMM จัดการเหตุการณ์และเรียก KVM_RUN
อีกครั้ง
ระหว่าง KVM_RUN
เธรดยังคงสามารถขัดขวางโดยตัวจัดกำหนดการโฮสต์ ยกเว้นสำหรับการดำเนินการของรหัสไฮเปอร์ไวเซอร์ EL2 ซึ่งไม่สามารถยอมให้มีการแทนที่ได้ guest 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 คือการบูตสแตรปการบูตที่ปลอดภัยและรับความลับเฉพาะของ pvmfw pvmfw ไม่ได้จำกัดให้ใช้กับระบบปฏิบัติการเฉพาะใดๆ เช่น Microdroid ตราบใดที่ระบบปฏิบัติการรองรับโดย crosvm และได้รับการลงนามอย่างถูกต้อง
ไบนารี pvmfw ถูกเก็บไว้ในพาร์ติชั่นแฟลชที่มีชื่อเดียวกันและอัปเดตโดยใช้ OTA
บูตเครื่อง
ลำดับขั้นตอนต่อไปนี้ถูกเพิ่มไปยังโพรซีเดอร์การบู๊ตของอุปกรณ์ที่เปิดใช้งาน pKVM:
- Android Bootloader (ABL) โหลด pvmfw จากพาร์ติชั่นลงในหน่วยความจำและยืนยันอิมเมจ
- ABL ได้รับความลับของ Device Identifier Composition Engine (DICE) (Compound Device Identifiers (CDI) และ Boot Certificate Chain (BCC)) จาก Root of Trust
- ABL ดำเนินการวัดและหาค่า DICE ของความลับของ pvmfw (CDI) และผนวกเข้ากับไบนารี pvmfw
- ABL เพิ่มโหนดภูมิภาคหน่วยความจำที่สงวนไว้สำหรับ
linux,pkvm-guest-firmware-memory
ให้กับ DT โดยอธิบายตำแหน่งและขนาดของไบนารี pvmfw และความลับที่ได้รับในขั้นตอนก่อนหน้า - ABL มอบการควบคุมให้กับ Linux และ Linux เริ่มต้น pKVM
- pKVM ยกเลิกการแมปภูมิภาคหน่วยความจำ pvmfw จากตารางเพจสเตจ 2 ของโฮสต์ และปกป้องจากโฮสต์ (และแขก) ตลอดระยะเวลาทำงานของอุปกรณ์
หลังจากบู๊ตอุปกรณ์แล้ว Microdroid จะถูกบู๊ตตามขั้นตอนในส่วน ลำดับการบู๊ต ของเอกสาร Microdroid
pVM บูต
เมื่อสร้าง pVM นั้น crosvm (หรือ VMM อื่น) ต้องสร้าง memslot ขนาดใหญ่พอที่จะเติมด้วยอิมเมจ pvmfw โดยไฮเปอร์ไวเซอร์ VMM ยังถูกจำกัดในรายการรีจิสเตอร์ที่มีค่าเริ่มต้นที่สามารถตั้งค่าได้ (x0-x14 สำหรับ vCPU หลัก ไม่มีสำหรับ vCPU รอง) รีจิสเตอร์ที่เหลือถูกสงวนไว้และเป็นส่วนหนึ่งของ hypervisor-pvmfw ABI
เมื่อ pVM ถูกรัน ไฮเปอร์ไวเซอร์จะควบคุม vCPU หลักไปยัง pvmfw ก่อน เฟิร์มแวร์คาดว่า crosvm จะโหลดเคอร์เนลที่ลงนามโดย AVB ซึ่งสามารถเป็น bootloader หรืออิมเมจอื่น ๆ และ FDT ที่ไม่ได้ลงนามไปยังหน่วยความจำที่ออฟเซ็ตที่รู้จัก pvmfw ตรวจสอบลายเซ็น AVB และหากสำเร็จ จะสร้างทรีอุปกรณ์ที่เชื่อถือได้จาก FDT ที่ได้รับ ล้างความลับของมันออกจากหน่วยความจำ และแยกสาขาไปยังจุดเริ่มต้นของเพย์โหลด หากหนึ่งในขั้นตอนการตรวจสอบล้มเหลว เฟิร์มแวร์จะออกไฮเปอร์คอล PSCI SYSTEM_RESET
ระหว่างการบู๊ต ข้อมูลเกี่ยวกับอินสแตนซ์ pVM จะถูกเก็บไว้ในพาร์ติชั่น (อุปกรณ์ virtio-blk) และเข้ารหัสด้วยความลับของ pvmfw เพื่อให้แน่ใจว่าเมื่อรีบูต ข้อมูลลับจะถูกจัดเตรียมไปยังอินสแตนซ์ที่ถูกต้อง