2 puan yazan GN⁺ 2024-10-27 | 1 yorum | WhatsApp'ta paylaş
  • Linux 6.10’daki mseal, çalışan sanal bellek bölgelerini mühürleyerek kod yürütme yetkisi elde eden bir saldırganın sonradan VMA izinlerini veya yerleşimini değiştirmesini zorlaştıran, exploit azaltmaya yönelik bir syscall’dur
  • mseal(start, len, flags), sayfa hizalı VMA aralığına VM_SEALED ekler; çekirdek mprotect, munmap, mmap(MAP_FIXED), mremap ve bazı yıkıcı madvise yollarında değişiklikleri reddeder
  • Mevcut memfd_create veya memfd_secret RAM tabanlı anonim dosyalar ve gizli bellek erişim denetimine daha yakınken, mseal uzak saldırganın kod yürütmesinden sonra izin değiştirme, unmapping ve remapping işlemlerini engellemeye odaklanır
  • Başlıca savunma hedefleri, mprotect(PROT_EXEC) ile NX’i atlatıp shellcode çalıştıran saldırılar ve munmap/remapping ile bellekte delik açtıktan sonra burayı saldırgan verisiyle dolduran yalnızca veri odaklı exploit’lerdir
  • glibc 2.41 sonrasında entegre edilmesi mümkün olsa da, yığın ve heap çalışma zamanında büyüyüp küçüldüğü için otomatik mühürleme hedefi değildir; bu nedenle geliştiricilerin uygulama zamanı ve kapsamını dikkatle belirlemesi gerekir

mseal’in sağladığı koruma

  • Bellek mühürleme (memory sealing), çalışan bir VMA aralığını sonraki tehlikeli değişikliklere karşı neredeyse değişmez hale getiren bir özelliktir
  • Saldırgan kod yürütme primitive’i elde etse bile, mühürlenmiş VMA’da sanal bellek işlemleriyle izinleri değiştirmesi veya yerleşimi lehine manipüle etmesi zorlaşır
  • Chrome Security ekibi, Linux tabanlı ChromeOS’te V8 CFI stratejisini desteklemek için bu syscall’u kullanıma aldı
  • Birkaç tartışma ve yeniden yazımın ardından Linux çekirdeğine girdi; glibc entegrasyonu sayesinde kullanım alanı tarayıcı dışına genişleyebilir

memfd ailesinden farkı

  • memfd_create ve memfd_secret, dosya mühürleme (file sealing) ailesine daha yakındır
    • RAM tabanlı anonim dosyalar oluşturabilir
    • memfd_secret, yalnızca dosya tanımlayıcısına sahip süreçlerin ilgili bellek bölgesine erişmesini sağlar
    • Hassas bellek içi verileri koruyan “secure enclave” tarzı kullanıcı alanı eşlemelerinde kullanılabilir
  • mseal, hassas bilgi sızdırmayı hedefleyen yerel saldırganlardan çok, kod yürütmeyi hedefleyen uzak saldırganlara karşı exploit azaltmaya göre tasarlanmış bir syscall’dur

Çekirdek içindeki çalışma şekli

  • syscall imzası int mseal(unsigned long start, size_t len, unsigned long flags) şeklindedir
    • start ve len, mühürlenecek geçerli VMA’nın başlangıcını ve uzunluğunu belirtir
    • len doğru şekilde sayfa hizalı olmalıdır
    • Şu anda flags kullanılmaz ve 0 olmalıdır
  • Linux 6.12 itibarıyla uygulama do_mseal çağırır
    • current->mm, çağıran sürecin tüm sanal bellek adres alanı olan mm_struct’ı gösterir
    • mm_struct içindeki mmap, mmap ile oluşturulmuş bitişik bellek bölgeleri olan vm_area_struct listesini içerir
    • Yığın veya VDSO gibi bölgeler de tek bir VMA olarak temsil edilebilir
  • do_mseal, aralığın bitiş adresini hesapladıktan sonra mmap_write_lock_killable ile bellek bölgesini kilitler
  • check_mm_seal, hedef aralıktaki her VMA üzerinde dolaşır ve önce sınır geçerliliğini kontrol eder
    • Aralığın ortasında ayrılmamış bellek varsa -ENOMEM döndürür
    • Bu ilk kontrol, hata durumunda yalnızca bazı VMA’ların mühürlenmesi gibi bir durumu önlemek içindir
  • apply_mm_seal, aynı aralığı yeniden dolaşır ve mseal_fixup aracılığıyla hedef VMA’ya VM_SEALED bayrağını ekler

Mühürleme sonrasında yasaklanan bellek işlemleri

  • Çekirdek yama seti, VM_SEALED kontrolünü mm/madvise.c, mm/mmap.c, mm/mprotect.c, mm/mremap.c, mm/mseal.c dosyalarına ekler
  • mprotect ve pkey_mprotect, içeride mprotect_fixup üzerinden can_modify_vma çağırır; VMA mühürlüyse -EPERM döndürülür
  • Mühürlenmiş VMA’da şu işlemlere izin verilmez
    • mprotect, pkey_mprotect üzerinden izin bitlerini değiştirme
    • munmap ile unmapping
    • mmap(MAP_FIXED) ile mühürlenmiş eşlemeyi değiştirilebilir ve mühürsüz bir eşlemeyle değiştirme
    • mremap ile boyutu büyütme veya küçültme
    • mremap(MREMAP_MAYMOVE | MREMAP_FIXED) ile yeni hedefe taşıma
    • Bazı yıkıcı bayraklarla madvise kullanımı
  • mremap taşımasında hem kaynak hem hedef VMA için mühür kontrolü uygulanır
  • MREMAP_DONTUNMAP yoksa kaynak VMA unmap edilir; bu durumda da munmap mühür kontrolünden geçmesi gerekir
  • Linux 6.10 ve üzerinde mseal doğrudan syscall çağrısıyla kullanılabilir; örnek wrapper syscall numarası olarak 462 ve flags=0 kullanır

NX’i güçlendirerek shellcode yürütmeyi engelleme

  • Saldırgan, ROP gibi kod yeniden kullanım teknikleri olsa bile shellcode yürütmeyi tercih edebilir
    • Çalıştırılamaz yığına veya heap’e shellcode serpiştirir
    • Zafiyet üzerinden ilk ROP zincirini çalıştırır
    • mprotect(PROT_EXEC) ile shellcode’un bulunduğu bölgenin NX bitini kapatır
    • O bölgeye atlayıp shellcode’u çalıştırır
  • CVE-2018-7445 kullanan MikroTik RouterOS SMB daemon saldırısı bu akışa bir örnektir
    • Soket tabanlı shellcode’u çalıştırılamaz heap’e serpiştirir
    • Stack overflow ile oluşturulan ROP zinciri heap bellek izinlerini değiştirir
    • Ardından shellcode’u çalıştırır
  • İlgili VMA mseal ile mühürlenirse, mprotect çağrısı sırasında can_modify_vma kontrolü izin değişikliğini engeller
  • Örnek kodda, yığındaki shellcode sayfası mühürlenmezse mprotect(PROT_READ|PROT_WRITE|PROT_EXEC) sonrasında yürütme mümkündür
  • Aynı sayfa mseal ile mühürlenirse mprotect gerçek izinleri değiştiremez ve shellcode yürütülürken segmentation fault oluşur

Yığın ve heap’e uygulamadaki kısıtlar

  • glibc 2.41 sonrasında mseal devreye alındığında dinamik yükleyicinin önceden belirlenmiş bir VMA kümesine mühür uygulaması planlanıyor
  • Mevcut planda yığın ve heap otomatik olarak mühürlenmez
  • Yığın ve heap çalışma sırasında genişleyebildiği için otomatik mühürleme uygulamanın davranışını bozabilir
    • Heap ayırıcısı alanı geri kazanmak için brk syscall’unu çağırabilir
    • Bu yolda arch_unmap ve do_vmi_unmap üzerinden küçülme gerçekleşebilir
    • Mühürlü durumda bu tür unmapping işlemlerine izin verilmez; bu da dinamik bellek ayırmayı bozabilir
  • Geliştiriciler, uygulama bağlamına göre hangi zamanda ve hangi bölgelerde mühürleme yapılabileceğine karar vermelidir
  • Örnek makro, güvenilmeyen veri bulunabilecek seçilmiş yığın frame’lerinin sayfalarını tekrar tekrar mühürler
  • Zaten mühürlenmiş bir VMA’ya yeniden mseal çağrılırsa no-op olarak işlenir ve hata oluşmaz
  • Otomatik yığın genişletme veya stack splitting gibi özellikler için ayrıca dikkat gerekir
  • Saldırgan shellcode’da ısrar ederse yeni bir çalıştırılabilir bölgeyi mmap edip okunabilir bir bölgeden payload’u kopyalayabilir; ancak süreç daha zahmetli hale gelir

Unmapping tabanlı yalnızca veri odaklı exploit’leri azaltma

  • mprotect engeli, mühürlenmiş bölgenin yazılabilir duruma geçirilmesini de engeller; bu, değiştirildiğinde exploit primitive’ini güçlendirebilecek veri değişkenlerini korumaya yardımcı olur
  • Chrome bakımcıları, bozuk bir pointer’ı unmapping/remapping syscall’larına vererek bellekte delik açma ve burayı saldırgan denetimindeki veriyle yeniden doldurma tekniğini dikkate aldı
  • Bu yöntem, yığın dönüş adresi veya fonksiyon pointer’ı gibi kontrol akışı geçişlerini doğrudan değiştirmediği için forward-edge ve backward-edge CFI garantilerini atlatabilir
  • JIT derleyicileri uygulayan tarayıcılarda bu teknik özellikle kullanışlı olabilir
    • V8’in Turbofan’ı RW ile RX arasında geçiş yapan bölgeler oluşturabilir
    • Saldırgan, JIT derleme sürecinde hot-path JavaScript ile çalıştırılabilir kod ürettirebilir
    • Unmap edilen bölgeyi doldurup kritik verilerin üzerine yazarak kod yürütmeye giden bir değişiklik oluşturabilir
  • Kontrol akışını doğrudan ele geçirmeyi veya pointer sızıntısını gerektirmeden, bellekteki belirli verileri manipüle ederek kontrol akışını etkileyen yalnızca veri odaklı exploit’tir
  • mseal, unmapping ve remapping işlemlerini engelleyerek bu tür hole-punching senaryolarını önleyebilir

House of Muney örneği

  • House of Muney, kullanıcı alanı heap exploit’lerinde benzer bir unmapping tabanlı teknik kullanır
  • Qualys, eski bir Qmail hatasına yönelik gerçek exploit içinde bu tekniği kullandı
  • Bu teknik, büyük allocation chunk’larının M_MAP_THRESHOLD değerinden büyük olduğunda malloc ve free’nin sırasıyla doğrudan mmap ve munmap çağırması özelliğine dayanır
  • Büyük chunk’larda arada freelist cache bulunmadığından exploit süreci basitleşir
  • Allocation chunk’ının üst kısmındaki boyut metadata’sı başka bir sayfa boyutuna dönüştürülüp free edilirse, chunk’a bitişik bellek bölgesi için munmap gerçekleşebilir
  • Dulin’in örneği, keyfi munmap ile .gnu.hash ve .dynsym bölgelerini hedefler
    • Ardından daha büyük bir mmap chunk’ı ile yeniden doldurur
    • Henüz çözülmemiş bir PLT girişinin üzerine yazmayı mümkün kılar
    • GOT overwrite tarzı saldırıyı yeniden canlandırır
  • Kısaltılmış PoC, iki büyük chunk ayırır; top[-1] içindeki size alanını manipüle ettikten sonra free(top) ile bitişik bölgeye kadar unmap eder ve daha büyük bir allocation ile X verisini yeniden doldurur
  • Bu teknik CFI olsa bile çalışabilir ve önceden ASLR sızıntısı gerektirmez
  • glibc’nin mseal entegrasyonunda planlanan VMA kümesi mühürlemesinin, eşlenmiş ikili kodu ve dinamik kütüphaneleri unmapping/remapping hilelerinden koruyarak bu saldırıyı otomatik olarak azaltması bekleniyor
  • Ek güçlendirme isteyen geliştiriciler, program ömrü boyunca genişlemeyecek veya unmap edilmeyecek mmap allocation’larını seçici olarak mühürleyebilir

Gelecekteki kullanım alanı

  • mseal, Linux çekirdeğinde görece yeni bir azaltma özelliğidir ve henüz ele alınmamış başka kullanım örnekleri olabilir
  • glibc entegrasyonu tamamlanıp olgunlaştıkça syscall’un gereksinimlerine uygun iyileştirmeler devam edebilir
  • Şu anda kullanılmayan flags parametresi için de gelecekte somut kullanım alanları netleşebilir
  • Gerçek yazılıma uygularken mühürlenecek belleğin ömrü ve değişiklik ihtiyacı birlikte değerlendirilmelidir

1 yorum

 
GN⁺ 2024-10-27
Hacker News yorumları
  • Çekirdek posta listesindeki hararetli tartışmada hangi itirazlar ve kaygılar vardı, içeriden biri özetlese iyi olurdu
    Posta listesinin kendisi bazen fazla sert olabildiği için uzak duruyorum; baş ağrım zaten yeterince kötü
    Mekanizmanın kendisi makul görünüyor ama böyle bir özelliğin çekirdekte hâlihazırda olmaması şaşırtıcı

    • Bağlantısı verilen thread dışında başka bir şey var mı bilmiyorum ama genel olarak Linus tarzı dobra bir üsluptu
      Önerilen flag’lerden biri seal’ları yok saymayı mümkün kılıyordu; Linus da “bir yerde munmap yapmayı engelleyip başka bir yerde seal’ı yok saymak mı istiyorsunuz?” tarzında tepki verdi
      Sonrasında “bir kez seal edildiyse seal edilmiştir” ve “bazı yerlerin seal’a uyup rastgele başka yerlerin uymaması” gibi bir şeyin olamayacağını daha sert biçimde söyledi
      Daha sonra seal’ların yok sayılamayacağını ve pazarlık konusu olmadığını, flag ile seal’ı yok sayma önerisi daha gelirse ignore list’e koyacağını bile söyledi
    • https://lwn.net/ml/linux-kernel/7071.1697661373@cvs.openbsd....
      Theo de Raadt, Jeff Xu’ya gönderdiği e-postada mimmutable() ile mseal() yaklaşımlarının farklı olsa da ikisinin de saldırganlara karşı belleği seal ederek Linux uygulamalarını daha güvenli hâle getirmeyi amaçladığı söylenince, “Sanırım mseal’i yalnızca Chrome için yapıyorsunuz” diye yanıt verdi
      Bunun genel olarak uygulamalara pek uymayacağını düşündü; gerekçe olarak da fazla karmaşık olmasını ve mimmutable() deneyimine göre uygulamaların bunu doğrudan ele almayıp execve(), libc başlatması ve ld.so tarafından üstlenilmesini gösterdi
    • Matthew Wilcox da Jeff Xu’ya “neyi engellemeniz gerektiğini bilmediğinizi gösterdiğiniz için teşekkürler” tarzında sert bir yanıt verdi
      Theo ve Linus’a katıldı; mimmutable()ın temel fikrinin iyi olduğunu ama bunun bölünme ve uygulanma biçiminin berbat olduğunu düşündü
    • Bu yazı yardımcı olabilir: https://lwn.net/Articles/948129/
  • Bu sistem çağrısının nasıl kullanılacağını merak ediyorum
    Chrome bunu istiyor, ama saldırgan farklı flag’lerle yeniden map edebileceği için seal edilmiş sayfalar unmap edilemiyor
    O zaman çalışma zamanında ayrılan sayfalarda, bunları prosesin tüm ömrü boyunca tutmayı düşünmüyorsanız, pratikte kullanılamaz değil mi?
    Öyleyse JS sandbox belleği gibi çok cazip hedeflere uygulamak zor olmaz mı?
    Bu tür işler ayrı bir proseste çalıştırılıp bellek seal edildikten sonra iş bitince prosesin öldürülmesiyle mi çözülüyor, merak ediyorum
    Chrome’un bellek ve proses yönetimini iyi bilmediğim için bunun neden sorun olmadığından emin değilim; bu özelliğin çoğu program için yararlı olmadığı sıkça söyleniyorsa sebebi de bu mu, merak ediyorum

    • Burada çoklu proses bir seçenek olabilir
      Chrome’un bunu yaygın biçimde kullandığını biliyorum; namespace’ler üzerinden izolasyon gibi nedenlerle de ayrı proses zaten gerektiğinden yön bu olabilir
  • mseal() sonrası tartışma, 20 Ekim 2023: https://lwn.net/Articles/948129/
    mseal() yaklaşıyor, 19 Ocak 2024: https://lwn.net/Articles/958438/
    GNU C Library için bellek seal etme, 12 Haziran 2024: https://lwn.net/Articles/978010/

  • Modern x86_64 mimarisinde güvenli programlama ve bilgi işlemeye yardımcı olacak çok sayıda özellik varken işletim sisteminin böyle çağrılar uygulamak zorunda kalması üzücü
    Eski miraslar ve düşünce biçimleri, bugünün dünyasına ve bilgisine uymayan paradigmalar üzerine kurulmuş eski sistemleri yamamaya çalışma tutumunun bilişimin ilerlemesini yavaşlattığını ve kelimenin tam anlamıyla milyarlarca insanı riske attığını düşünüyorum
    Elbette bu değişikliğin doğru yönde bir adım olmadığını söylemeye çalışmıyorum; ama işletim sisteminin çalışması gerektiğine dair mevcut ideali bir kenara bırakıp bugünkü sistemleri, bilgiyi ve insanların sistemlerden ne istediğini dikkate alınca, bugün geliştiricilere ve kullanıcılara yüklenen yük ve risklerden arınmış sistemler hayal edebiliriz
    Mimari hataların var olduğu doğru, fakat yazılım mevcut özelliklerden bile doğru dürüst yararlanmıyor; bu yüzden mimari hataları öne sürerek itiraz etmek asıl noktayı kaçırıyor
    Temel sallantılıysa daha ucuz ihlal yöntemleri her zaman var olacaktır

    • Merak ediyorum; x86_64’te işletim sisteminin bunu kullanması veya etkinleştirmesi için bir yol olmadan kullanılabilen kullanılmayan/az kullanılan güvenlik özellikleri neler, anlatırsanız iyi olurdu
      msealın neden gerekçelendirilemediğini düşündüğünüzü ve onun yerine neyin daha iyi olacağını da merak ediyorum
  • LD_PRELOAD hilesiyle mseal sistem çağrısının üzerine yazmak ya da onu devre dışı bırakmak mümkün mü?

    • mseal, Linux’un mevcut bellek koruma yöntemlerinden farklı olarak, bellekteki hassas sırları çıkarmaya çalışan yerel saldırganlardan çok uzaktan kod çalıştırma saldırılarını hafifletmeye odaklanan bir sistem çağrısıdır.
      Uzak saldırgan yerel ortamı değiştirebiliyorsa, zaten sisteme sızmış sayılmalıdır.
    • Muhtemelen LD_PRELOAD ile olmaz.
      Etkili olması için içe aktarılmış bir fonksiyon olması gerekir; ham sistem çağrıları bu şekilde yakalanamaz.
      Linux sistem çağrılarını yakalama tartışması: https://stackoverflow.com/questions/69859/how-could-i-interc...
      mseal çalışıyormuş gibi yapan yamalı bir çekirdeği doğrudan oluşturmak, özelliği “devre dışı bırakmanın” en kolay yolu olabilir.
      Ancak mseal kullanan bir program bunun gerçekten çalışıp çalışmadığını doğrulayabileceği için, bozulmuş çekirdeğin uygulandıktan sonra uygulamanın kontrollerini engellemek üzere msealı gizlice devre dışı bırakacak bir yönteme de ihtiyacı olur.
    • Sürecin erken aşamasında denetim sizdeyse üzerine yazmanın epey yolu vardır.
      Örneğin yürütülebilir dosyayı ptrace ile izleyip sistem çağrılarını gözetleyerek mseal(2) çağrısını atlatabilirsiniz.
      Bu sistem çağrısı, “saldırganın süreç başlatılmadan önce zaten erişim elde ettiği” tehdit modeli için tasarlanmış değildir.
    • mseal çağrı sarmalayıcısının üzerine yazılabilir, ama sistem çağrısının kendisinin üzerine yazılamaz.
      Araştırınca, preload tabanlı sistem çağrısı üzerine yazma yöntemlerinin hepsinin sarmalayıcıyı değiştirdiği görülüyor; doğrudan sistem çağrısı yapılırsa üzerine yazılamayacak gibi.
      Teknik olarak syscall fonksiyonunun kendisinin üzerine yazmak mümkün olabilir.
    • https://lwn.net/Articles/978010/’a göre bir glibc tunable eklenecek.
  • Meta: Yazıdaki mseal() prototipinin düzenlenmesi gerekiyor.
    İlk argüman unsigned start addr olarak gösterilmiş; muhtemelen doğrusu unsigned long start_addr olmalı.

    • Şu an iyi görünüyor: int mseal(unsigned long start, size_t len, unsigned long flags)
  • “Memory Sealing ‘Mseal’ System Call Merged for Linux 6.10” (2024) https://news.ycombinator.com/item?id=40474510#40474551 başlığında CPython’ın mseal() sistem çağrısını nasıl desteklemesi gerektiği daha önce tartışılmıştı.

  • OpenBSD’de uzun zamandır bulunan bir özellik: https://man.openbsd.org/mimmutable.2
    Bu kadar bariz bir özelliğin Linux’a neden ancak şimdi girdiğini merak ediyorum.

    • OpenBSD’nin mimmutable özelliği, 10 Nisan 2023’te yayımlanan OpenBSD 7.3 ile tanıtıldı; yani “uzun zamandır” denemez.
      Buna karşılık Linux ve FreeBSD’de memfd_create uzun zamandır vardı; OpenBSD’de ise anonim dosyalar olmadığı için shm_open’a dayanıyor.