GCC 14 में static analysis सुधार
(developers.redhat.com)- GCC 14 का
-fanalyzerC code के कई execution paths को symbolic execution के जरिए follow करता है और runtime से पहले पकड़ना मुश्किल defects को compile time पर खोजने पर केंद्रित है - इस बार के सुधार infinite loop detection, buffer overflow visualization, C string tracking, और taint analysis को default रूप से enable करने में बंटे हैं, और diagnostics को ज्यादा समझने योग्य बनाने पर केंद्रित हैं
-Wanalyzer-out-of-boundsसिर्फ warning से आगे बढ़कर text diagrams के जरिए buffer और write location के संबंध को दिखाता है, और UTF-8 strings में किस character के बीच में overflow हो रहा है यह भी दिखाता है- नया
null_terminated_string_arg(PARAM_IDX)attribute analyzer और code readers को बताता है कि API null-terminated string की अपेक्षा करता है, जिससे null-terminated न किए गए buffer को pass करने वाले paths बेहतर तरीके से सामने आते हैं - Taint analysis
-fanalyzerचुनने पर default रूप से चालू होता है, जिससे attacker-controlled values का upper-bound check के बिना size, index, offset आदि में इस्तेमाल होने वाला flow आसानी से देखा जा सकता है
-fanalyzer किन समस्याओं को संभालता है
-fanalyzerGCC का static analysis pass है, जो C source code के कई execution paths को symbolic execution करके compile time पर defects खोजने की कोशिश करता है- GCC 14 के सुधारों को अप्रैल 2024 की official release से पहले व्यवस्थित किया गया था, और लेख लिखे जाने के समय GCC 14.1 release अप्रैल 2024 में अपेक्षित थी
- GCC 14.0 prerelease पहले से Fedora 40 Beta में इस्तेमाल हो रही है
- Examples को Compiler Explorer पर नए compiler options के साथ आजमाया जा सकता है
सरल infinite loop detection
- GCC 14 में नई warning
-Wanalyzer-infinite-loopजोड़ी गई है - Example code में nested
forstatements में दूसरे loop की conditionj < nहै, लेकिन increment expressioni++ही रह गया है- यह पहले
forstatement को copy करने के बाद increment expression मेंiकोjमें न बदलने की गलती है - Analyzer इस path में
j < nकी true branch को लगातार follow करते हुए loop repetition की warning देता है
- यह पहले
- मौजूदा diagnostic output में flow समझने के लिए event numbers
(1)से(5)तक क्रम से पढ़ना आसान है - GCC 15 में control flow path को highlight करने वाली ASCII art जैसी विधि से readability बढ़ाने का विचार अभी इच्छा-सूची में है
- इस code को Compiler Explorer example में run किया जा सकता है
Buffer overflow को text में visualize करना
- GCC 13 में analyzer ने
-Wanalyzer-out-of-boundsके जरिए bounds checking support करना शुरू किया - GCC 14 में predicted buffer overflow के spatial relationship को text-based diagram के रूप में output किया जा सकता है
char buf[10]परstrcpy(buf, "hello")करने के बादstrcat(buf, " world!")call करने वाले example में stack-based buffer overflow detect होता है- पुराना message दिखाता था कि
bufकी capacity 10 bytes है और byte 10 से byte 12 तक out-of-bounds write होता है - GCC 14 का diagram
strcpyद्वारा भरे गए destination buffer औरstrcatके start point बनने वाले मौजूदा terminatingNULbyte को साथ में दिखाता है
- पुराना message दिखाता था कि
- Non-ASCII string example में भी UTF-8 representation को follow करते हुए overflow location दिखती है
char buf[11]में"サツキ"copy करने के बाद"メイ"append करने वाला code example के रूप में इस्तेमाल हुआ है- Diagram दिखाता है कि overflow
メcharacter, यानी U+30E1 के बीच में होता है
- संबंधित code ASCII string example और non-ASCII string example में देखा जा सकता है
C string operations की tracking बेहतर हुई
- GCC 14 analyzer ने C string operations tracking को बेहतर किया है, और null terminator byte खोजते हुए buffer scan करने वाली APIs को simulate करता है
- अगर pointer null-terminated न किए गए buffer को point करता है और उसे ऐसी API में pass करने वाला path है, तो warning देता है
- नया function attribute
null_terminated_string_arg(PARAM_IDX)analyzer और code readers को बताता है कि किसी specific parameter का null-terminated string होना जरूरी है - Example में
example_fn(const char *p)परnull_terminated_string_arg(1)औरnonnullattributes लगे हैंchar str[3] = "abc";में null terminator byte रखने की जगह नहीं हैexample_fn(str)call करते समय analyzerstrके अंत के बाद 1 byte पढ़ने वाली stack-based buffer over-read की warning देता है- Diagnostic में यह note भी output होता है कि
example_fnका पहला argument null-terminated string pointer होना चाहिए
- इस example को Compiler Explorer पर run किया जा सकता है
Taint analysis default रूप से enabled
- Analyzer का taint analysis attacker-controlled input, sanitization points, और बिना sanitization के इस्तेमाल होने वाली जगहों को track करता है
- पिछले GCC releases में bugs और बहुत ज्यादा false positives के कारण यह default रूप से enabled नहीं था और अलग command-line argument के पीछे छिपा था
- GCC 14 में कई bug fixes के बाद
-fanalyzerचुनने पर taint analysis default रूप से चालू होता है - इस बदलाव से नीचे की 6 taint-based warnings भी साथ में activate होती हैं
CVE-2011-2210 से देखा गया kernel analysis case
- Linux kernel के CVE-2011-2210 excerpt example को taint analysis case के रूप में इस्तेमाल किया गया है
__SYSCALL_DEFINExmacro में__attribute__((tainted_args))जोड़कर analyzer को बताया जाता है किosf_getsysinfoarguments trust boundary पार करके आए values हैं और उन्हें tainted values माना जाना चाहिए- GCC 14 analyzer
copy_to_user(buffer, hwrpb, nbytes)में warning देता है कि attacker-controlled valuenbytesको upper-bound check के बिना size के रूप में इस्तेमाल किया जा रहा है- Diagnostic दिखाता है कि
nbytesपरif (nbytes < sizeof(*hwrpb))में सिर्फ lower-bound check हुआ है copy_to_userका तीसरा parameteraccess(write_only, 1, 3)attribute से size parameter के रूप में दिखाया जाता है
- Diagnostic दिखाता है कि
- समस्या यह है कि sanitization condition
if (nbytes < sizeof(*hwrpb))के रूप में लिखी गई है- Intended condition
if (nbytes > sizeof(*hwrpb))जैसी थी - Condition ठीक की गई version में analyzer warning नहीं देता
- Intended condition
- Kernel पर analyzer चलाकर vulnerabilities ढूंढने और analyzer false positives को ठीक करने का काम जारी है
1 टिप्पणियां
Hacker News की राय
मेरे लिए fanalyzer, Clang की तुलना में GCC की killer features में से एक है। यह errors समझा देता है, जिससे C programming बहुत आसान हो जाती है, और error messages भी developer-friendly होने के मामले में Rust जैसे लगने लगे हैं
technology सीखना छोड़ देने की सबसे बड़ी वजह अक्सर frustrate करने वाले या अस्पष्ट errors होते हैं। बात थोड़ी विषय से हट गई, लेकिन मतलब यह था कि मुझे C पसंद है और Rust-level error messages हों तो यह और बेहतर हो जाएगा
error: missing semicolonके बजाय template instantiation से जुड़े error messages की 1000 से ज्यादा lines बरस जाती थींमैंने GCC analyzer कुछ बार इस्तेमाल किया है, लेकिन output को पढ़ने लायक बनाने वाला कोई अच्छा frontend नहीं मिला। Clang में काफी अच्छा HTML output, CodeChecker, Xcode integration जैसे कई विकल्प हैं; सोचता हूं GCC-side output कैसे पढ़ते हैं। ऊपर से GCC, Clang की तुलना में false positives कहीं ज्यादा देता लगता है
दूसरे thread में 36 और comments हैं: https://news.ycombinator.com/item?id=39918278
“GCC 14 Boasts Nice ASCII Art for Visualizing Buffer Overflows (phoronix.com)”, 2 घंटे पहले की post है
कुछ महीने पहले मैंने एक छोटा Linux utility बनाया था। यह किसी arbitrary executable की जगह लेने वाला drop-in shim था; call होने पर original program होने का नाटक करता, original को fork करता और stdout/stderr से जोड़ देता था
error output उस program के context को जानने वाले custom GPT assistant को भेजा जाता था, और assistant original error को human-readable form में बदलकर shim के stderr पर निकालता था। GCC/Clang के concept/template से जुड़े nested compiler dumps देखने से तंग आकर इसका इस्तेमाल कर रहा था, लेकिन चाहें तो किसी भी program के साथ इस्तेमाल किया जा सकता था। यह ठीक काम करता था, लेकिन मैं बहुत बीमार हो गया और आगे काम नहीं कर पाया; कोई इसे फिर से ठीक से बनाए और generalize करे तो अच्छा project होगा
analysis results के लिए बेहतर output format हो तो अच्छा होगा। मौजूदा तरीका screen readers के लिए नरक है
output का example यहां देख सकते हैं: https://godbolt.org/z/aan6Kfxds
article के पहले example में command-line option
-fdiagnostics-format=sarif-stderrजोड़ा गया है। diagrams को SVG में output करने का experiment भी किया था, लेकिन GCC 14 में डालने लायक पर्याप्त polish नहीं कर पायाoriginal code ऐसा था कि
nbytes < sizeof(*hwrpb)होने पर-1return करता था, औरcopy_to_user(buffer, hwrpb, nbytes)fail होने पर-2return करता था। लागू किया गया fixnbytes > sizeof(*hwrpb)check था, लेकिन मुझे लगता है सही fixcopy_to_user(buffer, hwrpb, sizeof(*hwrpb))हैhwrpbpointer सेsizeof(*hwrpb)के अलावा किसी और size को copy करना समझ में नहीं आताnbytes = 4पास करे औरsizeof(hwrpb)16 bytes हो, तो caller buffer से 12 bytes ज्यादा copy करके उस memory को read किया जा सकता है जिसका वह मालिक नहीं है। मेरे हिसाब से इसे avoid करना चाहिएबेहतर solution यह है कि caller और callee दोनों जितने minimum bytes support करते हैं, उतने ही copy किए जाएं। जैसे
nbytes = MIN(nbytes, sizeof(hwrpb));। यह मानते हुए किhwrpb->sizeकी version info maintained है, struct का कोई हिस्सा uninitialized होने पर भी backward/forward compatibility ensure की जा सकती हैnbytesसे बड़ा value पास भी नहीं किया जा सकतासच में शानदार। इसमें लगा काम बहुत बड़ा दिखता है। difficulty level standard library और C standard में fat pointer/array view introduce करने जैसा लगता है
-Wstringop-overflowमें false positives इतने ज्यादा हैं कि यह सबसे पहले बंद की जाने वाली warning है। analyzer variant इससे बेहतर होगा, इसमें संदेह हैबहुत बढ़िया। आजकल मैं ज्यादा C development नहीं करता, इसलिए सोचता हूं
strcpyऔरstrcatकितनी बार इस्तेमाल होते हैं। आखिरी बार जब देखा था, तो येgotoजितनी ही taboo चीजों के करीब थेबेशक kernel development में
gotoको अक्सर prefer किया जाता है, यह पता है। सोचता हूं C string analysis असल में कितना मददगार हैgotoका इस्तेमाल साफ तौर पर सही और elegant होता है। इसे हर हाल में avoid करने की कोशिश करने से maintain करना मुश्किल, बदसूरत और उलझा हुआ code बन सकता है। आम नहीं है, पर valid use cases हैंstrcpyजैसे functions कम recommended हैं, लेकिन ऐसी situations भी होती हैं जहां stronger invariants, जैसे language-level invariants, न टूटें तो उनका सही होना guaranteed होता है। अगर ऐसा case टूट गया है तो पहले से ही कहीं बड़ा problem है। rare cases में यह argument भी किया जा सकता है कि nominally ज्यादा safe alternative बिना benefit के थोड़ा कम efficient हो सकता हैgotoके कुछ uses अब भी C में idiomatic हैं। सावधानी चाहिए, लेकिन आखिर C है, तो ऐसा हो सकता हैहालांकि
longjmpमुझे बिल्कुल पसंद नहीं हैgotouse में कोई problem नहीं है। वहीं strxcpy family पूरी तरह mess है और किसी भी वजह से इस्तेमाल नहीं होनी चाहिए। kernel में इसका इस्तेमाल होना भयानक हैऐसे functions और उन्हें “ठीक करने” की सारी failed attempts को orbit से उड़ा देना चाहिए था
gotoसावधानी से इस्तेमाल करें तो ठीक है।strcpyऔरstrcatभी इस sense में “ठीक” हैं कि अगर आपको पता है code सही है और गलत हुआ तो बड़ा problem होगा। दुर्भाग्य से यह description C के बड़े हिस्से पर लागू होती हैgoto,strcat,strcpyजितना taboo है।gotoठीक है, और same scope में exact-sizemallocके बिना इस्तेमाल होने वालेstrcatऔरstrcpyज्यादा code smell जैसे हैंबहुत अच्छा। क्या गलत हुआ, यह समझाने वाली detailed reports सभी के साथ लगी हैं, यह देखकर खुशी हुई