
सुरक्षा सलाह: अनप्रमाणित मेमोरी लीक से मेमोरी समाप्ति (TinyWeb)
निर्धारित CVE ID: CVE-2026-67183
TinyWeb प्रत्येक अनुरोध को पार्स करते समय कई ऑब्जेक्ट आवंटित करता है और उन्हें कभी मुक्त नहीं करता। अनुरोध और हेडर संरचनाओं में कोई डिस्ट्रक्टर नहीं होता, और प्रतिक्रिया भेजे जाने के बाद उन्हें कोई हटाता नहीं है। वर्कर की मेमोरी हर अनुरोध के साथ बढ़ती है और कभी घटती नहीं, इसलिए सामान्य अनुरोधों की एक स्थिर धारा वर्कर की मेमोरी खत्म कर देती है।
TnyWeb/0.0.8e48f15d (2018-11-20), जहां ये संरचनाएं और पार्सर प्रस्तुत किए गए थे, से a381da2 (2023-11-22, master पर नवीनतम) तक।CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:Nएक अनधिकृत दूरस्थ हमलावर जो सर्वर के सुनने वाले TCP पोर्ट (शिप किए गए कॉन्फ़िगरेशन में 9090) तक पहुंच सकता है और मध्यम निरंतर दर पर अनुरोध भेज सकता है। कोई क्रेडेंशियल या उपयोगकर्ता इंटरैक्शन आवश्यक नहीं है। अनुरोध अच्छी तरह से बने हो सकते हैं; किसी विशेष पेलोड की आवश्यकता नहीं है।
प्रत्येक अनुरोध के लिए, HttpParser::execute() एक Url, एक HttpHeaders, और प्रत्येक हेडर पंक्ति के लिए एक HttpHeader आवंटित करता है:
// src/tiny_http/http_parser.cc:1692
request->url = new Url;
// src/tiny_http/http_parser.cc:1709
request->headers = new HttpHeaders;
// src/tiny_http/http_parser.cc:1033-1040
HttpHeader* header = new HttpHeader;
return_val = parseHeader(stream, offset, len, header);
...
result->generals.push_back(header); // stored in a raw-pointer list
HttpRequest और HttpHeaders बिना किसी डिस्ट्रक्टर के सादे struct हैं, इसलिए HttpRequest को नष्ट करने पर इनमें से कुछ भी मुक्त नहीं होता:
// src/tiny_http/http_parser.h:442
typedef struct HttpRequest {
...
Url* url;
HttpHeaders* headers;
HttpBody* body;
} HttpRequest;
// src/tiny_http/http_parser.h:279-304
typedef struct HttpHeaders {
...
std::list<HttpHeader*> generals; // raw pointers, never deleted
...
} HttpHeaders;
WebProtocol अनुरोध को एक std::shared_ptr<HttpRequest> (src/tiny_http/http_protocol.h:49) में रखता है। जब अगला अनुरोध इसे बदल देता है, तो डिफ़ॉल्ट ~HttpRequest चलता है और url, headers, body, तथा generals में मौजूद प्रत्येक HttpHeader को लीक कर देता है। कोड में एकमात्र delete request getDataFromProxy() (src/tiny_http/http_protocol.cc:194) में है, जो एक ऐसा फ़ंक्शन है जिसे अनुरोध पथ कभी कॉल नहीं करता। मेमोरी पूल से प्रति-अनुरोध प्रतिक्रिया बफर भी इस वृद्धि में योगदान करते हैं।
शिप किए गए कॉन्फ़िगरेशन के साथ सर्वर शुरू करें (पोर्ट 9090 पर सुनना)। किसी वर्कर की प्रक्रिया ID नोट करें।
वर्कर की रेज़िडेंट मेमोरी रिकॉर्ड करें:
grep VmRSS /proc/<worker_pid>/status
for i in $(seq 1 2000); do
curl -s -o /dev/null http://TARGET:9090/
done
VmRSS फिर से पढ़ें। यह बढ़ गया है और बाद में गिरता नहीं है। एक प्रतिनिधि रन:VmRSS before: 3704 kB
after 500 requests: 4788 kB
after 1000 requests: 22068 kB
after 1500 requests: 41652 kB
after 2000 requests: 59956 kB
वृद्धि एकसमान (monotonic) है, प्रति अनुरोध लगभग 20 से 28 kB, और इसमें कोई ठहराव (plateau) नहीं आता। बैच को दोहराने से वृद्धि जारी रहती है जब तक कि मेमोरी खत्म होने के कारण वर्कर को मार नहीं दिया जाता।
एक अनधिकृत हमलावर एक निरंतर अनुरोध धारा के साथ एक वर्कर की मेमोरी समाप्त कर सकता है और मेमोरी से बाहर (out-of-memory) की स्थिति को मजबूर कर सकता है, जिससे सेवा से इनकार होता है। सामान्य ट्रैफ़िक भी समय के साथ लीक होता है, इसलिए यह स्थिति बिना किसी हमलावर के भी उत्पन्न हो सकती है।
HttpRequest और HttpHeaders को ऐसे डिस्ट्रक्टर दें जो url, headers, body, और generals में मौजूद प्रत्येक HttpHeader को मुक्त करें, या उन्हें स्मार्ट पॉइंटर्स में रखें ताकि वे स्वचालित रूप से रिलीज़ हों। साथ ही, प्रतिक्रिया भेजे जाने के बाद प्रति-अनुरोध मेमोरी-पूल बफर को भी रिलीज़ करें।