Skip to content

GHSA-wj3v-c3hh-mhqr

CVE Information

Platform

Perl DBI (Database Interface) — XS core, DBI.xs preparse(). Cross-platform Perl module (CPAN). Affects DBI 1.650 and repo HEAD (1.652); the vulnerable line is long-standing. Exploitable on 32-bit perl builds (ptrsize/ivsize = 4). attachments.zip

Summary

preparse() sizes its output buffer with newSV(strlen(statement) * 7 + 16). strlen() returns size_t and the multiply is evaluated in STRLEN width. On 32-bit perl, STRLEN is 32 bits, so a statement of strlen ≥ 613,566,757 bytes (~585 MB) makes strlen * 7 wrap modulo 2³², producing a tiny allocation. preparse() then copies the full attacker-sized statement into that under-allocated buffer → heap out-of-bounds write of attacker-controlled bytes.

Description

DBI.xs (tag 1.650), preparse buffer allocation and the unguarded copy:

/* line 4213 */  new_stmt_sv = newSV(strlen(statement) * 7 + 16);
/* line 4363 */  *dest++ = *src++;     /* copy/emit loop, bound by input length, not reserved size */
  • strlen(statement) is size_t; strlen * 7 is computed in STRLEN (= size_t). On 32-bit perl size_t is 32-bit.
  • For strlen = 613,566,757: × 7 = 4,294,967,299; mod 2³² = 3; +16 = 19newSV(19).
  • The parser writes the input out through the raw dest pointer with no capacity clamp, so it writes ~585 MB into a 19-byte buffer → heap OOB write.
  • The idx >= 99999 placeholder cap (CVE-2026-14739) does not guard this path — the trigger uses non-placeholder content, which never reaches the cap. The CVE-2026-14739 change from * 6 to * 7 lowered the wrap threshold (~682.7 MB → ~585.1 MB), marginally widening exposure.
  • 64-bit perl is not practically affected: the wrap needs strlen ≥ 2⁶⁴/7 ≈ 2.3 EB.

Proof of Concept

32-bit perl (i686-linux-gnu, ptrsize=4), DBI built from tag 1.650:

use strict; use warnings; use DBI; $|=1;
my $s = "a" x 613_566_757;        # 613566757*7+16 wraps to 19 in 32-bit STRLEN -> newSV(19)
my $dbh = DBI->connect("dbi:ExampleP:", "", "", {RaiseError=>0, PrintError=>0});
$dbh->preparse($s, 2, 1);          # heap overflow inside preparse()

Reproduce end-to-end (native i386 container, no VM, $0): attachments/build-and-run.sh.

Expected Result

preparse() either sizes the buffer correctly or refuses an over-length statement with an error (as it already does for > 99,999 placeholders).

Observed Result

Heap buffer overflow inside preparse(). - Normal build: the ~585 MB source string allocates fine, then the process SIGSEGVs inside preparse() (autoflush markers confirm the crash is after "calling preparse", not during string allocation). - AddressSanitizer build: heap-buffer-overflow WRITE of size 1 ... #0 preparse DBI.xs:4363 ... 0 bytes to the right of a 21-byte region [Perl_safesysmalloc] (21 = wrapped newSV(19) + allocator rounding).

Negative control: the identical harness on 64-bit perl does not overflow — preparse() returns normally (the size math does not wrap at 64-bit STRLEN). This isolates the 32-bit STRLEN wrap as the load-bearing cause, not the input content or the API call itself. (Independently, adversarial testing showed the placeholder-count path — ? x 99998 etc. — never exceeds the strlen*7 budget on any bitness, confirming this residual is the integer-wrap, not the CVE-2026-14739 logic.)

Impact

Heap out-of-bounds write of attacker-controlled bytes — a memory-corruption primitive. In practice the very large write reaches unmapped memory quickly → reliable crash / denial of service; controlled-corruption / code-execution escalation is not demonstrated and would be constrained by the write extent. Reported honestly as a memory-safety defect, not a demonstrated RCE.

Reachability preconditions (both required): (1) a 32-bit perl build (32-bit Strawberry/ActiveState on Windows, ARM32/embedded appliances, legacy i686 Linux); (2) an application that passes attacker-controlled, unbounded SQL to DBI::preparse() (e.g. ?:pN placeholder-normalization middleware) with no input length cap.

Callstack

==ERROR: AddressSanitizer: heap-buffer-overflow ... WRITE of size 1
    #0 preparse                 DBI.xs:4363
    #1 XS_DBD_____db_preparse    DBI.c:5447
    #2 XS_DBI_dispatch           DBI.xs:3785
    #3 Perl_pp_entersub / Perl_runops_standard / perl_run / main
0x...915 is 0 bytes to the right of a 21-byte region allocated by Perl_safesysmalloc
SUMMARY: AddressSanitizer: heap-buffer-overflow DBI.xs:4363 in preparse

Evidence / Attachments

File What it shows
attachments/poc-asan-heap-overflow.txt ASAN heap-buffer-overflow WRITE at DBI.xs:4363 in preparse; 21-byte region
attachments/poc-normal-build-sigsegv.txt Normal 32-bit build: markers + SIGSEGV localized inside preparse
attachments/harness.pl Minimal trigger
attachments/build-and-run.sh End-to-end repro in a native i386 container ($0, no VM)
attachments/dbi-xs-4213-allocation.txt The vulnerable allocation line at tag 1.650