CVE-2024-46787
Təsvir
Linux nüvəsində aşağıdakı zəiflik aradan qaldırılıb: userfaultfd: böyük PMD yoxlamaları düzəldildi "userfaultfd: fix races around pmd_trans_huge() check", v2 yamaları seriyası. mfill_atomic() funksiyasındakı pmd_trans_huge() kodu nüvə versiyasından asılı olaraq üç fərqli şəkildə yanlışdır: 1. pmd_trans_huge() yoxlaması yarış vəziyyətinə (race condition) meyillidir və BUG_ON()-ə səbəb ola bilər (əgər iki düzgün yarış pəncərəsinə rast gəlinsə) - bunu bəzi əlavə mdelay() çağırışları olan nüvə versiyasında sınaqdan keçirmişəm. Yarış ssenarisinin təsviri üçün commit mesajına baxın. Köhnə nüvələrdə (6.5-dən əvvəl), düşünürəm ki, eyni xəta, əgər 5 dar yarış pəncərəsinə rast gəlinsə, nəzəri olaraq transhuge səhifə məzmununa səhifə cədvəli kimi daxil olmağa səbəb ola bilər (bu halı sınaqdan keçirməmişəm). 2. Qi Zheng tərəfindən qeyd edildiyi kimi, pmd_trans_huge() səhifə cədvəllərinə işarə etməyən PMD-ləri aşkar etmək üçün kifayət deyil. Köhnə nüvələrdə (6.5-dən əvvəl), buna nail olmaq üçün sadəcə bir geniş yarışda qalib gəlmək kifayət idi. Bunu 6.1 stabil versiyasında, try_to_migrate()-a mdelay() əlavə edərək miqrasiyanı UFFDIO_ZEROPAGE ilə qarşılaşdıraraq sınaqdan keçirmişəm - mənim x86 VM-imdə bu, ptlock_ptr()-də nüvə oops-una səbəb olur. 3. Yeni nüvələrdə (>=6.5), shmem xəritələnmələri üçün khugepaged-ə səhifə cədvəllərini altımızdan çəkməyə icazə verilir (bunu sınaqdan keçirməsəm də), ona görə də düşünürəm ki, mfill_atomic()-dəki BUG_ON() yoxlamaları sadəcə yanlışdır. Bunlar üçün iki ayrı düzəliş yazmağa qərar verdim (birinci düzəliş 1+2 nömrəli xətalar üçün, ikinci düzəliş 3 nömrəli xəta üçün), beləliklə birinci düzəliş 1+2 xətalarının təsir etdiyi nüvələrə geri qaytarıla (backport) bilsin. Bu yama (2-dən biri): Bu, iki problemi həll edir. Aşağıdakı yarışın baş verə biləcəyini aşkar etdim: mfill_atomic digər axın (thread) ============ ============ <zap PMD> pmdp_get_lockless() [none pmd oxuyur] <trans_huge olarsa çıx> <əgər none-dirsə:> <pagefault transhuge zeropage yaradır> __pte_alloc [no-op] <zap PMD> <pmd_trans_huge(*dst_pmd) olarsa çıx> BUG_ON(pmd_none(*dst_pmd)) Bunu əlavə mdelay() çağırışları olan nüvədə eksperimental olaraq təsdiqləmişəm; BUG_ON(pmd_none(*dst_pmd)) tetiklenir. 0d940a9b270b ("mm/pgtable: allow pte_offset_map[_lock]() to fail") commit-indən daha yeni olan nüvələrdə bu, BUG_ON()-dan daha pis bir şeyə səbəb ola bilməz, çünki səhifə cədvəlinə giriş köməkçiləri əslində səhifə cədvəllərinin eyni vaxtda yox olması ilə davranmaq üçün hazırlanmışdır; lakin köhnə nüvələrdə (<=6.4), düşünürəm ki, biz ehtimal ki, iki BUG_ON() yoxlamasını keçib sonda böyük səhifəni (hugepage) səhifə cədvəli kimi qəbul edə bilərdik. İkinci problem odur ki, Qi Zheng-in qeyd etdiyi kimi, pmd_trans_huge()-in tuta bilmədiyi digər növ böyük PMD-lər var: devmap PMD-ləri və swap PMD-ləri (xüsusilə miqrasiya PMD-ləri). <=6.4 versiyalarda bu, birinci problemdən daha pisdir: Əgər mfill_atomic() miqrasiya girişi olan bir PMD üzərində işləyirsə (hansı ki, sadəcə bir geniş yarışda qalib gəlməyi tələb edir), o, PMD-ni pte_offset_map_lock()-ə ötürəcək və bu funksiya PMD-nin səhifə cədvəlinə işarə etdiyini fərz edəcək. Nəticədə sistem pozulur: İlk öncə nüvə PTE kilidini götürməyə çalışır (miqrasiya girişi PMD-də ünvan bitləri üçün "struct page" yoxdursa, bu, çökməyə və ya daha pis bir şeyə səbəb olacaq - düşünürəm ki, ən azı X86-da PTE inversiya yumşaltması sayəsində adətən müvafiq "struct page" olmur, amd64 fərqli görünür). Əgər bu çökməsəydi, nüvə növbəti mərhələdə səhvən səhifə cədvəli olduğunu düşündüyü yerə PTE yazmağa çalışardı. Bu problemlərin həlli üçün __pte_alloc()-dən əvvəl pmd_trans_huge() yoxlamasından imtina edin - bu artıqdır, onsuz da __pte_alloc()-dən sonra bunu yoxlamaq məcburiyyətindəyik. Backport qeydi: Köhnə nüvələrdə pmdp_get_lockless() funksiyası pmd_read_atomic() kimi keçir.
Necə düzəltmək olar
- linux linux_kernel6.6.51, 6.10.10 və ya daha yeni versiya
Təsirlənən məhsullar
| Məhsul | Təsirlənən versiyalar | Düzəldildiyi versiya |
|---|---|---|
| linux linux_kernel | 4.3 ≤ v < 6.6.51, 6.7 ≤ v < 6.10.10, 6.11 | 6.6.51, 6.10.10 |
Versiyanızı yoxlayın
Məhsulu seçin və istifadə etdiyiniz versiyanı yazın; versiyanın təsirlənən aralıqda olub-olmadığını görün.
Attack Surface Management
Domenlərinizə bağlı aktivləri, onlarda işləyən texnologiyaları və məlum zəiflikləri bir siyahıda görün.