سلامة تدفق التحكم

**سلامة تدفق التحكم** (بالإنجليزية: Control-Flow Integrity، واختصاراً: CFI) هو مصطلح عام يشير إلى مجموعة من تقنيات أمان الكمبيوترالمصممة لمنع نطاق واسع من هجمات البرمجيات الخبيثة التي تحاول إعادة توجيه تدفق تنفيذ البرنامج (أي '''تدفق التحكم''').

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

يسعى المهاجمون إلى **حقن التعليمات البرمجية** في برنامج ما بهدف استغلال امتيازاته أو استخراج البيانات من مساحة الذاكرة الخاصة به. قبل أن يصبح الكود القابل للتنفيذ للقراءة فقط ممارسة شائعة (ميزة `W^X` للحماية من الكتابة والتنفيذ)، كان بإمكان المهاجمين تعديل الكود عشوائياً أثناء تشغيله، مستهدفين التحويلات المباشرة أو حتى عدم إجراء أي تحويلات على الإطلاق.

بعد الانتشار الواسع لـ `W^X`، يهدف المهاجمون إلى إعادة توجيه التنفيذ إلى منطقة منفصلة غير محمية تحتوي على التعليمات البرمجية الخبيثة المراد تشغيلها. يتم ذلك عادةً باستخدام **التحويلات غير المباشرة**: يمكن للمهاجم استبدال الجدول الافتراضي (في هجوم الحافة الأمامية) أو تغيير مكدس الاستدعاء (في هجوم الحافة الخلفية، مثل **[[البرمجة الموجهة للعودة]]**). صُممت تقنية **سلامة تدفق التحكم (CFI)** لحماية هذه التحويلات غير المباشرة ومنعها من الانتقال إلى مواقع غير مقصودة.

## التقنيات
تتضمن التقنيات المرتبطة بحماية تدفق التحكم **فصل مؤشر الكود (CPS)**، و**سلامة مؤشر الكود (CPI)**، و**كناري المكدس (Stack Canaries)**، و**مكدسات الظل (Shadow Stacks)**، و**التحقق من مؤشر الجدول الافتراضي (Virtual Table Pointer Validation)**.يمكن تصنيف هذه الحماية إلى **حبيبية خشنة (Coarse-Grained)** أو **حبيبية دقيقة (Fine-Grained)** بناءً على عدد الأهداف المقيدة. على سبيل المثال، قد يُقيد تطبيق `CFI` ذو الحبيبات الخشنة من النوع الأمامي (Forward-Edge CFI) مجموعة أهداف الاستدعاءات غير المباشرة لتشمل أي وظيفة يمكن استدعاؤها بشكل غير مباشر في البرنامج. بينما يمكن لتطبيق `CFI` ذي الحبيبات الدقيقة أن يُقيد كل موقع استدعاء غير مباشر على الوظائف التي تمتلك نفس نوع الوظيفة التي يجب استدعاؤها.بالمثل، بالنسبة لمخطط الحماية من النوع الخلفي (Backward-Edge CFI) الذي يحمي العائدات (Returns)، فإن التنفيذ ذو الحبيبات الخشنة سيسمح فقط للإجراء بالعودة إلى وظيفة من نفس النوع (والتي يمكن أن يكون هناك العديد منها، خاصة بالنسبة للنماذج الأولية الشائعة). في المقابل، يفرض التنفيذ الدقيق الحبيبات مطابقة العائد الدقيقة، مما يعني أنه لا يمكن العودة إلا إلى الوظيفة التي قامت بالاستدعاء الأصلي.

## التنفيذات
تتوفر تطبيقات ذات صلة لتقنيات سلامة تدفق التحكم في عدة منصات وأدوات، منها:Clang(ضمن إطار عمل LLVM الأوسع).Control Flow Guard من مايكروسوفت، بالإضافة إلى Return Flow Guard.Indirect Function-Call Checks من جوجل.Reuse Attack Protector (RAP).

### LLVM/Clang
يوفر إطار عمل **LLVM/Clang** خيار "CFI" الذي يعمل على **الحافة الأمامية** (forward-edge) عن طريق التحقق من الأخطاء في الجداول الافتراضية وعمليات تحويل الأنواع. يعتمد هذا الخيار على **تحسين وقت الارتباط (LTO)** لتحديد الوظائف التي يُفترض استدعاؤها في الظروف العادية. إضافة إلى ذلك، يوجد مخطط منفصل يُعرف بـ "**مكدس نداء الظل**" (Shadow Call Stack) والذي يدافع عن **الحافة الخلفية** (backward-edge) عبر التحقق من تعديلات مكدس النداء (call stack). هذا المخطط متاح حالياً فقط لمعمارية `aarch64`.

منذ عام 2018، تقوم **جوجل** بشحن نظام **[[أندرويد]]** الذي يضم نواة لينكس المجمعة باستخدام **Clang** مع تحسين وقت الارتباط (**LTO**) وتقنية **CFI**. كما أن **مكدس نداء الظل (SCS)** متاح كخيار لنواة لينكس، ويشمل ذلك استخدامه في أندرويد.

### تقنية إنتل لفرض التحكم في التدفق
تكتشف تقنية **Intel Control-flow Enforcement Technology (CET)**، وهي تقنية أمان مبنية على مستوى المعالج من إنتل، أي انتهاكات لسلامة تدفق التحكم (Control-flow Integrity) باستخدام مكونين رئيسيين: **مكدس الظل (Shadow Stack - SS)** وتتبع الفروع غير المباشر **(Indirect Branch Tracking - IBT)**.

يجب على النواة تخصيص منطقة في الذاكرة لـ **مكدس الظل (Shadow Stack)** بحيث تكون غير قابلة للكتابة لبرامج مساحة المستخدم إلا من خلال تعليمات خاصة. يخزن مكدس الظل نسخة من عنوان العودة لكل استدعاء (`CALL`). عند حدوث عملية عودة (`RET`)، يتحقق المعالج مما إذا كان عنوان الإرجاع المخزن في المكدس العادي ومكدس الظل متساويين. إذا كانت العناوين غير متطابقة، يُطلق المعالج **خطأ حماية تدفق التحكم** (`INT #21`).

يكتشف **تتبع الفرع غير المباشر (Indirect Branch Tracking - IBT)** تعليمات القفز (`JMP`) أو الاستدعاء (`CALL`) غير المباشرة التي تستهدف مواقع غير مصرح بها. يتم هذا التنفيذ بإضافة آلة حالة داخلية جديدة في المعالج.

يتغير سلوك تعليمات `JMP` و`CALL` غير المباشرة لتقوم بتبديل آلة الحالة من وضع **الخمول (IDLE)** إلى وضع **الانتظار لـ ENDBRANCH (WAIT_FOR_ENDBRANCH)**. في وضع `WAIT_FOR_ENDBRANCH`، يجب أن تكون التعليمة التالية التي سيتم تنفيذها هي تعليمة `ENDBRANCH` الجديدة (والتي تكون `ENDBR32` في وضع 32-بت أو `ENDBR64` في وضع 64-بت)، والتي بدورها تعيد آلة الحالة الداخلية إلى وضع `IDLE` مرة أخرى.

وبالتالي، يجب أن يبدأ كل هدف معتمد لتعليمات `JMP` أو `CALL` غير المباشرة بتعليمة `ENDBRANCH`. إذا كان المعالج في حالة `WAIT_FOR_ENDBRANCH` (مما يعني أن التعليمة السابقة كانت `JMP` أو `CALL` غير مباشرة) وكانت التعليمة التالية ليست `ENDBRANCH`، يقوم المعالج بإطلاق **خطأ حماية تدفق التحكم** (`INT #21`). بالنسبة للمعالجات التي لا تدعم `CET` تتبع الفرع غير المباشر، تُفسر تعليمات `ENDBRANCH` على أنها عمليات لا تفعل شيئاً (`NOPs`) وليس لها أي تأثير.

### Microsoft Control Flow Guard
أُصدرت تقنية **Control Flow Guard (CFG)** لأول مرة لنظام التشغيل ويندوز 8.1 تحديث 3 (KB3000850) في نوفمبر 2014. يمكن للمطورين دمج `CFG` في برامجهم عن طريق إضافة علامة الرابط `/guard:cf` قبل ربط البرنامج في بيئة **فيجوال ستوديو 2015** (فجول استيديو 2015) أو الإصدارات الأحدث.

اعتبارًا من تحديث Windows 10 Creators Update (ويندوز 10 الإصدار 1703)، تم تجميع نواة ويندوز باستخدام CFG. يستخدم نواة ويندوز تقنية هايبر في لمنع أكواد النواة الضارة من الكتابة فوق خريطة بتات CFG.

تعمل **Control Flow Guard (CFG)** عن طريق إنشاء **خريطة بتات (bitmap)** لكل عملية، حيث يشير البت المحدد فيها إلى أن العنوان هو وجهة صالحة. قبل إجراء كل استدعاء دالة غير مباشر، يتحقق التطبيق مما إذا كان عنوان الوجهة موجوداً في خريطة بتات. إذا لم يكن عنوان الوجهة موجوداً، يتم إنهاء البرنامج.

هذه الآلية تجعل من الصعب على المهاجمين استغلال نقاط الضعف من نوع "الاستخدام بعد التحرير" (use-after-free) عبر استبدال محتويات الكائن ثم استخدام استدعاء دالة غير مباشر لتنفيذ الشيفرة الضارة (الحمولة).

#### تفاصيل التنفيذ
بالنسبة لجميع استدعاءات الدوال غير المباشرة المحمية، تُستدعى دالة `_guard_check_icall`، والتي تقوم بتنفيذ الخطوات التالية:

# تحويل عنوان الهدف إلى إزاحة ورقم بت في خريطة البتات.
## أعلى 3 بايتات هي إزاحة البايت في خريطة البتات
## إزاحة البت هي قيمة مكونة من 5 بت. البتات الأربعة الأولى هي البتات من الرابع إلى الثامن من الترتيب المنخفض للعنوان.
## يتم تعيين البت الخامس من إزاحة البت إلى 0 إذا كان عنوان الوجهة محاذيًا لـ 0x10 (آخر أربعة بتات هي 0)، و1 إذا لم يكن كذلك.
# فحص قيمة عنوان الهدف في الخريطة النقطية
## إذا كان عنوان الهدف موجودًا في الخريطة النقطية، فارجع بدون خطأ.
## إذا لم يكن عنوان الهدف موجودًا في خريطة البتات، فقم بإنهاء البرنامج.

#### تقنيات التجاوز
هناك العديد من التقنيات العامة لتجاوز CFG:

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

### حماية التدفق الموسّع من Microsoft
لم يُصدر **eXtended Flow Guard (XFG)** رسمياً بعد، لكنه متاح حالياً ضمن برامج **ويندوز Insider** التجريبية، وقد قُدم علناً في مؤتمر BlueHat Shanghai عام 2019.

يُعد **XFG** (eXtended Flow Guard) توسيعًا لـ **CFG**، حيث يعزز الحماية من خلال التحقق من صحة **توقيعات استدعاء الدوال** (function call signatures)؛ لضمان أن استدعاءات الدوال غير المباشرة تقتصر فقط على مجموعة فرعية من الدوال التي تحمل نفس التوقيع.يُنفذ التحقق من صحة توقيع استدعاء الدالة بإضافة تعليمات برمجية لتخزين **تجزئة (hash)** الدالة المستهدفة في السجل `r10` مباشرة قبل الاستدعاء غير المباشر. كما تُخزن تجزئة الدالة المحسوبة في الذاكرة التي تسبق مباشرة رمز عنوان الوجهة. عند إجراء الاستدعاء غير المباشر، تقوم دالة التحقق الخاصة بـ `XFG` بمقارنة القيمة الموجودة في السجل `r10` بتجزئتها المخزنة في الدالة المستهدفة.

## انظر أيضا

* حماية تجاوز سعة المخزن المؤقت

## مراجع

تصنيف:أمن الحاسوب
تصنيف:صفحات بترجمات غير مراجعة