Apakah menggunakan kompiler C yang sudah usang merupakan risiko keamanan?

139

Kami memiliki beberapa sistem build dalam produksi yang tidak ada yang peduli dan mesin ini menjalankan versi GCC kuno seperti GCC 3 atau GCC 2.

Dan saya tidak dapat membujuk manajemen untuk memutakhirkannya ke yang lebih baru: mereka berkata, "jika tidak rusak, jangan memperbaikinya".

Karena kita memelihara basis kode yang sangat lama (ditulis pada tahun 80-an), kode C89 ini mengkompilasi dengan baik pada kompiler ini.

Tapi saya tidak yakin sebaiknya menggunakan barang-barang lama ini.

Pertanyaanku adalah:

Bisakah menggunakan kompiler C lama membahayakan keamanan program yang dikompilasi?

MEMPERBARUI:

Kode yang sama dibangun oleh Visual Studio 2008 untuk target Windows, dan MSVC belum mendukung C99 atau C11 (Saya tidak tahu apakah MSVC yang lebih baru melakukannya), dan saya dapat membangunnya di kotak Linux saya menggunakan GCC terbaru. Jadi jika kita hanya memasukkan GCC yang lebih baru, itu mungkin akan membangun sama baiknya dengan sebelumnya.

Calmarius
sumber
5
Pertanyaan menarik - ini mungkin layak dibaca cepat juga - developers.slashdot.org/story/13/10/29/2150211/ ... .. jadi kompiler yang lebih baru juga dapat membahayakan keamanan ketika mengoptimalkan.
Neil
6
Apakah versi gcc lama itu mendukung kompilasi ke PIC / PIE untuk ASLR? Apakah mereka mendukung tumpukan kenari? W ^ X (NX)? Jika tidak, kurangnya mitigasi untuk kerentanan adalah alasan yang baik untuk meningkatkannya.
EOF
12
Hanya dengan melihat peringatan dari gcc 4.x dapat segera mengungkapkan seluruh beban lubang keamanan yang ada yang tidak Anda ketahui.
OrangeDog
7
@OrangeDog: Mengapa gcc 4.x? gcc6 adalah seri rilis saat ini, dan gcc 5 telah ada untuk sementara waktu. Tapi ya, memperbaiki masalah yang diidentifikasi -O3 -Wall -Wextra -fsanitize=undefineddengan gcc dan dentang modern akan membantu.
Peter Cordes
4
@OrangeDog GCC telah beralih ke nomor versi pemasaran. GCC 5 layak mendapatkan versi utama, karena mereka mengubah standar C dan C ++ standar dan libstdc ++ ABI. GCC 6 seharusnya disebut 5.1.
zwol

Jawaban:

102

Sebenarnya saya berpendapat sebaliknya.

Ada sejumlah kasus di mana perilaku tidak ditentukan oleh standar C tetapi di mana jelas apa yang akan terjadi dengan "kompiler bodoh" pada platform tertentu. Kasus-kasus seperti membiarkan integer yang ditandatangani meluap atau mengakses memori yang sama melalui variabel dari dua tipe yang berbeda.

Versi terbaru gcc (dan dentang) telah mulai memperlakukan kasus-kasus ini sebagai peluang optimisasi yang tidak peduli jika mereka mengubah perilaku biner dalam kondisi "perilaku tidak terdefinisi". Ini sangat buruk jika basis kode Anda ditulis oleh orang-orang yang memperlakukan C seperti "assembler portabel". Seiring berjalannya waktu optimisers mulai melihat potongan kode yang lebih besar dan lebih besar ketika melakukan optimisasi ini meningkatkan kemungkinan biner pada akhirnya melakukan sesuatu selain dari "apa yang biner dibangun oleh kompiler bodoh" akan lakukan.

Ada switch kompiler untuk mengembalikan perilaku "tradisional" (-fwrapv dan -fno-strict-aliasing untuk dua yang saya sebutkan di atas), tetapi pertama-tama Anda harus tahu tentang mereka.

Sementara pada prinsipnya bug kompiler dapat mengubah kode yang sesuai menjadi lubang keamanan saya akan mempertimbangkan risiko ini diabaikan dalam skema besar hal.

plugwash
sumber
13
Namun argumen ini bekerja dua arah. Jika kompiler memiliki "perilaku tidak terdefinisi" yang dapat diprediksi, maka bisa dibilang lebih mudah untuk memanfaatkannya dengan jahat ...
André
18
@Andre Kode yang dikompilasi memiliki perilaku yang tidak dapat diprediksi yang dapat diprediksi. Yaitu, begitu kode telah dikompilasi, setiap perilaku yang tidak dapat diprediksi sekarang dapat diprediksi, dalam versi yang dikompilasi tersebut.
user253751
6
people who treated C like a "portable assembler"bukankah itu C?
Maks
10
@ Max Jawaban ini memperingatkan tentang fakta bahwa gagasan "assembler portabel" setidaknya sudah usang dalam praktik, karena pengoptimal modern. Dan saya berpendapat bahwa secara konsep tidak pernah benar untuk memulai.
Theodoros Chatzigiannakis
6
Tidak ada simpati di sini untuk mereka yang mengandalkan perilaku tidak terdefinisi dan kemudian mulai menuai apa yang mereka tabur. Ini tidak berarti kompiler baru secara inheren kurang aman - itu berarti kode tidak patuh adalah bom waktu. Menyalahkan harus dibagi sesuai.
underscore_d
52

Ada risiko dalam kedua tindakan tersebut.


Kompiler yang lebih tua memiliki keuntungan jatuh tempo, dan apa pun yang rusak di dalamnya mungkin (tetapi tidak ada jaminan) berhasil diselesaikan.

Dalam hal ini, kompiler baru adalah sumber potensial bug baru.


Di sisi lain, kompiler yang lebih baru hadir dengan tooling tambahan :

  • GCC dan Clang sekarang memiliki fitur sanitizers yang dapat menginstruksikan runtime untuk mendeteksi berbagai perilaku yang tidak terdefinisi (Chandler Carruth, dari tim Google Compiler, mengklaim tahun lalu bahwa ia berharap mereka telah mencapai cakupan penuh)
  • Dentang, setidaknya, fitur pengerasan , misalnya Integritas Aliran Kontrol adalah tentang mendeteksi hi-jack aliran kontrol, ada juga alat pengerasan untuk melindungi terhadap serangan penghancuran tumpukan (dengan memisahkan bagian aliran kontrol dari tumpukan dari bagian data) ; fitur pengerasan umumnya overhead rendah (<1% CPU overhead)
  • Dentang / LLVM juga bekerja pada libFuzzer , sebuah alat untuk membuat tes unit fuzzing yang diinstrumentasi yang mengeksplorasi ruang input dari fungsi yang sedang diuji dengan cerdas (dengan mengubah input untuk mengambil jalur eksekusi yang belum dieksplorasi)

Menginstruksikan biner Anda dengan pembersih (Pembersih Alamat, Pembersih Memori atau Pembersih Perilaku Tidak Terdefinisi) dan kemudian mengaburkannya (menggunakan American Fuzzy Lop misalnya) telah menemukan kerentanan dalam sejumlah perangkat lunak profil tinggi, lihat misalnya artikel LWN.net ini .

Alat-alat baru itu, dan semua alat masa depan, tidak dapat diakses oleh Anda kecuali Anda meningkatkan kompiler Anda.

Dengan tetap menggunakan kompiler yang kurang bertenaga, Anda meletakkan kepala di pasir dan menyilangkan jari yang tidak menemukan kerentanan. Jika produk Anda adalah target bernilai tinggi, saya mendorong Anda untuk mempertimbangkan kembali.


Catatan: bahkan jika Anda TIDAK meningkatkan kompiler produksi, Anda mungkin ingin menggunakan kompiler baru untuk memeriksa kerentanannya; Sadarilah bahwa karena mereka adalah kompiler yang berbeda, jaminannya berkurang.

Matthieu M.
sumber
1
+1 karena repot menyebutkan kasus-kasus di mana penyusun baru bisa lebih aman, daripada menumpuk di kereta musik 'b-tapi my old UB yang baik' dari jawaban lain. ini di atas banyak perbaikan lain yang mereka tawarkan yang tidak secara langsung berkaitan dengan keamanan tetapi memberikan dorongan lebih untuk menjadi modern yang masuk akal.
underscore_d
Meskipun rasanya seperti menganjurkan 'keamanan melalui ketidakjelasan'; bug yang memengaruhi kompiler lama diketahui dan publik. Meskipun saya setuju bahwa kompiler baru akan memperkenalkan bug, bug ini belum umum seperti yang ada pada versi sebelumnya, yang merupakan keamanan jika Anda sering memperbarui aplikasi.
The6P4C
Chandler Carruth sangat lucu, dan berbicara tentang hal-hal luar biasa. Saya akan menikah dengannya jika saya bisa.
Daniel Kamil Kozar
46

Kode kompilasi Anda mengandung bug yang dapat dieksploitasi. Bug berasal dari tiga sumber: Bug dalam kode sumber Anda, bug di kompiler dan pustaka, dan perilaku yang tidak terdefinisi dalam kode sumber Anda bahwa kompiler berubah menjadi bug. (Perilaku tidak terdefinisi adalah bug, tetapi belum bug dalam kode yang dikompilasi. Sebagai contoh, i = i ++; di C atau C ++ adalah bug, tetapi dalam kode yang dikompilasi Anda dapat meningkatkan i sebesar 1 dan menjadi OK, atau mengatur saya ke beberapa sampah dan menjadi bug).

Tingkat bug dalam kode yang dikompilasi Anda mungkin rendah karena pengujian dan untuk memperbaiki bug karena laporan bug pelanggan. Jadi mungkin ada sejumlah besar bug pada awalnya, tetapi itu sudah turun.

Jika Anda memutakhirkan ke kompiler yang lebih baru, Anda mungkin kehilangan bug yang diperkenalkan oleh bug kompiler. Tetapi semua bug ini akan menjadi bug yang sepengetahuan Anda tidak ada yang ditemukan dan dieksploitasi. Tetapi kompiler baru mungkin memiliki bug sendiri, dan yang penting kompiler baru memiliki kecenderungan yang lebih kuat untuk mengubah perilaku tidak terdefinisi menjadi bug dalam kode yang dikompilasi.

Jadi Anda akan memiliki banyak bug baru dalam kode kompilasi Anda; semua bug yang dapat ditemukan dan dieksploitasi oleh peretas. Dan kecuali Anda melakukan banyak pengujian, dan meninggalkan kode Anda dengan pelanggan untuk menemukan bug untuk waktu yang lama, itu akan kurang aman.

gnasher729
sumber
6
Jadi dengan kata lain ... tidak ada cara mudah untuk mengetahui masalah apa yang dikompilasi oleh kompiler, dan dengan mengalihkan semua yang Anda lakukan adalah mendapatkan serangkaian masalah yang tidak diketahui?
Jeremy Kato
1
@JeremyKato: well, ada beberapa kasus di mana Anda juga mendapatkan serangkaian masalah yang diketahui. Saya tidak yakin apa kelemahan keamanan yang diketahui ada di kompilator itu sendiri, tetapi demi contoh konkret anggap bahwa memperbarui ke kompiler baru berarti juga dapat mengambil libc terbaru (saat menggunakan yang lama berarti tidak dapat untuk melakukan ini), maka Anda akan tahu Anda sedang memperbaiki kekurangan ini di getaddrinfo(): access.redhat.com/articles/2161461 . Contoh itu sebenarnya bukan cacat keamanan kompiler, tetapi lebih dari 10+ tahun pasti ada beberapa kelemahan tetap yang diketahui.
Steve Jessop
2
Heh, sebenarnya cacat itu baru diperkenalkan pada 2008 sehingga si penanya mungkin aman darinya. Tapi poin saya bukan tentang contoh khusus itu, itu ada bug yang diketahui ada bahwa toolchain lama akan dimasukkan ke dalam kode Anda. Jadi, ketika Anda memperbarui memang benar bahwa Anda memperkenalkan set baru yang tidak diketahui, tapi bukan itu yang Anda lakukan . Pada dasarnya Anda hanya perlu menebak apakah Anda "lebih aman" meninggalkan kelemahan kritis yang diketahui yang diperbaiki oleh toolchain terbaru, atau mengambil konsekuensi yang tidak diketahui dari melempar dadu lagi pada semua perilaku tidak terdefinisi dalam kode Anda sendiri.
Steve Jessop
19

Jika tidak rusak, jangan memperbaikinya

Bos Anda kedengarannya benar mengatakan ini, namun, faktor yang lebih penting , adalah melindungi input, output, buffer overflows. Kurangnya itu selalu merupakan tautan terlemah dalam rantai dari sudut pandang itu terlepas dari kompiler yang digunakan.

Namun, jika basis kode adalah kuno, dan pekerjaan telah dilakukan untuk mengurangi kelemahan K&R C yang digunakan, seperti kurangnya keamanan jenis, tidak amannya anggaran, dll, menimbang pertanyaan " Apakah meningkatkan kompiler ke C99 yang lebih modern / Standar C11 menghancurkan segalanya? "

Asalkan, ada jalur yang jelas untuk bermigrasi ke standar C yang lebih baru, yang dapat menyebabkan efek samping, mungkin yang terbaik adalah mencoba garpu basis kode lama, menilai dan memasukkan cek tipe tambahan, pemeriksaan kewarasan, dan menentukan apakah meningkatkan ke kompiler yang lebih baru memiliki efek pada dataset input / output.

Kemudian Anda dapat menunjukkannya kepada atasan Anda, " Ini basis kode yang diperbarui, dire-refoured, lebih sesuai dengan standar C99 / C11 yang diterima industri ... ".

Itu pertaruhan yang harus dipertimbangkan, dengan sangat hati-hati , penolakan terhadap perubahan mungkin terlihat di sana di lingkungan itu dan mungkin menolak untuk menyentuh barang-barang baru.

EDIT

Hanya duduk santai selama beberapa menit, menyadari ini banyak, kode yang dihasilkan K&R dapat berjalan pada platform 16bit, kemungkinannya, peningkatan ke kompiler yang lebih modern benar-benar dapat memecahkan basis kode, saya berpikir dalam hal arsitektur, kode 32 bit akan dihasilkan , ini bisa memiliki efek samping yang lucu pada struktur yang digunakan untuk dataset input / output, yang merupakan faktor besar lainnya untuk dipertimbangkan dengan cermat.

Juga, karena OP telah menyebutkan menggunakan Visual Studio 2008 untuk membangun basis kode, menggunakan gcc dapat mendorong membawa ke lingkungan baik MinGW atau Cygwin, yang dapat memiliki dampak perubahan pada lingkungan, kecuali, targetnya adalah untuk Linux, maka itu akan menjadi layak dicoba, mungkin harus menyertakan sakelar tambahan ke kompiler untuk meminimalkan kebisingan pada basis kode K&R yang lama, hal penting lainnya adalah melakukan banyak pengujian untuk memastikan tidak ada fungsi yang rusak, dapat berubah menjadi latihan yang menyakitkan.

t0mm13b
sumber
Kode yang sama dibangun oleh Visual Studio 2008 untuk target Windows, dan MSVC belum mendukung C99 atau C11 (Saya tidak tahu apakah MSVC yang lebih baru melakukannya), dan saya dapat membangunnya di kotak Linux saya menggunakan GCC terbaru. Jadi jika kita hanya memasukkan GCC yang lebih baru, itu mungkin akan membangun sama baiknya dengan sebelumnya.
Calmarius
@Calmarius terima kasih atas sarannya, mungkin lebih baik mengedit pertanyaan Anda dengan memasukkan komentar, Itu penting :) Dan seharusnya ada di sana; D
t0mm13b
@Calmarius telah mengedit jawaban saya, yang merupakan pemikiran saya tentang pertanyaan yang baru diperbarui.
t0mm13b
2
"Bisa berjalan pada platform 16bit, kemungkinan besar, peningkatan ke kompiler yang lebih modern benar-benar dapat memecahkan basis kode, saya berpikir dalam hal arsitektur, kode 32bit" Saya tidak berpikir pertanyaannya adalah tentang porting kode ke implementasi baru yang ditentukan parameter.
Pascal Cuoq
Sepakat. Mungkin saja kerentanan runtime dapat dibuat oleh bug penyusun. Tetapi jauh lebih mungkin bahwa kode tersebut mengandung kerentanan runtime karena hal-hal seperti buffer dan stack overruns. Jadi, ketika Anda menginvestasikan waktu dalam membuat basis kode ini lebih aman, Anda harus menginvestasikannya dalam melakukan hal-hal seperti memeriksa panjang string input untuk memastikan mereka tidak melebihi batas program Anda. Mendapatkan kompiler yang lebih baru tidak akan banyak membantu. Menulis ulang kode dari awal dalam bahasa dengan string asli dan objek array akan banyak membantu. Tetapi bos Anda tidak akan membayar untuk itu.
O. Jones
9

Bisakah menggunakan kompiler C lama membahayakan keamanan program yang dikompilasi?

Tentu saja bisa, jika kompiler lama berisi bug yang dikenal yang Anda tahu akan memengaruhi program Anda.

Pertanyaannya adalah, bukan? Untuk mengetahui dengan pasti, Anda harus membaca seluruh log perubahan dari versi Anda hingga tanggal sekarang dan memeriksa setiap bug yang diperbaiki selama bertahun-tahun.

Jika Anda tidak menemukan bukti bug kompiler yang akan memengaruhi program Anda, memperbarui GCC hanya demi itu kelihatannya agak paranoid. Anda harus ingat bahwa versi yang lebih baru mungkin mengandung bug baru, yang belum ditemukan. Banyak perubahan yang dilakukan baru-baru ini dengan dukungan GCC 5 dan C11.

Yang sedang berkata, kode yang ditulis pada tahun 80-an kemungkinan besar sudah diisi sampai penuh dengan lubang keamanan dan bergantung pada perilaku yang tidak didefinisikan dengan baik, tidak peduli kompilator. Kita berbicara tentang pra-standar C di sini.

Lundin
sumber
6
Saya tidak berpikir itu paranoia; Saya pikir OP sedang mencoba untuk menemukan alasan untuk meyakinkan bosnya. Mungkin OP benar-benar menginginkan kompiler baru karena mereka membuat asm yang lebih baik (termasuk optimasi lintas-file dengan KPP), memiliki diagnostik / peringatan yang lebih berguna, dan memungkinkan fitur bahasa modern dan sintaksis. (misalnya stdatomik C11).
Peter Cordes
9

Ada risiko keamanan di mana pengembang jahat dapat menyelinap melalui pintu belakang melalui bug kompiler. Bergantung pada jumlah bug yang diketahui dalam kompiler yang digunakan, pintu belakang mungkin terlihat kurang menarik (dalam hal apa pun, intinya adalah bahwa kode tersebut benar, bahkan jika berbelit-belit, di tingkat sumber. Kode sumber mengulas dan menguji menggunakan kompiler non-kereta tidak akan menemukan backdoor, karena backdoor tidak ada dalam kondisi ini). Untuk poin penyangkalan tambahan, pengembang jahat juga dapat mencari bug kompiler yang sebelumnya tidak dikenal. Sekali lagi, kualitas kamuflase akan tergantung pada pilihan bug penyusun yang ditemukan.

Serangan ini diilustrasikan pada program sudo dalam artikel ini . bcrypt menulis tindak lanjut yang bagus untuk Javascript minifiers .

Terlepas dari keprihatinan ini, evolusi C compiler telah mengeksploitasi perilaku undefined lebih dan lebih dan lebih agresif, sehingga kode C lama yang ditulis dengan itikad baik akan benar-benar lebih secure dikompilasi dengan kompiler C dari waktu, atau disusun di -O0 (tetapi beberapa optimisasi eksploitasi UB pemecah-program baru diperkenalkan dalam versi baru kompiler bahkan pada -O0 ).

Pascal Cuoq
sumber
7

Kompiler lama mungkin tidak memiliki perlindungan terhadap serangan peretasan yang diketahui. Perlindungan menabrak tumpukan, misalnya, tidak diperkenalkan sampai GCC 4.1 . Jadi ya, kode yang dikompilasi dengan kompiler lama mungkin rentan dengan cara yang melindungi kompiler baru.

DrMcCleod
sumber
6

Aspek lain yang perlu dikhawatirkan adalah pengembangan kode baru .

Kompiler yang lebih lama mungkin memiliki perilaku yang berbeda untuk beberapa fitur bahasa daripada yang dibakukan dan diharapkan oleh programmer. Ketidakcocokan ini dapat memperlambat pengembangan dan memperkenalkan bug halus yang dapat dieksploitasi.

Kompiler lama menawarkan lebih sedikit fitur (termasuk fitur bahasa!) Dan tidak mengoptimalkan juga. Pemrogram akan meretas kekurangan ini - misalnya dengan mengimplementasikan kembali fitur yang hilang, atau menulis kode pintar yang tidak jelas tetapi berjalan lebih cepat - menciptakan peluang baru untuk pembuatan bug yang halus.


sumber
5

Nggak

Alasannya sederhana, kompiler lama mungkin memiliki bug dan exploit lama, tetapi kompiler baru akan memiliki bug dan exploit baru.

Anda tidak "memperbaiki" bug apa pun dengan memutakhirkan ke kompiler baru. Peralihan bug lama dan eksploitasi untuk bug dan exploit baru.

kapas
sumber
3
Ini kelihatannya sangat sederhana: kompiler baru mungkin memiliki kelemahannya, tetapi saya berharap mereka lebih kecil dari pada kompiler lama, dan kemungkinan mendeteksi beberapa kerentanan kode yang telah dikenal sejak saat itu.
PJTraill
Tetapi kompiler baru mungkin memiliki kelemahan baru yang tidak diketahui. Compiler sendiri bukan risiko keamanan yang perlu diperbarui. Anda tidak mengurangi luas permukaan Anda. Perdagangan Anda merupakan set masalah yang diketahui untuk set yang tidak dikenal.
coteyr
Alat untuk membantu menemukan bug telah meningkat pesat sejak awal GCC, dan alat ini (analisis statis, analisis dinamik kode / sanitiser, fuzzers, dll.) Telah diterapkan pada kode kompilator juga, untuk membantu meningkatkan kualitas. Jauh lebih sulit untuk menemukan semua kelas bug di era GCC 2. Perbandingan bug kompiler dengan versi - lihat halaman 7: cs.utah.edu/~regehr/papers/pldi11-preprint.pdf GCC 4.5 dan LLVM 2.8 (terbaru saat penerbitan) memiliki bug paling sedikit dari fuzzing.
Jetski S-type
2

Yah ada kemungkinan yang lebih tinggi bahwa setiap bug dalam kompiler lama dikenal dan didokumentasikan sebagai lawan menggunakan kompiler baru sehingga tindakan dapat diambil untuk menghindari bug tersebut dengan pengkodean di sekitar mereka. Jadi dengan cara yang tidak cukup sebagai argumen untuk peningkatan. Kami memiliki diskusi yang sama di mana saya bekerja, kami menggunakan GCC 4.6.1 pada basis kode untuk perangkat lunak tertanam dan ada keengganan besar (di antara manajemen) untuk memutakhirkan ke kompiler terbaru karena takut akan bug baru yang tidak berdokumen.

AndersK
sumber
0

Pertanyaan Anda terbagi dalam dua bagian:

  • Eksplisit: “Apakah ada risiko lebih besar dalam menggunakan kompiler yang lebih lama” (kurang lebih seperti pada judul Anda)
  • Tersirat: "Bagaimana saya bisa membujuk manajemen untuk meningkatkan"

Mungkin Anda bisa menjawab keduanya dengan menemukan kelemahan yang dapat dieksploitasi di basis kode yang ada dan menunjukkan bahwa kompiler yang lebih baru akan mendeteksinya. Tentu saja manajemen Anda mungkin mengatakan "Anda menemukan itu dengan kompiler lama", tetapi Anda dapat menunjukkan bahwa itu membutuhkan usaha yang cukup besar. Atau Anda menjalankannya melalui kompiler baru untuk menemukan kerentanan, kemudian mengeksploitasinya, jika Anda dapat / diizinkan untuk mengkompilasi kode dengan kompiler baru. Anda mungkin memerlukan bantuan dari peretas yang ramah, tetapi itu tergantung pada kepercayaan mereka dan kemampuan / diizinkan untuk menunjukkan kode (dan menggunakan kompiler baru).

Tetapi jika sistem Anda tidak terkena peretas, Anda mungkin harus lebih tertarik pada apakah peningkatan kompiler akan meningkatkan efektivitas Anda: Analisis Kode MSVS 2013 cukup sering menemukan bug potensial lebih cepat daripada MSVS 2010, dan itu kurang lebih mendukung C99 / C11 - tidak yakin apakah itu secara resmi, tetapi deklarasi dapat mengikuti pernyataan dan Anda dapat mendeklarasikan variabel di for-loops.

PJTraill
sumber