[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#970096: buster-pu: package libdbi-perl/1.642-1+deb10u1



Package: release.debian.org
Severity: normal
Tags: buster
User: release.debian.org@packages.debian.org
Usertags: pu
X-Debbugs-Cc: debian-perl@lists.debian.org

[ Reason ]
libdbi-perl is vulnerable to (low) security bug (CVE-2020-14392)

[ Impact ]
libdbi-perl may crash if an attacker can give a malformed login

[ Tests ]
No new test, current passed

[ Risks ]
This patch is very simple

[ Checklist ]
  [X] *all* changes are documented in the d/changelog
  [X] I reviewed all changes and I approve them
  [X] attach debdiff against the package in (old)stable
  [X] the issue is verified as fixed in unstable

[ Changes ]
Returned values are more tested
diff --git a/debian/changelog b/debian/changelog
index d2e35cc..d0ad39a 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,10 @@
+libdbi-perl (1.642-1+deb10u1) buster; urgency=medium
+
+  * Fix memory corruption in XS functions when Perl stack is reallocated
+    (Closes: CVE-2020-14392)
+
+ -- Xavier Guimard <yadd@debian.org>  Thu, 10 Sep 2020 10:04:13 +0200
+
 libdbi-perl (1.642-1) unstable; urgency=medium
 
   [ Xavier Guimard ]
diff --git a/debian/patches/CVE-2020-14392.patch b/debian/patches/CVE-2020-14392.patch
new file mode 100644
index 0000000..99c7a3e
--- /dev/null
+++ b/debian/patches/CVE-2020-14392.patch
@@ -0,0 +1,318 @@
+Description: Fix memory corruption in XS functions when Perl stack is reallocated
+ Macro ST(*) returns pointer to Perl stack. Other Perl functions which use
+ Perl stack (e.g. eval) may reallocate Perl stack and therefore pointer
+ returned by ST(*) macro is invalid.
+ .
+ Construction like this:
+ .
+ ST(0) = dbd_db_login6_sv(dbh, imp_dbh, dbname, username, password, attribs) ? &PL_sv_yes : &PL_sv_no;
+ .
+ where dbd_db_login6_sv() driver function calls eval may lead to
+ reallocating Perl stack and therefore invalidating ST(0) pointer.
+ So that construction would cause memory corruption as left part of
+ assignment is resolved prior executing dbd_db_login6_sv() function.
+ .
+ Correct way how to handle this problem: First call dbd_db_login6_sv()
+ function and then call ST(0) to retrieve stack pointer.
+ .
+ In this patch are fixes all occurrences of such constructions.
+ .
+ When running perl under valgrind I got memory corruption in DBD::ODBC
+ driver in that dbd_db_login6_sv() function due to above problem.
+Author: Pali <pali@cpan.org>
+Origin: upstream, https://github.com/perl5-dbi/dbi/commit/ea99b6aa
+Bug: https://security-tracker.debian.org/tracker/CVE-2020-14392
+Forwarded: not-needed
+Reviewed-By: Xavier Guimard <yadd@debian.org>
+Last-Update: 2020-09-10
+
+--- a/DBI.xs
++++ b/DBI.xs
+@@ -5252,9 +5252,12 @@
+     SV *        col
+     SV *        ref
+     SV *        attribs
++    PREINIT:
++    SV *ret;
+     CODE:
+     DBD_ATTRIBS_CHECK("bind_col", sth, attribs);
+-    ST(0) = boolSV(dbih_sth_bind_col(sth, col, ref, attribs));
++    ret = boolSV(dbih_sth_bind_col(sth, col, ref, attribs));
++    ST(0) = ret;
+     (void)cv;
+ 
+ 
+@@ -5492,21 +5495,27 @@
+ FETCH(h, keysv)
+     SV *        h
+     SV *        keysv
++    PREINIT:
++    SV *ret;
+     CODE:
+-    ST(0) = dbih_get_attr_k(h, keysv, 0);
++    ret = dbih_get_attr_k(h, keysv, 0);
++    ST(0) = ret;
+     (void)cv;
+ 
+ void
+ DELETE(h, keysv)
+     SV *        h
+     SV *        keysv
++    PREINIT:
++    SV *ret;
+     CODE:
+     /* only private_* keys can be deleted, for others DELETE acts like FETCH */
+     /* because the DBI internals rely on certain handle attributes existing  */
+     if (strnEQ(SvPV_nolen(keysv),"private_",8))
+-        ST(0) = hv_delete_ent((HV*)SvRV(h), keysv, 0, 0);
++        ret = hv_delete_ent((HV*)SvRV(h), keysv, 0, 0);
+     else
+-        ST(0) = dbih_get_attr_k(h, keysv, 0);
++        ret = dbih_get_attr_k(h, keysv, 0);
++    ST(0) = ret;
+     (void)cv;
+ 
+ 
+--- a/Driver.xst
++++ b/Driver.xst
+@@ -60,7 +60,7 @@
+ #ifdef dbd_discon_all
+ 
+ # disconnect_all renamed and ALIAS'd to avoid length clash on VMS :-(
+-void
++bool
+ discon_all_(drh)
+     SV *        drh
+     ALIAS:
+@@ -68,7 +68,9 @@
+     CODE:
+     D_imp_drh(drh);
+     PERL_UNUSED_VAR(ix);
+-    ST(0) = dbd_discon_all(drh, imp_drh) ? &PL_sv_yes : &PL_sv_no;
++    RETVAL = dbd_discon_all(drh, imp_drh);
++    OUTPUT:
++    RETVAL
+ 
+ #endif /* dbd_discon_all */
+ 
+@@ -102,7 +104,7 @@
+ MODULE = DBD::~DRIVER~    PACKAGE = DBD::~DRIVER~::db
+ 
+ 
+-void
++bool
+ _login(dbh, dbname, username, password, attribs=Nullsv)
+     SV *        dbh
+     SV *        dbname
+@@ -118,14 +120,16 @@
+     char *p = (SvOK(password)) ? SvPV(password,lna) : (char*)"";
+ #endif
+ #ifdef dbd_db_login6_sv
+-    ST(0) = dbd_db_login6_sv(dbh, imp_dbh, dbname, username, password, attribs) ? &PL_sv_yes : &PL_sv_no;
++    RETVAL = dbd_db_login6_sv(dbh, imp_dbh, dbname, username, password, attribs);
+ #elif defined(dbd_db_login6)
+-    ST(0) = dbd_db_login6(dbh, imp_dbh, SvPV_nolen(dbname), u, p, attribs) ? &PL_sv_yes : &PL_sv_no;
++    RETVAL = dbd_db_login6(dbh, imp_dbh, SvPV_nolen(dbname), u, p, attribs);
+ #else
+     PERL_UNUSED_ARG(attribs);
+-    ST(0) = dbd_db_login( dbh, imp_dbh, SvPV_nolen(dbname), u, p) ? &PL_sv_yes : &PL_sv_no;
++    RETVAL = dbd_db_login( dbh, imp_dbh, SvPV_nolen(dbname), u, p);
+ #endif
+     }
++    OUTPUT:
++    RETVAL
+ 
+ 
+ void
+@@ -296,33 +300,38 @@
+     CODE:
+     {
+     D_imp_dbh(dbh);
+-    ST(0) = dbd_db_last_insert_id(dbh, imp_dbh, catalog, schema, table, field, attr);
++    SV *ret = dbd_db_last_insert_id(dbh, imp_dbh, catalog, schema, table, field, attr);
++    ST(0) = ret;
+     }
+ 
+ #endif
+ 
+ 
+-void
++bool
+ commit(dbh)
+     SV *        dbh
+     CODE:
+     D_imp_dbh(dbh);
+     if (DBIc_has(imp_dbh,DBIcf_AutoCommit) && DBIc_WARN(imp_dbh))
+         warn("commit ineffective with AutoCommit enabled");
+-    ST(0) = dbd_db_commit(dbh, imp_dbh) ? &PL_sv_yes : &PL_sv_no;
++    RETVAL = dbd_db_commit(dbh, imp_dbh);
++    OUTPUT:
++    RETVAL
+ 
+ 
+-void
++bool
+ rollback(dbh)
+     SV *        dbh
+     CODE:
+     D_imp_dbh(dbh);
+     if (DBIc_has(imp_dbh,DBIcf_AutoCommit) && DBIc_WARN(imp_dbh))
+         warn("rollback ineffective with AutoCommit enabled");
+-    ST(0) = dbd_db_rollback(dbh, imp_dbh) ? &PL_sv_yes : &PL_sv_no;
++    RETVAL = dbd_db_rollback(dbh, imp_dbh);
++    OUTPUT:
++    RETVAL
+ 
+ 
+-void
++bool
+ disconnect(dbh)
+     SV *        dbh
+     CODE:
+@@ -339,8 +348,10 @@
+             SvPV(dbh,lna), (int)DBIc_ACTIVE_KIDS(imp_dbh), plural,
+             "(either destroy statement handles or call finish on them before disconnecting)");
+     }
+-    ST(0) = dbd_db_disconnect(dbh, imp_dbh) ? &PL_sv_yes : &PL_sv_no;
++    RETVAL = dbd_db_disconnect(dbh, imp_dbh);
+     DBIc_ACTIVE_off(imp_dbh);   /* ensure it's off, regardless */
++    OUTPUT:
++    RETVAL
+ 
+ 
+ void
+@@ -474,7 +485,7 @@
+ MODULE = DBD::~DRIVER~    PACKAGE = DBD::~DRIVER~::st
+ 
+ 
+-void
++bool
+ _prepare(sth, statement, attribs=Nullsv)
+     SV *        sth
+     SV *        statement
+@@ -484,11 +495,13 @@
+     D_imp_sth(sth);
+     DBD_ATTRIBS_CHECK("_prepare", sth, attribs);
+ #ifdef dbd_st_prepare_sv
+-    ST(0) = dbd_st_prepare_sv(sth, imp_sth, statement, attribs) ? &PL_sv_yes : &PL_sv_no;
++    RETVAL = dbd_st_prepare_sv(sth, imp_sth, statement, attribs);
+ #else
+-    ST(0) = dbd_st_prepare(sth, imp_sth, SvPV_nolen(statement), attribs) ? &PL_sv_yes : &PL_sv_no;
++    RETVAL = dbd_st_prepare(sth, imp_sth, SvPV_nolen(statement), attribs);
+ #endif
+     }
++    OUTPUT:
++    RETVAL
+ 
+ 
+ #ifdef dbd_st_rows
+@@ -505,7 +518,7 @@
+ 
+ #ifdef dbd_st_bind_col
+ 
+-void
++bool
+ bind_col(sth, col, ref, attribs=Nullsv)
+     SV *        sth
+     SV *        col
+@@ -530,20 +543,21 @@
+         }
+     }
+     switch(dbd_st_bind_col(sth, imp_sth, col, ref, sql_type, attribs)) {
+-    case 2:     ST(0) = &PL_sv_yes;        /* job done completely */
++    case 2:     RETVAL = TRUE;              /* job done completely */
+                 break;
+     case 1:     /* fallback to DBI default */
+-                ST(0) = (DBIc_DBISTATE(imp_sth)->bind_col(sth, col, ref, attribs))
+-                    ? &PL_sv_yes : &PL_sv_no;
++                RETVAL = DBIc_DBISTATE(imp_sth)->bind_col(sth, col, ref, attribs);
+                 break;
+-    default:    ST(0) = &PL_sv_no;         /* dbd_st_bind_col has called set_err */
++    default:    RETVAL = FALSE;             /* dbd_st_bind_col has called set_err */
+                 break;
+     }
+     }
++    OUTPUT:
++    RETVAL
+ 
+ #endif /* dbd_st_bind_col */
+ 
+-void
++bool
+ bind_param(sth, param, value, attribs=Nullsv)
+     SV *        sth
+     SV *        param
+@@ -567,12 +581,13 @@
+             DBD_ATTRIB_GET_IV(attribs, "TYPE",4, svp, sql_type);
+         }
+     }
+-    ST(0) = dbd_bind_ph(sth, imp_sth, param, value, sql_type, attribs, FALSE, 0)
+-                ? &PL_sv_yes : &PL_sv_no;
++    RETVAL = dbd_bind_ph(sth, imp_sth, param, value, sql_type, attribs, FALSE, 0);
+     }
++    OUTPUT:
++    RETVAL
+ 
+ 
+-void
++bool
+ bind_param_inout(sth, param, value_ref, maxlen, attribs=Nullsv)
+     SV *        sth
+     SV *        param
+@@ -602,9 +617,10 @@
+             DBD_ATTRIB_GET_IV(attribs, "TYPE",4, svp, sql_type);
+         }
+     }
+-    ST(0) = dbd_bind_ph(sth, imp_sth, param, value, sql_type, attribs, TRUE, maxlen)
+-                ? &PL_sv_yes : &PL_sv_no;
++    RETVAL = dbd_bind_ph(sth, imp_sth, param, value, sql_type, attribs, TRUE, maxlen);
+     }
++    OUTPUT:
++    RETVAL
+ 
+ 
+ void
+@@ -640,7 +656,8 @@
+     CODE:
+     {
+     D_imp_sth(sth);
+-    ST(0) = dbd_st_execute_for_fetch(sth, imp_sth, fetch_tuple_sub, tuple_status);
++    SV *ret = dbd_st_execute_for_fetch(sth, imp_sth, fetch_tuple_sub, tuple_status);
++    ST(0) = ret;
+     }
+ 
+ #endif
+@@ -659,7 +676,8 @@
+     CODE:
+     {
+     D_imp_sth(sth);
+-    ST(0) = dbd_st_last_insert_id(sth, imp_sth, catalog, schema, table, field, attr);
++    SV *ret = dbd_st_last_insert_id(sth, imp_sth, catalog, schema, table, field, attr);
++    ST(0) = ret;
+     }
+ 
+ #endif
+@@ -716,7 +734,7 @@
+     }
+ 
+ 
+-void
++bool
+ finish(sth)
+     SV *        sth
+     CODE:
+@@ -733,10 +751,12 @@
+         XSRETURN_YES;
+     }
+ #ifdef dbd_st_finish3
+-    ST(0) = dbd_st_finish3(sth, imp_sth, 0) ? &PL_sv_yes : &PL_sv_no;
++    RETVAL = dbd_st_finish3(sth, imp_sth, 0);
+ #else
+-    ST(0) = dbd_st_finish(sth, imp_sth) ? &PL_sv_yes : &PL_sv_no;
++    RETVAL = dbd_st_finish(sth, imp_sth);
+ #endif
++    OUTPUT:
++    RETVAL
+ 
+ 
+ void
diff --git a/debian/patches/series b/debian/patches/series
index 3a41634..969068f 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -2,3 +2,4 @@ t__06attrs.t__localefix.patch
 t__40profile.t__NTP.patch
 t__80proxy.t___syslogd.patch
 spelling.patch
+CVE-2020-14392.patch
diff --git a/debian/patches/spelling.patch b/debian/patches/spelling.patch
index 2ffb778..8874ab9 100644
--- a/debian/patches/spelling.patch
+++ b/debian/patches/spelling.patch
@@ -7,7 +7,7 @@ Bug: https://rt.cpan.org/Ticket/Display.html?id=114066
 
 --- a/DBI.pm
 +++ b/DBI.pm
-@@ -7884,7 +7884,7 @@
+@@ -7905,7 +7905,7 @@
          $self->{_buf} .= shift;
      #
      # DBI feeds us pieces at a time, so accumulate a complete line

Reply to: