- TRACTOR dari DARPA adalah program riset yang bertujuan mengonversi otomatis kode C lama ke Rust untuk menghilangkan kategori kerentanan keamanan memori pada program C
- Masalah keamanan memori pada C dan C++ telah dibahas selama lebih dari 20 tahun, tetapi muncul kesadaran bahwa alat pendeteksi bug saja tidak cukup
- Alternatifnya adalah memindahkan kode yang ada ke bahasa pemrograman aman yang menolak program tidak aman pada waktu kompilasi
- Hasil konversi menargetkan kualitas dan gaya yang setara dengan kode yang ditulis pengembang Rust berpengalaman, dengan menggabungkan analisis statis, analisis dinamis, dan pembelajaran mesin berbasis model bahasa besar
- MIT Lincoln Laboratory bertanggung jawab atas pengujian dan evaluasi, dan benchmark, proyek milestone, serta alat dipublikasikan di halaman terbuka
Tujuan TRACTOR
- TRACTOR adalah program “Translating All C to Rust” yang bertujuan mengonversi otomatis kode C lama ke Rust
- Dari sisi keamanan, program ini berupaya menghapus seluruh kategori kerentanan keamanan keamanan memori yang ada pada program C
- Kode hasil konversi tidak hanya ditujukan agar sekadar berjalan, tetapi juga mengarah pada kualitas dan gaya yang sama dengan kode buatan pengembang Rust berpengalaman
Mengapa konversi ke Rust diperlukan
- Masalah keamanan memori pada C dan C++ adalah tantangan yang telah ditangani komunitas rekayasa perangkat lunak selama lebih dari 20 tahun
- Telah terbentuk kesepakatan bahwa mengandalkan alat pendeteksi bug saja sulit menyelesaikan masalah ini secara memadai
- Pendekatan yang lebih disukai adalah menggunakan bahasa pemrograman aman yang dapat menolak program tidak aman pada waktu kompilasi
- TRACTOR menggunakan Rust sebagai bahasa targetnya
Teknologi yang digunakan untuk konversi otomatis
- TRACTOR menggabungkan berbagai teknik analisis perangkat lunak dan pembelajaran mesin untuk memindahkan kode C lama ke Rust
-
Teknik analisis
- Menggunakan analisis statis dan analisis dinamis secara bersamaan
- Teknik pembelajaran mesin, termasuk model bahasa besar, juga menjadi bagian dari kombinasi ini
- Kombinasi ini merupakan poros teknologi inti yang diperlukan untuk memahami struktur dan perilaku kode C, lalu mengonversinya otomatis menjadi kode Rust
Pengujian, evaluasi, dan materi publik
- Tim MIT Lincoln Laboratory melakukan pengujian dan evaluasi program riset ini
- Benchmark, proyek milestone, dan alat dipublikasikan di halaman TRACTOR MIT Lincoln Laboratory
- Sebagai konten terkait, ditautkan Eliminating Memory Safety Vulnerabilities Once and For All
1 komentar
Komentar Hacker News
Sebagai referensi, https://sam.gov/opp/1e45d648886b4e9ca91890285af77eb7/view juga layak dilihat
Disebutkan bahwa tujuan acara ini adalah menjelaskan tujuan dan tantangan teknis TRACTOR, menjawab pertanyaan dari calon pengusul, serta memberi kesempatan untuk meninjau bagaimana riset masing-masing dapat selaras dengan tujuan program TRACTOR
Ini terlihat sangat sulit. Terutama karena Rust idiomatis yang ditulis oleh orang berpengalaman sama sekali tidak mirip dengan C, dan sebagian besar kode yang menarik ditulis dalam C++
Pada akhirnya, sepertinya ini sama saja dengan menentukan secara statis seluruh masa hidup alokasi dalam program C. Termasuk alokasi yang diteruskan ke allocator buatan pengguna atau library proprietari. Riset di bidang seperti ini sudah lama ada, tetapi belum banyak yang sangat berhasil, dan program C/C++ dapat mengaitkan masa hidup alokasi dengan tombol apa yang ditekan pengguna tanpa pengaman seperti reference counting. Itu bukan ide yang bagus, tetapi bisa dilakukan
Masalah jelas lainnya adalah bahwa program yang dianalisis, menurut definisinya, adalah kode yang memiliki bug. Jika masa hidupnya masuk akal, tidak akan ada kerentanan memory safety dan tidak perlu diganti. Riset yang secara statis mendeteksi “bagaimana seharusnya masa hidupnya” biasanya berasumsi bahwa kode yang dianalisis pada awalnya sudah benar. Mungkin bisa menargetkan program yang menemukan titik-titik ketika masa hidup tidak dapat ditentukan lalu meminta bantuan developer
Namun ini bukan pertama kalinya DARPA mencoba penerjemahan program otomatis atau penerjemahan otomatis ke Rust[2]
[1]: https://www.urbandictionary.com/define.php?term=DARPA%20hard
[2]: https://c2rust.com/
Proyek ini cukup keren karena memiliki abstract syntax tree terpadu yang mendukung bahasa-bahasa tersebut pada dasarnya dengan kumpulan tipe node yang sama. Saat magang di Livermore pada musim panas 2014, saya sempat berkesempatan mengerjakannya
Ini juga open source: http://rosecompiler.org/ROSE_HTML_Reference/index.html
Jika bergulat dengan borrow checker saja sudah terasa sulit, menerjemahkan otomatis seluruh ruang program C yang mungkin, beserta undefined behavior-nya yang terkenal, menjadi kode yang disetujui borrow checker jauh lebih sulit. Salah satu masalah klasik dalam penulisan compiler adalah bahwa ruang program yang valid jauh lebih besar daripada ruang program yang dapat dikompilasi
Dengan pencarian singkat, ada juga upaya seperti c2rust[1]. Saya penasaran apa perbedaan TRACTOR
[1] https://github.com/immunant/c2rust
Akan lebih menarik jika caranya memasukkan manual program itu, alih-alih program aslinya. Namun manual jarang memuat semua perilaku halus sebuah program, jadi setidaknya untuk mendapatkan nilai acuan yang sebenarnya kemungkinan besar tetap perlu melihat source code
Inisiatif yang diusulkan ini sudah saya ketahui cukup lama, dan menarik melihatnya kini diumumkan ke publik. Ini proposal yang sangat ambisius, dan saya rasa tingkat ambisi seperti ini sesuai dengan misi DARPA, jadi saya berharap berhasil
Sebagai pihak yang mendukung Rust di bidang ini, saya selama ini berusaha menurunkan ekspektasi orang-orang yang mendorong proposal ini terhadap kemungkinan penerjemahan otomatis dari C ke Rust. Hambatan mendasar yang saya lihat adalah bahwa kode sumber C memuat lebih sedikit informasi daripada kode sumber Rust. Untuk menerjemahkan kode C ke kode Rust, seseorang atau sesuatu harus menciptakan informasi yang hilang itu. Dengan alasan yang sama seperti memperbesar gambar tidak bisa menghasilkan bit informasi yang tidak tertangkap dalam gambar asli tanpa kesalahan, mudah dibuktikan bahwa mustahil menghasilkan informasi yang hilang ini secara sempurna. Pada akhirnya, informasi yang hilang dari kode sumber yang ada harus diekstrapolasi, atau dengan kata lain diciptakan. Mengekstrapolasi dengan benar membutuhkan penilaian, dan terutama ketika dilakukan dalam skala besar oleh model bahasa tanpa supervisi, proses itu pasti akan menghasilkan kesalahan. Saya pernah mengusulkan solusi yang menurut saya bisa meredakan masalah ini sampai batas tertentu, tetapi saya tidak akan membahas detailnya
Pada akhirnya saya pikir proyek ini bisa meraih keberhasilan sampai tingkat tertentu, tetapi harus dijalankan dengan ekspektasi yang hati-hati dan terkendali. Pada saat yang sama, ada juga kemungkinan tidak ada hasil publik sama sekali, jadi saya ingin mengatakan agar jangan menafsirkannya berlebihan pada tahap ini. Secara khusus, pemerintah bukanlah satu entitas tunggal, jadi proyek ini tidak boleh ditafsirkan sebagai penolakan total terhadap C atau restu penuh bagi Rust. Tiap lembaga akan menentukan sendiri arah dan jadwal adopsi teknologi keamanan memori. Misalnya, NIST merekomendasikan bukan hanya Rust, tetapi juga Ada SPARK dan beberapa dialek C/C++ yang diperkuat
https://cpp-rust-assisted-migration.gitlab.io/blog/
Proyek Rust-ifikasi nyata sering berjalan seperti ini. Fuzzer juga bisa membantu membuat data uji tambahan untuk meningkatkan branch coverage
Secara pribadi saya tidak menyukai pola pikir “mari tulis ulang seluruh dunia dengan Rust”. Meski begitu, jika hendak mem-porting suatu proyek ke bahasa atau platform baru, penerjemahan mekanis adalah cara yang buruk
Kita perlu meluangkan waktu untuk merencanakan arsitektur yang lebih baik dan merancang sistem perangkat lunak yang lebih baik, lalu mencari cara menggantinya bagian demi bagian. Kalau membangun istana di atas awan, ia tidak akan pernah menyentuh tanah. Jika memutuskan memakai Rust untuk sistem ini, itu tidak masalah, tetapi harus ditulis dengan gaya Rust. Jangan mencoba mem-backport C ke Rust
Menurut saya proses yang jauh lebih baik dan matang adalah memperbarui C menjadi C modern, lalu memverifikasi keamanan memori, sumber daya, dan operasi integer dengan model checker seperti CBMC. Dengan begitu kita bisa memperoleh keamanan yang sama seperti penulisan ulang bertahap ke Rust, sambil tetap mempertahankan codebase, basis pengetahuan, dan para pengembang
Saya setuju bahwa menggantinya dengan versi Rust yang arsitekturnya dirancang manual jelas merupakan solusi yang lebih baik, tetapi biayanya juga lebih besar. Di sini tampaknya targetnya adalah produk ala RLBox yang “meningkatkan keamanan secara besar dengan hampir tanpa usaha”. Kalau ada sumber daya, bukan berarti jangan melakukan penulisan ulang manual sepenuhnya, tetapi maksudnya ini lebih baik daripada tidak melakukan apa-apa
Jika menanyakan masalah awal yang ingin dipecahkan kepada ChatGPT, jawabannya memang lebih sering benar, tetapi tetap saja umumnya tidak bagus. Untuk membuat hal-hal dasar dari output-nya saja bisa berjalan, masih perlu banyak perbaikan dan pemikiran
Bukan daya tarik sebagai ide yang jelas bagus. “Rust jelek” hasil terjemahan kemungkinan jauh lebih buruk untuk dikerjakan daripada C dengan noise latar berupa bug. Berkat terjemahan yang setia, bug-bug itu juga akan tetap ada di “Rust jelek” tersebut. Di C, orang-orang setidaknya cukup tahu cara menangani masalahnya, tetapi “Rust jelek” benar-benar jelek karena orang Rust tidak terbiasa dengan hal semacam itu
Meski begitu, peluang seseorang mengembangkan teknik untuk membersihkannya berulang kali hingga menjadi cukup bisa ditoleransi bukanlah nol. Selain itu, sebagai keluaran non-tujuan proyek, bisa saja muncul umpan balik linter seperti “tidak dapat diterjemahkan menjadi Rust yang bisa ditoleransi karena x, y, z”. Pengembang C dapat meninjaunya, dan jika kodenya sudah bisa diterjemahkan menjadi Rust yang baik, alasan untuk menerjemahkannya pun berkurang
Jika hasil seperti ini muncul, bagi sebagian orang mungkin akan lebih mudah menjelaskan solusi dalam C yang dapat dijalankan dan membiarkan “translator/linter” mengarahkan mereka ke pendekatan yang tidak rusak. Saya menganggap hasil-hasil positif seperti ini kemungkinannya cukup rendah, tetapi sesekali memasang taruhan dark horse tampaknya memang mendekati deskripsi pekerjaan DARPA
Intinya adalah mulai mengurangi CVE keamanan memori yang terbukti berkali-kali benar-benar menjadi masalah
Saya setuju bahwa jika terjemahan otomatis dan andal dari C/C++ ke Rust memang bisa dilakukan, itu sudah akan terjadi. Namun di suatu titik dalam proses merencanakan arsitektur dan sistem yang lebih baik lalu menggantinya bagian demi bagian, orang bisa merasa percaya diri bahwa “sekarang kita sudah menulis C jauh lebih baik, jadi bukankah kita tidak akan membuat bug keamanan memori lagi, mungkin berhenti di sini saja?”, dan dalam praktiknya mereka memang akan begitu. Lalu 6 bulan kemudian muncul lagi CVE buffer overflow yang tragik sekaligus menggelikan
Memperbarui C menjadi C modern dan memverifikasinya dengan CBMC juga merupakan investasi yang sangat besar. Kalau sudah sejauh itu, lebih baik sekalian pindah ke Rust. Klaim bahwa kita bisa memperoleh keamanan yang sama seperti penulisan ulang bertahap ke Rust mungkin saja benar, tetapi tampaknya cukup tidak pasti atau jauh dari kesimpulan yang jelas
Banyak orang membaca ini sebagai permintaan atau perintah untuk menerjemahkan semua kode C dan C++ ke Rust, tetapi terlepas dari nama proyeknya yang mencolok, abstraknya tidak terbaca seperti itu. Ada dua paragraf yang saling terkait tetapi berbeda
Pertama, C dan C++ tidak cukup aman dalam skala besar. Meski kita memprogram dengan hati-hati dan memakai alat yang bagus, desain yang pada dasarnya tidak aman menimbulkan terlalu banyak kerentanan. Karena itu, sebanyak mungkin kode harus diterjemahkan atau ditulis ulang dalam bahasa yang “aman”, khususnya bahasa yang menjamin keamanan memori
Kedua, mereka akan mendanai dan mengadakan kompetisi untuk software yang menerjemahkan kode C yang ada ke Rust
Ini bukan konsensus untuk menulis ulang dunia dalam Rust. Ini adalah konsensus untuk bermigrasi ke bahasa yang aman, Rust adalah salah satu contohnya, dan ada program dalam migrasi ini yang menargetkan Rust
unsafe, bagaimana aturan untuk memakainya? Tanpa sekumpulan aturan yang terdefinisi untuk digunakan di sini, pada akhirnya kita hanya kembali ke titik awalRust memiliki mode aman. Bukan berarti Rust adalah bahasa yang aman. Untuk melakukan hal-hal menarik, diperlukan blok
unsafe. Dengan ini kita tidak mendapatkan banyak halDi sisi lain, ada banyak bahasa dengan garbage collection yang bahkan tidak membiarkan programmer menyentuh pointer. Mengapa bahasa-bahasa itu tidak dipertimbangkan? Alasannya adalah performa. Karena para programmer Rust begitu “mementingkan” performa, bahasa itu tidak akan pernah bisa menyelesaikan masalah mendasarnya
Mau performa, atau mau keamanan? Keduanya tidak bisa didapat sekaligus
Sungguh mengejutkan kalau ini bisa bekerja lewat bentuk otomasi apa pun. Program C biasa tidak bisa ditranskripsikan baris demi baris ke Rust
Dalam program C, pointer dan aliasing ada di mana-mana, dan Rust secara eksplisit mencegah konsep seperti itu. Kecuali seluruhnya dibungkus dengan
unsafe, menulis ulang program C ke Rust mengharuskan banyak struktur khas dipikirkan ulang pada level yang lebih tinggiTidak perlu menerjemahkan semuanya sekaligus juga. Salah satu nilai compiler Rust adalah ia memberi banyak informasi konkret yang bisa dimasukkan kembali ke LLM untuk iterasi
Di startup saya, grit.io, kami sudah menangani masalah serupa, dan saya melihat C -> Rust akan cukup bisa ditangani dalam waktu dekat. Jelas tidak mudah, tetapi ini masalah yang dapat diselesaikan
Jika demikian, itu bisa diperlakukan sebagai satu submasalah, dan mendeteksi bagaimana data dibagikan antar-thread bisa dijadikan masalah lain. Untuk kasus terakhir, banyak program mungkin memiliki aturan ownership implisit seperti “thread T1 memasukkan ke queue Q, lalu thread T2 mengambilnya”. Ini bisa diterjemahkan menjadi “saat dimasukkan ke queue, ownership berpindah”
Mendeteksi aturan seperti ini tentu tidak mudah, tetapi juga tidak tampak sepenuhnya di luar jangkauan, dan sebagai proyek riset bisa cukup bermakna
unsafe, mengompilasinya menjadi binary yang sama, lalu pelan-pelan melepasunsafesambil terus memverifikasi ekuivalensinya?Dengan begitu, setidaknya sebanyak mungkin bagian bisa dibawa ke Rust, dan hanya konsep yang perlu dipikirkan ulang oleh engineer yang ditangani terpisah
unsafeSaya berasumsi agar AI benar-benar menghasilkan program yang berguna dan valid, ia harus memahami lifetime dan sebagainya. Kalau benar-benar bisa begitu, itu akan mengesankan
Jika mengikuti praktik coding yang sangat ketat dan mengintegrasikan alat verifikasi statis pihak ketiga yang mengharuskan banyak anotasi proprietari dalam kode, hasil serupa memang bisa didapat dengan C/C++
Atau cukup pakai Rust
Siapa yang waras akan membela bahasa dengan cacat desain sebesar dan sejelas itu ketika ada alternatif nyata
Sepertinya ini tidak akan berjalan baik. C memiliki abstraksi yang tidak bisa direplikasi di Rust tanpa perubahan besar
Di C, dua struktur data berbeda yang menyimpan pointer yang sama dan menulis ke pointer itu adalah hal umum. Ini tidak bisa direplikasi secara sepele di Rust, dan membutuhkan intervensi yang cukup cerdik
Namun mereka tidak akan mendapatkan output dengan bug lebih sedikit, atau proses otomatis yang menghasilkan struktur program yang menciptakan keandalan Rust
Apakah ini harus otomatis? Jika ya, bukankah program yang bisa mem-porting C ke Rust secara otomatis niscaya harus mencakup semua fungsi untuk membuat kode C itu sendiri aman?
Sebagian kode C bukan sekadar “kebenarannya tidak bisa diverifikasi”, melainkan “benar-benar salah dari sisi keamanan memori”. Kode seperti itu tidak akan diterjemahkan otomatis tanpa campur tangan manusia. Bagaimana mungkin, kalau tidak ada kode ekuivalen yang benar. Alatnya perlu jalan keluar untuk berkata, “Saya tidak tahu kode ini bermaksud melakukan apa, dan yang benar-benar dilakukannya adalah melanggar janji dengan compiler, jadi saya juga tahu itu bukan maksudnya. Manusia, tolong bantu”
Secara teoretis, mustahil membuat jalan keluar itu hanya dipakai ketika undefined behavior benar-benar terjadi. Ini karena teorema Rice. Secara praktis pun, kita tidak boleh menerjemahkan kode yang terlalu sulit dipahami secara membabi buta, jadi upaya melakukan itu sendiri kemungkinan besar tidak diinginkan
Pada akhirnya saya membayangkan alatnya akan menjadi semacam alat interaktif yang melakukan sebagian besar pekerjaan tetapi dipandu manusia. Dan sebagai hasil dari panduan manusia itu, yang keluar bukan kode yang persis ekuivalen, melainkan kode yang menjalankan tujuan yang sama
Jika 1) Rust tidak memiliki bug memori dan 2) C dapat diterjemahkan otomatis ke Rust, itu berarti semua bug memori bisa diperbaiki secara otomatis
Ini hampir pasti tidak benar. Pekerjaan ini kemungkinan besar sepenuhnya mustahil dalam kasus umum
Misalnya, semua alokasi memori dinamis bisa diganti dengan buffer tetap yang ditentukan saat penerjemahan, lalu semua input yang tidak muat dalam buffer tersebut ditolak