diff mbox series

[meta-oe,wrynose,4/5] libdbi-perl: Fix CVE-2026-14739

Message ID 20260729091840.84531-4-hthakar@cisco.com
State New
Headers show
Series [meta-oe,wrynose,1/5] libdbi-perl: Fix CVE-2026-9698 | expand

Commit Message

From: Hetvi Thakar <hthakar@cisco.com>

This patch applies the upstream fix as referenced in [2],
using the commit shown in [1].

[1] https://github.com/perl5-dbi/dbi/commit/2b77c88b655e9539a592c71a61fb965fc0075395
[2] https://nvd.nist.gov/vuln/detail/CVE-2026-14739

Signed-off-by: Hetvi Thakar <hthakar@cisco.com>
---
 .../perl/libdbi-perl/CVE-2026-14739.patch     | 124 ++++++++++++++++++
 .../perl/libdbi-perl_1.647.bb                 |   1 +
 2 files changed, 125 insertions(+)
 create mode 100644 meta-oe/recipes-devtools/perl/libdbi-perl/CVE-2026-14739.patch
diff mbox series

Patch

diff --git a/meta-oe/recipes-devtools/perl/libdbi-perl/CVE-2026-14739.patch b/meta-oe/recipes-devtools/perl/libdbi-perl/CVE-2026-14739.patch
new file mode 100644
index 0000000000..84d8b8391a
--- /dev/null
+++ b/meta-oe/recipes-devtools/perl/libdbi-perl/CVE-2026-14739.patch
@@ -0,0 +1,124 @@ 
+From 99798054e18bc9653ce0e29b2de90288981b4ad4 Mon Sep 17 00:00:00 2001
+From: "H.Merijn Brand - Tux" <linux@tux.freedom.nl>
+Date: Sat, 4 Jul 2026 11:38:24 +0200
+Subject: [PATCH] Set a hard limit of 99999 on '?' placeholders 
+ (CVE-2026-14739)
+
+CVE: CVE-2026-14739
+Upstream-Status: Backport [https://github.com/perl5-dbi/dbi/commit/2b77c88b655e9539a592c71a61fb965fc0075395]
+
+Backport Changes:
+- Applied the complete DBI.xs security fix without functional changes.
+  This patch follows CVE-2026-10879 because the upstream fix updates
+  that earlier fix's buffer allocation and adds the 99,999-placeholder
+  limit.
+- Omitted ChangeLog and lib/DBI/Changes.pm because they contain only
+  DBI 1.650 release-note updates.
+- Omitted dbixs_rev.h because it is generated from upstream Git history.
+  The fix does not change the DBIXS or DBISTATE interface.
+- Omitted DBI.pm because its upstream hunks only bump the package from
+  1.649 to 1.650 and document the new placeholder limit; they do not
+  compile or activate the DBI.xs security fix.
+- Omitted generated doc/DBI.3, doc/DBI.html, doc/DBI.man, and doc/DBI.md
+  because they only reproduce the DBI.pm version and documentation
+  changes and are absent from the DBI 1.647 CPAN source.
+
+(cherry picked from commit 2b77c88b655e9539a592c71a61fb965fc0075395)
+Signed-off-by: Hetvi Thakar <hthakar@cisco.com>
+---
+ DBI.xs | 53 +++++++++++++++++++++++++++++++++--------------------
+ 1 file changed, 33 insertions(+), 20 deletions(-)
+
+diff --git a/DBI.xs b/DBI.xs
+index fbfe405..0f9ea9c 100644
+--- a/DBI.xs
++++ b/DBI.xs
+@@ -4203,7 +4203,14 @@ preparse(SV *dbh, const char *statement, IV ps_return, IV ps_accept, void *foo)
+     }
+ 
+     /* XXX this allocation strategy won't work when we get to more advanced stuff */
+-    new_stmt_sv = newSV(strlen(statement) * 6 + 16);
++    /* The 7 is for length increase from '?' (length 1) to :p99999 (length 7)
++     * which imposes a limit of 99999 '?' placeholders POSIX style. Actual counts
++     * are a bit higher:
++     * using factor 5: :p1 .. :p1107
++     * using factor 6: :p1 .. :p11106
++     * using factor 7: :p1 .. :p111105
++     * and that count is insane already */
++    new_stmt_sv = newSV(strlen(statement) * 7 + 16);
+     sv_setpv(new_stmt_sv,"");
+     src  = statement;
+     dest = SvPVX(new_stmt_sv);
+@@ -4342,9 +4349,9 @@ preparse(SV *dbh, const char *statement, IV ps_return, IV ps_accept, void *foo)
+             continue;
+         }
+ 
+-       if (    !(*src==':' && (PS_accept(DBIpp_ph_cn) || PS_accept(DBIpp_ph_cs)))
+-           &&  !(*src=='?' &&  PS_accept(DBIpp_ph_qm))
+-       ){
++        if (    !(*src==':' && (PS_accept(DBIpp_ph_cn) || PS_accept(DBIpp_ph_cs)))
++            &&  !(*src=='?' &&  PS_accept(DBIpp_ph_qm))
++        ){
+             if (*src == '\'' || *src == '"')
+                 in_quote = *src;
+             *dest++ = *src++;
+@@ -4363,12 +4370,18 @@ preparse(SV *dbh, const char *statement, IV ps_return, IV ps_accept, void *foo)
+             if (PS_return(DBIpp_ph_qm))
+                 ;
+             else if (PS_return(DBIpp_ph_cn)) { /* '?' -> ':p1' (etc) */
++                if (idx >= 99999) {
++                    char buf[99];
++                    sprintf(buf, "preparse found more than 99999 '?' placeholders. Limit exceeded.");
++                    set_err_char(dbh, imp_xxh, "1", 1, buf, 0, "preparse");
++                    return &PL_sv_undef;
++                }
+                 sprintf(start,":p%d", idx++);
+                 dest = start+strlen(start);
+             }
+             else if (PS_return(DBIpp_ph_sp)) { /* '?' -> '%s' */
+-                   *start  = '%';
+-                   *dest++ = 's';
++                *start  = '%';
++                *dest++ = 's';
+             }
+         }
+         else if (isDIGIT(*src)) {   /* :1 */
+@@ -4376,24 +4389,24 @@ preparse(SV *dbh, const char *statement, IV ps_return, IV ps_accept, void *foo)
+             style = ":1";
+ 
+             if (PS_return(DBIpp_ph_cn)) { /* ':1'->':p1'  */
+-                   idx = pln;
+-                   *dest++ = 'p';
+-                   while(isDIGIT(*src))
+-                       *dest++ = *src++;
++                idx = pln;
++                *dest++ = 'p';
++                while(isDIGIT(*src))
++                    *dest++ = *src++;
+             }
+             else if (PS_return(DBIpp_ph_qm) /* ':1' -> '?'  */
+                  ||  PS_return(DBIpp_ph_sp) /* ':1' -> '%s' */
+             ) {
+-                   PS_return(DBIpp_ph_qm) ? sprintf(start,"?") : sprintf(start,"%%s");
+-                   dest = start + strlen(start);
+-                   if (pln != idx) {
+-                        char buf[99];
+-                        sprintf(buf, "preparse found placeholder :%d out of sequence, expected :%d", pln, idx);
+-                        set_err_char(dbh, imp_xxh, "1", 1, buf, 0, "preparse");
+-                        return &PL_sv_undef;
+-                   }
+-                   while(isDIGIT(*src)) src++;
+-                   idx++;
++                PS_return(DBIpp_ph_qm) ? sprintf(start,"?") : sprintf(start,"%%s");
++                dest = start + strlen(start);
++                if (pln != idx) {
++                    char buf[99];
++                    sprintf(buf, "preparse found placeholder :%d out of sequence, expected :%d", pln, idx);
++                    set_err_char(dbh, imp_xxh, "1", 1, buf, 0, "preparse");
++                    return &PL_sv_undef;
++                }
++                while(isDIGIT(*src)) src++;
++                idx++;
+             }
+         }
+         else if (isALNUM(*src))         /* :name */
diff --git a/meta-oe/recipes-devtools/perl/libdbi-perl_1.647.bb b/meta-oe/recipes-devtools/perl/libdbi-perl_1.647.bb
index a852dc276a..688b63d534 100644
--- a/meta-oe/recipes-devtools/perl/libdbi-perl_1.647.bb
+++ b/meta-oe/recipes-devtools/perl/libdbi-perl_1.647.bb
@@ -13,6 +13,7 @@  SRC_URI = "${CPAN_MIRROR}/authors/id/H/HM/HMBRAND/DBI-${PV}.tgz \
            file://CVE-2026-9698.patch \
            file://CVE-2026-10879.patch \
            file://CVE-2026-14380.patch \
+           file://CVE-2026-14739.patch \
            "
 SRC_URI[sha256sum] = "0df16af8e5b3225a68b7b592ab531004ddb35a9682b50300ce50174ad867d9aa"