لطالما مثلت إدارة إعادة إرسال الحزم عبر شبكات النطاق العريض (WAN) تحديا جوهريا لمهندسي بروتوكولات النقل. لعقود طويلة، اعتمد بروتوكول التحكم في النقل على نظام الإشعارات التراكمية (Cumulative ACKs) وفق معيار RFC 793. إذا فُقدت حزمة واحدة ضمن نافذة الإرسال، كان الطرف المرسل مضطرا لإعادة بث القطعة المفقودة وجميع القطع اللاحقة التي تلتها، مما أدى إلى هدر سعة النطاق الترددي وزيادة زمن الاستجابة.
لمعالجة هذا القصور، وضعت مجموعة مهندسي الإنترنت (IETF) معيار الإشعار الانتقائي لبروتوكول TCP (SACK) في وثيقة RFC 2018، مما أتاح للطرف المستقبل تحديد كتل البيانات غير المتتالية المستلمة بنجاح بدقة متناهية. غير أنه في عام 2019، اكتشف باحثو الأمان ثغرة خطيرة في مكدس شبكات نواة لينكس عُرفت باسم CVE-2019-11477 أو SACK Panic. من خلال التلاعب بحجم القطعة الأقصى (MSS) وإرسال كتل SACK خبيثة، تمكن المهاجمون من التسبب بطفحان في الأعداد الصحيحة بحجم 16 بت داخل طوابير مخازن المقابس، مؤدين إلى انهيار فوري لنظام التشغيل المضيف.
+-------------------------------------------------------------------------+
| الإشعار التراكمي مقابل الإشعار الانتقائي SACK |
+-------------------------------------------------------------------------+
| السيناريو: وصول الحزم 1 و 2 و 4 و 5؛ فقدان الحزمة 3 أثناء النقل عبر الشبكة|
| 1. الإشعار التراكمي (RFC 793): يُرسل المستقبل ACK=3؛ يعيد المرسل بث 3,4,5 |
| 2. خيار الإشعار الانتقائي (RFC 2018): المستقبل يرسل ACK=3 + SACK [4-6]؛ |
| يقوم المرسل بإعادة إرسال الحزمة رقم 3 فقط دون هدر في البيانات. |
+-------------------------------------------------------------------------+
تطور إشعارات استلام TCP: الإشعار التراكمي مقابل الانتقائي (RFC 2018)
في آلية الإشعار التراكمي الكلاسيكية، يحدد حقل رقم الإشعار المكون من 32 بت في ترويسة TCP الرقم التسلسلي التالي المتوقع استلامه، مؤكدا سلامة جميع البايتات السابقة. عندما تسقط حزم متعددة ومتباعدة، يجبر هذا النموذج المرسل على خيارين كلاهما مر: إما إعادة إرسال الحزمة الأولى فقط وانتظار زمن الذهاب والإياب (RTT) لمعرفة ما سقط تاليا، أو إعادة بث نافذة البيانات بأكملها بصورة عمياء.
قدم معيار RFC 2018 حلا لهذه المشكلة عبر استغلال حقل خيارات TCP الاختياري (TCP Options)، سامحا للمستقبل بالإبلاغ عن نطاقات كتل البيانات المنفصلة التي استقرت في ذاكرته المؤقتة بأمان.
+-------------------------------------------------------------+
| بنية خيار TCP SACK (RFC 2018) |
+-------------------------------------------------------------+
| الكود = 5 (بايت واحد) | الطول = 8*N + 2 (بايت واحد) |
+------------------------+------------------------------------+
| حافة الكتلة الأولى اليسرى (Left Edge) - 4 بايتات |
| حافة الكتلة الأولى اليمنى (Right Edge) - 4 بايتات |
+-------------------------------------------------------------+
| حافة الكتلة N اليسرى (Left Edge) - 4 بايتات |
| حافة الكتلة N اليمنى (Right Edge) - 4 بايتات |
+-------------------------------------------------------------+
تشريح بنية خيار SACK: تنسيقات الكتل ومحددات الحواف
تحتوي ترويسة TCP القياسية على مساحة إجمالية للخيارات لا تتجاوز 40 بايتا (حيث أن الحد الأقصى لطول ترويسة TCP هو 60 بايتا مع 20 بايتا للترويسة الأساسية). يتم التفاوض على تفعيل الخاصية خلال المصافحة الثلاثية عبر خيار SACK-Permitted بطول بايتين (النوع 4).
عند حدوث فقدان للبيانات، يرسل الطرف المستقبل خيار SACK الفعلي (النوع 5). يحدد طول الخيار عدد الكتل المبلغ عنها، حيث تتطلب كل كتلة 8 بايتات (4 بايتات للحافة اليسرى و4 بايتات للحافة اليمنى):
- الحافة اليسرى (Left Edge): أول رقم تسلسلي للكتلة المستلمة غير المتصلة.
- الحافة اليمنى (Right Edge): الرقم التسلسلي الذي يلي مباشرة آخر بايت مستلم في تلك الكتلة.
نظرا لقيود مساحة خيارات TCP البالغة 40 بايتا، ومع وجود خيار الطابع الزمني TCP Timestamps (الذي يستهلك 10 بايتات)، لا يمكن لحزمة TCP واحدة أن تحمل أكثر من 3 أو 4 كتل SACK كحد أقصى في آن واحد.
إدارة نواة لينكس للحزم غير المرتبة: طابور sk_buff Queue
في نواة لينكس، يمثل الهيكل البرمجي struct sk_buff (المعروف اختصارا باسم skb) الوحدة البنائية الأساسية لإدارة الحزم عبر كافة طبقات الشبكة. عندما يرسل تطبيق بيانات عبر مقبس TCP، تحتفظ النواة بالقطع الصادرة في طابور إعادة الإرسال (write_queue) حتى تتلقى إشعارا بتأكيد وصولها.
+-------------------------------------------------------------------------+
| هيكل SK_BUFF والتجزئة في نواة لينكس |
+-------------------------------------------------------------------------+
| struct sk_buff |
| ├── next / prev (مؤشرات القائمة المتصلة) |
| ├── len / data_len (أطوال البيانات الإجمالية والمجزأة) |
| └── skb_shared_info |
| ├── gso_segs (عداد أجزاء التجزئة: عدد صحيح 16 بت بدون إشارة) |
| ├── gso_size (حجم التجزئة الأقصى MSS) |
| └── frags[] (مصفوفة صفحات الذاكرة skb_frag_t) |
+-------------------------------------------------------------------------+
آليات تجزئة المخزن المؤقت للمقبس (skb) والبصمة التخزينية
لتخفيف العبء عن المعالج المركزي، تعتمد أنظمة لينكس الحديثة على تقنيات تسريع العتاد مثل Generic Segmentation Offload (GSO) و TCP Segmentation Offload (TSO). وبدلا من بناء هياكل sk_buff منفصلة لكل حزمة بحجم 1500 بايت، يقوم المكدس بتجميع ما يصل إلى 64 كيلوبايت من البيانات داخل هيكل sk_buff ضخم واحد يحتوي على مؤشرات لصفحات ذاكرة مجزأة.
عندما تصل إشعارات SACK تفيد باستلام أجزاء دقيقة تقع في منتصف هذا المخزن الكبير، تضطر النواة لاستدعاء دالة tcp_fragment() لتقسيم هيكل sk_buff إلى أجزاء أصغر حجما، مطابقة للحدود المبلغ عنها في خيار SACK.
آلية ثغرة SACK Panic (CVE-2019-11477): طفحان الأعداد الصحيحة 16 بت
تكمن الجذور الحقيقية لثغرة CVE-2019-11477 في دالة دمج القطع tcp_shifted_skb() داخل المجلد net/ipv4/tcp_input.c. صُممت هذه الدالة لدمج كتل SACK المتجاورة لتقليل التجزئة وتحسين كفاءة الذاكرة.
/* كود توضيحي مبسط لمنطق دمج القطع داخل نواة لينكس */
static bool tcp_shifted_skb(struct sock *sk, ..., unsigned int pcount, ...)
{
struct sk_buff *prev = tcp_write_queue_prev(sk, skb);
...
/* دمج عداد القطع في الهيكل السابق */
skb_shinfo(prev)->gso_segs += pcount;
...
}
في هيكل skb_shared_info، تم تعريف الحقل gso_segs كمتغير عددي صحيح قصير بدون إشارة من نوع 16 بت (u16). الحد الأقصى النظري الذي يمكن لمتغير 16 بت تمثيله هو:
$$2^{16} - 1 = 65,535$$
إذا تمكن المهاجم من دفع النواة لتقسيم ودمج الحزم بحيث يتجاوز مجموع gso_segs القيمة 65535، يحدث طفحان عددي (Integer Overflow) يلتف حول الصفر (wraparound)، ليتحول العداد فجأة إلى صفر أو رقم صغير غير منطقي. وعندما تكتشف دالة tcp_fragment() أو دوال إدارة الصفوف هذا التناقض الرياضي الصارخ، تُطلق النواة استدعاء BUG_ON()، مما يسفر عن انهيار فوري للنظام (Kernel Panic) وتوقف الخادم تماما عن العمل.
دور قيم Micro-MSS في تضخيم استنزاف مخازن النواة المؤقتة
لتحقيق طفحان عددي في متغير 16 بت، يحتاج المهاجم إلى توليد أكثر من 65535 قطعة تجزئة. في الحالات العادية بشبكات إيثرنت حيث يبلغ حجم القطعة الأقصى (MSS) عادة 1460 بايتا، لا تكفي نافذة TCP القصوى للوصول إلى هذا الرقم.
هنا ظهرت حيلة Micro-MSS:
- يقوم المهاجم بإنشاء اتصال TCP مع الخادم المستهدف، ويعلن خلال المصافحة الابتدائية عن قيمة MSS متناهية الصغر، مثلا 48 بايتا (وهو الحد الأدنى لمعيار IPv4 مع خيارات TCP).
- يطلب العميل المشبوه من الخادم إرسال كمية كبيرة من البيانات (مثل تنزيل ملف ثابت أو صفحة ويب كبيرة).
- تقوم النواة بتقسيم تدفق البيانات الصادر إلى عشرات الآلاف من القطع الدقيقة بحجم 48 بايتا لكل منها داخل طابور
write_queue. - يرسل المهاجم بعد ذلك سلسلة متتالية من حزم SACK المعدة بعناية، متخطيا حزمة واحدة وتاركا ثغرات متناوبة. تجبر هذه السلسلة دالة
tcp_shifted_skb()على محاولة دمج آلاف القطع المجهرية داخل مخزن واحد، متجاوزة سقف 65535 دفعة واحدة ومفجرة الانهيار فورا.
+-------------------------------------------------------------------------+
| تسلسل هجوم SACK PANIC عبر تلاعب MSS |
+-------------------------------------------------------------------------+
| [المهاجم] [الخادم المستهدف] |
| | | |
| |---- SYN (MSS=48, SACK-Permitted) -------------------->| |
| |<--- SYN-ACK (MSS=1460, SACK-Permitted) ---------------| |
| |---- ACK --------------------------------------------->| |
| |---- طلب تنزيل بيانات كبيرة -------------------------->| |
| |<--- إرسال سيل من الحزم الدقيقة (حجم 48 بايت) ---------| |
| | | |
| |---- كتل SACK خبيثة تفصل الحزم الفردية --------------->| |
| | (النواة تقسم sk_buff وتدمجها في gso_segs) | |
| | [طفحان عددي]|
| | [Kernel Panic]
+-------------------------------------------------------------------------+
تدهور أداء SACK واستنزاف موارد المعالجة (CVE-2019-11478 و CVE-2019-11479)
تزامنت مع ثغرة SACK Panic ثغرتان إضافيتان على درجة عالية من الخطورة:
- CVE-2019-11478 (SACK Sluggishness): في الإصدارات غير المصححة، كانت النواة تدير طابور إعادة إرسال SACK عبر قوائم متصلة ثنائية خطية (
linked lists). عند استلام كتل SACK مفككة ومعقدة، تضطر النواة لمسح القائمة بأكملها بشكل تكراري، مما يرفع التعقيد الحسابي إلى $O(N^2)$. يمكن لحركة مرور لا تتعدى عدة كيلوبايتات أن تستهلك 100% من طاقة المعالج في معالجة المقاطعات البرمجية (softirqd). - CVE-2019-11479: استغلال استهلاك الموارد المفرط عبر إجبار مكدس الشبكة على معالجة كتل مفرطة التشتت، مما يؤدي إلى استنفاد الذاكرة المؤقتة لمقابس الشبكة ورفض الخدمات الشرعية.
عبء المعالجة غير المتماثل في مسح القوائم المتصلة غير المحدثة
يمثل التباين الكبير بين التكلفة التي يتحملها المهاجم والجهد الذي يبذله الخادم جوهر خطورة هذه الهجمات الخوارزمية. فبينما يرسل المهاجم حزم إشعارات خفيفة للغاية، يستهلك الخادم دورات معالجة ضخمة في التنقل بين مؤشرات الذاكرة وتعديل أوزان الحزم، مما يشل الأداء العام للمنظومة دون الحاجة لتوليد سيل جارف من البيانات.
كيف يحمي نفق الطبقة الثالثة وبروتوكول RiceGuard من ثغرات SACK
توفر بنية الأنفاق المشفرة في الطبقة الثالثة (Layer 3 Tunneling) طبقة حماية جذرية تعزل مكدس بروتوكولات النواة المضيفة عن الحزم المشبوهة القادمة من الإنترنت العام.
عندما تعتمد المؤسسات على بنية VPNRice المعززة ببروتوكول RiceGuard المطور:
- العزل في الطبقة الثالثة عبر UDP: تعمل أنفاق RiceGuard بنقل حزم IP المغلفة فوق بروتوكول UDP الصرف، متجاوزة تماما منطق خيارات TCP المعقدة في بطاقات النواة المعرضة للشبكة الخارجية.
- إنهاء مسار TCP عند بوابات محصنة ومحدثة: تنتهي اتصالات TCP الخاصة بالمستخدمين داخل بوابات تخضع لمراقبة دقيقة وفحص أمني صارم، ومزودة بأنظمة نواة حديثة لا تسمح بمرور حزم مشوهة.
- تطبيق قيود صارمة على أحجام الحزم: يتم ضبط أجهزة الشبكة الافتراضية لمنع تفاوض قيم MSS الشاذة، مما يمنع تشكل متجهات هجوم Micro-MSS في مهدها.
يمكن للمستخدمين تنزيل أحدث أدوات الحماية الموثوقة عبر صفحة تحميل VPN لتأمين محطات العمل والأنظمة السحابية.
+-------------------------------------------------------------------------+
| عزل متجهات هجوم SACK عبر نفق RICEGUARD |
+-------------------------------------------------------------------------+
| [إنترنت عام غير موثوق] |
| │ |
| حزم TCP خبيثة (Micro-MSS / كتل SACK شاذة) |
| ▼ |
| [بوابة فحص الحزم وجدار حماية RICEGUARD] |
| │ |
| 1. إسقاط الحزم ذات MSS < 536 بايت فورا. |
| 2. عزل الجلسات وتغليف البيانات داخل نفق UDP مشفر. |
| ▼ |
| [نواة الخادم الداخلي أو محطة العمل] |
| مخازن الذاكرة sk_buff محمية تماما، والبيانات مستقرة بنظام حلقي محكم. |
+-------------------------------------------------------------------------+
تحصين النواة وفحص الحزم: ضبط Sysctl وتقييد حجم MSS
لحماية خوادم لينكس المعرضة للإنترنت العام ضد محاولات استغلال SACK، ينبغي على مديري الأنظمة تطبيق تدابير التحصين التالية:
1. تعطيل معالجة SACK كإجراء إسعافي طارئ: إذا تعذر تحديث النواة فورا، يمكن إيقاف معالجة خيار SACK مؤقتا لمنع حدوث الانهيار:
sudo sysctl -w net.ipv4.tcp_sack=0
ملاحظة: يؤدي هذا الإجراء إلى عودة الاتصالات لنظام الإشعار التراكمي الكلاسيكي، مما قد يقلل من سرعة نقل البيانات عبر الخطوط التي تعاني من فقدان حزم مرتفع.
2. تقييد أدنى قيمة مسموح بها لحجم القطعة (MSS Clamping):
يتم استخدام جدار الحماية iptables أو nftables لإسقاط أو تعديل أي اتصال يطلب حجما يقل عن 536 بايتا:
# إسقاط محاولات الاتصال ذات MSS شديد الصغر عبر iptables
sudo iptables -A INPUT -p tcp --tcp-flags SYN,RST SYN -m tcpmss --mss 1:535 -j DROP
3. ضبط الحد الأدنى لـ MSS في النواة (النوى المحدثة): في الإصدارات المصححة، توفر النواة متغير تحكم يفرض حدا أدنى لحجم الإرسال:
sudo sysctl -w net.ipv4.tcp_min_snd_mss=536
مقارنة معمارية: بروتوكول TCP التقليدي مقابل SACK الضعيف والأنفاق المحمية
توضح المقارنة المعمارية التالية الفروق التشغيلية ومستويات المرونة بين النماذج المختلفة:
| المعيار التشغيلي | بروتوكول TCP التقليدي (RFC 793) | مكدس SACK غير المصحح | نفق RiceGuard المحصن |
|---|---|---|---|
| سرعة التعافي من فقدان الحزم | بطيئة (إعادة بث كامل النافذة) | سريعة (إعادة بث انتقائي دقيق) | مثالية (إعادة بناء عبر طبقة UDP) |
| القابلية لانهيار النواة (Panic) | منيع تماما (غياب منطق SACK) | حرجة للغاية (ثغرة CVE-2019-11477) | معدومة (تطهير MSS وعزل كامل) |
| استهلاك المعالج تحت الهجوم | منخفض | حرج ومكلف (تفكك القوائم الخطية) | ضئيل للغاية ومستقر عتاديا |
| البصمة التخزينية للمخازن | خطية وثابتة | انفجارية وغير منضبطة | محددة بدقة داخل مخازن حلقية |
| تأثر الحزم بالتدخلات الخارجية | مرتفع (ترويسات مكشوفة) | متوسط (إمكانية إسقاط الخيارات) | معدوم (تشفير كبسولي شامل) |
| الكفاءة عبر الشبكات المتقلبة | انخفاض يصل إلى 60% | كفاءة تشغيلية مرتفعة | أعلى معدل نقل مستقر ومرن |
الإصلاح الحديث لنواة لينكس: طوابير أشجار RB-Tree وتحسينات الإزاحة
أحدث الكشف عن ثغرة SACK Panic مراجعة بنيوية شاملة لمنظومة إدارة الطوابير في نواة لينكس، حيث قامت فرق تطوير النواة بإجراء التحسينات الجذرية التالية:
- فحص حدود المتغيرات العددية: أُعيدت كتابة منطق دمج القطع في
tcp_shifted_skb()مع فرض فحوصات أمان صارمة تمنعgso_segsمن تجاوز الحدود المسموح بها أو الالتفاف الرياضي تحت أي ظرف. - التحول إلى أشجار البحث الثنائية الحمراء والسوداء (RB-Trees): استبدلت النواة القوائم المتصلة الخطية في طوابير الحزم غير المرتبة بهياكل
struct rb_node، مما قلص التعقيد الزمني لعمليات البحث والتحديث من $O(N)$ إلى $O(\log N)$، وقضى نهائيا على هجمات استنزاف المعالج (CVE-2019-11478). - تضمين حد أدنى لـ MSS في الشيفرة المصدرية: تم تثبيت أرضية برمجية غير قابلة للتجاوز تحظر إنشاء قطع بيانات مجهرية تقل عن 48 بايتا في دالة
tcp_fragment().
قائمة تدقيق لمهندسي الشبكات لتأمين بنية TCP SACK التحتية
لحماية بيئات الحوسبة السحابية والبوابات المؤسسية من مخاطر استنزاف الذاكرة، يُوصى باتباع قائمة الفحص الميدانية التالية:
- التحقق من ترقيات النواة: التأكد من تشغيل إصدارات لينكس المصححة (Linux 4.19.52+ أو 5.1.11+ أو التوزيعات المستقرة ذات الإصلاحات التراجعية).
- تطبيق عتبة MSS على البوابات الحدودية: تهيئة موجهات الحافة وموازنات الحمل لإسقاط أو إعادة كتابة أي حزمة TCP تتفاوض على حجم MSS يقل عن 536 بايتا.
- تدقيق متغيرات Sysctl: التحقق من ضبط
net.ipv4.tcp_min_snd_mss = 536على الخوادم المتصلة مباشرة بالإنترنت. - عزل حركة المرور الموزعة: تمرير جلسات العمل عن بُعد عبر أنفاق مشفرة تعتمد بروتوكول RiceGuard لإنهاء معالجة TCP الخام في محطات معزولة ومحمية.
- مراقبة نشاط المعالج للخدمات البرمجية: إعداد تنبيهات لمراقبة استهلاك مؤشرات
ksoftirqdلرصد محاولات الهجوم الخوارزمي في مراحلها المبكرة. - تفعيل ملفات كوكيز المزامنة: دمج تحصينات SACK مع إعداد
net.ipv4.tcp_syncookies = 1لتأمين مرحلة إنشاء الاتصال.
يضمن الجمع بين التحصين المنطقي لمكدس النواة وتقنيات التغليف المشفر في الطبقة الثالثة الحفاظ على أعلى معدلات الأداء الشبكي دون تعريض البنية التحتية لمخاطر انهيار الذاكرة.



