✓ProveIt
Examples / Report #3466896 Saved analysis

Heap Overflow in cURL AmigaOS Socket Implementation

curl · 2025-12-1635.0s analysis · $0.033 in model calls

What the report claims

Heap overflow in Curl_ipv4_resolve_r in AmigaOS socket backend

Compare with curl's recorded outcome

Labeled AI slop

curl's maintainer lists this report as AI slop

Shown for comparison after analysis. The pipeline did not see this label.

ProveIt's finding

Needs a policy review

The code does what the report says, but curl's own policy may exclude it. A maintainer decides.

curl policy: API misuse
Judgment withdrawn. The answer failed the evidence check.
See the withdrawn model reasoning

The following reasoning failed the citation check and does not support the final finding.

  • The curl code correctly allocates a buffer and passes its size to gethostbyname_r; any buffer overflow would be in the AmigaOS system library, not in curl's implementation.
  • The report's alignment/padding argument is speculative without the gethostbyname_r specification or implementation.
  • Issue C (resource leak) is contradicted by the code: curlx_free(buf) is called on all paths after allocation.
  • The project policy lists 'API misuse' as not a security issue: curl uses the system API as documented (passing buffer and size).
  • No evidence in the provided code that 9000 bytes is insufficient for legitimate DNS responses on AmigaOS.
What still needs checking
  • The AmigaOS bsdsocket.library gethostbyname_r implementation or documentation showing it ignores the buffer size parameter.
  • Evidence that legitimate DNS responses on AmigaOS exceed 9000 bytes in the hostent structure.
How this analysis ran 5 claims · 7 citations verified

Evidence check: the behavior is real; the project's policy section 'API misuse' may exclude it

Checked against curl master on 2025-12-16 (7b2783496ce7). Dev evaluation split. Citation verification checks that a referenced line was in the evidence; it does not prove the model interpreted it correctly.

1 · Grounding
partially grounded
no model · 18 references checked out, 7 did not
2 · Claims
NVIDIA-Nemotron-3-Nano-30B-A3B
5 claims · 7055 tokens · $0.0005
3 · Evidence
7 code snippets
real curl source at 7b2783496ce7
4 · Judgment
Nemotron-3-Ultra-550b-a55b
20034 tokens · 33.2s · $0.0320
5 · Receipts
7 of 7 citations verified
every citation must point at code the judge was shown
Inspect the withdrawn draft reply

This draft belongs to the withdrawn judgment. It may contain unsupported claims.

Thank you for the detailed report. The curl code in lib/amigaos.c correctly passes the buffer size (CURL_HOSTENT_SIZE - sizeof(struct hostent)) to gethostbyname_r, so any overflow would be in the AmigaOS system library, not in curl. The alignment argument assumes internal padding in gethostbyname_r without its specification. Issue C is contradicted: curlx_free(buf) runs on all paths. To proceed, we would need evidence that gethostbyname_r ignores the buffer size limit or that 9000 bytes is too small for valid AmigaOS DNS responses. Could you provide the bsdsocket.library documentation or a test showing the overflow with a legitimate (non-malicious) response?

Inspect all claims and source code 5 claims · 7 code excerpts

This model judgment was withdrawn. The claim assessments below are preserved for inspection and may be wrong.

Report claims

C1flaw not verifiable

Fixed buffer size of 8192 bytes allocated for gethostbyname_r response without considering actual DNS response size

Read the reasoning

The curl code allocates a 9000-byte buffer and correctly passes the data buffer size to gethostbyname_r. Whether this causes an overflow depends on the behavior of gethostbyname_r (an AmigaOS bsdsocket.library function), which is not provided in the curl source. The claim assumes gethostbyname_r ignores the buffer size limit, but no evidence of this is in the provided code.

C2location supported

Function Curl_ipv4_resolve_r in lib/amigaos.c

Read the reasoning

The function Curl_ipv4_resolve_r exists in lib/amigaos.c at the stated location.

C3trigger not verifiable

Providing specially crafted hostnames or DNS responses that exceed the fixed buffer size

Read the reasoning

The trigger depends on gethostbyname_r not respecting the buffer size limit. Without the system library implementation, this cannot be verified from curl code alone.

C4impact not verifiable

Remote code execution via heap metadata corruption

Read the reasoning

Remote code execution via heap corruption requires a demonstrated overflow in curl's code. The provided curl code shows correct buffer size passing; any overflow would be in the external gethostbyname_r implementation, not shown.

C5reproduction contradicted

Use long hostnames (4000+ characters) or multiple DNS records to overflow the buffer

Read the reasoning

The reproduction references MAX_HOSTNAME_LEN which does not exist in the current code (the report's patch proposes adding it). The current code has no hostname length validation, but the trigger still depends on the unproven gethostbyname_r behavior.

Deterministic checks that failed

  • symbol _Static_assert() does not exist in curl at 7b2783496ce7 or in any release since 7.50
  • symbol Curl_getaddrinfo exists in other curl releases but not at 7b2783496ce7
  • symbol PPC exists in other curl releases but not at 7b2783496ce7
  • quote only 0/2 quoted lines appear anywhere in curl at 7b2783496ce7
  • quote 1 of 3 quoted lines appear nowhere in curl, e.g. 'if(data_size < MIN_SAFE_DNS_BUFFER) {'
  • quote 1 of 2 quoted lines appear nowhere in curl, e.g. 'return Curl_getaddrinfo(hostname, port);'
  • quote only 0/12 quoted lines appear anywhere in curl at 7b2783496ce7
Read the original report (excerpt)

Full report on HackerOne ↗

** Buffer Overflow in cURL AmigaOS Socket Implementation** ## **Report Metadata** - **Report ID:** H1-CURL-AMIGAOS-001 - **Report Title:** Heap Buffer Overflow in `Curl_ipv4_resolve_r` in AmigaOS Socket Backend - **Component:** `/home/el-ha9/curl/lib/amigaos.c` - `Curl_ipv4_resolve_r` function - **Affected Versions:** All cURL versions with AmigaOS support (7.x - 8.x) - **Severity:** **High** (CVSS 8.1 - AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H) - **CWE-ID:** CWE-122 - Heap-based Buffer Overflow - **Disclosure:** Responsible ## **1. Vulnerability Summary** A heap-based buffer overflow vulnerability exists in the AmigaOS-specific hostname resolution function `Curl_ipv4_resolve_r`. The vulnerability allows remote attackers to corrupt heap memory by providing specially crafted hostnames or DNS responses, potentially leading to remote code execution when cURL processes malicious input. ## **2. Technical Details** ### **2.1 Vulnerable Code Location** **File:** `curl/lib/amigaos.c` **Function:** `Curl_ipv4_resolve_r` (lines ~123-173) ### **2.2 Root Cause Analysis** The vulnerability occurs in the buffer size calculation for the `gethostbyname_r` function: ```c buf = curlx_calloc(1, CURL_HOSTENT_SIZE); // 1. Fixed size allocation if(buf) { h = gethostbyname_r((STRPTR)hostname, buf, (char *)buf + sizeof(struct hostent), // 2. Incorrect buffer offset CURL_HOSTENT_SIZE - sizeof(struct hostent), // 3. Incorrect size calculation &h_errnop); ``` ### **2.3 The Flaw** Three critical issues combine to create the overflow: 1. **Fixed Buffer Size (`CURL_HOSTENT_SIZE`):** - Defined as `8192` in typical configurations - No consideration for actual DNS response size - Assumes all hostname resolutions fit within this limit 2. **Incorrect Pointer Arithmetic:** ```c (char *)buf + sizeof(struct hostent) ``` - Assumes `struct hostent` can be tightly packed - Ignores alignment requirements (struct padding) - Real offset should be: `ALIGN_UP(sizeof(struct hostent), alignof(max_align_t))` 3. **Incorrect Size Calculation:** ```c CURL_HOSTENT_SIZE - sizeof(struct hostent) ``` - Doesn't account for alignment padding - Could result in negative/underflow on some platforms - No safety margin for metadata storage ### **2.4 Memory Layout Exploitation** ``` Heap Layout Be …

Source code

lib/hostip.hlines 45–45 · definition of CURL_HOSTENT_SIZE
45#define CURL_HOSTENT_SIZE 9000
C1: CURL_HOSTENT_SIZE defined as 9000
lib/amigaos.clines 123–172 · definition of Curl_ipv4_resolve_r
123struct Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname, int port)
C2: Function Curl_ipv4_resolve_r defined at line 123
C5: No MAX_HOSTNAME_LEN constant exists in the function
124{
125 struct Curl_addrinfo *ai = NULL;
126 struct hostent *h;
127 struct SocketIFace *ISocket = __CurlISocket;
128
129 if(SocketFeatures & HAVE_BSDSOCKET_GETHOSTBYNAME_R) {
130 LONG h_errnop = 0;
131 struct hostent *buf;
132
133 buf = curlx_calloc(1, CURL_HOSTENT_SIZE);
C1: Buffer allocated with curlx_calloc(1, CURL_HOSTENT_SIZE)
C4: Heap allocation site
134 if(buf) {
135 h = gethostbyname_r((STRPTR)hostname, buf,
C1: gethostbyname_r called with data buffer size CURL_HOSTENT_SIZE - sizeof(struct hostent)
C3: hostname passed to gethostbyname_r
136 (char *)buf + sizeof(struct hostent),
137 CURL_HOSTENT_SIZE - sizeof(struct hostent),
138 &h_errnop);
139 if(h) {
140 ai = Curl_he2ai(h, port);
141 }
142 curlx_free(buf);
143 }
144 }
145 else {
146#ifdef CURLRES_THREADED
147 /* gethostbyname() is not thread safe, so we need to reopen bsdsocket
148 * on the thread's context
149 */
150 struct Library *base = OpenLibrary("bsdsocket.library", 4);
151 if(base) {
152 ISocket = (struct SocketIFace *)GetInterface(base, "main", 1, NULL);
153 if(ISocket) {
154 h = gethostbyname((STRPTR)hostname);
155 if(h) {
156 ai = Curl_he2ai(h, port);
157 }
158 DropInterface((struct Interface *)ISocket);
159 }
160 CloseLibrary(base);
161 }
162#else
163 /* not using threaded resolver - safe to use this as-is */
164 h = gethostbyname(hostname);
165 if(h) {
166 ai = Curl_he2ai(h, port);
167 }
168#endif
169 }
170
171 return ai;
172}
lib/amigaos.c@curl-8_17_0lines 127–177 · definition of Curl_ipv4_resolve_r as in release curl-8_17_0; differs from master; commits that changed it since: 47a1ab2ebe lib: fix formatting nits (part 1) | 193cb00ce9 build: stop overriding standard memory allocation functions
Show 51 lines (not cited by the judge)
127struct Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname,
128 int port)
129{
130 struct Curl_addrinfo *ai = NULL;
131 struct hostent *h;
132 struct SocketIFace *ISocket = __CurlISocket;
133
134 if(SocketFeatures & HAVE_BSDSOCKET_GETHOSTBYNAME_R) {
135 LONG h_errnop = 0;
136 struct hostent *buf;
137
138 buf = calloc(1, CURL_HOSTENT_SIZE);
139 if(buf) {
140 h = gethostbyname_r((STRPTR)hostname, buf,
141 (char *)buf + sizeof(struct hostent),
142 CURL_HOSTENT_SIZE - sizeof(struct hostent),
143 &h_errnop);
144 if(h) {
145 ai = Curl_he2ai(h, port);
146 }
147 free(buf);
148 }
149 }
150 else {
151 #ifdef CURLRES_THREADED
152 /* gethostbyname() is not thread safe, so we need to reopen bsdsocket
153 * on the thread's context
154 */
155 struct Library *base = OpenLibrary("bsdsocket.library", 4);
156 if(base) {
157 ISocket = (struct SocketIFace *)GetInterface(base, "main", 1, NULL);
158 if(ISocket) {
159 h = gethostbyname((STRPTR)hostname);
160 if(h) {
161 ai = Curl_he2ai(h, port);
162 }
163 DropInterface((struct Interface *)ISocket);
164 }
165 CloseLibrary(base);
166 }
167 #else
168 /* not using threaded resolver - safe to use this as-is */
169 h = gethostbyname(hostname);
170 if(h) {
171 ai = Curl_he2ai(h, port);
172 }
173 #endif
174 }
175
176 return ai;
177}
lib/curl_addrinfo.clines 246–334 · definition of Curl_he2ai
Show 89 lines (not cited by the judge)
246struct Curl_addrinfo *Curl_he2ai(const struct hostent *he, int port)
247{
248 struct Curl_addrinfo *ai;
249 struct Curl_addrinfo *prevai = NULL;
250 struct Curl_addrinfo *firstai = NULL;
251 struct sockaddr_in *addr;
252#ifdef USE_IPV6
253 struct sockaddr_in6 *addr6;
254#endif
255 CURLcode result = CURLE_OK;
256 int i;
257 char *curr;
258
259 if(!he)
260 /* no input == no output! */
261 return NULL;
262
263 DEBUGASSERT((he->h_name != NULL) && (he->h_addr_list != NULL));
264
265 for(i = 0; (curr = he->h_addr_list[i]) != NULL; i++) {
266 size_t ss_size;
267 size_t namelen = strlen(he->h_name) + 1; /* include null-terminator */
268#ifdef USE_IPV6
269 if(he->h_addrtype == AF_INET6)
270 ss_size = sizeof(struct sockaddr_in6);
271 else
272#endif
273 ss_size = sizeof(struct sockaddr_in);
274
275 /* allocate memory to hold the struct, the address and the name */
276 ai = curlx_calloc(1, sizeof(struct Curl_addrinfo) + ss_size + namelen);
277 if(!ai) {
278 result = CURLE_OUT_OF_MEMORY;
279 break;
280 }
281 /* put the address after the struct */
282 ai->ai_addr = (void *)((char *)ai + sizeof(struct Curl_addrinfo));
283 /* then put the name after the address */
284 ai->ai_canonname = (char *)ai->ai_addr + ss_size;
285 memcpy(ai->ai_canonname, he->h_name, namelen);
286
287 if(!firstai)
288 /* store the pointer we want to return from this function */
289 firstai = ai;
290
291 if(prevai)
292 /* make the previous entry point to this */
293 prevai->ai_next = ai;
294
295 ai->ai_family = he->h_addrtype;
296
297 /* we return all names as STREAM, so when using this address for TFTP
298 the type must be ignored and conn->socktype be used instead! */
299 ai->ai_socktype = SOCK_STREAM;
300
301 ai->ai_addrlen = (curl_socklen_t)ss_size;
302
303 /* leave the rest of the struct filled with zero */
304
305 switch(ai->ai_family) {
306 case AF_INET:
307 addr = (void *)ai->ai_addr; /* storage area for this info */
308
309 memcpy(&addr->sin_addr, curr, sizeof(struct in_addr));
310 addr->sin_family = (CURL_SA_FAMILY_T)(he->h_addrtype);
311 addr->sin_port = htons((unsigned short)port);
312 break;
313
314#ifdef USE_IPV6
315 case AF_INET6:
316 addr6 = (void *)ai->ai_addr; /* storage area for this info */
317
318 memcpy(&addr6->sin6_addr, curr, sizeof(struct in6_addr));
319 addr6->sin6_family = (CURL_SA_FAMILY_T)(he->h_addrtype);
320 addr6->sin6_port = htons((unsigned short)port);
321 break;
322#endif
323 }
324
325 prevai = ai;
326 }
327
328 if(result) {
329 Curl_freeaddrinfo(firstai);
330 firstai = NULL;
331 }
332
333 return firstai;
334}
lib/curl_addrinfo.c@curl-8_17_0lines 257–346 · definition of Curl_he2ai as in release curl-8_17_0; differs from master; commits that changed it since: 86b346443b lib: fix formatting nits (part 2) | 193cb00ce9 build: stop overriding standard memory allocation functions | ce06fe7771 hostip: make more functions return CURLcode
Show 90 lines (not cited by the judge)
257struct Curl_addrinfo *
258Curl_he2ai(const struct hostent *he, int port)
259{
260 struct Curl_addrinfo *ai;
261 struct Curl_addrinfo *prevai = NULL;
262 struct Curl_addrinfo *firstai = NULL;
263 struct sockaddr_in *addr;
264#ifdef USE_IPV6
265 struct sockaddr_in6 *addr6;
266#endif
267 CURLcode result = CURLE_OK;
268 int i;
269 char *curr;
270
271 if(!he)
272 /* no input == no output! */
273 return NULL;
274
275 DEBUGASSERT((he->h_name != NULL) && (he->h_addr_list != NULL));
276
277 for(i = 0; (curr = he->h_addr_list[i]) != NULL; i++) {
278 size_t ss_size;
279 size_t namelen = strlen(he->h_name) + 1; /* include null-terminator */
280#ifdef USE_IPV6
281 if(he->h_addrtype == AF_INET6)
282 ss_size = sizeof(struct sockaddr_in6);
283 else
284#endif
285 ss_size = sizeof(struct sockaddr_in);
286
287 /* allocate memory to hold the struct, the address and the name */
288 ai = calloc(1, sizeof(struct Curl_addrinfo) + ss_size + namelen);
289 if(!ai) {
290 result = CURLE_OUT_OF_MEMORY;
291 break;
292 }
293 /* put the address after the struct */
294 ai->ai_addr = (void *)((char *)ai + sizeof(struct Curl_addrinfo));
295 /* then put the name after the address */
296 ai->ai_canonname = (char *)ai->ai_addr + ss_size;
297 memcpy(ai->ai_canonname, he->h_name, namelen);
298
299 if(!firstai)
300 /* store the pointer we want to return from this function */
301 firstai = ai;
302
303 if(prevai)
304 /* make the previous entry point to this */
305 prevai->ai_next = ai;
306
307 ai->ai_family = he->h_addrtype;
308
309 /* we return all names as STREAM, so when using this address for TFTP
310 the type must be ignored and conn->socktype be used instead! */
311 ai->ai_socktype = SOCK_STREAM;
312
313 ai->ai_addrlen = (curl_socklen_t)ss_size;
314
315 /* leave the rest of the struct filled with zero */
316
317 switch(ai->ai_family) {
318 case AF_INET:
319 addr = (void *)ai->ai_addr; /* storage area for this info */
320
321 memcpy(&addr->sin_addr, curr, sizeof(struct in_addr));
322 addr->sin_family = (CURL_SA_FAMILY_T)(he->h_addrtype);
323 addr->sin_port = htons((unsigned short)port);
324 break;
325
326#ifdef USE_IPV6
327 case AF_INET6:
328 addr6 = (void *)ai->ai_addr; /* storage area for this info */
329
330 memcpy(&addr6->sin6_addr, curr, sizeof(struct in6_addr));
331 addr6->sin6_family = (CURL_SA_FAMILY_T)(he->h_addrtype);
332 addr6->sin6_port = htons((unsigned short)port);
333 break;
334#endif
335 }
336
337 prevai = ai;
338 }
339
340 if(result) {
341 Curl_freeaddrinfo(firstai);
342 firstai = NULL;
343 }
344
345 return firstai;
346}
lib/curl_setup.hlines 1065–1066 · definition of curlx_calloc
Show 2 lines (not cited by the judge)
1065#define curlx_calloc(nbelem,size) \
1066 curl_dbg_calloc(nbelem, size, __LINE__, __FILE__)
lib/curl_setup.hlines 1069–1069 · definition of curlx_free
Show 1 lines (not cited by the judge)
1069#define curlx_free(ptr) curl_dbg_free(ptr, __LINE__, __FILE__)