فشل الطلب. كان الكود قد نُفّذ بالفعل.
فشل الطلب. كان الكود قد نُفّذ بالفعل. هذه مشكلة الترتيب في LMCache CVE-2026-105192: يعمل مُزيل تسلسل غير آمن أثناء فك الوسائط، قبل أن تتاح لمعالج التطبيق فرصة رفضها. تأتي استجابة الفشل متأخرة عن أن تكون دليلاً على أن الطلب لم يُحدث ضرراً.
يشمل التنبيه LMCache من 0.3.9 إلى 0.5.5، وإصدارات 0.5.6 التمهيدية المتأثرة وبُنى التطوير السابقة للإصلاح. يتضمن الإصدار 0.5.6 المعالجة. هذا فحص للمصدر والتصحيح، وليس إعادة إنتاج؛ ويهم هذا التمييز خصوصاً عند مناقشة الاختبارات السلبية أدناه. التعرض يخص مسار النقل المتأثر والمتاح في وضع العمليات المتعددة، وليس كل تطبيق يستخدم vLLM. [1][2]
كيف يصل فك MessagePack إلى pickle؟
يقبل النقل رسائل MessagePack، لكن معالج الامتداد المخصص يعطي بعض البايتات تفسيراً ثانياً. يصل رمز الامتداد 1 إلى DeviceIPCWrapper.Deserialize، الذي يستدعي pickle.loads في التنفيذ المتأثر. يحدث ذلك في مسار REGISTER_KV_CACHE بينما لا يزال الخادم يبني الوسائط التي سيستلمها المعالج. لا تستطيع مراجعتها لاحقاً عكس أثر جانبي وقع بالفعل. [1][3]
هكذا أتتبع الحد في المراجعة: أبدأ بمُفكك الرسائل الشبكي، وأحصر الخطافات والمحولات المخصصة، ثم أتبع كل مسار حتى تصبح البايتات بيانات عادية أو عملية إعادة بناء قابلة للتنفيذ. لا يكفي اسم التنسيق في المخطط المعماري. قد يحتوي غلاف مخصص للبيانات امتداداً يعيد كل السلوك الخطر الذي بدا أن الغلاف الخارجي يتجنبه.
Affected decode path (schematic)
Peer-controlled frame
-> MessagePack argument decode
-> extension code 1
-> DeviceIPCWrapper.Deserialize
-> pickle.loads
-> only then: handler / later validation
A later error cannot undo an earlier side effect.احتاج المطوّر إلى استعادة الصنف الفرعي الصحيح
يشرح الكود المتأثر هدفه الهندسي: الحفاظ على النوع المحدد لغلاف الجهاز عبر النقل، حتى يختار المستقبِل التنفيذ الصحيح لتحويل البيانات إلى tensor. تؤدي أغلفة CPU والمسرّعات أعمالاً مختلفة. حلّ تسلسل الكائن مشكلة الاختيار بسهولة، لكنه سمح أيضاً للطرف الآخر بإرسال بايتات إلى آلية إعادة بناء كائنات Python. الخطأ الأمني يقع في التمثيل المختار لمطلب مشروع. [3]
لذلك يكون سؤال المراجعة أنفع من أمر عام بتجنب pickle: ما الحقائق التي يجب أن تعبر الحد، وأي قرارات تنفيذ يجب أن تبقى محلية؟ قد يحتاج المستقبِل نوع الجهاز أو الشكل أو واصف التخزين. لكنه لا يحتاج وصفة عشوائية لإنشاء كائنات Python. توثيق هذا الفرق يمنح التصحيح قاعدة ثابتة تبقى صحيحة عند تغيير وسيلة النقل.
يعيد التصحيح اختيار التنفيذ إلى الشيفرة المحلية
في 0.5.6، تفك Deserialize واصفاً محدد النوع هو WireIPCData، ثم تستخدم نوعه لاختيار إدخال من WRAPPER_TYPES. يأتي اختيار الوحدة والصنف من هذا الربط المحلي. وجود importlib في المسار المصحح ليس بحد ذاته ثغرة حقن جديدة؛ المهم هو هل يتحكم الإدخال في اسم الوحدة المستوردة أم يختار واصفاً مدعوماً صراحة فقط؟ [4]
يحافظ التصحيح على واجهة التسلسل، لكنه يرفض بيانات pickle القديمة. معيار القبول عندي أن تفشل البيانات غير الصحيحة أو غير المدعومة قبل إعادة بناء كائنات عشوائية، من دون فرع توافق يعيد المحاولة باستخدام pickle بصمت. أختبر الوسوم المجهولة والحقول غير المتوقعة والواصفات القديمة إلى جانب المدخلات الصحيحة. يجب أن يحافظ التصحيح على العمل المقصود ويزيل التفسير الخطر.
# Selected source lines; surrounding checks omitted [3][4]
# Vulnerable:
return pickle.loads(data)
# Fixed:
descriptor = msgspec.msgpack.decode(data, type=WireIPCData)
module, name = WRAPPER_TYPES[type(descriptor)]
# The fixed path selects implementation from a local mapping.اتبع مُفكك البيانات المشترك بعد المقبس الأول
ZeroMQ ليس المستدعي الوحيد الذي يستحق المراجعة. يحدد طلب الدمج المصحح codec في gRPC يستخدم مُزيل التسلسل نفسه عبر حقل اسمه pickled_payload. يبقى الاسم للتوافق، بينما يصبح المحتوى واصفاً جديداً. البحث عن الاسم القديم قد يبالغ في تقدير الخطر؛ والبحث في أول وسيلة نقل فقط قد يفوّت الحد المشترك. اتبع التدفق الفعلي للبيانات. [5]
الإصلاح أضيق أيضاً من إزالة كل استخدام لـpickle من LMCache. يحدد المشرفون مسارات engine-driven منفصلة خارج هذا الإصلاح، ويصفونها بأنها معطلة افتراضياً وغير متاحة عبر الشبكة في تلك التهيئة. هذا توصيفهم للنطاق، لا نتيجة تحقق من الوصول أُجري هنا. ولا يضيف التصحيح مصادقة RPC أو تفويضاً لاستخدام مورد الذاكرة المشتركة المشار إليه. صحة البنية والهوية وملكية المورد فحوص مستقلة. [5][6]
صحة الواصف لا تثبت ملكية المورد
تفعل البنية البديلة أكثر من تغيير مكتبة التسلسل. تقيّد TensorMetadata الحقول الرقمية وتتحقق من تطابق عدد أبعاد shape وstride؛ ويتحقق واصف ذاكرة CPU المشتركة من أن عرض tensor يقع ضمن الحجم المصرح به. تضبط هذه الفحوص معنى الواصف قبل أن يستخدمه الغلاف. إنها خصائص محددة يمكن للمراجع تحويلها إلى حالات حدودية، بدلاً من اعتبار عبارة «محدد النوع» ضماناً أمنياً. [7]
يبقى سؤال مستقل: من يحق له تسمية المورد الفعلي أو استخدامه؟ لا يجيب الوصف المتسق داخلياً عن ذلك وحده. يفصل طلب الدمج صراحة بين التحقق من الواصف والتفويض لملكية الذاكرة المشتركة. أسجل فحص ملكية المورد وموقعه منفصلين عن فحص فك البيانات، وأطلب دليلاً لكليهما حيث تقتضيهما علاقة الثقة. هذا ليس ادعاء بثغرة جديدة في النسخة المصححة، بل حد ما يثبته التصحيح. ينطبق الانضباط نفسه على أي إصلاح لمحلل: حدد القاعدة التي صار يفرضها، ثم القرارات الأمنية المستقلة التي لم يعد بتنفيذها. نجاح اختبار المحلل لا يشهد لهذه القرارات بالتبعية. [5]
غياب العلامة يحتاج دليلاً على انتهاء المعالجة
قد يعلن الاختبار الفشل قبل أن يعالج الخادم المتأثر مدخلاته. يعالج صاحب طلب الدمج مشكلة التوقيت غير المتزامن صراحة: يؤكد طلب لاحق على الاتصال نفسه انتهاء المعالجة قبل فحص العلامة. نتيجة المقارنة المنشورة تخص ذلك الباحث، وليست نتيجة مختبر لي. الدرس العام هو إثبات أن الفحص جرى بعد العمل المعني. [5]
أطلب من بيئة اختبار انحدار محلية أربع ملاحظات: وصول الطلب إلى مُفكك البيانات المقصود، وانتهاء المعالجة، وغياب الأثر الجانبي المحظور، واستمرار نجاح طلب صحيح. انتهاء المهلة لا يعادل الرفض. ورسالة الاستثناء لا تعوض مراقبة الآثار الجانبية؛ فقد يرمي المسار المتأثر استثناءً بعد التنفيذ. اربط كل استنتاج سلبي بالمسار وشرط الإكمال اللذين يثبتهما فعلاً.
Proposed regression evidence; not results from a run here
Affected build: path reached + completed + benign marker observed
Fixed build: path reached + completed + marker absent
Valid input: supported round trip still works
No completion: inconclusive, even when the marker is absentحدّث أطراف الاتصال ثم افحص من يستطيع الوصول إليها
ابدأ مراجعة النشر بنقطة الاستماع. توضح الوثائق أن الربط الافتراضي على localhost؛ أما نشر العمليات المتعددة الذي يتيحها عبر --host فله حد مختلف، وينبّه المشرفون إلى مثال Kubernetes السابق لديهم. يقلل localhost التعرض الشبكي لكنه لا يصادق الطرف المحلي. حدد الوضع والنسخة المحمّلة وعنوان الربط والعملاء القادرين على الوصول قبل اعتبار درجة الخطورة تقييماً لنشرك. [1][6]
حدّث العمال والخوادم المتواصلة معاً لأن صيغة الواصف تغيرت؛ ليس المزج بين الإصدارات خطة التوافق المقصودة. يسجل إصدار 0.5.6 الإصلاح، بينما يصف المشرفون أعمال الأمان الإضافية بصورة منفصلة. أبقِ الوصول إلى نقطة الاستماع مقيداً بعد التحديث. الاستنتاج القابل للدفاع هو تغير مسار معين لإعادة بناء الكائنات، لا أن خدمة الاستدلال أصبحت آمنة لأي عميل. [2][5]
اطلب من مراجعة الشيفرة إثبات حد الثقة
تحدد النتيجة المفيدة نقطة الدخول والخطاف المخصص والعملية الخطرة وشروطها والفحوص التي تأتي متأخرة. ويجب أن يحدد التحقق النسخة المنشورة ويغطي كل من يستدعي مُفكك البيانات المشترك. هذه نتيجة أقوى من العثور على كلمة pickle في المشروع، لأنها تخبر الفريق ما الذي يغيّره وكيف يتأكد أن التغيير وصل إلى الإنتاج.
هذا هو الحد الذي أتتبعه في مراجعة الشيفرة الآمنة: اللحظة التي تكتسب فيها البايتات غير الموثوقة سلوكاً، والافتراض الذي جعل هذا السلوك يبدو ضرورياً. إن كانت خدماتك تمرر كائنات عبر الذاكرة المؤقتة أو الطوابير أو أدوات IPC، فابدأ منها. الجزء الصعب غالباً أعمق بعدة استدعاءات من نقطة النهاية التي ظن الجميع أنهم راجعوها بالفعل.
المصادر
هل تحتاج إلى هذا الفحص في منتجك؟
مراجعة أمان الشيفرةهل تريد أن تتعلم اكتشاف ثغرات كهذه بنفسك؟
دورة مراجعة الكود الأمني بتدريب فردي