Bahasa C sangat kuat dan banyak digunakan di mana - terutama di kernel Linux - tetapi juga sangat berbahaya. Satu pengembang kernel Linux menjelaskan bagaimana menangani kerentanan keamanan C.Anda dapat melakukan hampir semua hal dalam C, tetapi ini tidak berarti bahwa itu harus dilakukan. Kode C sangat cepat, tetapi dibawa tanpa sabuk pengaman. Bahkan jika Anda seorang ahli, seperti
kebanyakan pengembang kernel Linux , kesalahan pembunuh masih mungkin terjadi.
Selain jebakan seperti
alias penunjuk , C memiliki kesalahan mendasar yang tidak diperbaiki yang menunggu korban mereka. Ini adalah kerentanan yang ditangani
Case Cook , insinyur keamanan kernel Google Linux, di
Konferensi Keamanan Linux di Vancouver.
βC adalah sejenis assembler. Ini hampir kode mesin, "kata Cook, merujuk pada audiensi beberapa ratus rekan yang memahami dan menghargai kecepatan aplikasi pada C. Tapi kabar buruknya adalah" C datang dengan beberapa bagasi berbahaya, perilaku tidak jelas, dan kelemahan lain yang mengarah pada
lubang keamanan dan infrastruktur yang rentan. "
Jika Anda menggunakan C dalam proyek Anda, Anda harus memperhatikan masalah keamanan.
Perlindungan kernel Linux
Seiring waktu, Cook dan rekannya menemukan banyak masalah dengan C. asli untuk mengatasinya,
Proyek Perlindungan Kernel diluncurkan. Dia perlahan dan terus bekerja untuk melindungi kernel Linux dari serangan, menghapus kode yang bermasalah dari sana.
Ini rumit, kata Cook, karena "kernel perlu melakukan hal-hal yang sangat spesifik untuk arsitektur tertentu untuk manajemen memori, penanganan interupsi, penjadwalan, dan sebagainya." Sejumlah besar kode mengacu pada tugas-tugas spesifik yang perlu diperiksa dengan cermat. Misalnya, "C tidak memiliki API untuk mengatur tabel halaman atau beralih ke mode 64-bit," katanya.
Dengan beban seperti itu dan dengan perpustakaan standar yang lemah di C, ada terlalu banyak perilaku yang tidak jelas. Masak dikutip - dan setuju - dengan artikel blog Raf Levien,
"Dengan Perilaku Tidak Terdefinisi, Segalanya Mungkin .
"Cook memberikan contoh spesifik: "Apa isi dari variabel" tidak diinisialisasi "? Ini semua yang ada di ingatanku sebelumnya! Tidak ada tipe dalam void pointer, tetapi bisakah fungsi yang diketik dipanggil melalui mereka? Tentu saja! Perakitan semua sama: Anda dapat menghubungi alamat mana pun! Mengapa
memcpy()
memiliki argumen 'panjang tujuan maks'? Tidak masalah, lakukan saja apa yang Anda katakan; semua area memori sama! β
Mengabaikan peringatan ... tetapi tidak selalu
Beberapa fitur ini relatif mudah ditangani. Cook berkomentar: βLinus [Torvalds] menyukai ide selalu menginisialisasi variabel lokal. Jadi lakukan saja. β
Tetapi dengan reservasi. Jika Anda menginisialisasi variabel lokal di switch, Anda akan menerima peringatan: "Pernyataan itu tidak akan pernah dieksekusi
[-Wswitch-unreachable]
" karena cara kompiler memproses kode. Peringatan ini bisa diabaikan.
Namun tidak semua peringatan bisa diabaikan. "Array panjang variabel selalu buruk," kata Cook. Masalah lain termasuk kelelahan tumpukan, garis meluap, dan pelanggaran perlindungan halaman. Selain itu, Cook menarik perhatian pada
lambatnya VLA . Menghapus semua VLA dari kernel meningkatkan kinerja sebesar 13%. Meningkatkan kecepatan dan keamanan adalah manfaat ganda.
Meskipun VLA hampir dihapus dari kernel, mereka masih tetap ada dalam beberapa kode. Untungnya, VLA mudah ditemukan menggunakan
-Wvla
compiler
-Wvla
.
Masalah lain disembunyikan dalam semantik C. Jika break tidak ada pada switch, lalu apa yang dimaksud oleh programmer? Melewati istirahat dapat menyebabkan eksekusi kode dari beberapa kondisi; Ini adalah masalah yang sudah diketahui.
Jika Anda mencari pernyataan break / switch dalam kode yang ada, Anda dapat menggunakan
-Wimplicit-fallthrough
untuk menambahkan pernyataan switch baru. Ini sebenarnya adalah komentar, tetapi kompiler modern menguraikannya. Anda juga dapat
secara eksplisit menandai tidak adanya istirahat dengan komentar "fallthrough" .
Masak juga menemukan hit kinerja ketika memeriksa batas-batas untuk
alokasi memori slab . Misalnya, memeriksa
strcpy()-family
mengurangi kinerja sebesar 2%. Alternatif seperti
strncpy()
memiliki masalah sendiri. Ternyata Strncpy tidak selalu berakhir dengan karakter nol. Cook dengan sedih berbicara kepada hadirin: "Di mana saya bisa mendapatkan API terbaik?"
Selama sesi tanya jawab, seorang pengembang Linux bertanya, "Bisakah saya menyingkirkan API yang lama dan buruk?" Cook menjawab bahwa Linux mendukung konsep API lama untuk beberapa waktu. Namun demikian, Torvalds menolak gagasan ini, dengan alasan bahwa jika ada API yang ketinggalan zaman, itu harus dibuang sepenuhnya. Namun, selamanya menjatuhkan API "berbahaya secara politis," tambah Cook. Jadi sementara kita terjebak.
Solusi jangka panjang untuk masalah ini? Semakin banyak pengembang yang memahami masalah keamanan
Masak meramalkan perjalanan yang panjang dan sulit. Gagasan membuat dialek Linux C dulu tampak menarik, tetapi tidak. Masalah sebenarnya dengan kode berbahaya adalah bahwa "orang tidak ingin melakukan pekerjaan membersihkan kode - tidak hanya kode yang buruk, tetapi C itu sendiri," katanya. Seperti halnya semua proyek open source, "kami membutuhkan lebih banyak pengembang, pengulas, penguji, dan spesialis backport yang berdedikasi."
Berbahaya C: pelajaran
- C adalah bahasa yang matang dan kuat, tetapi menciptakan kesulitan teknis dan masalah keamanan.
- Pengembang Linux memberikan perhatian khusus untuk mengamankan C (tanpa kehilangan kekuatannya), karena sebagian besar sistem operasi ditulis di atasnya.
- Insinyur keamanan kernel Linux Linux mengidentifikasi kerentanan bahasa tertentu dan menjelaskan cara menghindarinya.