Description:
Overview
--------
The code in the strmake() method in ./strings/strmake.c has a logic error. This code is guarded by the EXTRA_DEBUG flag. When compiled using this flag, the code writes past the end of the character array clobbering the memory following it. The next memory location after this array is the m_sql_errno in sql_class.h. See the Diagnostics_area class definition below.
Observations/Example Failure
----------------------------
The overrun causes the client to retrieve an incorrect error number for the latest error. This comes from m_sql_errno. Tests that use "--error ER_XYZ" fail with "wrong error" messages. The test suite reports errors like the following.
main.alias [ fail ]
mysqltest: At line 107: query 'select t1.* as 'with_alias' from t1' failed with
wrong errno 1114: 'You have an error in your SQL syntax; check the manual that c
orresponds to your MySQL server version for the right syntax to use near 'as 'wi
th_alias' from t1' at line 1', instead of 1064...
The result from queries just before the failure was:
< snip >
AUFNR varchar(12) NOT NULL default '',
PLNFL varchar(6) NOT NULL default '',
VORNR varchar(4) NOT NULL default '',
xstatus_vor smallint(5) unsigned NOT NULL default '0'
);
INSERT INTO t1 VALUES ('40004712','000001','0010',9);
INSERT INTO t1 VALUES ('40004712','000001','0020',0);
UPDATE t1 SET t1.xstatus_vor = Greatest(t1.xstatus_vor,1) WHERE t1.aufnr =
"40004712" AND t1.plnfl = "000001" AND t1.vornr > "0010" ORDER BY t1.vornr
ASC LIMIT 1;
drop table t1;
drop table if exists t1,t2,t3;
create table t1 (a int, b int, c int);
create table t2 (d int);
create table t3 (a1 int, b1 int, c1 int);
insert into t1 values(1,2,3);
insert into t1 values(11,22,33);
insert into t2 values(99);
select t1.* as 'with_alias' from t1;
ERROR HY000: You have an error in your SQL syntax; check the manual that corresp
onds to your MySQL server version for the right syntax to use near 'as 'with_ali
as' from t1' at line 1
More results from queries before failure can be found in d:\source\c++\mysql-6.0
-test\mysql-test\var\log\alias.log
Aborting: main.alias failed in default mode.
To continue, re-run with '--force'.
Stopping All Servers
Problem/Analysis
----------------
Here is the problem (see ./strings/strmake.c):
0044 uint n= strlen(src) + 1;
0045 if (n <= length)
0046 memset(dst + n, (int) 'Z', length - n + 1);
Analysis:
Given: src = 'test'
length = 10
dst is some valid memory location
after 0044, n = 5
when 0046 is executed, memset will copy (10 - 5 + 1 = 6) Z's starting at position 5
dst[0] = ?? (used later)
dst[1] = ?? (used later)
dst[2] = ?? (used later)
dst[3] = ?? (used later)
dst[4] = ?? (used later)
dst[5] = Z that's 1...
dst[6] = Z that's 2...
dst[7] = Z that's 3...
dst[8] = Z that's 4...
dst[9] = Z that's 5...
dst[10] = Z oh, my! <-- writes a 'Z' in part of the m_sql_errno memory!
class Diagnostics_area
{
[...]
private:
/** Message buffer. Can be used by OK or ERROR status. */
char m_message[MYSQL_ERRMSG_SIZE];
/**
SQL error number. One of ER_ codes from share/errmsg.txt.
Set by set_error_status.
*/
uint m_sql_errno;
[...]
Notes:
* The EXTRA_DEBUG flag is used in the online backup code.
* See mysql-6.0-backup/win for modifications to enable this flag on Windows.
(can also be enabled manually in Visual Studio).
* This bug does not appear on Linux despite compiling with EXTRA_DEBUG. It
is on the Windows platform (have tested XP and Vista) that the problem
appears.
* This code is in the mysql-6.0 tree.
How to repeat:
clone mysql-6.0
build on Windows using EXTRA_DEBUG
attempt to run any test that uses "--error ER_XXX" e.g. alias:
./mysql-test-run.pl alias
Witness the mayhem!
Suggested fix:
A patch has been proposed to correct the buffer overrun: