
क्रूशियल MX500 SSD फर्मवेयर अपडेट तंत्र में तीन कमजोरियों के लिए प्रूफ-ऑफ-कॉन्सेप्ट एक्सप्लॉइट्स, जो बफर ओवरफ्लो और ATA कमांड के माध्यम से संभावित कोड निष्पादन को सक्षम बनाते हैं।
प्रश्नगत उपकरण कोई भी MX500-श्रृंखला SSD है। ये SSD Sillicon-Motion SM2259 नियंत्रक (पुराने बैचों में पुराना नियंत्रक, Sillicon-Motion SM2258, था, लेकिन इस दस्तावेज़ का मुख्य फोकस नए पर है) द्वारा नियंत्रित होते हैं। SM2259 एक 4-चैनल SATA 6Gb/s माइक्रो-कंट्रोलर है जो ARC आर्किटेक्चर पर आधारित 32-बिट लिटिल-एंडियन CPU का उपयोग करता है।
इस दस्तावेज़ की तिथि पर लागू नवीनतम फ़र्मवेयर, जो M3CR046 है, का अवलोकन करने पर, कुछ समस्याएँ पहचानी गईं और स्थिर तथा गतिशील दोनों रूप से पुष्टि की गईं।
सभी समस्याएँ नियंत्रक के फ़र्मवेयर अद्यतन तंत्र में पाई गईं, जो माइक्रो-कंट्रोलर हैंडलर ATA PIO DOWNLOAD-MICROCODE (0x92) कमांड से संबंधित है, विशेष रूप से उस तर्क में जो ऑफ़सेट विधि का उपयोग करके फ़र्मवेयर डाउनलोड करता है, जो उपकमांड 0x03 और 0x0E से संबंधित है।
इस दस्तावेज़ में शामिल सभी बग Crucial MX500 500GB SSD (CT500MX500SSD1), SM2259H-AC नियंत्रक पर M3CR046 FW के साथ NY112 फ्लैश चिप्स और x86_64 CPU वाले PC पर सत्यापित किए गए।
FW कोड को आधार पते 0x80020000 पर मैप किया गया है, और कमजोर ATA हैंडलर पते 0x80024A9C पर स्थित है। आपकी सुविधा के लिए फ़ंक्शन का एक डीकंपाइल संस्करण resources/download_microcode_handler.c के अंतर्गत पाया जा सकता है।
जो लोग तकनीकी विवरणों से निपटना नहीं चाहते और निचली पंक्ति को समझना चाहते हैं, कृपया नीचे FAQ अनुभाग देखें।
चूंकि M3CR046 में कई फ़र्मवेयर इमेज हैं जिनमें से उपयुक्त फ़र्मवेयर अद्यतन तंत्र द्वारा चुना जाता है (शायद वास्तविक फ्लैश चिप्स या कुछ अन्य हार्डवेयर विशेषताओं पर निर्भर करता है), यह दस्तावेज़ पहले फ़र्मवेयर वेरिएंट की बारीकियों को कवर करेगा (क्योंकि यह हमारे विशिष्ट ड्राइव पर समर्थित फ़र्मवेयर है, और इस प्रकार हम केवल उस फ़र्मवेयर वेरिएंट का परीक्षण कर सकते हैं)। हालांकि, इस दस्तावेज़ में प्रस्तुत बग सभी फ़र्मवेयर वेरिएंट पर लागू होते प्रतीत होते हैं, लेकिन उन्हें पुन: प्रस्तुत करते समय वास्तविक बारीकियों में कुछ अंतर हो सकते हैं।
यह समस्या उन मामलों को संदर्भित करती है जहां भेजा गया पहला खंड 0x200 सेक्टर से बड़ा होता है। यदि हम ATA कमांड हैंडलर के अंदर देखें, विशेष रूप से उस तर्क पर जो तब निष्पादित होता है जब खंड का आकार सेक्टर आकार से बड़ा होता है और जब खंड पहला भेजा गया हो:

यह अगले ऑफ़सेट (जो हमारे मामले में, चूंकि हमने अब तक केवल एक खंड भेजा है, खंड की लंबाई सेक्टरों में है) और lower_bound_fw_offset नामक चर के आधार पर कुछ चर सेट करता है, जो ब्लॉक ऑफ़सेट है (अर्थात, सेक्टरों की ग्रैन्युलैरिटी में ऑफ़सेट) जिसके भीतर हमारी फ़र्मवेयर इमेज इनपुट डाउनलोड इमेज में पाई जाने की उम्मीद है। यह प्रति फ़र्मवेयर वेरिएंट एक हार्डकोडेड मान है, जो हमारे मामले में (पहला वेरिएंट), 0 के बराबर है।
इस स्थिति में, some_index के लिए घटाव परिणाम की गणना करते समय अंडरफ़्लो होता है, जिससे some_index का मान 0xFFFF जितना अधिक हो जाता है। यह अप्रत्याशित व्यवहार है, क्योंकि डाउनलोड बफर में डेटा ले जाने वाले तर्क के आधार पर:

हम देखते हैं कि जिस स्रोत पते से डेटा कॉपी किया जाता है वह some_index के अप्रत्याशित मान को देखते हुए मान्य नहीं हो सकता है।
जब पहले खंड के 0x200 सेक्टर से बड़े आकार के साथ फ़र्मवेयर अद्यतन अनुरोध भेजकर गतिशील रूप से परीक्षण किया जाता है, तो नियंत्रक हैंग हो जाता है और मूल अनुरोध का कोई उत्तर भी नहीं भेजता है। यह सुसंगत और आसानी से प्रतिलिपि करने योग्य है।
संभवतः ऐसा गणना किए गए स्रोत पते के अमान्य संदर्भ के कारण होता है, जो फिर एक अपवाद को ट्रिगर करता है जिससे नियंत्रक हैंग हो जाता है। यह सिद्ध नहीं हुआ है, बल्कि एक अनुमान है जो हैंग की व्याख्या कर सकता है।
इनपुट डाउनलोड इमेज (M3CR046 के लिए) का आकार 0x242400 बाइट्स है, और इस इमेज के अंदर 3 आंतरिक फ़र्मवेयर इमेज हैं जिनमें से केवल एक को फ़र्मवेयर अद्यतन प्रक्रिया के बाद फ्लैश में लिखा जाता है, प्रत्येक ऐसी इमेज का आकार 0xC0C00 बाइट्स (या 0x606 सेक्टर) है।
इसका मतलब है कि जब फ़र्मवेयर अद्यतन तंत्र इनपुट डाउनलोड इमेज से सही फ़र्मवेयर प्रतिलिपि निकालता है, तो उसे सत्यापित करना होता है कि इसका आकार 0xC0C00 बाइट्स से अधिक न हो।
नियंत्रक वास्तव में ऐसा करने का प्रयास करता है, लेकिन कुछ सीमांत स्थितियां अप्रत्याशित व्यवहार का कारण बन सकती हैं। आइए निम्नलिखित स्निपेट देखें (जो पिछले बग के साथ कुछ कोड साझा करता है):

यदि वर्तमान खंड 0x200 सेक्टर से बड़ा है और यह अनुक्रम में पहला खंड नहीं है, तो एक बार में 0x200 सेक्टर (0x40000 बाइट्स) कॉपी किए जाएंगे। फिर, एक जांच है जिसका उद्देश्य कॉपी करने के लिए बाइट्स की संख्या से अतिरिक्त बाइट्स को छोटा करना है, यदि फ़र्मवेयर इमेज का कुल आकार higher_bound_fw_offset (जो हमारे मामले में 0x606 सेक्टर है, क्योंकि फ़र्मवेयर का आकार बिल्कुल यही होना चाहिए) से अधिक हो जाता है।
यह तर्क समग्र रूप से समझ में आता है, लेकिन इसमें एक खामी है – यदि भेजा गया अंतिम खंड अगले ऑफ़सेट को बहुत अधिक कर देता है, जैसे कि अतिरिक्त बाइट्स की संख्या 0x200 सेक्टर (या 0x40000 बाइट्स) से अधिक हो जाती है, तो curr_bytes_to_copy को एक “ऋणात्मक” मान मिलता है, जो लगभग ~4GB (~0xFFFFFFFF) तक अंडरफ़्लो हो जाता है। जैसा कि हमने पहले देखा, इस चर का उपयोग डाउनलोड बफर में स्थानांतरित किए जाने वाले बाइट्स की संख्या निर्धारित करने के लिए किया जाता है।
यदि हम r_maybe_some_efficient_data_transfer के अंदर देखते हैं, तो हम निम्नलिखित कोड का टुकड़ा देखते हैं:

जिसका अर्थ है कि कॉपी आकार को 32MB (मूल ~4GB कॉपी आकार से) में छोटा कर दिया जाता है, लेकिन फिर भी यह एक बड़ी संख्या है जो 0x40000000 पर शुरू होने वाली मेमोरी रेंज का आकार 32MB से कम होने पर अपरिभाषित व्यवहार का कारण बन सकती है।
जब 0x600 के ऑफ़सेट पर पहुंचने के लिए ATA खंड भेजकर, और फिर अंडरफ़्लो को ट्रिगर करने के लिए 0x207 सेक्टर का एक बड़ा खंड भेजकर गतिशील रूप से परीक्षण किया जाता है, तो नियंत्रक फिर से हैंग हो जाता है, संभवतः कॉपी के दौरान अमान्य मेमोरी एक्सेस के कारण।
यह बग पिछले वाले की तुलना में अधिक दिलचस्प है, क्योंकि भले ही हमारे पास नियंत्रित ओवरराइट नहीं है (बल्कि, एक बड़ा ओवरराइट जो संभवतः एक अपवाद को ट्रिगर करता है जो नियंत्रक को हैंग कर देता है), यदि डेटा को डाउनलोड बफर में ले जाने वाला फ़ंक्शन वास्तव में क्रैश होने से पहले इतना डेटा स्थानांतरित करने में सफल हो जाता है (मुख्य मेमोरी में डाउनलोड बफर के ठीक बाद स्थित मेमोरी रेंज को ओवरराइट करते हुए), तो शायद अपवाद हैंडलर का व्यवहार ओवरराइट किए गए डेटा के आधार पर बदल सकता है। ऐसा संभवतः हो सकता है, यदि, उदाहरण के लिए, अपवाद हैंडलर ओवरराइट किए गए क्षेत्र से एक पॉइंटर पढ़ता है और फिर उस पर कूदता है (यह विशिष्ट मामला विशेष रूप से संभावित नहीं है, लेकिन कुछ और शोध के साथ, इस तरह की कोई चीज़ खोजी जा सकती है)।
जैसा कि बताया गया है, डाउनलोड इमेज का आकार 0x242400 (या 0x1212 सेक्टर) है। फ़र्मवेयर सत्यापित करता है कि स्थानांतरित इमेज का कुल आकार इस आकार से अधिक न हो, यह सुनिश्चित करके कि अगला ऑफ़सेट 0x1212 सेक्टर से अधिक न हो। यह जांच समझ में आती है, लेकिन अगले ऑफ़सेट की गणना त्रुटिपूर्ण है:

यदि वर्तमान ऑफ़सेट 0x600 सेक्टर है, और संसाधित होने वाला अगला ATA कमांड पर्याप्त बड़े आकार का है (मान लीजिए 0xFC00 सेक्टर, जो ATA मानक द्वारा अनुमत है), तो अगला ऑफ़सेट रैप अराउंड हो जाता है, जिससे उपरोक्त जांच ठीक से काम नहीं करती है:

या दूसरे शब्दों में, सामान्य मामले में, फ़र्मवेयर अद्यतन तंत्र अपनी स्थिति मशीन को रीसेट करेगा और एक त्रुटि लौटाएगा, लेकिन यदि हम बहुत बड़ा खंड भेजते हैं, तो हम इसे संसाधित करना जारी रखेंगे। निम्नलिखित कोड स्निपेट दिखाता है कि स्थानांतरण कैसे किया जाता है:
