يوفّر نظام التشغيل Android تنفيذًا مرجعيًا لجميع المكوّنات اللازمة لتنفيذ Android Virtualization Framework. في الوقت الحالي، يقتصر هذا التنفيذ على ARM64. توضّح هذه الصفحة بنية الإطار.
الخلفية
تتيح بنية Arm ما يصل إلى أربعة مستويات استثناء، حيث يكون مستوى الاستثناء 0 (EL0) هو الأقل امتيازًا، ومستوى الاستثناء 3 (EL3) هو الأكثر امتيازًا. يتم تشغيل الجزء الأكبر من قاعدة رموز Android البرمجية (جميع مكوّنات مساحة المستخدم) في مستوى EL0. أما بقية ما يُعرف عادةً باسم "Android"، فهو نواة Linux التي تعمل على مستوى EL1.
تسمح طبقة EL2 بتضمين برنامج مراقبة يتيح عزل الذاكرة والأجهزة في أجهزة pVM فردية على مستوى EL1/EL0، مع ضمانات قوية بشأن السرية والتكامل.
Hypervisor
تم إنشاء الجهاز الافتراضي المحمي المستند إلى النواة (pKVM) استنادًا إلى برنامج Linux KVM للإشراف على الأجهزة الافتراضية، الذي تم توسيعه ليشمل إمكانية حظر الوصول إلى الحِملات التي يتم تنفيذها في الأجهزة الافتراضية الضيف التي تم وضع علامة "محمي" عليها عند إنشائها.
يتوافق KVM/arm64 مع أوضاع تنفيذ مختلفة حسب توفّر ميزات معيّنة في وحدة المعالجة المركزية، وتحديدًا "إضافات مضيف المحاكاة الافتراضية" (VHE) (الإصدار ARMv8.1 والإصدارات الأحدث). في أحد هذين الوضعين، المعروف باسم وضع عدم VHE، يتم تقسيم رمز المشرف الفائق من صورة النواة أثناء التشغيل وتثبيته في 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.
تثق عملية التمهيد في برنامج الإقلاع للحفاظ على سلامة صورة النواة فقط أثناء التمهيد المبكر. عندما يتم إلغاء امتيازات النواة، لن يعود برنامج Hypervisor يعتبرها موثوقة، وبالتالي يصبح هو المسؤول عن حماية نفسه حتى إذا تم اختراق النواة.
يتيح تضمين نواة Android وبرنامج Hypervisor في صورة ثنائية واحدة إنشاء واجهة اتصال متكاملة بينهما. يضمن هذا الربط الوثيق إجراء تحديثات ذرية للمكوّنين، ما يغني عن الحاجة إلى الحفاظ على استقرار الواجهة بينهما، ويوفّر قدرًا كبيرًا من المرونة بدون التأثير في إمكانية الصيانة على المدى الطويل. يسمح الربط المحكم أيضًا بتحسين الأداء عندما يمكن للمكوّنين التعاون بدون التأثير في ضمانات الأمان التي يوفّرها برنامج Hypervisor.
علاوةً على ذلك، يتيح استخدام GKI في نظام Android الأساسي تلقائيًا نشر برنامج pKVM للإشراف على الأجهزة التي تعمل بنظام Android في الملف الثنائي نفسه الذي يتضمّن النواة.
حماية الوصول إلى ذاكرة وحدة المعالجة المركزية
تحدّد بنية Arm وحدة إدارة الذاكرة (MMU) المقسّمة إلى مرحلتين مستقلتين، ويمكن استخدام كلتا المرحلتين لتنفيذ ترجمة العناوين والتحكّم في الوصول إلى أجزاء مختلفة من الذاكرة. يتم التحكّم في وحدة إدارة الذاكرة (MMU) في المرحلة 1 من خلال EL1، وتتيح هذه الوحدة إجراء عملية ترجمة عناوين من المستوى الأول. يتم استخدام وحدة إدارة الذاكرة (MMU) في المرحلة 1 من قِبل نظام التشغيل Linux لإدارة مساحة العناوين الافتراضية الموفّرة لكل عملية في مساحة المستخدم ومساحة العناوين الافتراضية الخاصة بها.
يتم التحكّم في وحدة إدارة الذاكرة (MMU) في المرحلة 2 من خلال EL2، وتتيح تطبيق ترجمة ثانية للعناوين على عنوان الإخراج الخاص بوحدة إدارة الذاكرة (MMU) في المرحلة 1، ما يؤدي إلى عنوان فعلي (PA). يمكن أن تستخدم برامج الإشراف المرحلة الثانية من الترجمة للتحكّم في عمليات الوصول إلى الذاكرة وترجمتها من جميع الأجهزة الافتراضية الضيف. كما هو موضّح في الشكل 2، عند تفعيل كلتا مرحلتَي الترجمة، يُطلق على عنوان الإخراج في المرحلة 1 اسم العنوان الفعلي الوسيط (IPA). ملاحظة: تتم ترجمة العنوان الظاهري (VA) إلى عنوان IPA ثم إلى عنوان PA.
في السابق، كان يتم تشغيل KVM مع تفعيل الترجمة في المرحلة 2 أثناء تشغيل الأنظمة الضيف ويكون غير مفعّل أثناء تشغيل نواة Linux المضيفة. تتيح هذه البنية إمكانية وصول ذاكرة وحدة إدارة الذاكرة (MMU) في المرحلة 1 على الجهاز المضيف إلى وحدة إدارة الذاكرة (MMU) في المرحلة 2، وبالتالي تتيح الوصول غير المحدود من الجهاز المضيف إلى صفحات ذاكرة الجهاز الضيف. من ناحية أخرى، تتيح pKVM الحماية في المرحلة 2 حتى في سياق المضيف، وتضع برنامج المشرف في موضع المسؤولية عن حماية صفحات ذاكرة الجهاز الضيف بدلاً من المضيف.
تستفيد KVM بشكل كامل من ترجمة العناوين في المرحلة 2 لتنفيذ عمليات ربط معقّدة بين عناوين IPA وPA للأنظمة الضيفة، ما يخلق وهم الذاكرة المتجاورة للأنظمة الضيفة على الرغم من التجزئة المادية. ومع ذلك، يقتصر استخدام وحدة إدارة الذاكرة (MMU) في المرحلة 2 للمضيف على التحكّم في الوصول فقط. يتم ربط المرحلة 2 من المضيف بالهوية، ما يضمن أن تكون الذاكرة المتجاورة في مساحة IPA للمضيف متجاورة في مساحة PA. تتيح هذه البنية استخدام عمليات ربط كبيرة في جدول الصفحات، وبالتالي تقلل الضغط على مخزن مؤقت للبحث السريع عن الترجمة (TLB). بما أنّ عملية تحديد الهوية يمكن أن تفهرسها PA، يتم أيضًا استخدام المرحلة 2 من المضيف لتتبُّع ملكية الصفحة مباشرةً في جدول الصفحات.
الحماية من الوصول المباشر إلى الذاكرة (DMA)
كما هو موضّح سابقًا، فإنّ إلغاء ربط صفحات الضيف من مضيف Linux في جداول صفحات وحدة المعالجة المركزية هو خطوة ضرورية ولكنها غير كافية لحماية ذاكرة الضيف. ويجب أن توفّر pKVM أيضًا الحماية من عمليات الوصول إلى الذاكرة التي تجريها الأجهزة المتوافقة مع الوصول المباشر إلى الذاكرة (DMA) والخاضعة لتحكّم نواة المضيف، ومن إمكانية شنّ هجوم DMA من قِبل مضيف ضار. لمنع جهاز من هذا النوع من الوصول إلى ذاكرة الضيف، يتطلّب pKVM توفّر وحدة إدارة ذاكرة الإدخال والإخراج (IOMMU) لكل جهاز متوافق مع الوصول المباشر إلى الذاكرة (DMA) في النظام، كما هو موضّح في الشكل 3.
كحدّ أدنى، توفّر أجهزة IOMMU وسيلة لمنح إذن الوصول إلى الذاكرة الفعلية وقراءتها وكتابتها على مستوى الصفحة، كما توفّر وسيلة لإلغاء هذا الإذن. ومع ذلك، تحدّ هذه الأجهزة من استخدام الأجهزة في الأجهزة الافتراضية المحمية لأنّها تفترض مرحلة ثانية من عملية الربط بين العناوين والبيانات.
لضمان العزل بين الأجهزة الافتراضية، يجب أن يميّز IOMMU بين معاملات الذاكرة التي يتم إنشاؤها نيابةً عن كيانات مختلفة، وذلك حتى يمكن استخدام المجموعة المناسبة من جداول الصفحات للترجمة.
بالإضافة إلى ذلك، يُعدّ تقليل مقدار الرموز البرمجية الخاصة بنظام SoC في EL2 استراتيجية أساسية لتقليل إجمالي قاعدة الحوسبة الموثوقة (TCB) في pKVM، وهي تتعارض مع تضمين برامج تشغيل IOMMU في برنامج Hypervisor. للتخفيف من هذه المشكلة، يكون المضيف في مستوى EL1 مسؤولاً عن مهام إدارة IOMMU المساعدة، مثل إدارة الطاقة والإعداد والتعامل مع المقاطعات عند الاقتضاء.
ومع ذلك، فإنّ منح المضيف إذن التحكّم في حالة الجهاز يفرض متطلبات إضافية على واجهة برمجة تطبيقات أجهزة IOMMU لضمان عدم إمكانية تجاوز عمليات التحقّق من الأذونات بأي وسيلة أخرى، مثلاً بعد إعادة ضبط الجهاز.
إنّ وحدة إدارة ذاكرة النظام (SMMU) من Arm هي معيار IOMMU متوافق مع أجهزة Arm، ما يتيح إمكانية العزل والتخصيص المباشر. هذه البنية هي الحلّ المرجعي المقترَح.
ملكية الذكريات
عند بدء التشغيل، يُفترض أنّ المضيف يملك كل الذاكرة غير التابعة لبرنامج Hypervisor، ويتتبّع برنامج Hypervisor هذه الذاكرة على هذا الأساس. عند إنشاء آلة افتراضية محمية، يقدّم المضيف صفحات ذاكرة للسماح لها بالتمهيد، وينقل برنامج Hypervisor ملكية هذه الصفحات من المضيف إلى الآلة الافتراضية المحمية. وبالتالي، يفرض برنامج المشرف قيودًا على التحكّم في الوصول في جدول صفحات المرحلة 2 للمضيف لمنع الوصول إلى الصفحات مرة أخرى، ما يوفّر السرية للضيف.
يتم إتاحة التواصل بين المضيف والضيوف من خلال مشاركة الذاكرة بشكل محكوم بينهما. يُسمح للضيوف بمشاركة بعض صفحاتهم مع المضيف باستخدام استدعاء فائق، ما يوجّه المشرف إلى إعادة ربط تلك الصفحات في جدول صفحات المضيف في المرحلة 2. وبالمثل، يتمكّن المضيف من التواصل مع TrustZone من خلال عمليات مشاركة الذاكرة و/أو إقراضها، ويتم مراقبة كل هذه العمليات والتحكّم فيها عن كثب من خلال pKVM باستخدام مواصفات إطار عمل البرامج الثابتة لأجهزة Arm (FF-A).
بما أنّ متطلبات الذاكرة الخاصة بالجهاز الظاهري المحمي يمكن أن تتغيّر بمرور الوقت، يتم توفير استدعاء فائق يتيح التنازل عن ملكية صفحات معيّنة تابعة للمتصل وإعادتها إلى المضيف. في الواقع، يتم استخدام هذا الاستدعاء الفائق مع بروتوكول virtio balloon للسماح لبرنامج VMM بطلب استعادة الذاكرة من الجهاز الظاهري المحمي، وللسماح للجهاز الظاهري المحمي بإعلام برنامج VMM بالصفحات التي تم التخلي عنها، وذلك بطريقة منظَّمة.
يكون برنامج Hypervisor مسؤولاً عن تتبُّع ملكية جميع صفحات الذاكرة في النظام وما إذا كان يتم مشاركتها أو إعارتها إلى كيانات أخرى. يتم تتبُّع معظم هذه الحالات باستخدام بيانات وصفية مرفقة بجداول صفحات المرحلة 2 الخاصة بالمضيف والضيوف، وذلك باستخدام وحدات بت محجوزة في إدخالات جداول الصفحات (PTE)، وهي وحدات بت محجوزة للاستخدام في البرامج، كما يشير اسمها.
على المضيف التأكّد من عدم محاولة الوصول إلى الصفحات التي تم حظر الوصول إليها بواسطة برنامج الإشراف. يؤدي الوصول غير القانوني إلى المضيف إلى إدخال استثناء متزامن إلى المضيف من خلال برنامج Hypervisor، ما قد يؤدي إلى تلقّي مهمة مساحة المستخدم المسؤولة إشارة SEGV أو تعطُّل نواة المضيف. لمنع عمليات الوصول غير المقصودة، يمنع نظام التشغيل الأساسي للمضيف إمكانية تبديل أو دمج الصفحات التي تم منحها للضيوف.
التعامل مع المقاطعات والمؤقتات
تُعد المقاطعات جزءًا أساسيًا من طريقة تفاعل الضيف مع الأجهزة، ومن التواصل بين وحدات المعالجة المركزية، حيث تشكّل مقاطعات المعالجات المتداخلة (IPI) آلية التواصل الرئيسية. يتمثل نموذج KVM في تفويض جميع عمليات إدارة المقاطعات الافتراضية إلى المضيف في EL1، والذي يتصرف لهذا الغرض كجزء غير موثوق به من برنامج Hypervisor.
توفّر pKVM محاكاة كاملة لإصدار 3 من وحدة التحكّم العامة في المقاطعات (GICv3) استنادًا إلى رمز KVM الحالي. يتم التعامل مع المؤقتات وواجهات برمجة التطبيقات الداخلية (IPI) كجزء من رمز المحاكاة غير الموثوق به هذا.
توافق GICv3
يجب أن تضمن الواجهة بين EL1 وEL2 أن تكون حالة المقاطعة الكاملة مرئية للمضيف EL1، بما في ذلك نُسخ من سجلات برنامج المشرف المرتبطة بالمقاطعات. يتم تحقيق مستوى الظهور هذا عادةً باستخدام مناطق الذاكرة المشتركة، واحدة لكل وحدة معالجة مركزية افتراضية (vCPU).
يمكن تبسيط رمز دعم وقت التشغيل لتسجيل النظام ليتوافق فقط مع تسجيل السجلّات الخاصة بسجلّ مقاطعة البرامج (SGIR) وسجلّ إيقاف المقاطعة (DIR). تتطلّب البنية أن يتم دائمًا توجيه هذه السجلات إلى EL2، بينما كانت عمليات التوجيه الأخرى مفيدة حتى الآن فقط للتخفيف من الأخطاء المطبعية. ويتم التعامل مع كل ما عدا ذلك في الأجهزة.
من جهة MMIO، تتم محاكاة كل شيء في EL1، مع إعادة استخدام جميع البنية الأساسية الحالية في KVM. أخيرًا، يتم دائمًا إعادة توجيه Wait for Interrupt (WFI) إلى EL1، لأنّ هذا أحد بدائيات الجدولة الأساسية التي يستخدمها KVM.
الحصول على الدعم بشأن الموقّت
يجب عرض قيمة أداة المقارنة الخاصة بالمؤقّت الافتراضي على EL1 في كل عملية اعتراض WFI، كي يتمكّن EL1 من إدخال مقاطعات المؤقّت أثناء حظر وحدة المعالجة المركزية الافتراضية. يتم محاكاة المؤقت المادي بالكامل، ويتم نقل جميع عمليات الاعتراض إلى EL1.
معالجة MMIO
للتواصل مع برنامج مراقبة الجهاز الافتراضي (VMM) وتنفيذ محاكاة GIC، يجب إعادة توجيه عمليات اعتراض MMIO إلى المضيف في EL1 لإجراء المزيد من الفرز. تتطلّب pKVM ما يلي:
- عنوان IP وحجم الوصول
- البيانات في حال الكتابة
- Endianness of the CPU at the point of trapping
بالإضافة إلى ذلك، يتم نقل عمليات اعتراض ذات سجل للأغراض العامة (GPR) كمصدر/وجهة باستخدام سجلّ زائف مجرّد للنقل.
واجهات الضيوف
يمكن للضيف التواصل مع ضيف محمي باستخدام مجموعة من طلبات التنفيذ السريع والوصول إلى الذاكرة في المناطق المحصورة. يتم عرض Hypercalls وفقًا لمعيار SMCCC، مع حجز نطاق لتخصيص المورّد من خلال KVM. تتسم استدعاءات الوظائف الفائقة التالية بأهمية خاصة بالنسبة إلى الأجهزة الافتراضية pKVM.
استدعاءات النظام العامة
- توفّر واجهة PSCI آلية عادية للضيف للتحكّم في دورة حياة وحدات المعالجة المركزية الافتراضية، بما في ذلك تفعيلها وإيقافها وإيقاف تشغيل النظام.
- توفّر TRNG آلية عادية للضيف لطلب إنتروبيا من pKVM الذي يعيد توجيه الطلب إلى EL3. وتكون هذه الآلية مفيدة بشكل خاص في الحالات التي لا يمكن فيها الوثوق في المضيف لإجراء محاكاة افتراضية لمولّد أرقام عشوائية للأجهزة (RNG).
استدعاءات pKVM الفائقة
- مشاركة الذاكرة مع المضيف لا يمكن للمضيف الوصول إلى ذاكرة الضيف في البداية، ولكن يجب أن يتمكّن المضيف من الوصول إليها لإتاحة تبادل المعلومات عبر الذاكرة المشتركة ولأجهزة المحاكاة الموازية التي تعتمد على المخازن المؤقتة المشتركة. تتيح عمليات Hypercall لمشاركة الصفحات وإلغاء مشاركتها مع المضيف للضيف تحديد الأجزاء التي يمكن الوصول إليها من ذاكرة Android بدون الحاجة إلى مصافحة.
- التنازل عن الذاكرة للمضيف عادةً ما تكون جميع ذاكرة الجهاز الافتراضي مملوكة له إلى أن يتم إتلافها. قد تكون هذه الحالة غير كافية للأجهزة الافتراضية التي تعمل لفترة طويلة والتي تختلف متطلبات الذاكرة فيها بمرور الوقت. تسمح عملية استدعاء
relinquish
البرنامج الفائق للضيف بنقل ملكية الصفحات بشكل صريح إلى المضيف بدون الحاجة إلى إنهاء الضيف. - تتبُّع الوصول إلى الذاكرة على الجهاز المضيف في السابق، إذا وصل ضيف KVM إلى عنوان لا يتوافق مع منطقة ذاكرة صالحة، سيتم إنهاء سلسلة vCPU إلى المضيف، ويتم عادةً استخدام الوصول إلى MMIO ومحاكاته بواسطة VMM في مساحة المستخدم. لتسهيل عملية المعالجة هذه، يجب أن تعلن pKVM عن تفاصيل حول التعليمات التي تسبّبت في الخطأ، مثل عنوانها ومَعلمات التسجيل ومحتواها المحتمل، وذلك لإرسالها إلى الجهاز المضيف. وقد يؤدي ذلك إلى الكشف عن بيانات حساسة من جهاز ضيف محمي بدون قصد إذا لم يكن من المتوقّع حدوث الخطأ. تحلّ pKVM هذه المشكلة من خلال التعامل مع هذه الأخطاء على أنّها أخطاء خطيرة ما لم يسبق للجهاز الضيف إصدار طلب hypercall لتحديد نطاق IPA الذي تسبّب في الخطأ على أنّه نطاق يُسمح بالوصول إليه لإعادة توجيه الخطأ إلى الجهاز المضيف. يُشار إلى هذا الحل باسم MMIO guard.
جهاز الإدخال والإخراج الافتراضي (virtio)
Virtio هو معيار شائع وقابل للنقل ومكتمل لتنفيذ الأجهزة المحاكاة والتفاعل معها. يتم تنفيذ معظم الأجهزة المعرَّضة للضيوف المحميين باستخدام virtio. تستند Virtio أيضًا إلى تنفيذ vsock المستخدَم للتواصل بين جهاز افتراضي محمي وبقية نظام Android.
يتم عادةً تنفيذ أجهزة Virtio في مساحة المستخدم الخاصة بالمضيف من خلال VMM، الذي يعترض عمليات الوصول إلى الذاكرة المحاصرة من الضيف إلى واجهة MMIO لجهاز virtio ويحاكي السلوك المتوقع. تكون عمليات الوصول إلى MMIO مكلفة نسبيًا لأنّ كل عملية وصول إلى الجهاز تتطلّب رحلة ذهاب وعودة إلى VMM، لذا يتم تنفيذ معظم عمليات نقل البيانات الفعلية بين الجهاز والضيف باستخدام مجموعة من قوائم virtqueue في الذاكرة. من الافتراضات الأساسية في virtio أنّه يمكن للمضيف الوصول إلى ذاكرة الجهاز الضيف بشكل عشوائي. ويظهر هذا الافتراض في تصميم virtqueue، الذي قد يحتوي على مؤشرات إلى المخازن المؤقتة في الجهاز الضيف الذي من المفترض أن تصل إليه محاكاة الجهاز مباشرةً.
على الرغم من إمكانية استخدام طلبات الاستدعاء الفائق لمشاركة الذاكرة الموضّحة سابقًا لمشاركة مخازن بيانات virtio من الجهاز الضيف إلى الجهاز المضيف، يتم إجراء هذه المشاركة بالضرورة على مستوى دقة الصفحة، وقد يؤدي ذلك إلى عرض بيانات أكثر من المطلوب إذا كان حجم المخزن أقل من حجم الصفحة. بدلاً من ذلك، يتم ضبط الجهاز الظاهري لتخصيص كل من قوائم الانتظار الظاهرية ومخازن البيانات المؤقتة المقابلة من نافذة ثابتة للذاكرة المشتركة، مع نسخ البيانات (نقلها) من النافذة وإليها حسب الحاجة.
التفاعل مع TrustZone
على الرغم من أنّ الضيوف لا يمكنهم التفاعل مباشرةً مع TrustZone، يجب أن يظل بإمكان المضيف إصدار طلبات SMC إلى البيئة الآمنة. يمكن أن تحدّد هذه الاستدعاءات مخازن مؤقتة للذاكرة معنونة فعليًا ولا يمكن الوصول إليها من المضيف. بما أنّ البرنامج الآمن لا يكون على دراية بشكل عام بإمكانية الوصول إلى المخزن المؤقت، يمكن لمضيف ضار استخدام هذا المخزن المؤقت لتنفيذ هجوم "النائب المرتبك" (مشابه لهجوم الوصول المباشر إلى الذاكرة). لمنع مثل هذه الهجمات، تحظر pKVM جميع طلبات استدعاء SMC من المضيف إلى EL2 وتعمل كخادم وكيل بين المضيف وبرنامج المراقبة الآمن في EL3.
يتم إعادة توجيه طلبات PSCI من المضيف إلى البرنامج الثابت EL3 مع إجراء الحد الأدنى من التعديلات. على وجه التحديد، تتم إعادة كتابة نقطة الدخول لوحدة المعالجة المركزية (CPU) التي يتم تفعيلها أو استئنافها من حالة التعليق، وذلك لتثبيت جدول صفحات المرحلة 2 في EL2 قبل الرجوع إلى المضيف في EL1. أثناء عملية التشغيل، يتم فرض هذه الحماية من خلال pKVM.
تعتمد هذه البنية على توفّر PSCI في نظام SoC، ويُفضّل أن يتم ذلك من خلال استخدام إصدار حديث من 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 التي لم تتم معالجتها بأمان لأنّ البرامج الثابتة تدرك الاحتياطات اللازمة للحفاظ على عزل الآلات الافتراضية المحمية.
برنامج مراقبة الأجهزة الافتراضية
crosvm هو برنامج مراقبة للأجهزة الافتراضية (VMM) يشغّل الأجهزة الافتراضية من خلال واجهة KVM في نظام التشغيل Linux. ما يميّز crosvm هو تركيزها على الأمان من خلال استخدام لغة البرمجة Rust ووضع الحماية حول الأجهزة الافتراضية لحماية نواة المضيف. لمزيد من المعلومات عن crosvm، يمكنك الاطّلاع على المستندات الرسمية هنا.
واصفات الملفات وioctls
تعرض KVM جهاز /dev/kvm
للمستخدمين مع ioctls التي تشكّل واجهة برمجة تطبيقات KVM. تنتمي عمليات ioctl إلى الفئات التالية:
- تستعلم أو تضبط طلبات ioctl للنظام سمات عامة تؤثر في نظام KVM الفرعي بأكمله، وتنشئ آلات افتراضية محمية.
- تستعلم طلبات ioctl الخاصة بالأجهزة الافتراضية عن السمات وتضبطها، وهي السمات التي تنشئ وحدات معالجة مركزية افتراضية (vCPU) وأجهزة، وتؤثر في جهاز افتراضي محمي بالكامل، مثل تضمين تخطيط الذاكرة وعدد وحدات المعالجة المركزية الافتراضية (vCPU) والأجهزة.
- تستعلم vCPU ioctls عن السمات التي تتحكّم في تشغيل وحدة معالجة مركزية افتراضية واحدة وتضبطها.
- طلب البحث عن سمات ioctls للجهاز وضبطها، وهي السمات التي تتحكّم في تشغيل جهاز افتراضي واحد.
يشغّل كل عملية crosvm مثيلاً واحدًا بالضبط من جهاز افتراضي. تستخدم هذه العملية وظيفة KVM_CREATE_VM
ioctl في النظام لإنشاء واصف ملف آلة افتراضية يمكن استخدامه لإصدار وظائف ioctl في الآلة الافتراضية المحمية. يؤدي تنفيذ KVM_CREATE_VCPU
أو KVM_CREATE_DEVICE
ioctl
على واصف ملف جهاز افتراضي إلى إنشاء وحدة معالجة مركزية افتراضية/جهاز افتراضي وعرض واصف ملف يشير إلى
المورد الجديد. ويمكن استخدام ioctl على واصف ملف وحدة معالجة مركزية افتراضية أو جهاز افتراضي للتحكّم في الجهاز
الذي تم إنشاؤه باستخدام ioctl على واصف ملف جهاز افتراضي. بالنسبة إلى وحدات المعالجة المركزية الافتراضية، يشمل ذلك المهمة المهمة المتمثلة في تنفيذ رمز الضيف.
داخليًا، يسجّل crosvm واصفات الملفات الخاصة بالجهاز الافتراضي في النواة باستخدام واجهة epoll
التي يتم تشغيلها عند الحافة. بعد ذلك، يُعلم النواة crosvm كلما كان هناك حدث جديد معلّق في أي من واصفات الملفات.
تضيف pKVM إمكانية جديدة، وهي KVM_CAP_ARM_PROTECTED_VM
، التي يمكن استخدامها للحصول على معلومات حول بيئة pVM وإعداد الوضع المحمي لجهاز افتراضي. تستخدم crosvm هذه الإمكانية أثناء إنشاء pVM إذا تم تمرير العلامة --protected-vm
، وذلك للاستعلام عن مقدار الذاكرة المناسب وحجزه لبرامج pVM الثابتة، ثم لتفعيل الوضع المحمي.
تخصيص الذاكرة
تتمثل إحدى المسؤوليات الرئيسية لمدير الجهاز الافتراضي في تخصيص ذاكرة الجهاز الافتراضي وإدارة تصميم الذاكرة. تُنشئ crosvm تصميمًا ثابتًا للذاكرة موصوفًا بشكل عام في الجدول أدناه.
FDT في الوضع العادي | PHYS_MEMORY_END - 0x200000
|
إخلاء مساحة | ...
|
Ramdisk | ALIGN_UP(KERNEL_END, 0x1000000)
|
فرقعة | 0x80080000
|
برنامج الإقلاع | 0x80200000
|
FDT في وضع BIOS | 0x80000000
|
عنوان قاعدة الذاكرة الفعلية | 0x80000000
|
البرامج الثابتة للآلة الافتراضية المحمية | 0x7FE00000
|
ذاكرة الجهاز | 0x10000 - 0x40000000
|
يتم تخصيص الذاكرة الفعلية باستخدام mmap
ويتم منح الذاكرة إلى الجهاز الظاهري لتعبئة مناطق الذاكرة، التي تُسمى memslots، باستخدام KVM_SET_USER_MEMORY_REGION
ioctl. وبالتالي، يتم إسناد كل ذاكرة pVM للضيف إلى مثيل crosvm الذي يديرها، ويمكن أن يؤدي ذلك إلى إيقاف العملية (إنهاء الآلة الافتراضية) إذا بدأ المضيف ينفد من الذاكرة الحرة. عند إيقاف جهاز افتراضي، يمحو المشرف الذاكرة تلقائيًا ويعيدها إلى نواة المضيف.
في نظام KVM العادي، يحتفظ برنامج VMM بإذن الوصول إلى جميع ذاكرة الجهاز الضيف. باستخدام pKVM، تتم إزالة ربط ذاكرة الجهاز الافتراضي من مساحة العنوان الفعلي للجهاز المضيف عند منحها للجهاز الافتراضي. الاستثناء الوحيد هو الذاكرة التي يشاركها الضيف بشكل صريح، مثل أجهزة virtio.
تُترك مناطق MMIO في مساحة عنوان الضيف بدون ربط. يتم حظر وصول الضيف إلى هذه المناطق، ما يؤدي إلى حدث إدخال/إخراج على واصف الملف الخاص بالجهاز الظاهري. يتم استخدام هذه الآلية لتنفيذ الأجهزة الافتراضية. في الوضع المحمي، يجب أن يقر الضيف بأنّه سيتم استخدام جزء من مساحة العناوين الخاصة به في MMIO باستخدام استدعاء فائق، وذلك للحد من خطر تسرُّب المعلومات عن طريق الخطأ.
الجدولة
يتم تمثيل كل وحدة معالجة مركزية افتراضية (CPU) بسلسلة POSIX ويتم جدولتها من خلال برنامج جدولة Linux المضيف. يُصدر مؤشر الترابط طلب KVM_RUN
ioctl على واصف ملف وحدة المعالجة المركزية الافتراضية، ما يؤدي إلى انتقال برنامج Hypervisor إلى سياق وحدة المعالجة المركزية الافتراضية للضيف. يحتسب برنامج جدولة المضيف الوقت المنقضي في سياق الضيف كوقت مستخدَم من خلال سلسلة وحدات المعالجة المركزية الافتراضية المقابلة. تعرض KVM_RUN
عند حدوث حدث يجب أن يتعامل معه
مدير الجهاز الافتراضي (VMM)، مثل الإدخال/الإخراج أو انتهاء المقاطعة أو توقّف وحدة المعالجة المركزية الافتراضية (vCPU). يتعامل VMM مع الحدث ويطلب KVM_RUN
مرة أخرى.
أثناء KVM_RUN
، يظلّ بإمكان برنامج جدولة المضيف إيقاف مؤقت لسلسلة التعليمات، باستثناء تنفيذ رمز برنامج الإشراف EL2 الذي لا يمكن إيقافه مؤقتًا. ولا تتضمّن الآلة الافتراضية الضيف أي آلية للتحكّم في هذا السلوك.
بما أنّ جميع سلاسل vCPU تتم جدولتها مثل أي مهام أخرى في مساحة المستخدم، فإنّها تخضع لجميع آليات جودة الخدمة العادية. على وجه التحديد، يمكن ربط كل سلسلة محادثات لوحدة المعالجة المركزية الافتراضية بوحدات المعالجة المركزية الفعلية، ووضعها في مجموعات وحدات المعالجة المركزية، وتعزيزها أو الحدّ من استخدامها باستخدام التثبيت على معدل الاستخدام، وتغيير الأولوية أو سياسة الجدولة، وغير ذلك.
الأجهزة الافتراضية
يتوافق crosvm مع عدد من الأجهزة، بما في ذلك ما يلي:
- virtio-blk لصور الأقراص المركّبة، للقراءة فقط أو للقراءة والكتابة
- vhost-vsock للتواصل مع المضيف
- virtio-pci كبروتوكول نقل virtio
- pl030 real time clock (RTC)
- 16550a UART للتواصل التسلسلي
البرامج الثابتة للآلة الافتراضية المحمية
البرامج الثابتة للأجهزة الافتراضية المحمية (pvmfw) هي الرمز الأول الذي يتم تنفيذه بواسطة جهاز افتراضي محمي، وهي تشبه ذاكرة القراءة فقط الخاصة بالتمهيد في الأجهزة المادية. والهدف الأساسي من البرامج الثابتة للأجهزة الافتراضية المحمية هو بدء التمهيد الآمن واستخلاص السر الفريد للجهاز الافتراضي المحمي. ولا يقتصر استخدام البرامج الثابتة للأجهزة الافتراضية المحمية على أي نظام تشغيل معيّن، مثل Microdroid، طالما أنّ نظام التشغيل متوافق مع crosvm وتم توقيعه بشكل صحيح.
يتم تخزين ملف pvmfw الثنائي في قسم فلاش بالاسم نفسه ويتم تعديله باستخدام OTA.
تشغيل الجهاز
تتم إضافة تسلسل الخطوات التالي إلى إجراءات بدء تشغيل جهاز متوافق مع pKVM:
- يحمّل برنامج Android Bootloader (ABL) ملف pvmfw من قسمه إلى الذاكرة ويتحقّق من الصورة.
- يحصل ABL على أسرار Device Identifier Composition Engine (DICE) (معرّفات الأجهزة المركّبة (CDI) وسلسلة شهادات DICE) من Root of Trust.
- يستمدّ ABL ملفات CDI اللازمة لـ pvmfw، ويضيفها إلى ملف pvmfw الثنائي.
- يضيف ABL عقدة
linux,pkvm-guest-firmware-memory
لمنطقة الذاكرة المحجوزة إلى شجرة الأجهزة، ويصف الموقع الجغرافي وحجم ملف pvmfw الثنائي والأسرار التي تم استخلاصها في الخطوة السابقة. - يسلّم ABL عناصر التحكّم إلى Linux، ويبدأ Linux في تهيئة pKVM.
- يزيل pKVM ربط منطقة ذاكرة pvmfw من جداول صفحات المرحلة 2 الخاصة بالمضيف ويحميها من المضيف (والضيوف) طوال مدة تشغيل الجهاز.
بعد تشغيل الجهاز، يتم تشغيل Microdroid وفقًا للخطوات الواردة في قسم تسلسل التشغيل من مستند Microdroid.
تشغيل الجهاز الظاهري المحمي (pVM)
عند إنشاء آلة افتراضية محمية، يجب أن ينشئ crosvm (أو أي مدير آلة افتراضية آخر) memslot كبيرًا بما يكفي ليتم ملؤه بصورة pvmfw من خلال برنامج Hypervisor. يتم أيضًا تقييد VMM في قائمة السجلات التي يمكنه ضبط قيمتها الأولية (من x0 إلى x14 لوحدة المعالجة المركزية الافتراضية الأساسية، ولا شيء لوحدات المعالجة المركزية الافتراضية الثانوية). بقية السجلات محجوزة وهي جزء من واجهة التطبيق الثنائية (ABI) الخاصة ببرنامج hypervisor-pvmfw.
عند تشغيل الجهاز الافتراضي المحمي، يسلّم برنامج Hypervisor أولاً التحكّم في وحدة المعالجة المركزية الافتراضية الأساسية إلى pvmfw. تتوقّع البرامج الثابتة أن يكون crosvm قد حمّل نواة موقّعة من AVB،
والتي يمكن أن تكون برنامج إقلاع أو أي صورة أخرى، بالإضافة إلى شجرة FDT غير موقّعة إلى الذاكرة في
إزاحات معروفة. يتحقّق pvmfw من توقيع AVB، وفي حال نجاحه،
ينشئ شجرة أجهزة موثوقة من شجرة FDT التي تم تلقّيها، ويمحو أسراره من
الذاكرة، وينتقل إلى نقطة الدخول للحِمل. إذا تعذّر تنفيذ إحدى خطوات التحقّق، سيصدر البرنامج الثابت استدعاء نظام SYSTEM_RESET
hypercall من خلال واجهة PSCI.
بين عمليات إعادة التشغيل، يتم تخزين معلومات حول مثيل pVM في قسم (جهاز virtio-blk) ويتم تشفيرها باستخدام سر pvmfw لضمان توفير السر للمثيل الصحيح بعد إعادة التشغيل.