Penyangga waider yang melimpah tetap menjadi salah satu kerentanan keamanan yang paling gigih dan berbahaya dalam pemrograman C. Meskipun telah terdokumentasi dengan baik selama beberapa dekade, mereka terus menyebabkan isu-isu serius seperti korupsi data, kerusakan sistem, dan eksekusi kode jarak jauh. Menulis kode C aman membutuhkan pemahaman mendalam tentang bagaimana buffer overflows terjadi dan pendekatan yang disiplin untuk mencegah mereka. Artikel ini menyediakan panduan komprehensif untuk menulis kode C yang kuat, tahan-limpah, meliputi konsep fundamental, fungsi aman, teknik validasi, perlindungan kompiler, dan langkah defensif modern.

Memahami Penimbal Berlimpah

Sebuah buffer overflow terjadi ketika sebuah program menulis lebih banyak data ke blok memori yang berdampingan (sebuah penyangga) daripada buffer yang dialokasikan untuk ditahan. Karena buffer berada dalam tumpukan atau memori tumpukan, melebihi batas mereka menimpa lokasi memori yang berdekatan. Kebejatan ini dapat mengubah keadaan program, memperkenalkan perilaku yang tidak terduga, atau dieksploitasi oleh penyerang untuk menyuntikkan dan mengeksekusi kode sewenang-wenang.

Konsekuensi-konsekuensi bergantung pada apa yang akan ditimpa. Menggantikan alamat kembali pada stack dapat mengarahkan eksekusi ke kode yang dikendalikan penyerang. Overwriting pointer dapat mengarah ke memori arbitrary menulis. Bahkan kecelakaan sederhana dapat ditunaikan untuk serangan penolakan-dari-layanan. Memahami mekanika adalah langkah pertama untuk pencegahan.

Aliran Beralir Berasaskan Stack-Based

Variabel lokal BAHANA, termasuk penyangga yang dinyatakan di dalam fungsi, disimpan di dalam tumpukan. Tumpukan juga menyimpan alamat kembali, penunjuk bingkai tersimpan, dan data kontrol lainnya. Ketika buffer linier seperti diserbu, tumpahan data ke alamat kembali dan seterusnya. Eksploitasi klasik seperti cacing Morris (1988) menggunakan stack overflows untuk mendapatkan akses tanpa izin.

Aliran yang Berdasar Heap

Secara diafizically alokasi penyangga (via , , dll.) berdiam di atas tumpukan. Overflows di sini dapat merusak data meta yang digunakan oleh allocator, mengarah ke crashes atau eksploitasi melalui semprotan tumpukan atau serangan bebas use-after. Heap overflows lebih sulit untuk dieksploitasi tetapi sama berbahaya.

Fungsi Bersama dan Alternatif Aman Mereka

Perpustakaan standar C menyediakan beberapa fungsi yang tidak melakukan pengecekan batas. Menggunakannya adalah penyebab paling umum dari limpahan buffer. Menggantikannya dengan counterparts yang lebih aman adalah praktik terbaik yang mendasar.

Salinan dan Konterasi Rentetan Iuran

  • Parameter trans fLT:0]] — Unsafe: copy sampai terminator null, no long limit.
    ]Safe alternatif: — copy pada kebanyakan karakter n; catatan bahwa tidak null-terminate jika sumber lebih panjang dari n, jadi selalu secara manual null-terminate.
  • Lebih baik lagi: — tersedia pada BSD dan banyak sistem Linux; selalu null-terminate dan mengembalikan panjang string sumber untuk deteksi truncation.
  • ]] — Unsafe: concatenates tanpa batas.
    Safe alternatif:] — gabung pada kebanyakan karakter n dan selalu null-terminates.

Keluaran dan Input Terformat Bofdan

  • [ZANZAL:0]] — Unsafe: write formatted output to a buffer with no size checking.
    ]Safe alternatif:] — batas output ke karakter ukuran-1 ditambah terminator null.
  • [[GANDAFLT:0]] — Risiko serupa; gunakan sebagai gantinya.
  • [[GANDAFLT:0]] — Sangat berbahaya; dibuang dari standar C11. Gunakan sebagai gantinya.
  • [[NOLFLT:0]] — Tidak ada batas yang diperiksa. Gunakan atau dengan penspesifikasi lebar medan.

Peng Salin dan Pindah Memori Memory Memory

  • ¡Ezéz [[ZLT:0]]]]] — Aman hanya jika n diverifikasi untuk tidak melebihi ukuran buffer tujuan.
    Safer alternatif: (handles overlaped) dan selalu memastikan n ukuran dest vaine.
  • Beberapa platform tools menyediakan dari Annex K (optional dalam C11), tetapi adopsi terbatas.

Pengevalidasi dan Manajemen Ukuran

Bahkan dengan fungsi aman, Anda harus memvalidasi panjang input, memastikan ukuran penyangga yang tepat, dan menangani kemungkinan pemotongan dengan anggun.

Mengecek Panjang Masukan

Aidin sebelum menyalin atau memproses input eksternal (pengguna masukan, data jaringan, isi berkas), menentukan panjang maksimumnya yang dapat diterima dan menolak atau memangkas data yang melebihinya. Sebagai contoh:

#define MAX_INPUT 255
char buffer[MAX_INPUT + 1]; // +1 for null
if (strlen(user_input) > MAX_INPUT) {
 // Handle error: reject or truncate
 fputs("Input too long", stderr);
 return -1;
}
strncpy(buffer, user_input, sizeof(buffer) - 1);
buffer[sizeof(buffer) - 1] = '\0';

Fific Gunakan Penyangga Saring-Tetap dengan Batas yang Diketahui

Kapanpun mungkin, definisikan buffer dengan ukuran konstan dan ditegakkan di seluruh kode. Hindari array panjang-variabel (VLAs) yang dapat menyebabkan tumpukan melimpah jika ukuran besar diberikan. Sebaliknya, peruntukan secara dinamis dengan pemeriksaan ukuran eksplisit.

Handle Truncation secara eksplisit

Fungsi-fungsi seperti dan dapat memangkas data. Perlu diwaspadai nilai kembali untuk mendeteksi pemotongan dan memutuskan apakah data yang dipangkas dapat diterima atau jika kesalahan harus dinaikkan. Mengabaikan pemindakan dapat meninggalkan buffer dalam keadaan tidak terduga.

Bendera Keamanan Pengkompila dan Perlindungan Waktu Jalan

Pengkompil modern kompilasi kompilasi fanfanfando menawarkan bendera yang menambahkan deteksi overflow buffer dan mitigasi tanpa perubahan kode. Aktifkan mereka dalam sistem build Anda.

  • ]]] / — Mengisi kanal stack (nilai acak) sebelum alamat kembali. Jika sebuah buffer overflow menindih kanary sebelum memodifikasi alamat kembali, program menggugurkan sebelum eksploitasi selesai.
  • [5] ¡¡¡FLT:0]]]] — Mengganti panggilan ke fungsi tidak aman seperti dan dengan versi yang diperiksa yang menggugurkan jika buffer tujuan terlalu kecil. Memerlukan atau optimasi yang lebih tinggi.
  • [[EfleksifLT:0]]]] — Peringatkan mengenai kerentanan string format yang dapat menyebabkan buffer melimpah atau kebocoran informasi.
  • [[GANDAFLT:0]] — AddressSanitizer (ASan) kode instrumen untuk mendeteksi buffer overflow, use-after-free, dan kesalahan memori lainnya pada waktu jalan. Memperlambat eksekusi tetapi tidak ternilai untuk pengujian.
  • [[GANDAFLT:0]] — Hindari mengoptimalkan cek limpahan yang melimpah (gunakan dengan hati-hati).

Perlindungan Sistem Operasi Operasional

Canari-kana ari ari-kana ari hanya satu lapisan. Teknologi mitigasi eksploit dalam OS modern termasuk:

  • Pencegahan Pelaksanaan Data (DEP) / NX bit — Marks stack and tumpuk sebagai tidak-executable, mencegah eksekusi shellcode.
  • [[AfLT:0]]Aksi Ruang Alamat Tata Letak Acak (ASLR) — Acakkan alamat memori (stack, tumpuk, perpustakaan terbagi) agar lebih sulit memprediksi target.
  • [[GALAL:0]]Relokasi Baca-Hanya-Atas (RELRO) — Proteksi GOT (Global Offset Tabel) dari overwriting.

Membenarkan perlindungan ini (biasanya default) menimbulkan bar untuk eksploitasi tetapi tidak menggantikan coding yang aman.

Audit Kode Ukraino dan Analisis Statik

Uji coba Human review dikombinasikan dengan analisis statis otomatis dapat menangkap buffer overflow isu awal. Integrasikan ini ke dalam alur kerja pengembangan Anda.

  • [[GANDAFLT:0]]Manual code review — Cari penggunaan fungsi yang tidak aman, pemeriksaan ukuran yang hilang, dan loop yang menulis di luar batas penyangga.
  • [NeaflefT:0]] Alat analisis statistik]] — Alat seperti , , , dan mendeteksi potensi overflow, penggunaan fungsi berbahaya, dan kesalahan off-by-one. Mereka dapat dijalankan dalam pipa CI.
  • [[NOLFLT:0]]Fuzzing]] — Gunakan libFuzzer, AFL, atau fuzzer lain untuk secara otomatis menguji penanganan input dengan data tak terduga yang mungkin memicu overflow.

Contoh Praktis dari Kode Aman

Salin Rentetan Aman dengan Batas Memeriksa

#include <stdio.h>
#include <string.h>

int safe_string_copy(char *dest, size_t dest_size, const char *src) {
 if (!dest || !src || dest_size == 0) {
 return -1; // Invalid parameters
 }
 size_t src_len = strlen(src);
 if (src_len >= dest_size) {
 // Source too large; truncation or error
 // Option: copy what fits and null-terminate
 strncpy(dest, src, dest_size - 1);
 dest[dest_size - 1] = '\0';
 return 1; // Truncation occurred
 }
 strncpy(dest, src, dest_size);
 // strncpy fills remaining with null, so dest_size fits; no need to null-terminate if src shorter
 return 0; // Success, no truncation
}

Awaybi Aman Mengendalikan Integer untuk Ukuran Penimbal

limpahan limpahan limpahan limpahan limpahan limpahan limpahan limpahan limpahan limpahan limpahan limpahan limpahan limpahan limpahan limpahan limpahan limpahan limpahan limpahan limpahan limpahan limpahan limpahan limpahan limpahan limpahan limpahan limpahan limpahan limpahan limpahan limpahan limpahan limpahan limpahan limpahan limpahan limpahan limpahan limpahan limpahan limpah juga dapat dihasilkan dari limpahan integer ketika ukuran komputasi. Selalu periksa aritmetika sebelum alokasi.

#include <stdlib.h>
#include <limits.h>
#include <errno.h>

void *safe_malloc_array(size_t nmemb, size_t size) {
 if (nmemb == 0 || size == 0) {
 return NULL; // Or handle zero-size allocation
 }
 if (nmemb > SIZE_MAX / size) {
 // Integer overflow would occur
 errno = ENOMEM;
 return NULL;
 }
 return malloc(nmemb * size);
}

Nama samaran untuk Rentetan Terformat

char log_message[256];
int ret = snprintf(log_message, sizeof(log_message),
 "User %s logged in from %s", username, ip_address);
if (ret < 0) {
 // Output error
} else if ((size_t)ret >= sizeof(log_message)) {
 // Truncation occurred; handle if needed
}

Praktek Terbaik Tambahan dari Artikel Lain

  • [[LALT:0]]Initialisasi buffer[ — Selalu buffer nol-initialize untuk menghindari kebocoran memori tidak terinisialisasi.
  • [[LLT:0]]Avoid rekursi dengan kedalaman tidak terbatas[] — Tumpukan limpahan dapat terjadi dari rekursi mendalam; gunakan iterasi atau kedalaman batas.
  • Use kualifier[ — Membantu pengkompilasi mengoptimalkan dan mungkin menangkap isu alias, meskipun tidak secara langsung mencegah overflow.
  • [[ECONFLT:0]]Prefer -koreksi — Melarang modifikasi tidak sengaja dari string masukan dan penegakan niat.
  • [[ChanexifolFLT:0]]Penerapan kesalahan penimplementasian — Jangan abaikan nilai kembali dari fungsi seperti , , , dll.

Sumber Daya Daya untuk Belajar Lebih Jauh

  • [[GALALT:0]]SEI CERT C Coding Standard[ — Aturan komprehensif untuk coding C yang aman.
  • [[NOLFLT:0]]CWE-120: Salinan buffer tanpa Memeriksa Ukuran Masukan — Klasifikasi MITRE terhadap kelemahan buffer overflow.
  • [[CHUCKLET:0]]OWASP Buffer Overflow[]] — Panduan praktis dari Proyek Keamanan Aplikasi Web Terbuka.
  • [[Lantun:0]]GNU C Manual Perpustakaan: Utilitas String and Array — Dokumentasi untuk fungsi string aman.
  • ]]AddressSanitisizer — Sebuah detektor kesalahan memori cepat.

Kekecualian Kesimpulan

Pencegahan terhadap buffer yang melimpah di C bukanlah pilihan; ini adalah tanggung jawab fundamental dari setiap pengembang yang bekerja dengan bahasa. Dengan memahami mekanisme overflow, mengganti fungsi berbahaya dengan alternatif yang lebih aman, sangat tidak memvalidasi masukan dan ukuran, mengaktifkan perlindungan kompiler, dan mempekerjakan analisis statis dan pengujian, Anda dapat secara dramatis mengurangi risiko kerentanan ini. Tidak ada teknik tunggal yang cukup; pertahanan dalam kedalaman — menggabungkan disiplin koding, bendera kompiler, mitigasi OS, dan pengujian menyeluruh — menyediakan perlindungan terkuat. Dengan praktik ini, Anda dapat menulis kode C yang kuat dan aman, baik yang dapat berjalan dengan aman, sistem kritis. Ingat bahwa koding yang sedang berlangsung, tidak dapat diperbaiki dan kode yang terus-menerus. Tetap fixing tentang kode dan kode baru Anda terus-menerus diberitahu.