تنفيذ dm-verity

يدعم نظام التشغيل Android 4.4 والإصدارات الأحدث عملية التحقق من التمهيد من خلال ميزة 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 ويطبق تقنية تسمى التشذير لتقليل المساحة الزائدة وزيادة عدد الكتل التالفة التي يمكن استعادتها. لمزيد من التفاصيل حول FEC، راجع التمهيد الذي تم التحقق منه بشكل صارم مع تصحيح الأخطاء .

تطبيق

ملخص

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

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

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

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

<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، مما ينتج عنه صورة أصغر بكثير. يتم تشكيل الطبقة الثانية بشكل مماثل، مع تجزئات SHA256 للطبقة الأولى.

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

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

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

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

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

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

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

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

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

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

التوقيع على جدول 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.
  • قم بتجربة إعدادات مختلفة للقراءة المسبقة والجلب المسبق للعثور على أفضل تكوين لجهازك.