CVE-2026-89928 in Linuxالمعلومات

الملخص

بحسب VulDB • 16/09/2026

في نواة لينكس، تم إصلاح الثغرة التالية:

KVM: x86/mmu: استهلاك قيمة rmap المقفلة أثناء اجتياز rmap بدون قفل (lockless)

تقوم الدالة `__kvm_rmap_lock()` بتجاوز (elide) قفل rmap عمدًا عندما تلاحظ أن rmap فارغ. في هذه الحالة، تعيد دالة `kvm_rmap_lock_readonly()` تمكين المقاطعة (preemption) وتعيد القيمة صفر، وبالتالي لا يمسك المتصل بقفل rmap ولا بمرجع مقاطعة (preemption reference). ويوثق التجاوز الثابتة (invariant) التي يعتمد عليها:

* تجاهل القفل إذا كان rmap فارغًا، لأن الماجزين الذين يعملون بدون قفل (في وضع القراءة فقط) لا يحتاجون إلى اجتياز rmap فارغ، ولا يمكنهم إضافة عناصر إليه. أي أن المسارات الوحيدة التي تعالج rmaps الفارغة تفعل ذلك أثناء امتلاكها لقفل mmu للكتابة، وهي متبادلة الاستبعاد (mutually exclusive).

تقوم دالة `kvm_rmap_age_gfn_range()` بتجاهل القيمة المعادة وتدخل بشكل غير مشروط في حلقة التكرار `for_each_rmap_spte_lockless()`. بدأ الماجز باستخدام `rmap_get_first()`، والتي تعيد قراءة قيمة `rmap_head->val` بدلاً من استخدام القيمة التي أعادها القفل. إذا قام كاتب (writer) بتعبئة rmap بين عملية القراءة الخاصة بالقفل وعملية إعادة القراءة للماجز، فإن مسار الشيخوخة (aging path) سيجتاز rmap المثبت حديثًا دون امتلاك قفله.

بالنسبة لـ KVM_RMAP_MANY في rmap، هذا يترك الماجز يتبع سلسلة `pte_list_desc` التي لم يقم بقفلها أبدًا. قد يقوم كاتب يمتلك قفل mmu للكتابة بتحرير هذه السلسلة (على سبيل المثال عبر `kvm_zap_all_rmap_sptes()` على مسار إعادة التدوير، أو أي عملية zap لـ rmap) باستخدام `kmem_cache_free()` بينما يكون الاجتياز قيد التقدم، مما يؤدي إلى حدوث ثغرة Use-After-Free في الذاكرة من نوع slab. لا يوجد ما يعزل (serialises) بين العمليتين: يعمل مسار الشيخوخة دون قفل mmu عندما تكون الخانة `CONFIG_KVM_MMU_LOCKLESS_AGING` مفعلة (`y`)، وكان قفل rmap الذي كان سيستبعد الكاتب قد تم تجاهله. وبسبب إعادة تفعيل المقاطعة في المسار الفارغ، يمكن أن تمتد الفترة الزمنية بين العمليتين القرائيتين لتشمل تأخير جدولة (scheduling delay) تعسفيًا.

تم إصلاح فئة الثغرة من خلال جعل الاجتياز بدون قفل يستهلك القيمة المعادة من قبل القفل بدلاً من إعادة قراءة rmap. تم تقسيم `rmap_get_first()` إلى دالتين: `__rmap_get_first()`، التي تبدأ ماجزًا (iterator) بناءً على قيمة rmap مقروءة مسبقًا، وجعل `for_each_rmap_spte_lockless()` تأخذ هذه القيمة وتستدعي `__rmap_get_first()` مباشرة. تمرر دالة `kvm_rmap_age_gfn_range()` القيمة المعادة من قبل `kvm_rmap_lock_readonly()`: عندما تم تجاهل القفل تكون القيمة صفر، وتعيد `__rmap_get_first()` قيمة NULL، ويتم تخطي الاجتياز. لا يعيد أي مازج بدون قفل قراءة rmap، وبالتالي لا يمكن انتهاك الثابتة الخاصة بتجاهل القفل (lock-elision invariant)، ولا يتم إضافة مسار لـ lock()-without-paired-unlock() إلى كود الشيخوخة.

If you want to get best quality of vulnerability data, you may have to visit VulDB.

مسؤول

Linux

حجز

11/09/2026

إفشاء

17/09/2026

الاعتدال

تمت الموافقة

إدخال

VDB-405767

EPSS

0.00000

KEV

لا

النشاطات

منخفض جدًا

المصادر

Might our Artificial Intelligence support you?

Check our Alexa App!