متطلبات البرمجة الآمنة من ناحية الذاكرة تعيد تشكيل طريقة كتابة برمجيات النظم في غوغل ومايكروسوفت ونواة لينكس

مشاركة:
متطلبات البرمجة الآمنة من ناحية الذاكرة تعيد تشكيل طريقة كتابة برمجيات النظم في غوغل ومايكروسوفت ونواة لينكس

في فبراير 2024، نشر مكتب المدير الوطني للأمن السيبراني في البيت الأبيض تقريراً بعنوان بسيط وحجة واضحة: نحو 70 بالمئة من الثغرات التي تصلحها مايكروسوفت وغوغل كل عام مصدرها أخطاء سلامة الذاكرة — تجاوز سعة المخزن المؤقت (buffer overflow)، والاستخدام بعد التحرير (use-after-free)، والقراءة خارج الحدود — وهي تماماً الفئة من الأخطاء التي تجعل لغتي C و C++ سهلتي الكتابة وصعبتي الاكتشاف. بعد عامين، لم تعد هذه الحجة مجرد نقطة حوارية، بل أصبحت بنداً فعلياً في كيفية تخطيط أكبر شركات البرمجيات للأعمال الجديدة.

تقارير الشفافية الخاصة بغوغل حول أندرويد هي الدليل الأوضح على أن هذا ليس مجرد خطاب. في عام 2019، مثّلت أخطاء سلامة الذاكرة نحو 76 بالمئة من الثغرات الخطيرة في أندرويد. وبحسب آخر التقارير، تراجعت هذه النسبة إلى أوائل العشرينيات بالمئة — ليس لأن الكود القديم بلغتي C و C++ أُعيدت كتابته، بل لأن السياسة تغيّرت: الكود الجديد المضاف إلى أندرويد منذ عام 2019 يُكتب افتراضياً بلغات آمنة من ناحية الذاكرة، معظمها Rust و Kotlin، ومعدل الثغرات في هذا الكود الجديد كان قريباً من الصفر. خلاصة غوغل، كما ذُكرت صريحة في مدونتها الأمنية، هي أن خطر قاعدة الكود يتناسب مع حجم الكود الجديد غير الآمن الذي تستمر في كتابته، لا مع إجمالي حجم قاعدة الكود.

أين تحدث إعادة الكتابة فعلياً

تُعد نواة لينكس الحالة الاختبارية الأكثر أهمية، لأن أخطاء النواة هي الهدف الأعلى قيمة في هذا المجال — فخطأ واحد في سلامة الذاكرة داخل أحد التعريفات يمكن أن يتحول إلى هروب من البيئة المعزولة أو اختراق كامل للنظام. دُمج دعم Rust في الفرع الرئيسي للنواة في أواخر عام 2022، وبحلول عام 2026 لم يعد مجرد بنية تجريبية. توجد الآن تعريفات إنتاجية بلغة Rust لوحدات تحكم تخزين NVMe، ولآلية Binder IPC في أندرويد — وهي من أكثر أسطح النواة التي تتعرض للهجوم في كل هاتف أندرويد — وللمعالجات الرسومية في شرائح أبل الخاصة عبر تعريف AGX التابع لمشروع Asahi Linux. لا شيء من هذا يستبدل الكود القديم بلغة C بالكامل؛ بل هي أنظمة فرعية جديدة أو إعادة كتابة لمكونات معينة عرضة للهجوم، اختيرت لأنها تقع مباشرة في مسار المدخلات غير الموثوقة.

كانت مايكروسوفت أكثر هدوءاً في التصريحات العلنية، لكنها نشطة بنفس القدر داخلياً. قال مارك روسينوفيتش، كبير مسؤولي التقنية في Azure، علناً إن المشاريع الجديدة في مجال النظم بمايكروسوفت تستخدم Rust افتراضياً ما لم يكن هناك سبب محدد يمنع ذلك، وأُعيدت كتابة أجزاء من مكدس عرض النصوص والخطوط في ويندوز — الذي كان تاريخياً مصدراً غنياً لأخطاء تنفيذ الكود عن بُعد لأن الخطوط هي مدخلات غير موثوقة يتحكم فيها المهاجم ويتم تحليلها بعمق داخل النواة — بلغة Rust تحت اسم DWriteCore. تحليل الخطوط مثال كلاسيكي على سبب أهمية هذا الأمر: فهو تماماً نوع الكود الذي يأخذ بايتات مرسلة من المهاجم ويطبق عليها عمليات حسابية على المؤشرات (pointer arithmetic).

اتخذ متصفح Chrome نهجاً أضيق لكنه لا يزال ملفتاً. فبدلاً من إعادة كتابة كاملة، دفعت غوغل Rust إلى محللات عالية الخطورة محددة — برامج فك ترميز الصور، وJSON، وبعض معالجة بروتوكولات الشبكة — مع ترك الجزء الأكبر من كود C++ في Chromium كما هو وتعزيزه بتقنيات مثل MiraclePtr، التي تحوّل أخطاء الاستخدام بعد التحرير إلى أعطال آمنة بدلاً من تلف ذاكرة قابل للاستغلال. هذا هو المسار الوسطي الواقعي لقاعدة كود تضم ثلاثين مليون سطر: محللات جديدة بلغة Rust، وكود قديم مُعزز بدلاً من إعادة كتابته.

لماذا لن تختفي لغتا C و C++

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

الخطر الجديد الذي يخلقه هذا يكمن في نقاط الالتقاء. كل مكوّن Rust مُدمج داخل قاعدة كود أكبر بلغة C/C++ يحتاج إلى حد واجهة استدعاء خارجية (FFI)، وحدود FFI هي بالضبط حيث تتوقف ضمانات سلامة Rust عن التطبيق — فكتلة unsafe في جانب Rust، أو مستدعٍ بلغة C يمرّر مؤشراً خاطئاً، يعيد إدخال نفس فئة الأخطاء التي كانت إعادة الكتابة تهدف إلى إزالتها. حدّدت فرق الأمان في غوغل ومايكروسوفت مراجعة حدود FFI بأنها المشكلة الصعبة التالية، لا مشكلة محلولة.

ما يعنيه هذا إن لم تكن تبني نواة نظام تشغيل

معظم فرق الهندسة لا تصون نظام تشغيل أو متصفحاً، لكن الدرس الأساسي قابل للتعميم مباشرة:

  • الكود الجديد الذي يحلل مدخلات غير موثوقة هو حيث يجب تطبيق هذه السياسة أولاً. إذا كنت تكتب محللاً جديداً أو أداة إلغاء تسلسل أو معالج بروتوكول في عام 2026، فإن اختيار Rust أو Go أو لغة أخرى آمنة من ناحية الذاكرة افتراضياً أصبح أسهل بكثير في تسويقه لمراجع أمني مما كان عليه قبل خمس سنوات — فالأدوات، ومنظومة المكتبات، ومجمع التوظيف جميعها نضجت.
  • كود C/C++ القديم الذي لا يمكنك إعادة كتابته يجب أن يحصل على تغطية أدوات التعقيم (sanitizers) والفحص العشوائي (fuzzing)، لا مشروع إعادة كتابة. تكتشف أدوات AddressSanitizer وMemorySanitizer والفحص العشوائي المستمر (libFuzzer، OSS-Fuzz) نفس فئات الأخطاء التي كانت إعادة الكتابة ستزيلها، بجزء صغير من التكلفة الهندسية، وهي تعمل اليوم على كود لا تنوي لمسه.
  • إذا كنت تبيع برمجيات للحكومة الفيدرالية الأمريكية، تحقق من حالة تعهدك بميثاق Secure by Design التابع لوكالة CISA. وقّعت عليه أكثر من 300 شركة، ويتضمن الميثاق تعهداً بنشر خارطة طريق لسلامة الذاكرة — ليس امتثالاً كاملاً من اليوم الأول، بل خطة علنية بجدول زمني. إذا كانت شركتك من الموقّعين ولم تنشر هذه الخارطة، فهذه ثغرة سيسألك عنها مدقق أو فريق أمني لدى عميل عاجلاً أم آجلاً.
  • تعامل مع كل حد FFI جديد كأنه عنصر أمني قابل للمراجعة، لا تفصيلاً تنفيذياً. إذا كانت وحدة Rust ووحدة C تتحدثان مع بعضهما، فهذا الحد يستحق نفس الدقة التي يحصل عليها محلل جديد، لأنه بالضبط حيث تنتهي ضمانات السلامة فعلياً.
مشاركة: