@@ -77,8 +77,43 @@ size_t HttpOperation::WriteMemoryCallback(void *contents, size_t size, size_t nm
7777 return 0 ;
7878 }
7979
80- self->raw_response_ .insert (self->raw_response_ .end (), static_cast <char *>(contents),
81- static_cast <char *>(contents) + (size * nmemb));
80+ const size_t data_size = size * nmemb;
81+
82+ // This code is defensive on purpose, to avoid allocation of unbound
83+ // amounts of memory, controlled by the (remote) endpoint response.
84+
85+ // 1: Check data_size did not overflow
86+ if (nmemb != 0 )
87+ {
88+ if (data_size / nmemb != size)
89+ {
90+ // Should be impossible, really:
91+ // CURL will report a huge response small chunks at a time,
92+ // not in one block, which would be a DOS in CURL already.
93+ return 0 ;
94+ }
95+ }
96+
97+ // 2: Check internal integrity
98+ if (self->raw_response_ .size () > self->max_response_size_ )
99+ {
100+ // Should be impossible,
101+ // this means the previous call did exceed the max size already.
102+ return 0 ;
103+ }
104+
105+ // 3: Protect against memory exhaustion caused by the remote endpoint
106+ if (data_size > self->max_response_size_ - self->raw_response_ .size ())
107+ {
108+ // This one is possible and must be protected against (CVE-2026-44967).
109+ // Checks 1 and 2 ensure the math is correct.
110+ return 0 ;
111+ }
112+
113+ const unsigned char *begin = static_cast <unsigned char *>(contents);
114+ const unsigned char *end = begin + data_size;
115+
116+ self->raw_response_ .insert (self->raw_response_ .end (), begin, end);
82117
83118 if (self->WasAborted ())
84119 {
@@ -95,7 +130,7 @@ size_t HttpOperation::WriteMemoryCallback(void *contents, size_t size, size_t nm
95130 self->DispatchEvent (opentelemetry::ext::http::client::SessionState::Sending);
96131 }
97132
98- return size * nmemb ;
133+ return data_size ;
99134}
100135
101136size_t HttpOperation::WriteVectorHeaderCallback (void *ptr, size_t size, size_t nmemb, void *userp)
@@ -106,8 +141,33 @@ size_t HttpOperation::WriteVectorHeaderCallback(void *ptr, size_t size, size_t n
106141 return 0 ;
107142 }
108143
144+ const size_t data_size = size * nmemb;
145+
146+ // See comments in HttpOperation::WriteMemoryCallback().
147+
148+ if (nmemb != 0 )
149+ {
150+ if (data_size / nmemb != size)
151+ {
152+ return 0 ;
153+ }
154+ }
155+
156+ // Common limit for header + body
157+ if (self->response_headers_ .size () + self->response_body_ .size () > self->max_response_size_ )
158+ {
159+ return 0 ;
160+ }
161+
162+ if (data_size >
163+ self->max_response_size_ - self->response_headers_ .size () - self->response_body_ .size ())
164+ {
165+ return 0 ;
166+ }
167+
109168 const unsigned char *begin = static_cast <unsigned char *>(ptr);
110- const unsigned char *end = begin + size * nmemb;
169+ const unsigned char *end = begin + data_size;
170+
111171 self->response_headers_ .insert (self->response_headers_ .end (), begin, end);
112172
113173 if (self->WasAborted ())
@@ -125,7 +185,7 @@ size_t HttpOperation::WriteVectorHeaderCallback(void *ptr, size_t size, size_t n
125185 self->DispatchEvent (opentelemetry::ext::http::client::SessionState::Sending);
126186 }
127187
128- return size * nmemb ;
188+ return data_size ;
129189}
130190
131191size_t HttpOperation::WriteVectorBodyCallback (void *ptr, size_t size, size_t nmemb, void *userp)
@@ -136,8 +196,33 @@ size_t HttpOperation::WriteVectorBodyCallback(void *ptr, size_t size, size_t nme
136196 return 0 ;
137197 }
138198
199+ const size_t data_size = size * nmemb;
200+
201+ // See comments in HttpOperation::WriteMemoryCallback().
202+
203+ if (nmemb != 0 )
204+ {
205+ if (data_size / nmemb != size)
206+ {
207+ return 0 ;
208+ }
209+ }
210+
211+ // Common limit for header + body
212+ if (self->response_headers_ .size () + self->response_body_ .size () > self->max_response_size_ )
213+ {
214+ return 0 ;
215+ }
216+
217+ if (data_size >
218+ self->max_response_size_ - self->response_headers_ .size () - self->response_body_ .size ())
219+ {
220+ return 0 ;
221+ }
222+
139223 const unsigned char *begin = static_cast <unsigned char *>(ptr);
140- const unsigned char *end = begin + size * nmemb;
224+ const unsigned char *end = begin + data_size;
225+
141226 self->response_body_ .insert (self->response_body_ .end (), begin, end);
142227
143228 if (self->WasAborted ())
@@ -155,7 +240,7 @@ size_t HttpOperation::WriteVectorBodyCallback(void *ptr, size_t size, size_t nme
155240 self->DispatchEvent (opentelemetry::ext::http::client::SessionState::Sending);
156241 }
157242
158- return size * nmemb ;
243+ return data_size ;
159244}
160245
161246size_t HttpOperation::ReadMemoryCallback (char *buffer, size_t size, size_t nitems, void *userp)
0 commit comments