एवीएफ़ आर्किटेक्चर

Android, Android वर्चुअलाइज़ेशन फ़्रेमवर्क को लागू करने के लिए ज़रूरी सभी कॉम्पोनेंट के रेफ़रंस लागू करने की सुविधा देता है. फ़िलहाल, यह सुविधा सिर्फ़ ARM64 पर काम करती है. इस पेज पर, फ़्रेमवर्क के आर्किटेक्चर के बारे में बताया गया है.

बैकग्राउंड

Arm आर्किटेक्चर में, अपवाद के चार लेवल की अनुमति होती है. अपवाद लेवल 0 (EL0) में सबसे कम और अपवाद लेवल 3 (EL3) में सबसे ज़्यादा विशेषाधिकार होते हैं. Android कोड बेस का सबसे बड़ा हिस्सा (सभी यूज़रस्पेस कॉम्पोनेंट) EL0 पर चलता है. बाकी हिस्सा, जिसे आम तौर पर "Android" कहा जाता है वह Linux kernel है, जो EL1 पर चलता है.

EL2 लेयर की मदद से, हाइपरवाइजर को शामिल किया जा सकता है. इससे EL1/EL0 पर, मेमोरी और डिवाइसों को अलग-अलग पीवीएम में अलग-अलग रखा जा सकता है. साथ ही, गोपनीयता और सुरक्षा की गारंटी भी मिलती है.

हाइपरवाइजर

सुरक्षित कर्नेल पर आधारित वर्चुअल मशीन (pKVM), Linux KVM हाइपरवाइजर पर बनाई गई है. इसमें, वर्चुअल मशीन बनाने के समय 'सुरक्षित' के तौर पर मार्क की गई मेहमान वर्चुअल मशीनों में चल रहे पेलोड के ऐक्सेस पर पाबंदी लगाने की सुविधा जोड़ी गई है.

KVM/arm64, सीपीयू की कुछ सुविधाओं की उपलब्धता के आधार पर, अलग-अलग तरीके से काम करता है. जैसे, वर्चुअलाइज़ेशन होस्ट एक्सटेंशन (VHE) (ARMv8.1 और उसके बाद के वर्शन). इनमें से एक मोड को आम तौर पर नॉन-वीएचई मोड कहा जाता है. इसमें, बूट के दौरान हाइपरवाइजर कोड को कर्नेल इमेज से अलग किया जाता है और उसे EL2 पर इंस्टॉल किया जाता है. वहीं, कर्नेल खुद EL1 पर चलता है. KVM का EL2 कॉम्पोनेंट, लिनक्स कोडबेस का हिस्सा है. हालांकि, यह एक छोटा कॉम्पोनेंट है, जो एक से ज़्यादा EL1 के बीच स्विच करने की सुविधा देता है. हाइपरवाइजर कॉम्पोनेंट को Linux के साथ कॉम्पाइल किया जाता है. हालांकि, यह vmlinux इमेज के अलग और खास मेमोरी सेक्शन में मौजूद होता है. pKVM, इस डिज़ाइन का फ़ायदा उठाता है. इसके लिए, वह हाइपरवाइजर कोड को नई सुविधाओं के साथ बढ़ाता है. इससे, Android होस्ट कर्नेल और उपयोगकर्ता स्पेस पर पाबंदियां लगाई जा सकती हैं. साथ ही, होस्ट के ऐक्सेस को मेहमान मेमोरी और हाइपरवाइजर तक सीमित किया जा सकता है.

pKVM वेंडर मॉड्यूल

pKVM वेंडर मॉड्यूल, हार्डवेयर के हिसाब से बनाया गया मॉड्यूल है. इसमें डिवाइस के हिसाब से काम करने वाली सुविधाएं होती हैं. जैसे, इनपुट-आउटपुट मेमोरी मैनेजमेंट यूनिट (IOMMU) ड्राइवर. इन मॉड्यूल की मदद से, सुरक्षा से जुड़ी उन सुविधाओं को पोर्ट किया जा सकता है जिन्हें pKVM के अपवाद लेवल 2 (EL2) के ऐक्सेस की ज़रूरत होती है.

pKVM वेंडर मॉड्यूल को लागू और लोड करने का तरीका जानने के लिए, pKVM वेंडर मॉड्यूल लागू करना लेख पढ़ें.

बूट प्रोसेस

इस इलस्ट्रेशन में, pKVM को बूट करने की प्रोसेस दिखाई गई है:

pKVM बूट प्रोसेस

पहली इमेज. pKVM को बूट करने का तरीका

  1. बूटलोडर, EL2 पर सामान्य कर्नेल में प्रवेश करता है.
  2. सामान्य कर्नेल को पता चलता है कि वह EL2 पर चल रहा है और वह खुद को EL1 पर ले जाता है. हालांकि, pKVM और उसके मॉड्यूल, EL2 पर चलते रहते हैं. इसके अलावा, इस समय pKVM वेंडर मॉड्यूल लोड होते हैं.
  3. सामान्य कर्नेल सामान्य तरीके से बूट होता है. साथ ही, यूज़र स्पेस तक पहुंचने तक डिवाइस के सभी ज़रूरी ड्राइवर लोड करता है. इस समय, pKVM सही जगह पर है और स्टेज-2 पेज टेबल को हैंडल करता है.

बूट करने की प्रोसेस में, बूटलोडर पर भरोसा किया जाता है, ताकि वह शुरुआती बूट के दौरान, कर्नेल इमेज को पूरी तरह से सुरक्षित रख सके. जब कर्नेल से विशेष अधिकार हटा दिए जाते हैं, तो उसे अब हायपरवाइजर के भरोसेमंद नहीं माना जाता. इसके बाद, हायपरवाइजर की यह ज़िम्मेदारी होती है कि वह खुद को सुरक्षित रखे, भले ही कर्नेल से छेड़छाड़ की गई हो.

Android kernel और hypervisor को एक ही बाइनरी इमेज में रखने से, उनके बीच बेहतर तरीके से इंटरफ़ेस किया जा सकता है. इस टाइट कपलिंग से, दोनों कॉम्पोनेंट के परमाणु अपडेट की गारंटी मिलती है. इससे, उनके बीच इंटरफ़ेस को स्थिर रखने की ज़रूरत नहीं पड़ती. साथ ही, लंबे समय तक बनाए रखने की सुविधा के साथ-साथ, ज़्यादा सुविधाएं भी मिलती हैं. टाइट कपलिंग की मदद से, परफ़ॉर्मेंस को ऑप्टिमाइज़ भी किया जा सकता है. ऐसा तब होता है, जब दोनों कॉम्पोनेंट मिलकर काम करते हैं. हालांकि, इससे हाइपरवाइजर की ओर से दी गई सुरक्षा की गारंटी पर कोई असर नहीं पड़ता.

इसके अलावा, Android नेटवर्क में GKI (जीकेआई) को अपनाने से, pKVM हाइपरवाइज़र को Android डिवाइसों पर उसी बाइनरी में अपने-आप डिप्लॉय कर दिया जाता है जिसमें कर्नेल का इस्तेमाल किया जाता है.

सीपीयू मेमोरी ऐक्सेस की सुरक्षा

Arm आर्किटेक्चर में, मेमोरी मैनेजमेंट यूनिट (MMU) को दो अलग-अलग चरणों में बांटा गया है. इन दोनों का इस्तेमाल, मेमोरी के अलग-अलग हिस्सों में ऐड्रेस ट्रांसलेशन और ऐक्सेस कंट्रोल लागू करने के लिए किया जा सकता है. चरण 1 एमएमयू को EL1 से कंट्रोल किया जाता है और पते का पहले लेवल में अनुवाद करने की अनुमति दी जाती है. Linux, पहले चरण के एमएमयू का इस्तेमाल, हर यूज़रस्पेस प्रोसेस और अपने वर्चुअल पता स्पेस के लिए दिए गए वर्चुअल पता स्पेस को मैनेज करने के लिए करता है.

दूसरे चरण का एमएमयू, EL2 से कंट्रोल किया जाता है. साथ ही, यह पहले चरण के एमएमयू के आउटपुट पते पर, दूसरे पते के अनुवाद को लागू करने की सुविधा देता है. इससे, फ़िज़िकल पता (पीए) बनता है. दूसरे चरण के अनुवाद का इस्तेमाल, सभी मेहमान VM से मेमोरी ऐक्सेस को कंट्रोल और अनुवाद करने के लिए, हाइपरवाइजर कर सकते हैं. जैसा कि दूसरी इमेज में दिखाया गया है, जब अनुवाद के दोनों चरण चालू होते हैं, तो पहले चरण के आउटपुट पते को इंटरमीडिएट फ़िज़िकल पता (आईपीए) कहा जाता है ध्यान दें: वर्चुअल पते (VA) का अनुवाद आईपीए और फिर पीए में किया जाता है.

सीपीयू की मेमोरी के ऐक्सेस से जुड़ी सुरक्षा

दूसरी इमेज. सीपीयू मेमोरी ऐक्सेस की सुरक्षा

पहले, KVM मेहमान के वर्शन को चलाते समय, ट्रांसलेशन के दूसरे चरण को चालू रखता था और होस्ट के Linux kernel को चलाते समय, ट्रांसलेशन के दूसरे चरण को बंद रखता था. इस आर्किटेक्चर की मदद से, होस्ट के पहले चरण के एमएमयू से मेमोरी ऐक्सेस, दूसरे चरण के एमएमयू से गुज़रते हैं. इससे होस्ट से मेहमान के मेमोरी पेजों को बिना किसी पाबंदी के ऐक्सेस किया जा सकता है. दूसरी ओर, pKVM होस्ट कॉन्टेक्स्ट में भी दूसरे चरण की सुरक्षा चालू करता है. साथ ही, होस्ट के बजाय मेहमान मेमोरी पेजों की सुरक्षा करने का काम, हाइपरवाइजर को सौंपता है.

केवीएम, मेहमानों के लिए कॉम्प्लेक्स आईपीए/पीए मैपिंग को लागू करने के लिए, दूसरे चरण में पते के अनुवाद का पूरा इस्तेमाल करता है. इससे मेहमानों के लिए, अलग-अलग तरह की मेमोरी के होने का भ्रम पैदा होता है. हालांकि, होस्ट के लिए स्टेज 2 एमएमयू का इस्तेमाल सिर्फ़ ऐक्सेस कंट्रोल के लिए किया जा सकता है. होस्ट के दूसरे चरण को पहचान के हिसाब से मैप किया जाता है. इससे यह पक्का किया जाता है कि होस्ट IPA स्पेस में एक साथ मौजूद मेमोरी, PA स्पेस में भी एक साथ मौजूद हो. इस आर्किटेक्चर की मदद से, पेज टेबल में बड़ी मैपिंग का इस्तेमाल किया जा सकता है. इससे ट्रांसलेशन लुकसाइड बफ़र (TLB) पर दबाव कम हो जाता है. पहचान की मैपिंग को पीए से इंडेक्स किया जा सकता है, इसलिए होस्ट स्टेज 2 का इस्तेमाल, सीधे पेज टेबल में पेज के मालिकाना हक को ट्रैक करने के लिए भी किया जाता है.

डायरेक्ट मेमोरी ऐक्सेस (डीएमए) की सुरक्षा

जैसा कि पहले बताया गया है, मेहमान मेमोरी की सुरक्षा के लिए, Linux होस्ट से सीपीयू पेज की टेबल में मेहमान पेजों को अनमैप करना ज़रूरी है, लेकिन यह काफ़ी नहीं है. pKVM को होस्ट कर्नेल के कंट्रोल के तहत, डीएमए-सुविधा वाले डिवाइसों से किए गए मेमोरी ऐक्सेस से सुरक्षा की भी ज़रूरत होती है. साथ ही, नुकसान पहुंचाने वाले होस्ट के डीएमए हमले की संभावना को भी सुरक्षित रखना होता है. इस तरह के डिवाइस को मेहमान मेमोरी ऐक्सेस करने से रोकने के लिए, pKVM को सिस्टम में डीएमए की सुविधा वाले हर डिवाइस के लिए इनपुट-आउटपुट मेमोरी मैनेजमेंट यूनिट (IOMMU) हार्डवेयर की ज़रूरत होती है, जैसा कि तीसरे चित्र में दिखाया गया है.

डीएमए मेमोरी ऐक्सेस की सुरक्षा

तीसरी इमेज. डीएमए के तहत मेमोरी के ऐक्सेस की सुरक्षा

कम से कम, IOMMU हार्डवेयर, किसी डिवाइस को फ़िज़िकल मेमोरी के लिए, पेज के हिसाब से, पढ़ने/लिखने का ऐक्सेस देने और रद्द करने का तरीका उपलब्ध कराता है. हालांकि, यह IOMMU हार्डवेयर, pVM में डिवाइसों के इस्तेमाल पर पाबंदी लगाता है, क्योंकि वे पहचान से मैप किए गए दूसरे चरण का अनुमान लगाते हैं.

वर्चुअल मशीनों के बीच अलगाव को पक्का करने के लिए, अलग-अलग इकाइयों के लिए जनरेट किए गए मेमोरी ट्रांज़ैक्शन को IOMMU से अलग किया जाना चाहिए, ताकि अनुवाद के लिए पेज टेबल के सही सेट का इस्तेमाल किया जा सके.

इसके अलावा, EL2 पर SoC के लिए बने कोड की मात्रा को कम करना, pKVM के कुल भरोसेमंद कंप्यूटिंग बेस (टीसीबी) को कम करने की सबसे अहम रणनीति है. साथ ही, यह Hypervisor में IOMMU ड्राइवर शामिल करने के ख़िलाफ़ विरोध करता है. इस समस्या को कम करने के लिए, EL1 पर मौजूद होस्ट, IOMMU के सहायक मैनेजमेंट टास्क के लिए ज़िम्मेदार होता है. जैसे, पावर मैनेजमेंट, शुरू करना, और जहां ज़रूरी हो वहां इंटरप्ट मैनेज करना.

हालांकि, होस्ट को डिवाइस की स्थिति के कंट्रोल में रखने पर, IOMMU हार्डवेयर के प्रोग्रामिंग इंटरफ़ेस पर अतिरिक्त ज़रूरी शर्तें लागू होती हैं. इससे यह पक्का किया जा सकता है कि अनुमति की जांच को दूसरे तरीकों से बायपास न किया जा सके. उदाहरण के लिए, डिवाइस को रीसेट करने के बाद.

Arm डिवाइसों के लिए, स्टैंडर्ड और अच्छी तरह से काम करने वाला IOMMU, Arm सिस्टम मेमोरी मैनेजमेंट यूनिट (SMMU) आर्किटेक्चर है. यह आर्किटेक्चर, अलगाव और डायरेक्ट असाइनमेंट, दोनों को मुमकिन बनाता है. हमारा सुझाव है कि रेफ़रंस के तौर पर इस आर्किटेक्चर का इस्तेमाल करें.

मेमोरी का मालिकाना हक

बूट होने के समय, यह माना जाता है कि Hypervisor के अलावा बाकी सभी मेमोरी का मालिकाना हक होस्ट के पास है. साथ ही, Hypervisor इसे इस तरह से ट्रैक करता है. जब कोई पीवीएम पैदा होता है, तो होस्ट उसे चालू होने की अनुमति देने के लिए मेमोरी पेज दान करता है. हाइपरवाइज़र उन पेजों के मालिकाना हक को होस्ट से पीवीएम में बदल देता है. इसलिए, हाइपरवाइजर, होस्ट के दूसरे चरण की पेज टेबल में ऐक्सेस कंट्रोल की पाबंदियां लगाता है, ताकि वह पेजों को फिर से ऐक्सेस न कर सके. इससे, मेहमान की गोपनीयता बनी रहती है.

होस्ट और मेहमानों के बीच बातचीत करने के लिए, कंट्रोल की गई मेमोरी शेयर की जाती है. मेहमान, हाइपरकॉल का इस्तेमाल करके अपने कुछ पेजों को होस्ट के साथ शेयर कर सकते हैं. यह हाइपरवाइजर को, होस्ट के दूसरे चरण की पेज टेबल में उन पेजों को फिर से मैप करने का निर्देश देता है. इसी तरह, TrustZone के साथ होस्ट का कम्यूनिकेशन, मेमोरी शेयर करने और/या क़र्ज़ देने की प्रोसेस की वजह से मुमकिन हो पाता है. इन सभी पर pKVM, बारीकी से नज़र रखता है और इन्हें कंट्रोल करता है. इसके लिए, फ़र्मवेयर फ़्रेमवर्क फ़ॉर आर्म (FF-A) स्पेसिफ़िकेशन की मदद ली जाती है.

समय के साथ, pVM की मेमोरी की ज़रूरतें बदल सकती हैं. इसलिए, एक हाइपरकॉल दिया जाता है, जिसकी मदद से कॉलर के कुछ पेजों का मालिकाना हक, होस्ट को वापस दिया जा सकता है. आम तौर पर, इस हाइपरकॉल का इस्तेमाल, virtio balloon प्रोटोकॉल के साथ किया जाता है, ताकि VMM, pVM से मेमोरी वापस पाने का अनुरोध कर सके. साथ ही, pVM, कंट्रोल किए गए तरीके से VMM को छोड़े गए पेजों की सूचना दे सके.

सिस्टम में मौजूद सभी मेमोरी पेजों के मालिकाना हक को ट्रैक करने की ज़िम्मेदारी, हाइपरवाइजर की होती है. साथ ही, यह भी ट्रैक किया जाता है कि उन्हें अन्य इकाइयों के साथ शेयर किया जा रहा है या उन्हें उधार दिया जा रहा है. ज़्यादातर मामलों में, होस्ट और मेहमानों के दूसरे चरण की पेज टेबल में जोड़े गए मेटाडेटा का इस्तेमाल करके, इस स्थिति को ट्रैक किया जाता है. इसके लिए, पेज टेबल एंट्री (पीटीई) में रिज़र्व किए गए बिट का इस्तेमाल किया जाता है. जैसा कि नाम से पता चलता है, ये बिट सॉफ़्टवेयर के इस्तेमाल के लिए रिज़र्व किए जाते हैं.

होस्ट को यह पक्का करना होगा कि वह ऐसे पेजों को ऐक्सेस करने की कोशिश न करे जिन्हें हायपरवाइज़र ने ऐक्सेस करने की अनुमति नहीं दी है. होस्ट का गैर-कानूनी ऐक्सेस होने पर, हाइपरवाइजर, होस्ट में सिंक्रोनस अपवाद इंजेक्ट करता है. इसकी वजह से, उपयोगकर्ता स्पेस के टास्क को SEGV सिग्नल मिल सकता है या होस्ट कर्नेल क्रैश हो सकता है. मेहमानों को दिए गए पेजों को, होस्ट कर्नेल के ज़रिए स्वैप या मर्ज करने की अनुमति नहीं दी जाती, ताकि वे अनजाने में ऐक्सेस न हो पाएं.

रुकावट को मैनेज करना और टाइमर

इंटरप्ट, किसी मेहमान के डिवाइसों के साथ इंटरैक्ट करने के तरीके और सीपीयू के बीच कम्यूनिकेशन के लिए ज़रूरी हैं. इंटरप्ट, कम्यूनिकेशन का मुख्य तरीका है. केवीएम मॉडल, EL1 में होस्ट को रुकावट डालने वाले सभी वर्चुअल मैनेजमेंट का ऐक्सेस देता है. इस वजह से, यह हायपरवाइज़र के गैर-भरोसेमंद हिस्से की तरह काम करता है.

pKVM, मौजूदा KVM कोड के आधार पर, जनरल इंटरप्ट कंट्रोलर वर्शन 3 (GICv3) का पूरा इम्यूलेशन उपलब्ध कराता है. टाइमर और आईपीआई को, इस गैर-भरोसेमंद इम्यूलेशन कोड के हिस्से के तौर पर मैनेज किया जाता है.

GICv3 के साथ काम करना

EL1 और EL2 के बीच के इंटरफ़ेस को यह पक्का करना होगा कि पूरी इंटरप्ट स्थिति, EL1 होस्ट को दिखे. इसमें इंटरप्ट से जुड़े हाइपरवाइजर रजिस्टर की कॉपी भी शामिल हैं. आम तौर पर, शेयर की गई स्मृति वाले क्षेत्रों का इस्तेमाल करके, यह जानकारी देखी जा सकती है. हर वर्चुअल सीपीयू (vCPU) के लिए एक क्षेत्र होता है.

सिस्टम रजिस्टर के रनटाइम के लिए सहायता कोड को आसान बनाया जा सकता है, ताकि सिर्फ़ सॉफ़्टवेयर जनरेटेड इंटरप्ट रजिस्टर (एसजीआईआर) और इंटरप्ट रजिस्टर (डीआईआर) को ट्रैप किया जा सके. आर्किटेक्चर के मुताबिक, ये रजिस्टर हमेशा EL2 पर ट्रैप होते हैं. वहीं, अब तक अन्य ट्रैप का इस्तेमाल सिर्फ़ गड़बड़ियों को कम करने के लिए किया गया है. बाकी सभी काम, हार्डवेयर में किए जा रहे हैं.

एमएमआईओ की बात करें, तो हर चीज़ EL1 पर सिम्युलेट की जाती है और केवीएम के सभी मौजूदा इन्फ़्रास्ट्रक्चर का फिर से इस्तेमाल किया जाता है. आखिर में, इंटरप्ट के लिए इंतज़ार करें (WFI) को हमेशा EL1 पर भेजा जाता है, क्योंकि यह शेड्यूलिंग के बुनियादी प्राइमिटिव में से एक है. इसका इस्तेमाल KVM करता है.

टाइमर से जुड़ी सहायता

वर्चुअल टाइमर के लिए तुलना करने वाली वैल्यू, हर ट्रैपिंग WFI पर EL1 को दिखानी चाहिए, ताकि vCPU ब्लॉक होने के दौरान EL1, टाइमर इंटरप्ट इंजेक्ट कर सके. फ़िज़िकल टाइमर को पूरी तरह से एमुलेट किया जाता है और सभी ट्रैप को EL1 पर भेजा जाता है.

एमएमआईओ मैनेज करना

वर्चुअल मशीन मॉनिटर (VMM) के साथ कम्यूनिकेट करने और GIC इम्यूलेशन करने के लिए, MMIO ट्रैप को EL1 में होस्ट पर वापस भेजा जाना चाहिए, ताकि आगे की जांच की जा सके. pKVM के लिए, ये ज़रूरी हैं:

  • आईपीए और ऐक्सेस का साइज़
  • डेटा को लिखने के मामले में
  • ट्रैपिंग के समय सीपीयू का Endianness

इसके अलावा, सोर्स/डेस्टिनेशन के तौर पर जनरल यूज़ रजिस्टर (जीपीआर) वाले ट्रैप को, ऐब्स्ट्रैक्ट ट्रांसफ़र pseudo-रजिस्टर की मदद से रिले किया जाता है.

मेहमानों के लिए इंटरफ़ेस

कोई मेहमान, हाइपरकॉल और ट्रैप किए गए क्षेत्रों के लिए मेमोरी ऐक्सेस का इस्तेमाल करके, सुरक्षित मेहमान से बातचीत कर सकता है. हाइपरकॉल, एसएमसीसी स्टैंडर्ड के मुताबिक दिखाए जाते हैं. साथ ही, KVM की मदद से वेंडर को तय सीमा में एलोकेशन दिया जाता है. नीचे दिए गए हाइपरकॉल, pKVM के मेहमानों के लिए खास तौर पर अहम हैं.

सामान्य हाइपरकॉल

  • PSCI, मेहमान को अपने vCPU के लाइफ़साइकल को कंट्रोल करने के लिए एक स्टैंडर्ड तरीका उपलब्ध कराता है. इसमें, ऑनलाइन करना, ऑफ़लाइन करना, और सिस्टम शटडाउन करना शामिल है.
  • टीआरएनजी, मेहमान के लिए एक स्टैंडर्ड तरीका उपलब्ध कराता है, ताकि वह pKVM से एन्ट्रापी का अनुरोध कर सके. यह अनुरोध, EL3 को भेजा जाता है. यह तरीका खास तौर पर तब काम आता है, जब किसी हार्डवेयर रैंडम नंबर जनरेटर (RNG) को वर्चुअलाइज़ करने के लिए होस्ट पर भरोसा नहीं किया जा सकता.

pKVM हाइपरकॉल

  • होस्ट के साथ मेमोरी शेयर की जा रही है. शुरुआत में, होस्ट के पास मेहमान की सभी मेमोरी का ऐक्सेस नहीं होता. हालांकि, शेयर की गई मेमोरी के ज़रिए कम्यूनिकेट करने के लिए और शेयर किए गए बफ़र पर काम करने वाले पैरावर्चुअलाइज़ किए गए डिवाइसों के लिए, होस्ट का ऐक्सेस ज़रूरी होता है. होस्ट के साथ पेजों को शेयर करने और अनशेयर करने के लिए, हाइपरकॉल की सुविधा का इस्तेमाल करके मेहमान यह तय कर सकते हैं कि Android के बाकी हिस्सों को मेमोरी के किन हिस्सों को ऐक्सेस करने की अनुमति दी जाए. इसके लिए, उन्हें हैंडशेक की ज़रूरत नहीं पड़ती.
  • होस्ट की याददाश्त छोड़ना. आम तौर पर, मेहमान की सभी यादें तब तक उसके पास रहती हैं, जब तक उन्हें मिटा नहीं दिया जाता. यह स्थिति, लंबे समय तक चलने वाले ऐसे वर्चुअल मशीन के लिए सही नहीं हो सकती जिनकी मेमोरी की ज़रूरत समय के साथ बदलती रहती है. relinquish हाइपरकॉल की मदद से, मेहमान पेजों का मालिकाना हक, होस्ट को वापस ट्रांसफ़र कर सकता है. इसके लिए, मेहमान को हटाने की ज़रूरत नहीं होती.
  • होस्ट के लिए मेमोरी ऐक्सेस ट्रैपिंग. आम तौर पर, अगर कोई KVM मेहमान किसी ऐसे पते को ऐक्सेस करता है जो मान्य मेमोरी क्षेत्र से मेल नहीं खाता है, तो vCPU थ्रेड होस्ट पर निकल जाता है. आम तौर पर, ऐक्सेस का इस्तेमाल MMIO के लिए किया जाता है और उपयोगकर्ता स्पेस में VMM इसे एमुलेट करता है. इस गड़बड़ी को ठीक करने के लिए, pKVM को गड़बड़ी वाले निर्देश की जानकारी, जैसे कि उसका पता, रजिस्टर पैरामीटर, और होस्ट को उनके कॉन्टेंट की जानकारी देनी होगी. अगर ट्रैप की उम्मीद नहीं थी, तो हो सकता है कि सुरक्षित मेहमान का संवेदनशील डेटा अनजाने में ज़ाहिर हो जाए. pKVM इस समस्या को हल करता है, लेकिन ऐसा तब तक होता है, जब तक मेहमान ने पहले से ही गड़बड़ी वाली आईपीए रेंज की पहचान करने के लिए, हाइपरकॉल जारी न किया हो. ऐसा करने पर, होस्ट को ट्रैप करने के लिए ऐक्सेस की अनुमति दी जाती है. इस समाधान को MMIO गार्ड कहा जाता है.

वर्चुअल I/O डिवाइस (virtio)

Virtio, पैरावर्चुअलाइज़ किए गए डिवाइसों को लागू करने और उनसे इंटरैक्ट करने के लिए, एक लोकप्रिय, पोर्टेबल, और बेहतर स्टैंडर्ड है. सुरक्षित मेहमानों को दिखाए जाने वाले ज़्यादातर डिवाइसों को virtio का इस्तेमाल करके लागू किया जाता है. Virtio, vsock के लागू होने में भी मदद करता है. इसका इस्तेमाल, सुरक्षित मेहमान और Android के बाकी हिस्सों के बीच कम्यूनिकेशन के लिए किया जाता है.

आम तौर पर, वर्चुअल मशीन मॉनिटर (VMM) की मदद से, वर्चुअल डिवाइसों को होस्ट के यूज़र स्पेस में लागू किया जाता है. यह मेहमान से वर्चुअल डिवाइस के एमएमआईओ इंटरफ़ेस तक ट्रैप की गई मेमोरी ऐक्सेस को इंटरसेप्ट करता है और उम्मीद के मुताबिक व्यवहार को एमुलेट करता है. एमएमआईओ ऐक्सेस करना अपेक्षाकृत महंगा होता है, क्योंकि डिवाइस को हर बार ऐक्सेस करने के लिए, वीएमएम में राउंड ट्रिप की ज़रूरत होती है. इसलिए, डिवाइस और मेहमान के बीच ज़्यादातर डेटा ट्रांसफ़र, मेमोरी में वर्चुअल कतार के सेट का इस्तेमाल करके होता है. वर्टिओ की एक अहम शर्त यह है कि होस्ट, मेहमान की मेमोरी को मनमुताबिक ऐक्सेस कर सकता है. यह अनुमान, वर्चुअल कतार के डिज़ाइन में साफ़ तौर पर दिखता है. इसमें मेहमान में मौजूद बफ़र के पॉइंटर हो सकते हैं, जिन्हें डिवाइस इम्यूलेशन सीधे तौर पर ऐक्सेस करना चाहता है.

हालांकि, पहले बताए गए मेमोरी शेयर करने वाले हाइपरकॉल का इस्तेमाल, वर्चुअल मशीन के डेटा बफ़र को मेन मेमोरी में शेयर करने के लिए किया जा सकता है, लेकिन यह शेयरिंग ज़रूर पेज के हिसाब से की जाती है. अगर बफ़र का साइज़ पेज के साइज़ से कम है, तो ज़रूरत से ज़्यादा डेटा शेयर हो सकता है. इसके बजाय, मेहमान को प्रॉपर्टी की विशेषताएं और उनसे जुड़ा डेटा बफ़र, दोनों को शेयर की गई मेमोरी की एक तय विंडो से बांटने के लिए कॉन्फ़िगर किया जाता है. साथ ही, ज़रूरत के हिसाब से विंडो में और उससे डेटा कॉपी (बाउंस) किया जाता है.

आभासी उपकरण

चौथी इमेज. Virtio डिवाइस

TrustZone के साथ इंटरैक्शन

हालांकि, मेहमान TrustZone से सीधे इंटरैक्ट नहीं कर सकते, लेकिन होस्ट के पास यह ज़रूरी है कि वह SMC कॉल को सुरक्षित तरीके से जारी कर सके. इन कॉल से, फ़िज़िकल ऐड्रेस वाले ऐसे मेमोरी बफ़र के बारे में पता चल सकता है जिन्हें होस्ट ऐक्सेस नहीं कर सकता. आम तौर पर, सुरक्षित सॉफ़्टवेयर को बफ़र के ऐक्सेस की जानकारी नहीं होती. इसलिए, कोई नुकसान पहुंचाने वाला होस्ट, इस बफ़र का इस्तेमाल करके, 'कनफ़्यूज़्ड डिप्टी अटैक' (डीएमए अटैक जैसा) कर सकता है. ऐसे हमलों से बचने के लिए, pKVM, EL2 पर होस्ट के सभी SMC कॉल को ट्रैप करता है. साथ ही, EL3 पर होस्ट और सुरक्षित मॉनिटर के बीच प्रॉक्सी के तौर पर काम करता है.

होस्ट से किए गए PSCI कॉल, कम से कम बदलावों के साथ EL3 फ़र्मवेयर पर फ़ॉरवर्ड किए जाते हैं. खास तौर पर, ऑनलाइन आने वाले या निलंबित होने के बाद फिर से शुरू होने वाले सीपीयू के एंट्री पॉइंट को फिर से लिखा जाता है, ताकि EL1 पर होस्ट पर वापस जाने से पहले, चरण 2 की पेज टेबल को EL2 पर इंस्टॉल किया जा सके. बूट के दौरान, यह सुरक्षा pKVM से लागू की जाती है.

यह आर्किटेक्चर, PSCI के साथ काम करने वाले SoC पर निर्भर करता है. इसके लिए, TF-A के अप-टू-डेट वर्शन को EL3 फ़र्मवेयर के तौर पर इस्तेमाल करना बेहतर होता है.

फ़र्मवेयर फ़्रेमवर्क फ़ॉर आर्म (FF-A) सामान्य और सुरक्षित दुनिया के बीच इंटरैक्शन का मानक तय करता है, खास तौर पर तब, जब कोई सुरक्षित हाइपरवाइज़र मौजूद हो. स्पेसिफ़िकेशन के एक बड़े हिस्से में, सुरक्षित वर्ल्ड के साथ मेमोरी शेयर करने के लिए एक तरीका बताया गया है. इसमें, आम मैसेज फ़ॉर्मैट और उस पेज के लिए अनुमतियों के मॉडल, दोनों का इस्तेमाल किया जाता है. pKVM, FF-A मैसेज को प्रॉक्सी करता है, ताकि यह पक्का किया जा सके कि होस्ट, सुरक्षित वर्ल्ड के साथ ऐसी मेमोरी शेयर न कर रहा हो जिसके लिए उसके पास ज़रूरी अनुमतियां नहीं हैं.

यह आर्किटेक्चर, सेफ़ वर्ल्ड सॉफ़्टवेयर पर निर्भर करता है, जो मेमोरी ऐक्सेस मॉडल को लागू करता है. इससे यह पक्का होता है कि सेफ़ वर्ल्ड में चल रहे भरोसेमंद ऐप्लिकेशन और अन्य सॉफ़्टवेयर, मेमोरी को सिर्फ़ तब ऐक्सेस कर सकते हैं, जब उसका मालिकाना हक सेफ़ वर्ल्ड के पास हो या उसे FF-A का इस्तेमाल करके, साफ़ तौर पर उसके साथ शेयर किया गया हो. एस-ईएल2 वाले सिस्टम पर, मेमोरी ऐक्सेस मॉडल को लागू करने का काम सिक्योर पार्टिशन मैनेजर कोर (एसपीएमसी) जैसे कि Hafnium को करना चाहिए. यह सुरक्षित दुनिया के लिए स्टेज 2 पेज टेबल मैनेज करता है. ऐसे सिस्टम पर जिसमें S-EL2 नहीं है, TEE, स्टेज 1 पेज टेबल के ज़रिए मेमोरी ऐक्सेस मॉडल को लागू कर सकता है.

अगर EL2 पर एसएमसी कॉल, PSCI कॉल या FF-A से तय किया गया मैसेज नहीं है, तो बिना मैनेज किए गए एसएमसी, EL3 पर फ़ॉरवर्ड कर दिए जाते हैं. यह माना जाता है कि भरोसेमंद और सुरक्षित फ़र्मवेयर, मैनेज नहीं किए गए एसएमसी को सुरक्षित तरीके से मैनेज कर सकता है. ऐसा इसलिए, क्योंकि फ़र्मवेयर को pVM आइसोलेशन को बनाए रखने के लिए ज़रूरी सावधानियों के बारे में पता होता है.

वर्चुअल मशीन मॉनिटर

crosvm एक वर्चुअल मशीन मॉनिटर (VMM) है, जो Linux के KVM इंटरफ़ेस की मदद से वर्चुअल मशीन चलाता है. crosvm को खास बनाने वाली बात यह है कि यह Rust प्रोग्रामिंग भाषा का इस्तेमाल करके, सुरक्षा पर फ़ोकस करता है. साथ ही, होस्ट कर्नेल को सुरक्षित रखने के लिए, वर्चुअल डिवाइसों के आस-पास सैंडबॉक्स बनाता है. crosvm के बारे में ज़्यादा जानने के लिए, यहां इसका आधिकारिक दस्तावेज़ देखें.

फ़ाइल डिस्क्रिप्टर और ioctls

KVM, ioctls की मदद से /dev/kvm वर्ण डिवाइस को यूज़रस्पेस में दिखाता है. ये ioctls, KVM API का हिस्सा होते हैं. ioctls इन कैटगरी में आते हैं:

  • सिस्टम ioctls क्वेरी करता है और पूरे केवीएम सबसिस्टम पर असर डालने वाले ग्लोबल एट्रिब्यूट को सेट करता है. साथ ही, पीवीएम बनाता है.
  • VM ioctls, वर्चुअल सीपीयू (vCPUs) और डिवाइस बनाने वाले एट्रिब्यूट की क्वेरी करते हैं और उन्हें सेट करते हैं. साथ ही, वे पूरे pVM पर असर डालते हैं. जैसे, मेमोरी लेआउट और वर्चुअल सीपीयू (vCPUs) और डिवाइसों की संख्या.
  • vCPU ioctls, एक वर्चुअल सीपीयू के काम को कंट्रोल करने वाले एट्रिब्यूट की क्वेरी करते हैं और उन्हें सेट करते हैं.
  • डिवाइस ioctls, एक वर्चुअल डिवाइस के काम को कंट्रोल करने वाले एट्रिब्यूट के बारे में क्वेरी करते हैं और उन्हें सेट करते हैं.

हर crosvm प्रोसेस, वर्चुअल मशीन का सिर्फ़ एक इंस्टेंस चलाती है. यह प्रोसेस, KVM_CREATE_VM सिस्टम ioctl का इस्तेमाल करके एक VM फ़ाइल डिस्क्रिप्टर बनाती है. इसका इस्तेमाल, pVM ioctls जारी करने के लिए किया जा सकता है. किसी VM FD पर KVM_CREATE_VCPU या KVM_CREATE_DEVICE ioctl, एक vCPU/डिवाइस बनाता है और नए संसाधन की जानकारी देने वाला फ़ाइल डिस्क्रिप्टर दिखाता है. किसी vCPU या डिवाइस FD पर ioctl का इस्तेमाल, उस डिवाइस को कंट्रोल करने के लिए किया जा सकता है जिसे VM FD पर ioctl का इस्तेमाल करके बनाया गया था. vCPU के लिए, इसमें मेहमान कोड को चलाने का अहम काम शामिल है.

अंदरूनी तौर पर, crosvm, एज-ट्रिगर किए गए epoll इंटरफ़ेस का इस्तेमाल करके, वीएम के फ़ाइल डिस्क्रिप्टर को कर्नेल के साथ रजिस्टर करता है. इसके बाद, जब भी किसी फ़ाइल डिस्क्रिप्टर में कोई नया इवेंट बाकी होता है, तो कर्नेल, crosvm को इसकी सूचना देता है.

pKVM में एक नई सुविधा, KVM_CAP_ARM_PROTECTED_VM जोड़ी गई है. इसका इस्तेमाल, pVM एनवायरमेंट के बारे में जानकारी पाने और किसी VM के लिए सुरक्षित मोड सेट अप करने के लिए किया जा सकता है. अगर --protected-vm फ़्लैग पास किया जाता है, तो crosvm इसका इस्तेमाल pVM बनाते समय करता है. इससे, pVM फ़र्मवेयर के लिए ज़रूरत के मुताबिक मेमोरी को क्वेरी करने और रिज़र्व करने के साथ-साथ, सुरक्षित मोड को चालू करने में मदद मिलती है.

मेमोरी का बंटवारा

वीएमएम की मेमोरी असाइन करना और इसके मेमोरी लेआउट को मैनेज करना, वीएमएम की मुख्य ज़िम्मेदारियों में से एक है. क्रोस्मम एक तय मेमोरी लेआउट जनरेट करता है, जिसके बारे में नीचे दी गई टेबल में आम तौर पर जानकारी दी गई है.

सामान्य मोड में FDT PHYS_MEMORY_END - 0x200000
खाली जगह ...
Ramdisk ALIGN_UP(KERNEL_END, 0x1000000)
कर्नेल 0x80080000
बूटलोडर 0x80200000
बीआईओएस मोड में एफ़डीटी 0x80000000
फ़िज़िकल मेमोरी का आधार 0x80000000
pVM फ़र्मवेयर 0x7FE00000
डिवाइस का स्टोरेज 0x10000 - 0x40000000

mmap की मदद से फ़िज़िकल मेमोरी को एलोकेट किया जाता है. साथ ही, KVM_SET_USER_MEMORY_REGION ioctl की मदद से, memslots नाम के मेमोरी क्षेत्रों को पॉप्युलेट करने के लिए, मेमोरी को VM को दान किया जाता है. इसलिए, मेहमान pVM की सारी मेमोरी, उसे मैनेज करने वाले crosvm इंस्टेंस को एट्रिब्यूट की जाती है. अगर होस्ट में खाली मेमोरी कम होने लगती है, तो प्रोसेस को बंद किया जा सकता है (वीएम को बंद किया जा सकता है). जब वीएम को बंद किया जाता है, तो हाइपरवाइज़र मेमोरी को अपने-आप वाइप कर देता है. इसके बाद, वह होस्ट कर्नेल में वापस आ जाता है.

सामान्य KVM में, VMM के पास मेहमान की सभी मेमोरी का ऐक्सेस होता है. pKVM की मदद से, मेहमान को मेमोरी देने पर, उसे होस्ट के फ़िज़िकल पते के स्पेस से अनमैप कर दिया जाता है. हालांकि, इसमें सिर्फ़ एक अपवाद है, वह मेमोरी जिसे मेहमान ने साफ़ तौर पर शेयर किया है, जैसे कि Virtio डिवाइसों के लिए.

मेहमान के पते के स्पेस में, एमएमआईओ क्षेत्रों को मैप नहीं किया जाता. मेहमान के इन क्षेत्रों को ऐक्सेस करने पर, उसे ट्रैप कर दिया जाता है. इस वजह से, VM FD पर I/O इवेंट होता है. इस तरीके का इस्तेमाल, वर्चुअल डिवाइसों को लागू करने के लिए किया जाता है. सुरक्षित मोड में, मेहमान को यह स्वीकार करना होगा कि इसके पते की जगह के एक क्षेत्र का इस्तेमाल, हाइपरकॉल का इस्तेमाल करके एमएमआईओ के लिए किया गया है. इससे, जानकारी के गलती से लीक होने का जोखिम कम किया जा सकता है.

समय-निर्धारण

हर वर्चुअल सीपीयू को POSIX थ्रेड से दिखाया जाता है और होस्ट के Linux शेड्यूलर से शेड्यूल किया जाता है. थ्रेड, vCPU FD पर KVM_RUN ioctl को कॉल करता है. इससे, हाइपरवाइजर, मेहमान vCPU कॉन्टेक्स्ट पर स्विच कर देता है. होस्ट शेड्यूलर, मेहमान के कॉन्टेक्स्ट में बिताए गए समय को, उससे जुड़े vCPU थ्रेड के इस्तेमाल किए गए समय के तौर पर गिना जाता है. KVM_RUN तब दिखता है, जब कोई ऐसा इवेंट होता है जिसे VMM को मैनेज करना होता है. जैसे, I/O, इंटरप्ट का खत्म होना या vCPU का रुक जाना. VMM, इवेंट को मैनेज करता है और KVM_RUN को फिर से कॉल करता है.

KVM_RUN के दौरान, होस्ट शेड्यूलर, थ्रेड को पहले से ही रोक सकता है. हालांकि, EL2 हाइपरवाइज़र कोड को लागू होने के बाद, थ्रेड को पहले से नहीं हटाया जा सकता. इस व्यवहार को कंट्रोल करने के लिए, मेहमान पीवीएम का कोई तरीका नहीं होता.

सभी vCPU थ्रेड को किसी दूसरे यूज़रस्पेस टास्क की तरह शेड्यूल किया जाता है. इसलिए, वे सभी स्टैंडर्ड QoS मैकेनिज़्म पर निर्भर होते हैं. खास तौर पर, हर वर्चुअल सीपीयू थ्रेड को फ़िज़िकल सीपीयू के हिसाब से बेहतर बनाया जा सकता है, cpuset में रखा जा सकता है, इस्तेमाल को कंट्रोल करने की सुविधा का इस्तेमाल करके उसे बेहतर या सीमित किया जा सकता है, उसकी प्राथमिकता/शेड्यूलिंग की नीति में बदलाव किया जा सकता है वगैरह.

वर्चुअल डिवाइस

crosvm कई डिवाइसों के साथ काम करता है. इनमें ये डिवाइस भी शामिल हैं:

  • कंपोज़िट डिस्क इमेज, रीड-ओनली या रीड-राइट के लिए virtio-blk
  • होस्ट के साथ कम्यूनिकेट करने के लिए vhost-vsock
  • virtio-pci as virtio transport
  • pl030 रीयल टाइम क्लॉक (आरटीसी)
  • सीरियल कम्यूनिकेशन के लिए 16550a UART

pVM फ़र्मवेयर

पीवीएम फ़र्मवेयर (pvmfw), किसी डिवाइस के बूट ROM की तरह ही pVM से चलाया जाने वाला पहला कोड है. pvmfw का मुख्य मकसद बूटस्ट्रैप को सुरक्षित करना और पीवीएम का खास सीक्रेट पता करना है. pvmfw का किसी खास ओएस के साथ इस्तेमाल नहीं किया जा सकता, जैसे कि माइक्रोड्रोइड की सुविधा लंबे समय से इस्तेमाल की जा रही है.

pvmfw बाइनरी, इसी नाम के फ़्लैश पार्टिशन में सेव होती है और इसे ओटीए का इस्तेमाल करके अपडेट किया जाता है.

डिवाइस का बूट

pKVM की सुविधा वाले डिवाइस को बूट करने के लिए, यहां दिया गया सिलसिलेवार तरीका अपनाएं:

  1. Android बूटलोडर (ABL) अपनी तय की गई सीमा से pvmfw को मेमोरी में लोड करता है और इमेज की पुष्टि करता है.
  2. एबीएल, डिवाइस आइडेंटिफ़ायर कॉम्पोज़िशन इंजन (डीआईसीई) के पास मौजूद गोपनीय जानकारी (कंपाउंड डिवाइस आइडेंटिफ़ायर (सीडीआई) और डीआईसीई सर्टिफ़िकेट चेन) को ट्रस्ट रूट से हासिल करता है.
  3. एबीएल, pvmfw के लिए ज़रूरी सीडीआई इकट्ठा करता है और उन्हें pvmfw बाइनरी में जोड़ता है.
  4. ABL, DT में linux,pkvm-guest-firmware-memory रिज़र्व्ड मेमोरी क्षेत्र का नोड जोड़ता है. इसमें pvmfw बाइनरी की जगह और साइज़ के साथ-साथ, पिछले चरण में मिले गुप्त पासकोड की जानकारी होती है.
  5. Linux और Linux पर ABL हैंड कंट्रोल, pKVM को शुरू करता है.
  6. pKVM, होस्ट के स्टेज 2 पेज टेबल से pvmfw मेमोरी क्षेत्र को अनमैप करता है और डिवाइस के चालू रहने के दौरान, उसे होस्ट (और मेहमानों) से सुरक्षित रखता है.

डिवाइस के बूट होने के बाद, Microdroid दस्तावेज़ के बूट क्रम सेक्शन में दिए गए चरणों के हिसाब से Microdroid को बूट किया जाता है.

पीवीएम बूट

pVM बनाते समय, crosvm (या कोई अन्य VMM) को इतना बड़ा स्लॉट बनाना होगा कि उसमें हाइपरवाइजर, pvmfw इमेज डाल सके. वीएमएम को उन रजिस्टर की सूची में भी शामिल किया जाता है जिनकी शुरुआती वैल्यू सेट की जा सकती है. जैसे, मुख्य vCPU के लिए x0-x14, सेकंडरी vCPU के लिए कोई नहीं. बाकी के रजिस्टर रिज़र्व रखे जाते हैं और ये सुपरवाइज़र-pvmfw एबीआई का हिस्सा हैं.

pVM के चालू होने पर, हाइपरवाइजर सबसे पहले प्राइमरी vCPU का कंट्रोल, pvmfw को सौंपता है. फ़र्मवेयर को उम्मीद है कि crosvm ने AVB से हस्ताक्षर किया गया कर्नेल लोड किया होगा, जो बूटलोडर या कोई अन्य इमेज हो सकती है. साथ ही, वह मेमोरी में जाने-पहचाने ऑफ़सेट पर, हस्ताक्षर नहीं किया गया एफ़डीटी भी लोड करेगा. pvmfw, AVB हस्ताक्षर की पुष्टि करता है. पुष्टि होने पर, वह मिले एफ़डीटी से भरोसेमंद डिवाइस ट्री जनरेट करता है. साथ ही, मेमोरी से उसके गोपनीय डेटा को मिटा देता है और पेलोड के एंट्री पॉइंट पर भेज देता है. अगर पुष्टि करने का कोई चरण पूरा नहीं होता है, तो फ़र्मवेयर PSCI SYSTEM_RESET हाइपरकॉल जारी करता है.

बूट के बीच, pVM इंस्टेंस की जानकारी एक पार्टिशन (virtio-blk device) में सेव की जाती है और pvmfw के सीक्रेट के साथ एन्क्रिप्ट की जाती है, ताकि यह पक्का किया जा सके कि, फिर से चालू होने के बाद, सीक्रेट को सही इंस्टेंस के लिए प्रावधान किया जा रहा है.