FlawOpen

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

● servo/rust-smallvec · CVE-2021-25900 · January 2021 · CVSS 9.8 · अति गंभीर
सुरक्षा अनुसंधान · FlawOpen

CVE-2021-25900: Rust smallvec heap बफ़र ओवरफ़्लो

SmallVec::insert_many ने size_hint की निचली सीमा पर भरोसा किया; iterator अधिक आइटम देता तो heap buffer से बाहर लिखता। 0.6.14 और 1.6.1 में सुधार हुआ।

💡 आसान भाषा में (ELI5)

एक गोदाम इसलिए सुरक्षित माना जाता है क्योंकि हर शेल्फ़ पर कुछ रखने से पहले एक रोबोट उसे जाँचता है। कुछ कामों के लिए रोबोट बंद कर दिया जाता है और एक व्यक्ति सावधानी का वादा करके हाथ से काम करता है। ऐसे एक व्यक्ति ने ड्राइवर से पूछा: "लगभग कितने डिब्बे ला रहे हो?", उतनी बड़ी शेल्फ़ बनाई और रखना शुरू कर दिया। अनुमान बस अंदाज़ा था, गारंटी नहीं, और जब वादे से ज़्यादा डिब्बे आए तो ढेर शेल्फ़ के किनारे से बाहर चला गया।

इस पेज के मुख्य शब्द

SmallVec
Rust का एक संग्रह जो कुछ ही तत्वों को अपने भीतर रखता है और बढ़ने पर हीप बफ़र पर चला जाता है। इसकी तेज़ी उस unsafe कोड से आती है जो इस बफ़र को हाथ से संभालता है।
size_hint
Iterator का एक मेथड जो बचे हुए आइटमों की अनुमानित निचली और ऊपरी सीमा बताता है। यह केवल संकेत है: safe कोड कोई भी मान लौटा सकता है, ग़लत भी।
unsafe Rust
unsafe ब्लॉक का कोड ऐसे काम कर सकता है जिन्हें कंपाइलर नहीं जाँच सकता, जैसे रॉ पॉइंटर से लिखना; लेखक को हर संभव safe कॉलर के लिए मेमोरी सुरक्षा बनाए रखनी होती है।
साउंडनेस
कोई safe API साउंड है अगर कोई भी safe कोड, कितना भी असामान्य हो, उसके ज़रिए अपरिभाषित व्यवहार न करा सके। insert_many साउंड नहीं था, क्योंकि एक वैध size_hint मेमोरी बिगाड़ सकता था।

फ्रेमवर्क मैपिंग

  • इस गाइड में बताई गई कमजोरी के लिए CWE संदर्भ: CWE-122 CWE-787

घटना का समयक्रम (Timeline)

2021-01-08

Yechan Bae और Georgia Tech के SSLab का Rust समूह इस बग की सूचना देते हैं; RustSec, RUSTSEC-2021-0003 प्रकाशित करता है और smallvec 0.6.14 व 1.6.1 में सुधार आता है।

2021-01

CVE-2021-25900 आवंटित होती है; cargo audit डिपेंडेंसी ट्री में प्रभावित संस्करणों को चिह्नित करने लगता है।

हमले का चरण-दर-चरण प्रवाह

चरण 1

इटरेटर अपनी लंबाई कम बताता है

insert_many को ऐसे इटरेटर के साथ बुलाया जाता है जिसके size_hint की निचली सीमा वास्तव में दिए जाने वाले आइटमों से कम है। safe कोड को ऐसा करने की अनुमति है।

चरण 2

संकेत के आधार पर जगह रखी जाती है

insert_many केवल निचली सीमा जितनी जगह रखता है और मौजूदा तत्वों को उतना ही खिसकाता है।

चरण 3

फिर भी हर आइटम लिखा जाता है

unsafe ब्लॉक के भीतर लूप हर आइटम को रॉ पॉइंटर से लिखता है, इसलिए अतिरिक्त आइटम आवंटित जगह के अंत के बाहर पहुँच जाते हैं।

चरण 4

हीप बिगड़ जाता है

ओवरफ़्लो पड़ोसी हीप मेमोरी को ओवरराइट कर देता है। जो प्रोग्राम अविश्वसनीय इनपुट से प्रभावित इटरेटर insert_many को देते हैं, वे जोखिम में हैं।

सोर्स कोड: कमज़ोर बनाम सुरक्षित कार्यान्वयन

कमज़ोर कार्यान्वयन
// एक *hint* के आधार पर allocate करें...
let (lower, _) = iter.size_hint();
self.reserve(lower);

unsafe {
    let ptr = self.as_mut_ptr().add(index);
    for (i, item) in iter.enumerate() {
        // ...लेकिन वास्तव में आने वाले
        // सभी items लिखें।
        ptr::write(ptr.add(i), item);
    }
}
सुरक्षित और सुदृढ़ फ़िक्स
// हर item के लिए capacity फिर से जाँचें।
// safe code के किसी value को
// unsafe द्वारा उपयोग की जाने वाली सीमा तय न करने दें।
for (i, item) in iter.enumerate() {
    self.reserve(1);
    unsafe {
        let ptr = self.as_mut_ptr()
                      .add(index + i);
        ptr::write(ptr, item);
    }
}

// वास्तविक सुधार ने
// unsafe surface को भी काफी घटाया।

इंजीनियरिंग और सिस्टम सुरक्षा चेकलिस्ट

स्रोत