สถาปัตยกรรม AVF

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 เพื่อรักษาความสมบูรณ์ของเคอร์เนลอิมเมจเฉพาะในระหว่างการบู๊ตในช่วงต้นเท่านั้น เมื่อเคอร์เนลหมดสิทธิ์ ไฮเปอร์ไวเซอร์จะไม่ถือว่าเคอร์เนลนั้นเชื่อถือได้อีกต่อไป ซึ่งจะมีหน้าที่ในการป้องกันตัวเองแม้ว่าเคอร์เนลจะถูกบุกรุก

ขั้นตอนการบูต pKVM

รูปที่ 1. ขั้นตอนการบูต pKVM

การมีเคอร์เนล 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

การป้องกันการเข้าถึงหน่วยความจำ CPU

รูปที่ 2. การป้องกันการเข้าถึงหน่วยความจำ CPU

ในอดีต 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

การป้องกันการเข้าถึงหน่วยความจำ Dma

รูปที่ 3 การป้องกันการเข้าถึงหน่วยความจำ DMA

อย่างน้อยที่สุด ฮาร์ดแวร์ 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 และบัฟเฟอร์ข้อมูลที่เกี่ยวข้องจากหน้าต่างคงที่ของหน่วยความจำที่ใช้ร่วมกัน โดยข้อมูลจะถูกคัดลอก (ตีกลับ) ไปยังและจากหน้าต่างตามต้องการ

อุปกรณ์เสมือน

รูปที่ 4. อุปกรณ์ Virtio

การโต้ตอบกับ 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:

  1. Android Bootloader (ABL) โหลด pvmfw จากพาร์ติชั่นลงในหน่วยความจำและยืนยันอิมเมจ
  2. ABL ได้รับความลับของ Device Identifier Composition Engine (DICE) (Compound Device Identifiers (CDI) และ Boot Certificate Chain (BCC)) จาก Root of Trust
  3. ABL ดำเนินการวัดและหาค่า DICE ของความลับของ pvmfw (CDI) และผนวกเข้ากับไบนารี pvmfw
  4. ABL เพิ่มโหนดภูมิภาคหน่วยความจำที่สงวนไว้สำหรับ linux,pkvm-guest-firmware-memory ให้กับ DT โดยอธิบายตำแหน่งและขนาดของไบนารี pvmfw และความลับที่ได้รับในขั้นตอนก่อนหน้า
  5. ABL มอบการควบคุมให้กับ Linux และ Linux เริ่มต้น pKVM
  6. 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 เพื่อให้แน่ใจว่าเมื่อรีบูต ข้อมูลลับจะถูกจัดเตรียมไปยังอินสแตนซ์ที่ถูกต้อง