FlawOpen

flawopen.com/Incidents/rust-unsafe-smallvec-overflow-january-2021

● servo/rust-smallvec · CVE-2021-25900 · January 2021 · CVSS 9.8 · Kritis
Riset Keamanan · FlawOpen

CVE-2021-25900: heap overflow pada smallvec Rust

SmallVec::insert_many memercayai batas bawah size_hint; jika iterator menghasilkan lebih, buffer heap terlampaui. Diperbaiki di 0.6.14 dan 1.6.1.

💡 Penjelasan Sederhana (ELI5)

Sebuah gudang terkenal aman karena robot memeriksa setiap rak sebelum barang ditaruh. Untuk beberapa tugas, robot dimatikan dan seorang pekerja bekerja manual sambil berjanji berhati-hati. Salah satunya bertanya kepada sopir, "Kira-kira berapa kardus yang dibawa?", membuat rak seukuran itu, lalu mulai menumpuk. Perkiraan itu hanya tebakan, bukan jaminan, dan ketika datang lebih banyak kardus dari yang dijanjikan, tumpukannya melewati ujung rak.

Konsep Kunci & Istilah

SmallVec
Koleksi Rust yang menyimpan sedikit elemen secara inline dan pindah ke buffer heap saat membesar. Kecepatannya berasal dari kode unsafe yang mengelola buffer itu secara manual.
size_hint
Metode Iterator yang melaporkan perkiraan batas bawah dan atas jumlah item yang tersisa. Ini hanya petunjuk: kode safe boleh mengembalikan nilai apa pun, termasuk yang salah.
Rust unsafe
Kode di dalam blok unsafe boleh melakukan hal yang tidak bisa diperiksa kompiler, seperti menulis lewat pointer mentah; penulisnya wajib menjaga keamanan memori untuk setiap pemanggil safe yang mungkin.
Soundness
API safe disebut sound jika tidak ada kode safe, seaneh apa pun, yang dapat memicu perilaku tak terdefinisi melaluinya. insert_many tidak sound, karena size_hint yang sah bisa merusak memori.

Pemetaan kerangka kerja

  • Referensi CWE untuk kelemahan yang dijelaskan dalam panduan ini: CWE-122 CWE-787

Kronologi Insiden

2021-01-08

Yechan Bae dan kelompok Rust di SSLab Georgia Tech melaporkan bug ini; RustSec menerbitkan RUSTSEC-2021-0003 dan smallvec 0.6.14 serta 1.6.1 membawa perbaikannya.

2021-01

CVE-2021-25900 ditetapkan; cargo audit mulai menandai versi terdampak di pohon dependensi.

Alur Serangan Langkah demi Langkah

Langkah 1

Iterator melaporkan panjang yang terlalu kecil

insert_many dipanggil dengan iterator yang batas bawah size_hint-nya lebih kecil dari jumlah item yang benar-benar dihasilkan. Kode safe diizinkan berbuat begitu.

Langkah 2

Ruang disediakan menurut petunjuk

insert_many hanya menyediakan ruang untuk batas bawah dan menggeser elemen yang ada sebanyak itu.

Langkah 3

Semua item tetap ditulis

Di dalam blok unsafe, perulangan menulis setiap item lewat pointer mentah, sehingga item berlebih jatuh melewati akhir alokasi.

Langkah 4

Heap rusak

Overflow menimpa memori heap di sebelahnya. Program yang meneruskan ke insert_many iterator yang dipengaruhi masukan tak tepercaya menjadi rentan.

Kode Sumber: Rentan vs Aman

IMPLEMENTASI RENTAN
// Alokasikan berdasarkan sebuah *petunjuk*...
let (lower, _) = iter.size_hint();
self.reserve(lower);

unsafe {
    let ptr = self.as_mut_ptr().add(index);
    for (i, item) in iter.enumerate() {
        // ...tetapi tulis sebanyak
        // item yang benar-benar diterima.
        ptr::write(ptr.add(i), item);
    }
}
PERBAIKAN AMAN & KUAT
// Periksa ulang kapasitas untuk setiap item.
// Jangan biarkan nilai dari kode aman
// menentukan batas yang digunakan oleh kode unsafe.
for (i, item) in iter.enumerate() {
    self.reserve(1);
    unsafe {
        let ptr = self.as_mut_ptr()
                      .add(index + i);
        ptr::write(ptr, item);
    }
}

// Perbaikan sebenarnya juga memangkas
// cakupan unsafe secara signifikan.

Daftar Periksa Penguatan Sistem Rekayasa

Sumber