Unsafe use of strcpy in Curl_ldap_err2string (packages/OS400/os400sys.c) — stack-buffer-overflow (PoC + ASan)
What the report claims
The report claims that the function Curl_ldap_err2string in packages/OS400/os400sys.c contains unsafe strcpy usage leading to a stack buffer overflow on OS/400.
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
Key code references could not be verified in the targeted curl version.
Why this finding?
- The report names a function (Curl_ldap_err2string) that does not exist at the checked revision; the deterministic check finds only a Curl_ldap_err2string_* family.
- The provided source snippet shows Curl_ldap_get_dn_a at the cited line 741/742, where the strcpy is bounded by a malloc(strlen(cp)+1) and therefore not an overflow.
- The actual Curl_ldap_err2string_* functions (which likely reside at or near lines 773 and 804) are not included in the provided source, so the central claim cannot be verified or refuted.
- The project policy notes that crashes triggered by a malicious server are often not considered security issues unless special circumstances exist (e.g., RCE), but that determination requires confirming the overflow first.
What still needs checking
- The source code for the Curl_ldap_err2string_* family functions (e.g., Curl_ldap_err2string_a) around lines 773 and 804 in packages/OS400/os400sys.c.
How this analysis ran 5 claims · 4 citations verified
Checked against curl master on 2025-11-10 (77be4a7ab2b5). Test evaluation split. Citation verification checks that a referenced line was in the evidence; it does not prove the model interpreted it correctly.
Review a draft reply to the reporter
Edit and verify before sending.
Thank you for the detailed report. The function name Curl_ldap_err2string does not exist in the current master (77be4a7); only a Curl_ldap_err2string_* family is present. The provided source snippet shows Curl_ldap_get_dn_a at line 742, where the strcpy is bounded by a preceding malloc(strlen(cp)+1). The actual Curl_ldap_err2string_* functions (likely near lines 773 and 804) are not in the snippet. Please confirm the exact function name and, if possible, share the relevant lines for those functions so we can assess the bounds of the destination buffer.
Inspect all claims and source code 5 claims · 1 code excerpts
Report claims
The function Curl_ldap_err2string uses strcpy(cp, cp2); without bounds checking, causing a stack buffer overflow when cp2 is longer than the destination buffer.
Read the reasoning
The report claims the flaw is in Curl_ldap_err2string, but that exact function does not exist in the codebase at the checked revision. The provided source snippet shows Curl_ldap_get_dn_a (line 717) which contains a strcpy at line 742, but that function allocates cp2 to match strlen(cp) before the copy, making the strcpy bounded. The Curl_ldap_err2string_* family functions are not shown, so the claim cannot be verified against the provided code.
The flaw occurs in packages/OS400/os400sys.c at lines 741, 773, and 804 where strcpy is called.
Read the reasoning
The report cites lines 741, 773, and 804 in Curl_ldap_err2string. The provided source shows line 742 (the only strcpy in the snippet) is in a different function (Curl_ldap_get_dn_a) and is bounded by the preceding malloc. Lines 773 and 804 are not in the provided snippet. The deterministic check confirms no Curl_ldap_err2string symbol exists.
An attacker controls the LDAP server response string cp2, which is copied into the vulnerable buffer.
Read the reasoning
The report claims cp2 is populated directly from the LDAP server response and is attacker-controlled. In the shown function (Curl_ldap_get_dn_a), cp2 is a local malloc'd buffer filled by QadrtConvertE2A from cp, which came from the LDAP library. The actual Curl_ldap_err2string_* functions are not provided, so whether their cp2 is attacker-controlled cannot be determined.
The overflow can lead to denial of service, information disclosure, or remote code execution.
Read the reasoning
Impact claims (DoS, info disclosure, RCE) depend on the existence and exploitability of the buffer overflow. Since the overflow itself is not verified in the provided code (the shown strcpy is bounded; the target functions are not shown), the impact cannot be assessed.
The report demonstrates exploitation using AddressSanitizer on a compiled curl binary against a rogue LDAP server that returns an oversized error message.
Read the reasoning
The reproduction describes using ASAN against a rogue LDAP server. Without the actual vulnerable function code, it is impossible to confirm whether the described PoC would trigger an overflow in the real Curl_ldap_err2string_* functions.
Deterministic checks that failed
- symbol no Curl_ldap_err2string, but the Curl_ldap_err2string_* family exists (e.g. Curl_ldap_err2string_a)
- symbol strncpy() is not called in packages/OS400/os400sys.c at 77be4a7ab2b5; curl's own source checker (checksrc.pl) bans strncpy() at this revision
Read the original report (excerpt)
Source code
| 716 | |
| 717 | char * |
| C1: The provided source shows Curl_ldap_get_dn_a at line 717, not Curl_ldap_err2string. The deterministic check confirms no symbol named Curl_ldap_err2string exists at this revision, only a Curl_ldap_err2string_* family (e.g., Curl_ldap_err2string_a). The actual vulnerable functions are not in the provided snippet. | |
| C2: Line 717 begins Curl_ldap_get_dn_a, not Curl_ldap_err2string. The strcpy at line 742 is inside Curl_ldap_get_dn_a. | |
| 718 | Curl_ldap_get_dn_a(void *ld, LDAPMessage *entry) |
| 719 | { |
| 720 | int i; |
| 721 | char *cp; |
| 722 | char *cp2; |
| 723 | |
| 724 | cp = ldap_get_dn(ld, entry); |
| C3: In Curl_ldap_get_dn_a, cp comes from ldap_get_dn(ld, entry), an LDAP library call. cp2 is allocated locally based on strlen(cp), not directly attacker-controlled. | |
| 725 | |
| 726 | if(!cp) |
| 727 | return cp; |
| 728 | |
| 729 | i = strlen(cp); |
| 730 | |
| 731 | cp2 = malloc(i + 1); |
| 732 | if(!cp2) |
| 733 | return cp2; |
| 734 | |
| 735 | QadrtConvertE2A(cp2, cp, i, i); |
| 736 | cp2[i] = '\0'; |
| 737 | |
| 738 | /* No way to allocate a buffer here, because it will be released by |
| 739 | ldap_memfree() and ldap_memalloc() does not exist. The solution is to |
| 740 | overwrite the EBCDIC buffer with ASCII to return it. */ |
| 741 | |
| 742 | strcpy(cp, cp2); |
| C2: strcpy(cp, cp2) at line 742 is in Curl_ldap_get_dn_a, where cp2 was allocated at line 731 as malloc(i+1) with i=strlen(cp) from line 729, so the copy is size-matched. | |
| 743 | free(cp2); |
| 744 | return cp; |
| 745 | } |
| 746 | |
| 747 | char * |
| 748 | Curl_ldap_first_attribute_a(void *ld, |
| 749 | LDAPMessage *entry, BerElement **berptr) |
| 750 | { |
| 751 | int i; |
| 752 | char *cp; |
| 753 | char *cp2; |
| 754 | |
| 755 | cp = ldap_first_attribute(ld, entry, berptr); |
| 756 | |
| 757 | if(!cp) |
| 758 | return cp; |
| 759 | |
| 760 | i = strlen(cp); |
| 761 | |
| 762 | cp2 = malloc(i + 1); |
| 763 | if(!cp2) |
| 764 | return cp2; |
| 765 | |
| 766 | QadrtConvertE2A(cp2, cp, i, i); |