3 puan yazan GN⁺ 2024-07-31 | 1 yorum | WhatsApp'ta paylaş
  • DARPA’nın TRACTOR programı, eski C kodlarını otomatik olarak Rust’a dönüştürerek C programlarındaki bellek güvenliği açığı kategorilerini ortadan kaldırmayı hedefleyen bir araştırma programıdır
  • C ve C++’ın bellek güvenliği sorunları 20 yılı aşkın süredir ele alınsa da, yalnızca hata tespit araçlarının yeterli olmadığı yönünde bir anlayış oluştu
  • Alternatif, mevcut kodu derleme zamanında güvenli olmayan programları reddeden güvenli programlama dillerine taşımaktır
  • Dönüştürme sonucunun, deneyimli bir Rust geliştiricisinin yazdığı kodla aynı kalite ve stile sahip olması hedefleniyor; statik ve dinamik analiz ile büyük dil modeli tabanlı makine öğrenimi birleştiriliyor
  • MIT Lincoln Laboratory test ve değerlendirmeyi üstleniyor; benchmark’lar, kilometre taşı projeleri ve araçlar herkese açık sayfada yayımlanıyor

TRACTOR’ın hedefi

  • TRACTOR, “Translating All C to Rust” programıdır ve eski C kodlarını otomatik olarak Rust’a dönüştürmeyi amaçlar
  • Güvenlik açısından, C programlarında bulunan bellek güvenliği güvenlik açıkları kategorisinin tamamını ortadan kaldırmaya çalışır
  • Dönüştürülen kodun yalnızca çalışır durumda olması değil, deneyimli bir Rust geliştiricisinin ürettiği kodla aynı kalite ve stile sahip olması hedeflenir

Rust’a dönüştürme neden gerekli?

  • C ve C++’ın bellek güvenliği sorunları, yazılım mühendisliği topluluğunun 20 yılı aşkın süredir ele aldığı bir meseledir
  • Yalnızca hata tespit araçlarına dayanan yaklaşımla sorunu yeterince çözmenin zor olduğu konusunda bir uzlaşı oluştu
  • Daha çok tercih edilen yaklaşım, derleme zamanında güvenli olmayan programları reddedebilen güvenli programlama dilleri kullanmaktır
  • TRACTOR bu hedef dil olarak Rust’ı kullanır

Otomatik dönüştürmede kullanılan teknolojiler

  • TRACTOR, eski C kodlarını Rust’a taşımak için çeşitli yazılım analiz teknikleri ile makine öğrenimi tekniklerini birleştirir
  • Analiz teknikleri

    • Statik analiz ve dinamik analiz birlikte kullanılır
    • Büyük dil modellerini içeren makine öğrenimi teknikleri de bu birleşime dahildir
    • Bu birleşim, C kodunun yapısını ve davranışını anlamak ve Rust koduna otomatik dönüştürme için gereken temel teknik ekseni oluşturur

Test, değerlendirme ve açık kaynaklar

1 yorum

 
GN⁺ 2024-07-31
Hacker News yorumları
  • Bu arada https://sam.gov/opp/1e45d648886b4e9ca91890285af77eb7/view de bakmaya değer

    • Teklif sahipleri bilgilendirme toplantısı PDF'ine doğrudan bağlantı: https://sam.gov/api/prod/opps/v3/opportunities/resources/fil...
      Bu etkinliğin amacının TRACTOR'ın teknik hedeflerini ve zorluklarını açıklamak, potansiyel teklif sahiplerinin sorularını yanıtlamak ve kendi araştırmalarının TRACTOR program hedefleriyle nasıl örtüşebileceğini değerlendirme fırsatı sunmak olduğu belirtiliyor
  • Bu gerçekten çok zor görünüyor. Özellikle deneyimli kişilerin yazdığı deyimsel Rust, C'ye hiç benzemiyor ve ilginç kodların çoğu C++ ile yazılmış durumda
    Sonuçta bu, bir C programındaki tüm ayırmaların ömürlerini statik olarak belirlemekle aynı şey değil mi diye düşünüyorum. Kullanıcı tanımlı ayırıcılar veya kapalı kaynak kütüphaneler üzerinden yapılan ayırmalar da buna dahil. Bu alanda uzun süredir araştırmalar var ama büyük başarılar pek yok; C/C++ programları, referans sayımı gibi güvenlik önlemleri olmadan bile ayırma ömürlerini kullanıcının hangi düğmeye bastığına bağlayabiliyor. İyi bir fikir değil ama mümkün
    Bir başka bariz sorun da analiz edilecek programın tanım gereği hatalı kod olması. Ömürler mantıklı olsaydı bellek güvenliği açıkları da olmazdı ve değiştirilmesine gerek kalmazdı. Statik olarak “ömürlerin nasıl olması gerektiğini” tespit etmeye çalışan araştırmalar genellikle analiz edilen kodun baştan doğru olduğunu varsayar. Ömürlerin belirlenemediği noktaları bulup geliştiriciden yardım isteyen bir program hedeflenebilir

    • Çok zor bir iş ve DARPA zor işlere para vermeyi sever[1]
      Bununla birlikte DARPA'nın otomatik program çevirisini ya da Rust'a otomatik çeviriyi denediği ilk sefer bu değil[2]
      [1]: https://www.urbandictionary.com/define.php?term=DARPA%20hard
      [2]: https://c2rust.com/
    • Zor işlerden söz açılmışken, DOE de 20 yılı aşkın süredir devam eden ROSE adlı bir projeyi finanse ediyor. Statik analiz ve C/C++/Cuda arasında otomatik çevirinin yanı sıra Python gibi üst düzey dilleri ve HPC için C/C++ varyantlarını da kapsıyor
      Bu proje, bu dilleri fiilen aynı düğüm tipi kümesiyle destekleyen birleşik bir soyut sözdizimi ağacına sahip olduğu için epey güzel. 2014 yazında Livermore'da staj yaparken üzerinde çalışma fırsatım olmuştu
      Açık kaynak da: http://rosecompiler.org/ROSE_HTML_Reference/index.html
    • Genel durumda unsafe Rust'a çevrileceğini, yalnızca ara sıra izole uç düğümlerin güvenli Rust'a çevrileceğini düşünüyorum
      Ödünç alma denetleyicisiyle uğraşmak bile zor geliyorsa, C'nin mümkün tüm program uzayını ve meşhur tanımsız davranışlarını da hesaba katarak ödünç alma denetleyicisinin onaylayacağı koda otomatik çevirmek çok daha zordur. Derleyici yazımının klasik sorunlarından biri, geçerli programların uzayının derlenebilir programların uzayından çok daha büyük olmasıdır
      Kısa bir aramada c2rust gibi denemeler de olduğunu gördüm[1]. TRACTOR'ın bundan nasıl farklı olduğunu merak ediyorum
      [1] https://github.com/immunant/c2rust
    • DARPA projelerine DARPA-hard denmesinin bir nedeni var
    • Yaklaşım muhtemelen “yapay zeka programın işlevini bir tür teknik dilde özetler, ardından aynı işlevler kümesini kapsayan Rust kodu sentezler” şeklinde olacaktır
      Kaynak programı vermek yerine o programın kılavuzunu vermek daha ilginç olurdu. Ancak kılavuzların programın tüm ince davranışlarını kapsaması nadirdir; bu yüzden en azından gerçek referans değerleri elde etmek için kaynak koda bakmak gerekmesi muhtemel
  • Önerilen bu girişimden bir süredir haberdardım; artık kamuya açılıyor olması heyecan verici. Çok iddialı bir öneri ve bu düzeyde bir iddianın DARPA’nın misyonuna uygun olduğunu düşünüyor, başarılı olmasını diliyorum.
    Bu alanda Rust’ı savunan biri olarak, bu öneriyi ileri taşıyanların C’den Rust’a otomatik çeviri olasılığına dair beklentilerini düşürmeye çalıştım. Bana göre temel engel, C kaynak kodunun Rust kaynak koduna göre daha az bilgi içermesi. C kodunu Rust koduna çevirmek için birinin ya da bir şeyin eksik bilgiyi üretmesi gerekir. Bir görüntüyü çok büyütmenin, orijinal görüntüde yakalanmamış bilgi bitlerini hatasız biçimde üretememesiyle aynı nedenle, bu eksik bilgiyi kusursuz üretmenin imkânsız olduğu kolayca kanıtlanabilir. Sonuçta mevcut kaynak kodda eksik olan bilgiyi ekstrapole etmek, yani icat etmek gerekir. Doğru ekstrapolasyon muhakeme gerektirir ve özellikle gözetimsiz dil modelleri bunu büyük ölçekte yaptığında kaçınılmaz olarak hata üretecek bir süreçtir. Bu sorunu bir ölçüde hafifletebileceğini düşündüğüm bir çözüm önermişliğim var, ama ayrıntılarına girmeyeceğim.
    Nihayetinde bu projenin bir ölçüde başarı elde edebileceğini düşünüyorum; ancak temkinli ve ölçülü beklentilerle ilerlenmeli. Aynı zamanda kamuya açık hiçbir sonuç çıkmama olasılığı da var, bu yüzden bu aşamada aşırı anlam yüklenmemesi gerektiğini söylemek isterim. Özellikle hükümet tekil bir varlık değildir; dolayısıyla bu proje C’ye yönelik topyekûn bir reddiye ya da Rust’a yönelik topyekûn bir kutsama olarak yorumlanmamalı. Her kurum bellek güvenliği teknolojilerini benimseme yönünü ve takvimini kendisi belirleyecektir. Örneğin NIST yalnızca Rust’ı değil, Ada SPARK’ı ve çeşitli güçlendirilmiş C/C++ lehçelerini de öneriyor.

    • Grammatech’in CRAM çalışmasıyla nasıl bir ilişkisi var?
      https://cpp-rust-assisted-migration.gitlab.io/blog/
    • C kodunun biçimsel anlamını korumaya çalışmayıp, çeviriden sonra yalnızca test suite’ten geçmesini yeterli sayarsanız çeviri için çok daha fazla hareket alanı oluşur.
      Gerçek Rust’a geçirme projeleri çoğu zaman bu şekilde işler. Fuzzer’lar da ek test verisi üreterek dal kapsamasını artırmaya yardımcı olabilir.
  • Şahsen “tüm dünyayı Rust ile baştan yazalım” zihniyetini sevmiyorum. Yine de bir projeyi yeni bir dile ya da platforma taşımaya çalışıyorsanız mekanik çeviri kötü bir yöntemdir.
    Daha iyi bir mimari planlamak ve daha iyi bir yazılım sistemi tasarlamak için zaman ayırmalı, ardından parçaları tek tek değiştirmenin yolunu bulmalısınız. Havada şato kurarsanız asla yere inmez. Bu sistemde Rust kullanmaya karar verdiyseniz sorun yok, ama Rust’a uygun biçimde yazmalısınız. C’yi Rust’a geri taşımaya çalışmamalısınız.
    Bence çok daha iyi ve olgun süreç, C’yi modern C’ye güncellemek ve CBMC gibi bir model denetleyiciyle bellek, kaynak ve tamsayı aritmetiği güvenliğini doğrulamaktır. Kod tabanını, bilgi birikimini ve geliştiricileri korurken, kademeli Rust yeniden yazımıyla aynı güvenliği elde edebilirsiniz.

    • Olmaz. CBMC harika, ama hiç “gerçek” bir programı biçimsel olarak doğruladınız mı?
      Elle mimarisi tasarlanmış bir Rust sürümüyle değiştirmenin kesinlikle daha iyi bir çözüm olduğuna katılıyorum, ama maliyeti de daha yüksek. Burada hedeflenen şey, RLBox tarzında “neredeyse hiç çaba harcamadan güvenliği büyük ölçüde iyileştiren” bir ürün gibi görünüyor. Kaynak varsa tamamen elle yeniden yazmayın demek değil; ama hiç yapmamaktan iyidir.
    • Modern C de klasik C ile tamamen aynı şekilde dizilerde ve string’lerde güvenlik açıklarına sahip; 50 yıldır değişen bir şey yok.
    • Bu, eski sistemlerden çıkarken elde olsa iyi olacak türden, kesinlikle havada kalan bir DARPA meydan okuması. Ama bir dildeki bir fonksiyonu ya da metodu ChatGPT’ye verip başka bir dile çevirmesini isteseniz de genelde pek iyi sonuç vermez.
      Başta çözmeye çalıştığınız problemi ChatGPT’ye sorarsanız daha sık doğru yanıt verir, ama yine de genel olarak iyi değildir. Çıktıdaki en temel şeyleri bile çalışır hâle getirmek için hâlâ çok fazla düzeltme ve düşünme gerekir.
    • Her yerde çalışan ama kimsenin dokunmadığı uykuda bir kod için “yeniden el sürmeden önce kötü Rust’a çevir” yaklaşımının bir miktar cazibesi var.
      Bunun açıkça iyi bir fikir olması anlamında bir cazibe değil. Çeviriyle oluşan “kötü Rust”, arka planda bug gürültüsü olan C’ye kıyasla üzerinde çalışılması çok daha kötü olabilir. Sadık çeviri sayesinde o bug’lar da “kötü Rust”ta aynen bulunacaktır. C’de insanlar sorunlarla nasıl başa çıkacaklarını bir ölçüde biliyor; ama “kötü Rust”ta Rust insanları böyle şeylere alışık olmadığından gerçekten kötü olur.
      Yine de birilerinin bunu tekrar tekrar temizleyip katlanılabilir hâle getirecek teknikler geliştirme olasılığı sıfır değil. Ayrıca projenin hedef dışı bir çıktısı olarak “x, y, z yüzünden katlanılabilir Rust’a çevrilemez” türünde linter geri bildirimi de ortaya çıkabilir. C geliştiricileri bunu inceleyebilir; kod iyi Rust’a çevrilebilir hâle geldiyse, çevirmeye gerek kalması da azalır.
      Böyle bir sonuç çıkarsa, bazıları için çözümü çalıştırılabilir C ile tarif edip “çevirici/linter”ın onları bozulmamış bir yaklaşıma yönlendirmesi daha kolay olabilir. Bu olumlu sonuçların olasılığını epey düşük görüyorum, ama ara sıra karanlık at bahsi yapmak DARPA’nın iş tanımına yakın değil mi diye düşünüyorum.
    • “Tüm dünyayı Rust ile baştan yazalım” diye bir zihniyet hiçbir yerde yok. Dinamik dillerde ya da Go gibi çöp toplamalı statik tipli dillerde bırakılması çok daha iyi olan muazzam miktarda yazılım var. İyi mühendis, işe uygun aracı kullanmak gerektiğini anlar.
      Asıl mesele, gerçek hayatta defalarca sorun olduğu kanıtlanmış bellek güvenliği CVE’lerini azaltmaya başlamak.
      C/C++’tan Rust’a otomatik ve güvenilir biçimde çeviri yapılabilseydi bunun çoktan yapılmış olacağına katılıyorum. Ancak daha iyi mimari ve sistem planlayıp parçaları tek tek değiştirme sürecinin bir noktasında insanlar “Artık C’yi çok daha iyi kullanıyoruz, bellek güvenliği bug’ları da yapmıyoruz; burada durabiliriz, değil mi?” özgüvenine kapılabilir ve gerçekten de öyle yaparlar. Sonra 6 ay sonra yine trajikomik bir buffer overflow CVE’si çıkar.
      C’yi modern C’ye güncellemek ve CBMC ile doğrulamak da muazzam bir yatırımdır. O kadarını yapacaksanız, bence Rust’a geçmek daha iyi. Kademeli Rust yeniden yazımıyla aynı güvenliği elde edeceğiniz sözü mümkün olabilir, ama oldukça belirsiz ya da net bir sonuçtan uzak görünüyor.
  • Pek çok kişi bunu tüm C ve C++ kodlarını Rust’a çevirme talebi ya da emri olarak okuyor, ama dikkat çekici proje adına rağmen özet öyle okunmuyor. Birbiriyle ilişkili ama ayrı iki paragraf var
    Birincisi, C ve C++ büyük ölçekte yeterince güvenli değil. Dikkatli programlama ve iyi araçlar kullanılsa bile, temelde güvenli olmayan tasarımları yüzünden çok fazla güvenlik açığı ortaya çıkıyor. Bu nedenle mümkün olduğunca çok kodun “güvenli” dillere, özellikle bellek güvenliğini garanti eden dillere çevrilmesi ya da yeniden yazılması gerekiyor
    İkincisi, mevcut C kodunu Rust’a çeviren yazılımların finanse edilip yarışmaya açılacağı
    Bu, dünyayı Rust ile yeniden yazma mutabakatı değil. Güvenli dillere geçiş mutabakatı; Rust bunun örneklerinden biri ve bu geçişte Rust’ı hedefleyen bir program olduğu anlamına geliyor

    • Bu dillerde unsafe söz dizimi varsa, onu kullanma kuralları ne olacak? Burada kullanılacak tanımlı bir kurallar kümesi yoksa, sonunda yine başlangıç noktasına dönülür
      Rust’ın güvenli modu var. Rust’ın kendisi güvenli bir dil değil. İlginç işler yapmak için unsafe blokları gerekiyor. Bununla çok şey kazanılmıyor
      Öte yandan programcının pointer’lara dokunmasına bile izin vermeyen çok sayıda garbage-collected dil var. Neden bu diller dikkate alınmıyor? Sebep performans. Rust programcıları performansı bu kadar “önemsediği” için, o dille temel problem asla çözülemez
      Performans mı istiyorsunuz, güvenlik mi? İkisine birden sahip olamazsınız
  • Bunun herhangi bir otomasyon yöntemiyle çalışabilmesi gerçekten şaşırtıcı. Sıradan bir C programını Rust’a satır satır aktarmak mümkün değil
    C programlarında pointer’lar ve aliasing her yerdedir; Rust ise bu kavramları açıkça engeller. Tamamını unsafe ile sarmalamadıkça, bir C programını Rust’ta yeniden yazmak için pek çok tipik yapıyı daha yüksek seviyede yeniden düşünmek gerekir

    • Satır satır çeviri imkânsız; bu yüzden daha büyük anlamsal çıkarım yapmak için AI kullanmak gerekiyor
      Her şeyi tek seferde çevirmek de gerekmez. Rust derleyicisinin değerlerinden biri, tekrar LLM’e verilip yineleme yapılabilecek çok sayıda somut bilgi sağlamasıdır
      Benim startup’ım grit.io’da benzer bir problem üzerinde çalışıyoruz ve C -> Rust’ın yakın vadede yeterince ele alınabilir olduğunu düşünüyorum. Kesinlikle kolay değil ama çözülebilir bir problem
    • Çok iş parçacıklı programları hariç tutarsak, uzun ömürlü aliasing gerçekten C programlarının genelinde her yerde mi? Birçok programda bunun çoğunun tek bir fonksiyon kapsamında ya da onun içindeki fonksiyon çağrıları boyunca gerçekleşmesini beklerim. Bu durumda borrowing ile çözülmez mi?
      Öyleyse bunu bir alt problem olarak ele alıp, verinin thread’ler arasında nasıl paylaşıldığını tespit etmeyi de başka bir problem yapabiliriz. İkinci durumda birçok programda “thread T1, kuyruk Q’ya koyar; thread T2 alır” gibi örtük sahiplik kuralları olacaktır. Bu, “kuyruğa koyunca sahiplik devredilir” şeklinde çevrilebilir
      Bu tür kuralları tespit etmek kolay olmayacaktır, ama tamamen erişilemez bir iş gibi de görünmüyor; bir araştırma projesi olarak yeterince anlamlı olabilir
    • Saf bir yeni başlayan olarak soruyorum: Satır satır gidip tamamını unsafe ile sarmalayarak, aynı binary’ye derleyip, eşdeğerliği sürekli doğrularken unsafe kısımlarını yavaş yavaş çıkaramaz mıyız?
      Böylece en azından mümkün olduğunca çok kısmı Rust’a taşımış, mühendislerin yeniden düşünmesi gereken kavramları da ayrı ele almış oluruz gibi geliyor
    • Satır satır çeviri için çok fazla “AI” bile gerekmez. Kabaca, çoğunlukla unsafe olan bir Rust çevirisi yapılabilir gibi
      AI’ın gerçekten işe yarar ve geçerli bir program üretebilmesi için lifetime’ları vb. anlaması gerektiğini varsayıyorum. Gerçekten bunu yaparsa etkileyici olur
    • Makroları yoğun kullanan codebase’lerde bunun özellikle nasıl sonuçlanacağını merak ediyorum
  • Çok sıkı kodlama pratiklerine uyup, koda özel açıklama notları yığmayı gerektiren üçüncü taraf statik doğrulama araçlarını entegre ederseniz C/C++ ile de benzer sonuçlar elde edilebilir
    Ya da sadece Rust kullanırsınız

    • C/C++ topluluğunun Rust’a tepki göstermesini görmek epey komik. O dillerle geçen onlarca yıllık emek ve deneyim, belli ki muhakeme devrelerinin üzerine yazmış
      Gerçek bir alternatif varken, bu kadar büyük ve bariz tasarım kusurları olan bir dili aklı başında kim savunur ki
    • “Tekel durumu” değil, özel açıklama notları demek istemiştim. Telefonun otomatik tamamlaması yüzünden
  • Bunun iyi gideceğini sanmıyorum. C’de Rust’ta büyük değişiklikler olmadan kopyalanamayacak soyutlamalar var
    C’de aynı pointer’ı içeren iki farklı veri yapısının o pointer’a yazması yaygındır. Bu Rust’ta basitçe kopyalanamaz ve epey akıllıca müdahale gerektirir

    • Derlenen, hem “Rust” hem de “AI” olan bir şeyler üretilebilir gibi. Moda sözcük gereksinimini iki kat karşılıyor, bu da araştırma projesini gerekçelendirmek için iyi
      Ama daha az hatalı bir çıktı ya da Rust’ın güvenilirliğini yaratan program yapısını otomatik üreten bir süreç elde edilmeyecek
  • Bunun otomatik olması mı gerekiyor? Öyleyse C’yi Rust’a otomatik port edebilen bir programın kaçınılmaz olarak C kodunun kendisini güvenli kılacak tüm işlevleri de içermesi gerekmez mi?

    • O cümleyi makul şekilde okursak tam otomasyon anlamına geldiğini söylemek zor; öyleyse sorunun cevabı hayır
      Bazı C kodları yalnızca “doğruluğu kanıtlanamaz” değil, “bellek güvenliği açısından fiilen yanlıştır”. Böyle kodlar insan müdahalesi olmadan otomatik çevrilmeyecektir. Doğru eşdeğer kod yoksa bu nasıl mümkün olsun? Aracın “Bu kodun ne yapmaya çalıştığını bilmiyorum; gerçekten yaptığı şeyin derleyiciyle yapılan anlaşmayı bozmak olduğunu ve dolayısıyla amaçlanan şey olmadığını da biliyorum. İnsan, yardım et” diyebileceği bir kaçış yoluna ihtiyacı var
      Teorik olarak bu kaçış yolunun yalnızca tanımsız davranış gerçekten ortaya çıktığında kullanılmasını sağlamak imkânsızdır. Rice teoremi nedeniyle. Pratikte de aşırı karmaşık kodu körlemesine çevirmemek gerekir; bu yüzden bunu yapmaya çalışmanın kendisi büyük olasılıkla arzu edilir değildir
      Sonuçta aracın işin çoğunu yapan ama insanın yönlendirdiği etkileşimli bir araç gibi olacağını hayal ediyorum. Ve o insan yönlendirmesinin sonucu olarak tam olarak eşdeğer kod değil, aynı amacı yerine getiren kod ortaya çıkacaktır
  • Eğer 1) Rust’ta bellek hatası yoksa ve 2) C otomatik olarak Rust’a çevrilebiliyorsa, bu tüm bellek hatalarının otomatik olarak düzeltilebileceği anlamına gelir
    Bu neredeyse kesinlikle doğru değil. Bu işin genel durumda tamamen imkânsız olma olasılığı çok yüksek

    • C kodunun tüm davranışlarını korumak istediğinizi belirtmediğiniz için, bu sorunun basit bir çözümü var
      Örneğin tüm dinamik bellek ayırmalarını çeviri zamanında belirlenen sabit tamponlarla değiştirip, bu tamponlara sığmayan tüm girdileri reddetmek yeterli olur