Commit a8b97e47 authored by Salvatore Bonaccorso's avatar Salvatore Bonaccorso

New upstream version 4.041

parent 9ac378bd
2016-11-28 Patrick Galbraith, Michiel Beijen, DBI/DBD community (4.041)
* Fix use-after-free for repeated fetchrow_arrayref calls when
mysql_server_prepare=1
Function dbd_st_fetch() via Renew() can reallocate output buffer for
mysql_stmt_fetch() call. But it does not update pointer to that buffer in
imp_sth->stmt structure initialized by mysql_stmt_bind_result() function.
That leads to use-after-free in any mysql function which access
imp_sth->stmt structure (e.g. mysql_stmt_fetch()).
This patch fix this problem and properly updates pointer in imp_sth->stmt
structure after Renew() call.
This is a medium level security issue to which the Debian security team
assigned identifier CVE-2016-1251. Discovered and fixed by Pali Rohár.
* auto_reconnect now also matches CR_SERVER_LOST, previously this only
matched CR_SERVER_GONE.
Fixes http://bugs.mysql.com/bug.php?id=27613
Fix suggested by Wouter de Jong.
* Fix compilation fixes (Pali Rohár).
2016-11-19 Patrick Galbraith, Michiel Beijen, DBI/DBD community (4.040)
* Since 4.038 we had problems compiling on big-endian architectures, such
as MIPS, s390 and Sparc. Thanks to Salvatore Bonaccorso @ Debian project
......
......@@ -57,7 +57,7 @@
"x_IRC" : "irc://irc.perl.org/#dbi",
"x_MailingList" : "mailto:dbi-dev@perl.org"
},
"version" : "4.040",
"version" : "4.041",
"x_contributors" : [
"Alexandr Ciornii <alexchorny@gmail.com>",
"Alexey Molchanov <alexey.molchanov@portaone.com>",
......
......@@ -30,7 +30,7 @@ resources:
homepage: http://dbi.perl.org/
license: http://dev.perl.org/licenses/
repository: https://github.com/perl5-dbi/DBD-mysql
version: '4.040'
version: '4.041'
x_contributors:
- 'Alexandr Ciornii <alexchorny@gmail.com>'
- 'Alexey Molchanov <alexey.molchanov@portaone.com>'
......
......@@ -1426,6 +1426,7 @@ void dbd_init(dbistate_t* dbistate)
{
dTHX;
DBISTATE_INIT;
PERL_UNUSED_ARG(dbistate);
}
......@@ -1448,7 +1449,6 @@ void do_error(SV* h, int rc, const char* what, const char* sqlstate)
{
dTHX;
D_imp_xxh(h);
STRLEN lna;
SV *errstr;
SV *errstate;
......@@ -1469,7 +1469,7 @@ void do_error(SV* h, int rc, const char* what, const char* sqlstate)
/* NO EFFECT DBIh_EVENT2(h, ERROR_event, DBIc_ERR(imp_xxh), errstr); */
if (DBIc_TRACE_LEVEL(imp_xxh) >= 2)
PerlIO_printf(DBIc_LOGPIO(imp_xxh), "%s error %d recorded: %s\n",
what, rc, SvPV(errstr,lna));
what, rc, SvPV_nolen(errstr));
if (DBIc_TRACE_LEVEL(imp_xxh) >= 2)
PerlIO_printf(DBIc_LOGPIO(imp_xxh), "\t\t<-- do_error\n");
}
......@@ -1481,7 +1481,6 @@ void do_warn(SV* h, int rc, char* what)
{
dTHX;
D_imp_xxh(h);
STRLEN lna;
SV *errstr = DBIc_ERRSTR(imp_xxh);
sv_setiv(DBIc_ERR(imp_xxh), (IV)rc); /* set err early */
......@@ -1489,7 +1488,7 @@ void do_warn(SV* h, int rc, char* what)
/* NO EFFECT DBIh_EVENT2(h, WARN_event, DBIc_ERR(imp_xxh), errstr);*/
if (DBIc_TRACE_LEVEL(imp_xxh) >= 2)
PerlIO_printf(DBIc_LOGPIO(imp_xxh), "%s warning %d recorded: %s\n",
what, rc, SvPV(errstr,lna));
what, rc, SvPV_nolen(errstr));
warn("%s", what);
}
......@@ -2302,7 +2301,11 @@ int dbd_discon_all (SV *drh, imp_drh_t *imp_drh) {
dTHR;
#endif
dTHX;
#if defined(DBD_MYSQL_EMBEDDED)
D_imp_xxh(drh);
#else
PERL_UNUSED_ARG(drh);
#endif
#if defined(DBD_MYSQL_EMBEDDED)
if (imp_drh->embedded.state)
......@@ -4047,6 +4050,8 @@ process:
Renew(fbh->data, fbh->length, char);
buffer->buffer_length= fbh->length;
buffer->buffer= (char *) fbh->data;
imp_sth->stmt->bind[i].buffer_length = fbh->length;
imp_sth->stmt->bind[i].buffer = (char *)fbh->data;
if (DBIc_TRACE_LEVEL(imp_xxh) >= 2) {
int j;
......@@ -4907,7 +4912,7 @@ int dbd_bind_ph(SV *sth, imp_sth_t *imp_sth, SV *param, SV *value,
char *buffer= NULL;
int buffer_is_null= 0;
int buffer_is_unsigned= 0;
int buffer_length= slen;
int buffer_length= 0;
unsigned int buffer_type= 0;
#endif
......@@ -5123,7 +5128,8 @@ int mysql_db_reconnect(SV* h)
else
imp_dbh= (imp_dbh_t*) imp_xxh;
if (mysql_errno(imp_dbh->pmysql) != CR_SERVER_GONE_ERROR)
if (mysql_errno(imp_dbh->pmysql) != CR_SERVER_GONE_ERROR &&
mysql_errno(imp_dbh->pmysql) != CR_SERVER_LOST)
/* Other error */
return FALSE;
......
......@@ -3,7 +3,7 @@ package Bundle::DBD::mysql;
use strict;
use warnings;
our $VERSION = '4.040';
our $VERSION = '4.041';
1;
......
......@@ -15,7 +15,7 @@ our @ISA = qw(DynaLoader);
# SQL_DRIVER_VER is formatted as dd.dd.dddd
# for version 5.x please switch to 5.00(_00) version numbering
# keep $VERSION in Bundle/DBD/mysql.pm in sync
our $VERSION = '4.040';
our $VERSION = '4.041';
bootstrap DBD::mysql $VERSION;
......
......@@ -10,11 +10,22 @@ require "t/lib.pl";
my $dbh = eval { DBI->connect($test_dsn, $test_user, $test_password, { PrintError => 1, RaiseError => 1, AutoCommit => 0, mysql_server_prepare => 1, mysql_server_prepare_disable_fallback => 1 }) };
plan skip_all => "no database connection" if $@ or not $dbh;
plan tests => 17;
plan tests => 39;
ok $dbh->do("CREATE TEMPORARY TABLE t (i INTEGER NOT NULL, n TEXT)");
my $sth;
ok my $sth = $dbh->prepare("SELECT * FROM t WHERE i=? AND n=?");
ok $dbh->do("CREATE TEMPORARY TABLE t (i INTEGER NOT NULL, n LONGBLOB)");
ok $sth = $dbh->prepare("INSERT INTO t(i, n) VALUES(?, ?)");
ok $sth->execute(1, "x" x 10);
ok $sth->execute(2, "x" x 100);
ok $sth->execute(3, "x" x 1000);
ok $sth->execute(4, "x" x 10000);
ok $sth->execute(5, "x" x 100000);
ok $sth->execute(6, "x" x 1000000);
ok $sth->finish();
ok $sth = $dbh->prepare("SELECT * FROM t WHERE i=? AND n=?");
ok $sth->bind_param(2, "x" x 1000000);
ok $sth->bind_param(1, "abcx", 12);
......@@ -34,6 +45,34 @@ ok $sth = $dbh->prepare("SELECT 1 FROM t WHERE i = ?" . (" OR i = ?" x 10000));
ok $sth->execute((1) x (10001));
ok $sth->finish();
my $test;
ok $sth = $dbh->prepare("SELECT i,n FROM t WHERE i = ?");
ok $sth->execute(1);
ok $sth->fetchrow_arrayref();
ok $sth->execute(2);
$test = map { $_ } 'a';
ok $sth->fetchrow_arrayref();
ok $sth->execute(3);
$test = map { $_ } 'b' x 10000000; # try to reuse released memory
ok $sth->fetchrow_arrayref();
ok $sth->execute(4);
$test = map { $_ } 'cd' x 10000000; # try to reuse of released memory
ok $sth->fetchrow_arrayref();
ok $sth->execute(5);
$test = map { $_ } 'efg' x 10000000; # try to reuse of released memory
ok $sth->fetchrow_arrayref();
ok $sth->execute(6);
$test = map { $_ } 'hijk' x 10000000; # try to reuse of released memory
ok $sth->fetchrow_arrayref();
ok $sth->finish();
ok $dbh->do("SELECT 1 FROM t WHERE i = ?" . (" OR i = ?" x 10000), {}, (1) x (10001));
ok $dbh->disconnect();
......@@ -36,8 +36,16 @@ my $ok = eval {
1;
};
if (not $ok) {
is ( $DBI::err, 2006, 'Received error 2006' );
is ( $DBI::errstr, 'MySQL server has gone away', 'Received MySQL server has gone away');
# if we're connected via a local socket we receive error 2006
# (CR_SERVER_GONE_ERROR) but if we're connected using TCP/IP we get
# 2013 (CR_SERVER_LOST)
if ($DBI::err == 2006) {
pass("received error 2006 (CR_SERVER_GONE_ERROR)");
} elsif ($DBI::err == 2013) {
pass("received error 2013 (CR_SERVER_LOST)");
} else {
fail('Should return error 2006 or 2013');
}
eval { $sth->finish(); } if defined $sth;
eval { $dbh->disconnect(); } if defined $dbh;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment