تنفيذ dm-verity

يدعم الإصدار 4.4 من نظام التشغيل Android والإصدارات الأحدث التمهيد المعتمد من خلال ميزة kernel (dm-verity) الاختيارية التي توفر فحصًا شفافًا لسلامة الأجهزة المحظورة. يساعد dm-verity في منع الجذور الخفية المستمرة التي يمكنها الاحتفاظ بامتيازات الجذر وتعريض الأجهزة للخطر. تساعد هذه الميزة مستخدمي Android على التأكد عند تشغيل الجهاز من أنه في نفس الحالة التي تم استخدامه بها آخر مرة.

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

تتيح لك ميزة dm-verity إلقاء نظرة على جهاز الحظر ، وطبقة التخزين الأساسية لنظام الملفات ، وتحديد ما إذا كان يطابق التكوين المتوقع. يقوم بذلك باستخدام شجرة تجزئة مشفرة. لكل كتلة (عادةً 4k) ، هناك تجزئة SHA256.

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

dm- الحقيقة- جدول التجزئة

الشكل 1. جدول تجزئة dm-verity

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

عملية

تعيش حماية dm-verity في النواة. لذلك إذا كان برنامج التجذير يضر بالنظام قبل ظهور النواة ، فسيحتفظ بهذا الوصول. للتخفيف من هذه المخاطر ، تتحقق معظم الشركات المصنعة من النواة باستخدام مفتاح تم نسخه في الجهاز. لا يمكن تغيير هذا المفتاح بمجرد مغادرة الجهاز للمصنع.

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

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

بدلاً من ذلك ، يتحقق dm-verity من الكتل بشكل فردي وفقط عند الوصول إلى كل منها. عند قراءتها في الذاكرة ، يتم تجزئة الكتلة بالتوازي. ثم يتم التحقق من التجزئة فوق الشجرة. ونظرًا لأن قراءة الكتلة عملية باهظة الثمن ، فإن زمن الانتقال الذي يقدمه هذا التحقق على مستوى الكتلة هو اسمي نسبيًا.

في حالة فشل التحقق ، يقوم الجهاز بإنشاء خطأ إدخال / إخراج يشير إلى تعذر قراءة الكتلة. سيظهر كما لو أن نظام الملفات تالف كما هو متوقع.

قد تختار التطبيقات المتابعة بدون البيانات الناتجة ، على سبيل المثال عندما لا تكون هذه النتائج مطلوبة للوظيفة الأساسية للتطبيق. ومع ذلك ، إذا تعذر على التطبيق المتابعة بدون البيانات ، فسوف يفشل.

تصحيح الخطأ المرسل

يعمل Android 7.0 والإصدارات الأحدث على تحسين قوة dm-verity من خلال تصحيح الخطأ الأمامي (FEC). يبدأ تطبيق AOSP بكود Reed-Solomon الشائع لتصحيح الأخطاء ويطبق تقنية تسمى interleaving لتقليل المساحة الزائدة وزيادة عدد الكتل التالفة التي يمكن استعادتها. لمزيد من التفاصيل حول FEC ، راجع التمهيد المعتمد بفرض صارم مع تصحيح الخطأ .

تطبيق

ملخص

  1. قم بإنشاء صورة نظام ext4.
  2. قم بإنشاء شجرة تجزئة لتلك الصورة.
  3. قم ببناء جدول dm-verity لشجرة التجزئة هذه.
  4. قم بتسجيل جدول dm-verity لإنتاج توقيع الجدول.
  5. قم بتجميع توقيع الجدول وجدول dm-verity في بيانات وصفية حقيقية.
  6. اربط صورة النظام وبيانات تعريف الحقيقة وشجرة التجزئة.

راجع TheChromium Projects - التحقق من التمهيد للحصول على وصف تفصيلي لشجرة التجزئة وجدول dm-verity.

توليد شجرة التجزئة

كما هو موضح في المقدمة ، فإن شجرة التجزئة جزء لا يتجزأ من dm-verity. ستنشئ أداة التشفير شجرة تجزئة لك. بدلاً من ذلك ، يتم تعريف متوافق هنا:

<your block device name> <your block device name> <block size> <block size> <image size in blocks> <image size in blocks + 8> <root hash> <salt>

لتكوين التجزئة ، يتم تقسيم صورة النظام عند الطبقة 0 إلى كتل 4k ، كل منها يتم تعيين تجزئة SHA256. تتشكل الطبقة الأولى من خلال ضم تجزئات SHA256 هذه فقط إلى كتل 4k ، مما ينتج عنه صورة أصغر بكثير. يتم تكوين الطبقة 2 بشكل متماثل ، باستخدام تجزئات SHA256 للطبقة 1.

يتم ذلك حتى يمكن احتواء تجزئات SHA256 للطبقة السابقة في كتلة واحدة. عندما تحصل على SHA256 لتلك الكتلة ، يكون لديك تجزئة جذر الشجرة.

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

إذا كان لديك كتلة في طبقة لم يتم ملؤها بشكل طبيعي بالكامل بواسطة تجزئات الطبقة السابقة ، فيجب أن تقوم بتثبيتها بالأصفار لتحقيق 4K المتوقع. يتيح لك هذا معرفة أن شجرة التجزئة لم تتم إزالتها ويتم استكمالها ببيانات فارغة بدلاً من ذلك.

لإنشاء شجرة التجزئة ، قم بتجميع تجزئات الطبقة 2 على تلك الخاصة بالطبقة 1 ، والطبقة 3 تجزئات على تلك الموجودة في الطبقة 2 ، وهكذا. اكتب كل هذا على القرص. لاحظ أن هذا لا يشير إلى الطبقة 0 من تجزئة الجذر.

للتلخيص ، الخوارزمية العامة لبناء شجرة التجزئة هي كما يلي:

  1. اختر ملحًا عشوائيًا (ترميز سداسي عشري).
  2. قم بتحويل صورة النظام إلى كتل 4K.
  3. لكل كتلة ، احصل على تجزئة SHA256 (المملحة).
  4. اربط هذه التجزئات لتشكيل مستوى
  5. ضع المستوى الذي يحتوي على 0 ثانية على حد الكتلة 4K.
  6. اربط المستوى بشجرة التجزئة.
  7. كرر الخطوات من 2 إلى 6 باستخدام المستوى السابق كمصدر للمستوى التالي حتى يكون لديك تجزئة واحدة فقط.

نتيجة ذلك هي تجزئة واحدة ، وهي تجزئة الجذر. يتم استخدام هذا والملح الخاص بك أثناء إنشاء جدول رسم خرائط dm-verity.

بناء جدول رسم الخرائط dm-verity

قم ببناء جدول تعيين dm-verity ، الذي يحدد جهاز الكتلة (أو الهدف) للنواة وموقع شجرة التجزئة (وهي نفس القيمة.) يُستخدم هذا التعيين لإنشاء fstab والتمهيد. يحدد الجدول أيضًا حجم الكتل و hash_start ، موقع بدء شجرة التجزئة (على وجه التحديد ، رقم الكتلة الخاص بها من بداية الصورة).

راجع إعداد التشفير للحصول على وصف تفصيلي لحقول جدول تعيين هدف الحقيقة.

التوقيع على جدول dm-verity

قم بتوقيع جدول dm-verity لإنتاج توقيع الجدول. عند التحقق من أحد الأقسام ، يتم التحقق من صحة توقيع الجدول أولاً. يتم ذلك مقابل مفتاح في صورة التمهيد الخاصة بك في مكان ثابت. عادةً ما يتم تضمين المفاتيح في أنظمة إنشاء الشركات المصنعة للتضمين التلقائي في الأجهزة الموجودة في موقع ثابت.

للتحقق من القسم باستخدام هذا التوقيع ومجموعة المفاتيح:

  1. أضف مفتاح RSA-2048 بتنسيق متوافق مع libmincrypt إلى قسم /boot في /verity_key . حدد موقع المفتاح المستخدم للتحقق من شجرة التجزئة.
  2. في fstab للإدخال ذي الصلة ، أضف verify إلى إشارات fs_mgr .

تجميع توقيع الجدول في البيانات الوصفية

قم بتجميع توقيع الجدول وجدول dm-verity في بيانات وصفية حقيقية. يتم إصدار كتلة البيانات الوصفية بالكامل بحيث يمكن توسيعها ، مثل إضافة نوع ثانٍ من التوقيع أو تغيير بعض الترتيب.

كتحقق من الصحة ، يتم ربط رقم سحري بكل مجموعة من البيانات الوصفية للجدول التي تساعد في تحديد الجدول. نظرًا لأن الطول مضمن في رأس صورة نظام ext4 ، فإن هذا يوفر طريقة للبحث عن البيانات الوصفية دون معرفة محتويات البيانات نفسها.

هذا يضمن أنك لم تختر التحقق من قسم لم يتم التحقق منه. إذا كان الأمر كذلك ، فإن عدم وجود هذا الرقم السحري سيوقف عملية التحقق. هذا الرقم يشبه:
0xb001b001

قيم البايت في النظام الست عشري هي:

  • البايت الأول = b0
  • البايت الثاني = 01
  • البايت الثالث = b0
  • البايت الرابع = 01

الرسم البياني التالي يصور تفصيل البيانات الوصفية للحقيقة:

<magic number>|<version>|<signature>|<table length>|<table>|<padding>
\-------------------------------------------------------------------/
\----------------------------------------------------------/   |
                            |                                  |
                            |                                 32K
                       block content

ويصف هذا الجدول حقول البيانات الوصفية.

الجدول 1. حقول واصفات البيانات الحقيقية

مجال غاية مقاس قيمة
الرقم السحري المستخدمة من قبل fs_mgr كتحقق من الصحة 4 بايت 0xb001b001
إصدار تستخدم لإصدار كتلة البيانات الوصفية 4 بايت حاليا 0
إمضاء توقيع الجدول في شكل PKCS1.5 مبطن 256 بايت
طول الجدول طول جدول dm-verity بالبايت 4 بايت
طاولة جدول dm-verity الموصوف سابقًا طول الجدول بايت
حشوة هذا الهيكل مبطن من 0 إلى 32 كيلو في الطول 0

تحسين صحة DM

للحصول على أفضل أداء من dm-verity ، يجب عليك:

  • في النواة ، قم بتشغيل NEON SHA-2 لـ ARMv7 وامتدادات SHA-2 لـ ARMv8.
  • جرب إعدادات مختلفة للقراءة المسبقة والجلب المسبق للكتلة للعثور على أفضل تكوين لجهازك.