بنية AVF

يوفّر نظام التشغيل 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:

إجراءات تشغيل pKVM

الشكل 1: إجراءات التشغيل في pKVM

  1. الإعداد: يدخل برنامج الإقلاع إلى النواة العامة في EL2. يتم بعد ذلك تهيئة pKVM ووحداته من خلال رمز النواة الموثوق به في كل من EL2 وEL1. خلال هذه المرحلة، يثق EL2 في EL1، وبالتالي لا يتم تنفيذ أي رمز غير موثوق به.
  2. إزالة امتيازات النواة: ترصد النواة العامة أنّها تعمل على مستوى EL2 وتزيل امتيازاتها إلى مستوى EL1، بينما يستمر تشغيل pKVM ووحداتها على مستوى EL2.
  3. وقت التشغيل: يبدأ تشغيل النواة العامة بشكل طبيعي، ويتم تحميل جميع برامج تشغيل الأجهزة اللازمة إلى أن يتم الوصول إلى مساحة المستخدم. في هذه المرحلة، يكون pKVM جاهزًا ويتعامل مع جداول الصفحات في المرحلة 2.

تثق عملية التشغيل في برنامج الإقلاع للتحقّق من سلامة صورة النواة والحفاظ عليها خلال مرحلة التهيئة. بعد إزالة امتيازات النواة، لن يعتبرها مراقب الأجهزة الافتراضية موثوقة، وسيكون هو المسؤول عن حماية نفسه حتى إذا تم اختراق النواة.

يتيح تضمين نواة 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.

الحماية من الوصول إلى ذاكرة وحدة المعالجة المركزية

الشكل 2. حماية الوصول إلى ذاكرة وحدة المعالجة المركزية

في السابق، كان يتم تشغيل KVM مع تفعيل الترجمة في المرحلة 2 أثناء تشغيل الضيوف ومع إيقاف الترجمة في المرحلة 2 أثناء تشغيل نواة Linux المضيفة. تتيح هذه البنية إمكانية وصول ذاكرة وحدة إدارة الذاكرة (MMU) في المرحلة 1 على الجهاز المضيف إلى وحدة إدارة الذاكرة (MMU) في المرحلة 2، وبالتالي تتيح الوصول غير المحدود من الجهاز المضيف إلى صفحات ذاكرة الجهاز الضيف. من ناحية أخرى، تتيح pKVM الحماية في المرحلة 2 حتى في سياق المضيف، وتضع برنامج Hypervisor مسؤولاً عن حماية صفحات ذاكرة الجهاز الضيف بدلاً من المضيف.

تستفيد KVM بشكل كامل من ترجمة العناوين في المرحلة 2 لتنفيذ عمليات ربط معقّدة بين عناوين IP وعناوين فعلية للأنظمة الضيفة، ما يخلق وهم الذاكرة المتجاورة للأنظمة الضيفة على الرغم من التجزئة المادية. ومع ذلك، يقتصر استخدام وحدة إدارة الذاكرة (MMU) في المرحلة 2 للمضيف على التحكّم في الوصول فقط. يتم ربط المرحلة 2 من المضيف بتحديد الهوية، ما يضمن أن تكون الذاكرة المتجاورة في مساحة IPA للمضيف متجاورة في مساحة PA. تتيح هذه البنية استخدام عمليات ربط كبيرة في جدول الصفحات، وبالتالي تقلّل الضغط على مخزن مؤقت للبحث السريع عن الترجمة (TLB). بما أنّ عملية تحديد الهوية يمكن أن تفهرسها PA، يتم أيضًا استخدام المرحلة 2 من المضيف لتتبُّع ملكية الصفحة مباشرةً في جدول الصفحات.

الحماية من الوصول المباشر إلى الذاكرة (DMA)

كما هو موضّح سابقًا، فإنّ إلغاء ربط صفحات الضيف من مضيف Linux في جداول صفحات وحدة المعالجة المركزية هو خطوة ضرورية ولكنها غير كافية لحماية ذاكرة الضيف. تحتاج pKVM أيضًا إلى الحماية من عمليات الوصول إلى الذاكرة التي تجريها الأجهزة المتوافقة مع الوصول المباشر إلى الذاكرة (DMA) تحت سيطرة نواة المضيف، ومن احتمال حدوث هجوم DMA يبدأه مضيف ضار. لمنع جهاز من هذا النوع من الوصول إلى ذاكرة الضيف، يتطلّب pKVM توفّر وحدة إدارة ذاكرة الإدخال والإخراج (IOMMU) لكل جهاز متوافق مع الوصول المباشر إلى الذاكرة (DMA) في النظام، كما هو موضّح في الشكل 3.

Dma memory access protection

الشكل 3. حماية الوصول إلى الذاكرة المباشر (DMA)

كحدّ أدنى، توفّر أجهزة IOMMU وسائل لمنح وإبطال إذن الوصول للقراءة والكتابة لجهاز إلى الذاكرة الفعلية بدقة الصفحة. ومع ذلك، تحدّ هذه الأجهزة من استخدام الأجهزة في الأجهزة الافتراضية المحمية لأنّها تفترض مرحلة ثانية من عملية الربط بين المعرّف والعنوان.

لضمان العزل بين الأجهزة الافتراضية، يجب أن يكون بإمكان وحدة إدارة الإدخال والإخراج للذاكرة (IOMMU) التمييز بين معاملات الذاكرة التي يتم إنشاؤها نيابةً عن كيانات مختلفة، وذلك حتى يمكن استخدام المجموعة المناسبة من جداول الصفحات للترجمة.

بالإضافة إلى ذلك، يُعدّ تقليل مقدار الرمز البرمجي الخاص بنظام التشغيل على مستوى الشريحة (SoC) في EL2 استراتيجية أساسية لتقليل إجمالي قاعدة الحوسبة الموثوقة (TCB) في pKVM، وهو ما يتعارض مع تضمين برامج تشغيل IOMMU في برنامج Hypervisor. للتخفيف من هذه المشكلة، يكون المضيف في EL1 مسؤولاً عن مهام إدارة IOMMU المساعدة، مثل إدارة الطاقة والإعداد والتعامل مع المقاطعات عند الاقتضاء.

ومع ذلك، فإنّ وضع المضيف في موضع التحكّم في حالة الجهاز يفرض متطلبات إضافية على واجهة برمجة تطبيقات أجهزة IOMMU لضمان عدم إمكانية تجاوز عمليات التحقّق من الأذونات بأي وسائل أخرى، مثل إجراء إعادة ضبط للجهاز.

إنّ وحدة إدارة الذاكرة في نظام Arm (SMMU) هي بنية أساسية موحّدة ومتوافقة بشكل جيد مع أجهزة Arm، وتتيح إمكانية العزل والتخصيص المباشر. هذه البنية هي الحلّ المرجعي المقترَح.

ملكية الذكريات

عند بدء التشغيل، يُفترض أنّ المضيف يملك كل الذاكرة غير التابعة لبرنامج Hypervisor، ويتتبّع برنامج 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 الحالي. يتم التعامل مع المؤقتات وواجهات برمجة التطبيقات الخاصة بالمعلومات الشخصية الحساسة كجزء من رمز المحاكاة غير الموثوق به هذا.

دعم GICv3

يجب أن تضمن الواجهة بين EL1 وEL2 أن تكون حالة المقاطعة الكاملة مرئية للمضيف EL1، بما في ذلك نُسخ من سجلات برنامج المشرف ذات الصلة بالمقاطعات. يتم تحقيق مستوى الظهور هذا عادةً باستخدام مناطق ذاكرة مشتركة، واحدة لكل وحدة معالجة مركزية افتراضية.

يمكن تبسيط رمز دعم وقت التشغيل لتسجيل النظام ليتوافق فقط مع تسجيل "مقاطعة من إنشاء البرامج" (SGIR) وتسجيل "إيقاف المقاطعة" (DIR). تتطلّب البنية أن يتم دائمًا نقل التحكم إلى EL2 عند حدوث أخطاء في هذه السجلات، بينما كانت الأخطاء الأخرى مفيدة حتى الآن فقط للتخفيف من الأخطاء المطبعية. ويتم التعامل مع كل ما عدا ذلك في الأجهزة.

من جهة MMIO، تتم محاكاة كل شيء في EL1، مع إعادة استخدام جميع البنية الأساسية الحالية في KVM. أخيرًا، يتم دائمًا إعادة توجيه الانتظار حتى حدوث مقاطعة (WFI) إلى EL1، لأنّ هذا أحد بدائيات الجدولة الأساسية التي تستخدمها KVM.

الحصول على الدعم بشأن الموقّت

يجب عرض قيمة أداة المقارنة الخاصة بالمؤقّت الافتراضي على EL1 في كل عملية اعتراض WFI، كي يتمكّن EL1 من إدخال مقاطعات المؤقّت أثناء حظر وحدة المعالجة المركزية الافتراضية. يتم محاكاة المؤقت المادي بالكامل، ويتم نقل جميع المصائد إلى مستوى الامتياز 1.

معالجة MMIO

للتواصل مع برنامج مراقبة الجهاز الافتراضي (VMM) وتنفيذ محاكاة GIC، يجب إعادة توجيه عمليات اعتراض MMIO إلى المضيف في EL1 لإجراء المزيد من الفرز. يتطلّب pKVM ما يلي:

  • الوصول إلى IPA وحجمه
  • البيانات في حال الكتابة
  • Endianness of the CPU at the point of trapping

بالإضافة إلى ذلك، يتم نقل عمليات الاعتراض التي تستخدم سجلًّا للأغراض العامة (GPR) كمصدر/وجهة باستخدام سجلّ زائف مجرّد للنقل.

واجهات الضيوف

يمكن للضيف التواصل مع ضيف محمي باستخدام مجموعة من طلبات التنفيذ السريع والوصول إلى الذاكرة في المناطق المحصورة. يتم عرض Hypercalls وفقًا لمعيار SMCCC، مع حجز نطاق لتخصيص المورّد من خلال KVM. تتسم استدعاءات النظام الفائق التالية بأهمية خاصة بالنسبة إلى الأجهزة الافتراضية pKVM.

استدعاءات فائقة عامة

  • توفّر PSCI آلية عادية للضيف للتحكّم في دورة حياة وحدات المعالجة المركزية الافتراضية، بما في ذلك تفعيلها وإيقافها وإيقاف تشغيل النظام.
  • توفّر TRNG آلية عادية للضيف لطلب إنتروبيا من pKVM الذي يعيد توجيه الطلب إلى EL3. وتكون هذه الآلية مفيدة بشكل خاص في الحالات التي لا يمكن فيها الوثوق في المضيف لإجراء محاكاة افتراضية لمولّد أرقام عشوائية للأجهزة (RNG).

استدعاءات المشرف في pKVM

  • مشاركة الذكريات مع المضيف لا يمكن للمضيف في البداية الوصول إلى ذاكرة الضيف، ولكن يجب أن يتمكّن المضيف من الوصول إليها لإتاحة التواصل عبر الذاكرة المشتركة ولأجهزة المحاكاة الموازية التي تعتمد على المخازن المؤقتة المشتركة. تتيح عمليات استدعاء Hypercall لمشاركة الصفحات وإلغاء مشاركتها مع المضيف للضيف تحديد الأجزاء التي يمكن الوصول إليها من ذاكرة Android بدون الحاجة إلى مصافحة.
  • التنازل عن الذاكرة للمضيف عادةً ما تكون جميع ذاكرة الجهاز الافتراضي ملكًا له إلى أن يتم إتلافها. قد تكون هذه الحالة غير كافية للأجهزة الافتراضية التي تعمل لفترة طويلة والتي تختلف متطلبات الذاكرة فيها بمرور الوقت. تسمح عملية relinquish hypercall للضيف بنقل ملكية الصفحات بشكل صريح إلى المضيف بدون الحاجة إلى إنهاء الضيف.
  • تحديد الوصول إلى الذاكرة على الجهاز المضيف في السابق، إذا وصل ضيف KVM إلى عنوان لا يتوافق مع منطقة ذاكرة صالحة، سيتم إيقاف سلسلة المحادثات الخاصة بوحدة المعالجة المركزية الافتراضية (vCPU) ونقلها إلى المضيف، ويتم عادةً استخدام الوصول إلى MMIO ومحاكاته بواسطة VMM في مساحة المستخدم. لتسهيل عملية المعالجة هذه، يجب أن تعلن pKVM عن تفاصيل حول التعليمات التي تسبّبت في الخطأ، مثل عنوانها ومَعلمات التسجيل ومحتواها المحتمل، إلى الجهاز المضيف، ما قد يؤدي إلى الكشف عن بيانات حساسة من جهاز ضيف محمي بدون قصد إذا لم يكن من المتوقّع حدوث الخطأ. تحلّ pKVM هذه المشكلة من خلال التعامل مع هذه الأخطاء على أنّها أخطاء قاتلة ما لم يسبق أن أصدر الجهاز الضيف استدعاءً فائقًا لتحديد نطاق عنوان IP الذي تسبّب في الخطأ على أنّه نطاق يُسمح بالوصول إليه لإعادة توجيه الخطأ إلى الجهاز المضيف. يُشار إلى هذا الحل باسم MMIO guard.

جهاز الإدخال والإخراج الافتراضي (virtio)

‫Virtio هو معيار شائع وقابل للنقل ومكتمل لتنفيذ الأجهزة المحاكاة والتفاعل معها. يتم تنفيذ معظم الأجهزة المعرَّضة للضيوف المحميين باستخدام virtio. تستند Virtio أيضًا إلى تنفيذ vsock المستخدَم للتواصل بين جهاز افتراضي محمي وبقية نظام Android.

يتم عادةً تنفيذ أجهزة Virtio في مساحة المستخدم الخاصة بالمضيف من خلال VMM، الذي يعترض عمليات الوصول إلى الذاكرة المحظورة من الضيف إلى واجهة MMIO لجهاز virtio ويحاكي السلوك المتوقّع. تكون عملية الوصول إلى MMIO مكلفة نسبيًا لأنّ كل عملية وصول إلى الجهاز تتطلّب رحلة ذهاب وإياب إلى VMM والعودة، لذا يتم نقل معظم البيانات الفعلية بين الجهاز والضيف باستخدام مجموعة من قوائم virtqueue في الذاكرة. من الافتراضات الأساسية في virtio أنّه يمكن للمضيف الوصول إلى ذاكرة الجهاز الضيف بشكل عشوائي. ويظهر هذا الافتراض في تصميم virtqueue، الذي قد يحتوي على مؤشرات إلى المخازن المؤقتة في الجهاز الضيف التي من المفترض أن تصل إليها محاكاة الجهاز مباشرةً.

على الرغم من إمكانية استخدام طلبات الاستدعاء الفائق لمشاركة الذاكرة الموضّحة سابقًا لمشاركة مخازن بيانات virtio من الجهاز الضيف إلى الجهاز المضيف، يتم إجراء هذه المشاركة بالضرورة على مستوى دقة الصفحة، وقد يؤدي ذلك إلى عرض بيانات أكثر من المطلوب إذا كان حجم المخزن أصغر من حجم الصفحة. بدلاً من ذلك، يتم ضبط الجهاز الضيف لتخصيص كل من قوائم الانتظار الافتراضية ومخازن البيانات المؤقتة المقابلة من نافذة ثابتة للذاكرة المشتركة، مع نسخ البيانات (نقلها) من النافذة وإليها حسب الحاجة.

جهاز افتراضي

الشكل 4. جهاز 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) وأجهزة، كما تؤثّر في الجهاز الافتراضي المحمي (pVM) بأكمله، مثل تضمين تخطيط الذاكرة وعدد وحدات المعالجة المركزية الافتراضية (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 الثابتة، ثم لتفعيل الوضع المحمي.

تخصيص الذاكرة

تتمثل إحدى المسؤوليات الرئيسية لبرنامج VMM في تخصيص ذاكرة الجهاز الافتراضي وإدارة تصميم الذاكرة. تُنشئ crosvm تصميمًا ثابتًا للذاكرة موصوفًا بشكل عام في الجدول أدناه.

FDT في الوضع العادي PHYS_MEMORY_END - 0x200000
مساحة خالية ...
Ramdisk ALIGN_UP(KERNEL_END, 0x1000000)
Kernel 0x80080000
برنامج الإقلاع 0x80200000
FDT في وضع BIOS 0x80000000
عنوان قاعدة الذاكرة الفعلية 0x80000000
البرامج الثابتة لآلة VM الافتراضية المحمية 0x7FE00000
ذاكرة الجهاز 0x10000 - 0x40000000

يتم تخصيص الذاكرة الفعلية باستخدام mmap ويتم منح الذاكرة إلى الجهاز الظاهري لتعبئة مناطق الذاكرة، التي تُسمى memslots، باستخدام KVM_SET_USER_MEMORY_REGION ioctl. وبالتالي، يتم إسناد كل ذاكرة pVM للضيف إلى مثيل crosvm الذي يديرها، وقد يؤدي ذلك إلى إيقاف العملية (إنهاء الجهاز الافتراضي) إذا بدأ المضيف ينفد من الذاكرة الحرة. عند إيقاف جهاز افتراضي، يمحو مراقب الأجهزة الافتراضية الذاكرة تلقائيًا ويعيدها إلى نواة المضيف.

في نظام KVM العادي، يحتفظ مدير الجهاز الافتراضي (VMM) بإذن الوصول إلى جميع ذاكرة الجهاز الضيف. باستخدام pKVM، يتم إلغاء ربط ذاكرة الجهاز الافتراضي بعنوان المساحة الفعلية للجهاز المضيف عند منحها للجهاز الافتراضي. الاستثناء الوحيد هو الذاكرة التي يشاركها الضيف بشكل صريح، مثل أجهزة virtio.

تُترك مناطق MMIO في مساحة عنوان الضيف بدون ربط. يتم حظر وصول الضيف إلى هذه المناطق، ما يؤدي إلى حدث إدخال/إخراج على واصف الملف الخاص بالجهاز الظاهري. يتم استخدام هذه الآلية لتنفيذ الأجهزة الافتراضية. في الوضع المحمي، يجب أن يقر الضيف بأنّه سيتم استخدام جزء من مساحة العناوين الخاصة به في MMIO باستخدام استدعاء فائق، وذلك للحد من خطر تسرُّب المعلومات عن طريق الخطأ.

الجدولة

يتم تمثيل كل وحدة معالجة مركزية افتراضية بسلسلة POSIX ويتم جدولتها من خلال برنامج جدولة Linux المضيف. يستدعي مؤشر الترابط KVM_RUN ioctl على واصف ملف وحدة المعالجة المركزية الافتراضية، ما يؤدي إلى انتقال برنامج Hypervisor إلى سياق وحدة المعالجة المركزية الافتراضية للضيف. تحتسب أداة جدولة المضيف الوقت المنقضي في سياق الضيف كوقت مستخدَم من خلال سلسلة وحدة المعالجة المركزية الافتراضية (vCPU) المقابلة. تعرض KVM_RUN عند حدوث حدث يجب أن يتعامل معه مدير الجهاز الافتراضي، مثل الإدخال/الإخراج أو انتهاء المقاطعة أو توقّف وحدة المعالجة المركزية الافتراضية. يتعامل VMM مع الحدث ويطلب KVM_RUN مرة أخرى.

أثناء KVM_RUN، تظلّ سلسلة التعليمات قابلة للمقاطعة من خلال برنامج جدولة المضيف، باستثناء تنفيذ رمز مراقب الأجهزة الافتراضية EL2 الذي لا يمكن مقاطعته. لا تتضمّن الآلة الافتراضية الضيف pVM أي آلية للتحكّم في هذا السلوك.

وبما أنّه يتم جدولة جميع سلاسل vCPU مثل أي مهام أخرى في مساحة المستخدم، فإنّها تخضع لجميع آليات جودة الخدمة العادية. على وجه التحديد، يمكن ربط كل سلسلة محادثات لوحدة المعالجة المركزية الافتراضية بوحدات المعالجة المركزية الفعلية، ووضعها في مجموعات وحدات المعالجة المركزية، وتعزيزها أو الحدّ من استخدامها باستخدام التثبيت على مستوى الاستخدام، وتغيير أولوية/سياسة الجدولة الخاصة بها، وغير ذلك.

الأجهزة الافتراضية

يتوافق crosvm مع عدد من الأجهزة، بما في ذلك ما يلي:

  • ‫virtio-blk لصور الأقراص المركّبة، للقراءة فقط أو للقراءة والكتابة
  • vhost-vsock للتواصل مع المضيف
  • ‫virtio-pci كوسيلة نقل virtio
  • pl030 real time clock (RTC)
  • 16550a UART للتواصل التسلسلي

البرامج الثابتة لآلة VM الافتراضية المحمية

البرامج الثابتة للأجهزة الافتراضية المحمية (pvmfw) هي الرمز الأول الذي يتم تنفيذه بواسطة جهاز افتراضي محمي، على غرار ذاكرة القراءة فقط الخاصة بالتشغيل (ROM) في الأجهزة المادية. والهدف الأساسي من البرامج الثابتة للأجهزة الافتراضية المحمية هو بدء التشغيل الآمن واستخلاص السر الفريد للجهاز الافتراضي المحمي. ولا يقتصر استخدام البرامج الثابتة للأجهزة الافتراضية المحمية على أي نظام تشغيل معيّن، مثل Microdroid، طالما أنّ نظام التشغيل متوافق مع crosvm وتم توقيعه بشكل صحيح.

يتم تخزين ملف pvmfw الثنائي في قسم فلاش يحمل الاسم نفسه، ويتم تعديله باستخدام OTA.

تشغيل الجهاز

تتم إضافة تسلسل الخطوات التالي إلى إجراءات بدء تشغيل جهاز متوافق مع pKVM:

  1. يحمّل برنامج Android Bootloader (ABL) ملف pvmfw من قسمه إلى الذاكرة ويتحقّق من الصورة.
  2. يحصل ABL على أسرار Device Identifier Composition Engine (DICE) (معرّفات الأجهزة المركّبة (CDI) وسلسلة شهادات DICE) من جذر الثقة.
  3. يستمدّ ABL ملفات CDI اللازمة لـ pvmfw، ويضيفها إلى ملف pvmfw الثنائي.
  4. يضيف ABL عقدة linux,pkvm-guest-firmware-memory لمنطقة الذاكرة المحجوزة إلى شجرة الأجهزة، ويصف الموقع الجغرافي وحجم ملف pvmfw الثنائي والأسرار التي تم استخلاصها في الخطوة السابقة.
  5. تسلِّم ABL عناصر التحكّم إلى Linux، ويبدأ Linux في تهيئة pKVM.
  6. يزيل pKVM ربط منطقة ذاكرة pvmfw من جداول صفحات المرحلة 2 الخاصة بالمضيف ويحميها من المضيف (والضيوف) طوال مدة تشغيل الجهاز.

بعد تشغيل الجهاز، يتم تشغيل Microdroid وفقًا للخطوات الواردة في قسم تسلسل التشغيل من مستند Microdroid.

تشغيل الجهاز الظاهري المحمي

عند إنشاء آلة افتراضية محمية، يجب أن ينشئ crosvm (أو أي مدير آلة افتراضية آخر) فتحة ذاكرة كبيرة بما يكفي ليملأها برنامج Hypervisor بصورة pvmfw. يتم أيضًا تقييد VMM في قائمة السجلات التي يمكنه ضبط قيمتها الأولية (من x0 إلى x14 لوحدة المعالجة المركزية الافتراضية الأساسية، ولا شيء لوحدات المعالجة المركزية الافتراضية الثانوية). السجلات المتبقية محجوزة وهي جزء من واجهة ABI الخاصة ببرنامج hypervisor-pvmfw.

عند تشغيل الجهاز الافتراضي المحمي، يسلّم برنامج Hypervisor أولاً التحكّم في وحدة المعالجة المركزية الافتراضية الأساسية إلى pvmfw. تتوقّع البرامج الثابتة أن يكون crosvm قد حمّل نواة موقّعة من AVB، والتي يمكن أن تكون برنامج تحميل أو أي صورة أخرى، بالإضافة إلى شجرة FDT غير موقّعة إلى الذاكرة في إزاحات معروفة. يتحقّق pvmfw من توقيع AVB، وفي حال نجاحه، ينشئ شجرة أجهزة موثوقة من شجرة FDT المستلَمة، ويمحو أسراره من الذاكرة، وينتقل إلى نقطة الدخول للحِمل. إذا تعذّر تنفيذ إحدى خطوات التحقّق، سيصدر البرنامج الثابت استدعاء نظام SYSTEM_RESET hypercall من خلال واجهة PSCI.

يتم تخزين معلومات حول مثيل pVM بين عمليات إعادة التشغيل في قسم (جهاز virtio-blk) ويتم تشفيرها باستخدام سر pvmfw لضمان توفير السر للمثيل الصحيح بعد إعادة التشغيل.