CVE-2022-49999
Açıklama
Linux kernel içerisinde aşağıdaki güvenlik açığı giderilmiştir: btrfs: alan önbelleği bozulması ve potansiyel çift tahsisatların düzeltilmesi Geniş bir makine kümesinde space_cache v2 test edilirken bazı belirtilerle karşılaşılmıştır: 1. "unable to add free space :-17" (EEXIST) hataları. 2. Eksik boş alan bilgi öğeleri; bazen "missing free space info for X" hatasıyla tespit edilmiştir. 3. Çift hesaplanmış alanlar: hem extent ağacında tahsis edilmiş hem de boş alan ağacında boş olarak işaretlenmiş aralıklar, extent ağacında iki kez tahsis edilmiş olarak işaretlenmiş aralıklar veya boş alan ağacında iki kez boş olarak işaretlenmiş aralıklar. Eğer sonuncusu diske yazılmışsa, bir sonraki yeniden başlatmada add_new_free_space() içindeki BUG_ON() tetiklenecektir. 4. Disk üzerinde herhangi bir bozulma veya hata mesajı olmayan bazı ana makinelerde, bellek içi alan önbelleği (drgn ile dökümü alındığında) boş alan ağacı ile uyuşmamaktadır. Tüm bu belirtilerin temel nedeni aynıdır: Bir blok grubu için boş alanı önbelleğe alma işlemi ile sabitlenmiş (pinned) extent'ler için boş alanı bellek içi alan önbelleğine geri döndürme işlemi arasındaki bir yarış durumu (race condition), boş bir aralığın alan önbelleğine iki kez eklenmesine neden olmaktadır. Bu yarış durumu, boş alanın boş alan ağacından (space_cache=v2) veya extent ağacından (nospace_cache veya önbelleğin yeniden oluşturulması gereken durumlarda space_cache=v1) önbelleğe alınması sırasında oluşur. struct btrfs_block_group::last_byte_to_unpin ve struct btrfs_block_group::progress yapıları normalde bu yarış durumuna karşı koruma sağlamalıdır, ancak d0c2f4fa555e numaralı commit ("btrfs: make concurrent fsyncs wait less when waiting for a transaction commit"), birden fazla işlemin (transaction) aynı anda extent'lerin sabitlemesini kaldırmasına (unpinning) izin vererek bunu dolaylı olarak bozmuştur. Özellikle yarış durumu şu şekildedir: 1. İşlem A'da, önbelleğe alınmamış bir blok grubundan bir extent silinir. 2. İşlem A için btrfs_commit_transaction() çağrılır. 3. btrfs_run_delayed_refs() -> __btrfs_free_extent(), silinen extent için gecikmeli referansı çalıştırır. 4. __btrfs_free_extent() -> do_free_extent_accounting() -> add_to_free_space_tree(), silinen extent'i tekrar boş alan ağacına ekler. 5. do_free_extent_accounting() -> btrfs_update_block_group() -> btrfs_cache_block_group(), blok grubunu önbelleğe alınmak üzere sıraya alır. block_group->progress, block_group->start değerine ayarlanır. 6. İşlem A için btrfs_commit_transaction(), switch_commit_roots() fonksiyonunu çağırır. block_group->last_byte_to_unpin değerini block_group->progress'e ayarlar; blok grubu henüz önbelleğe alınmadığı için bu değer block_group->start olur. 7. Önbellekleme iş parçacığı ilgili blok grubuna ulaşır. Commit kökleri zaten değiştirildiği için load_free_space_tree() silinen extent'i boş olarak görür ve onu alan önbelleğine ekler. Önbellekleme işlemini bitirir ve block_group->progress değerini U64_MAX yapar. 8. btrfs_commit_transaction(), işlem A'yı TRANS_STATE_SUPER_COMMITTED durumuna ilerletir. 9. fsync, işlem B için btrfs_commit_transaction() çağrısı yapar. İşlem A zaten TRANS_STATE_SUPER_COMMITTED durumunda olduğu ve commit işlemi fsync için yapıldığı için süreç ilerler. 10. İşlem B için btrfs_commit_transaction(), switch_commit_roots() fonksiyonunu çağırır. Bu sefer blok grubu zaten önbelleğe alınmıştır, bu nedenle block_group->last_byte_to_unpin değerini U64_MAX yapar. 11. İşlem A için btrfs_commit_transaction(), silinen extent için unpin_extent_range() fonksiyonunu çağıran btrfs_finish_extent_commit() fonksiyonunu çağırır. last_byte_to_unpin değerinin U64_MAX olduğunu görür (İşlem B tarafından!) ve böylece silinen extent'i alan önbelleğine tekrar ekler! Bu durum yukarıdaki tüm belirtileri açıklamaktadır: * Olaylar dizisi tam olarak yukarıda açıklandığı gibiyse, adım 11'de boş alan yeniden eklendiğinde EEXIST hatası oluşacaktır. * Eğer başka bir iş parçacığı, 7. ve 11. adımlar arasında silinen extent'i yeniden tahsis ederse, 11. adım aslında tahsis edilmiş olan bu alanı sessizce boş olarak alan önbelleğine tekrar ekleyecektir. Daha sonra, bu alan *tekrar* tahsis edilirse, boş alan ağacı bozulacaktır (yani yanlış öğe silinecektir). * Boş alan ağacı bozulmasını yakalayamazsak...
Nasıl düzeltilir
- linux linux_kernel5.15.65, 5.19.6 ya da sonraki bir sürüm
Etkilenen ürünler
| Ürün | Etkilenen sürümler | Düzeltildiği sürüm |
|---|---|---|
| linux linux_kernel | 5.12 ≤ v < 5.15.65, 5.16 ≤ v < 5.19.6, 6.0 | 5.15.65, 5.19.6 |
Sürümünüzü kontrol edin
Ürünü seçin ve kullandığınız sürümü yazın; sürümün etkilenen aralıkta olup olmadığını görün.
Attack Surface Management
Alan adlarınıza bağlı varlıkları, bu varlıklarda çalışan teknolojileri ve bilinen zafiyetleri tek listede görün.