
GNU coreutils split प्रोग्राम में हीप ओवरफ्लो भेद्यता का राइटअप। CVE-2024-0684
GNU coreutils के "split" प्रोग्राम में एक कमजोरी है जो उपयोगकर्ता-नियंत्रित डेटा के साथ हीप बफर ओवरफ्लो (heap buffer overflow) की अनुमति देती है।
इसे 40bf1591bb4362fa91e501bcec7c2029c5f65a43 में 2023-03-04 को पेश किया गया था। इसका सुधार (fix) c4c5ed8f4e9cd55a12966d4f520e3a13101637d9 के साथ 2024-01-17 को जारी किया गया।
प्रभावित संस्करण: GNU coreutils v9.4; v9.3; v9.2
प्रूफ ऑफ कॉन्सेप्ट:
इस रिपॉजिटरी में मौजूद split_me उदाहरण फ़ाइल का उपयोग प्रभावित संस्करणों में क्रैश ट्रिगर करने के लिए किया जा सकता है।
split -C 1024 ./split_me
यह split को सेगमेंटेशन फॉल्ट (SIGABRT) के साथ क्रैश कर देगा।
मैंने इस कमजोरी की खोज QR कोड का उपयोग करके एयर-गैप्ड (air-gapped) सिस्टम से डेटा निष्कर्षण स्वचालित करने का प्रयास करते समय की।
qrencode से जनरेट किए गए QR कोड की क्षमता ~4000 वर्णों की होती है, इसलिए split का भारी उपयोग आवश्यक था।
एक विशिष्ट परीक्षण मामले में, split सेगमेंटेशन फॉल्ट के साथ क्रैश हो गया।
चूंकि GNU coreutils ओपन सोर्स है, हम बाइनरी को रिवर्स इंजीनियर करने के बजाय, बग की पहचान करने के लिए स्रोत का उपयोग कर सकते हैं। ओपन सोर्स प्रोजेक्ट्स पर, आप अपनी बग रिपोर्ट में यथासंभव विशिष्ट होना चाहते हैं, आदर्श रूप से बग पेश करने वाले सटीक कमिट और लाइन के साथ-साथ एक प्रस्तावित सुधार भी प्रदान करें। यह मेंटेनर को आपकी रिपोर्ट को शीघ्रता से सत्यापित करने में सक्षम बनाता है और प्रतिक्रिया समय को छोटा करता है।
विभिन्न प्रणालियों पर बग की पुष्टि करते समय,
मैंने देखा कि क्रैश केवल split के अपेक्षाकृत हाल के संस्करणों पर हुआ।
यदि आपके पास एक अच्छा और एक बुरा कमिट है,
तो यह आपको कमिट इतिहास पर बाइनरी सर्च करने की अनुमति देता है,
ताकि वह कमिट मिल सके जिसने वास्तव में बग पेश किया।
Git इस उपयोग के लिए एक विशिष्ट उपकरण प्रदान करता है: git bisect।
यह स्वचालित रूप से परीक्षण के लिए कमिट सुझाएगा और आपको उन्हें अच्छा या बुरा चिह्नित करने की अनुमति देगा।
अंततः आप उस कमिट तक पहुँचते हैं जिसने बग पेश किया; हमारे मामले में:
commit 40bf1591bb4362fa91e501bcec7c2029c5f65a43
Author: Paul Eggert <[email protected]>
Date: Sat Mar 4 11:42:16 2023 -0800
split: prefer signed integers to size_t
This allows for better runtime checking with gcc
-fsanitize=undefined.
* src/split.c: Include idx.h.
(open_pipes_alloc, n_open_pipes, suffix_length)
(set_suffix_length, input_file_size, sufindex, outbase_length)
(outfile_length, addsuf_length, create, cwrite, bytes_split)
(lines_split, line_bytes_split, lines_chunk_split)
(bytes_chunk_extract, ofile_open, lines_rr, main):
Prefer signed integers (typically idx_t) to size_t.
src/split.c | 105 ++++++++++++++++++++++++++++++------------------------------
1 file changed, 52 insertions(+), 53 deletions(-)
फिर हम प्रोग्राम को संकलित कर सकते हैं (आदर्श रूप से एड्रेस सैनिटाइज़र के साथ),
ताकि वह सटीक लाइन मिल सके जिस पर यह क्रैश होता है।
केवल ~50 लाइनों को देखने के साथ,
बग की पहचान करना आसान हो जाता है।
हमारे मामले में, क्रैश गलत इंडेक्स के साथ एक memcpy() कॉल में हुआ।
और वास्तव में, यदि हम memcpy() कॉल के आस-पास के क्षेत्र की जाँच करते हैं,
तो हमें ठीक पहले इंडेक्स गणनाओं को बदलने वाला एक diff मिलता है:
@@ -816,15 +820,10 @@
/* Update hold if needed. */
if ((eoc && split_rest) || (!eoc && n_left))
{
- size_t n_buf = eoc ? split_rest : n_left;
+ idx_t n_buf = eoc ? split_rest : n_left;
if (hold_size - n_hold < n_buf)
- {
- if (hold_size <= SIZE_MAX - bufsize)
- hold_size += bufsize;
- else
- xalloc_die ();
- hold = xrealloc (hold, hold_size);
- }
+ hold = xpalloc (hold, &hold_size, n_buf - (hold_size - n_hold),
+ -1, sizeof *hold);
memcpy (hold + n_hold, sob, n_buf);
n_hold += n_buf;
n_left -= n_buf;
यदि हम इन परिवर्तनों को पूर्ववत करके पुनः संकलित करते हैं,
split हमारे सभी परीक्षण मामलों को बिना किसी त्रुटि के संसाधित करता है।
बस इतना शेष है कि बग को सत्यापित करने और सुधार विकसित करने के लिए तर्क (logic) से गुजरना है।