Bug #28934 server crash when receiving malformed com_execute packets
Submitted: 6 Jun 2007 20:38 Modified: 18 Jun 2007 15:35
Reporter: Shane Bester (Platinum Quality Contributor) Email Updates:
Status: Closed Impact on me:
None 
Category:MySQL Server: Prepared statements Severity:S1 (Critical)
Version:5.0 OS:Any
Assigned to: Georgi Kodinov CPU Architecture:Any
Tags: crash, DoS, prepared statements

[6 Jun 2007 20:38] Shane Bester
Description:
If a program that binds X parameters to a prepared statement handle somehow changes stmt->param_count to be some different to X, then mysql_stmt_execute can crash the client or server.  

Mostly, a C/C++ client would crash, but not always.   Server crash is easy to get when a client doesn't crash, or is JDBC or not C api based for example.

In a case where the server crashed, I enabled the general query log to examine the query and it's parameters:

2 Connect     root@ as anonymous on test
2 Query       drop table if exists t1
2 Query       create table t1(id int)
2 Query       insert into t1 values (1),(2),(3),(4),(5)
2 Prepare     [1] select * from t1 where id in(?,?,?,?, ?)
2 Execute     [1] select * from t1 where id in(,,,0, 0)
2 Quit       

Notice the Execute has not correctly been run.
I'll get a stack trace from a server later and upload it. 

How to repeat:
I'll upload a complete testcase later, but for now see the below code snippet which shows us the concept:

#define SELECT1 "select * from t1 where id in(?,?,?,?,?)"
MYSQL_BIND bind[5];
stmt= mysql_stmt_init(conn);
res= mysql_stmt_prepare(stmt, SELECT1, (unsigned long)strlen(SELECT1));
memset(&bind, 0, sizeof(bind));
for(cnt=0;cnt<5;cnt++)
{	
  bind[cnt].buffer_type=MYSQL_TYPE_LONG;
  bind[cnt].buffer=(char*)&cnt;
  bind[cnt].buffer_length=0;
}

mysql_stmt_bind_param(stmt, bind);

//now change the number of bound parameters the server thinks it needs!!
stmt->param_count=2;

//this can crash client or server!
mysql_stmt_execute(stmt);

Suggested fix:
fix the protocol?
[6 Jun 2007 20:38] Shane Bester
since you cannot disable prepared statements on the server, this bug can be exploited fairly easily.
[6 Jun 2007 21:10] Shane Bester
on 5.0.42 and 5.0.38-debug on windows, the server asserted with this stack trace:

mysqld-debug.exe!_NMSG_WRITE(int rterrnum=10)
mysqld-debug.exe!abort
mysqld-debug.exe!_assert
mysqld-debug.exe!Item_param::query_val_str
mysqld-debug.exe!insert_params_withlog
mysqld-debug.exe!mysql_stmt_execute
mysqld-debug.exe!dispatch_command
mysqld-debug.exe!do_command
mysqld-debug.exe!handle_one_connection
mysqld-debug.exe!pthread_start
mysqld-debug.exe!_threadstart
kernel32.dll!BaseThreadInitThunk

Version: '5.0.38-enterprise-gpl-debug-log'  socket: ''  port: 3306  MySQL Enterprise Server - Debug (GPL)
Assertion failed: 0, file .\item.cpp, line 2823
[6 Jun 2007 21:20] Shane Bester
The above crash happens when the general/binary/slow logs are enabled.  I doubt the problem is limited to only that scope though.
[8 Jun 2007 14:22] Shane Bester
new testcase simply specifies random types for parameters. Look at this code:
#ifdef MANGLE_TYPES
ptr+=int_to_buff(ptr,2,rand()%254); //param is any type!

Causes crashes/out of memory for server and errors like this:

Version: '5.0.42-enterprise-gpl-debug-log'  socket: ''  port: 3306  MySQL Enterprise Server - Debug (GPL)
070608 16:15:49 [ERROR] mysqld-debug: Out of memory at line 51, '.\sql_string.cc'
070608 16:15:49 [ERROR] mysqld-debug: needed -654311344 byte (3555329k), memory in use: 8635822 bytes (8434k)
Assertion failed: 0, file .\item.cc, line 2826
[11 Jun 2007 19:53] Bugs System
A patch for this bug has been committed. After review, it may
be pushed to the relevant source trees for release in the next
version. You can access the patch from:

  http://lists.mysql.com/commits/28522

ChangeSet@1.2529, 2007-06-11 22:53:06+03:00, gkodinov@magare.gmz +2 -0
  Bug #28934: server crash when receiving malformed com_execute packets
   Sometimes a parameter slot may not get a value because of the protocol
   data being plain wrong.
   Such cases should be detected and handled by returning an error.
   Fixed by checking data stream constraints where possible (like maximum
   length) and reacting to the case where a value cannot be constructed.
[12 Jun 2007 8:02] Bugs System
A patch for this bug has been committed. After review, it may
be pushed to the relevant source trees for release in the next
version. You can access the patch from:

  http://lists.mysql.com/commits/28561

ChangeSet@1.2529, 2007-06-12 11:02:34+03:00, gkodinov@magare.gmz +2 -0
  Bug #28934: server crash when receiving malformed com_execute packets
   Sometimes a parameter slot may not get a value because of the protocol
   data being plain wrong.
   Such cases should be detected and handled by returning an error.
   Fixed by checking data stream constraints where possible (like maximum
   length) and reacting to the case where a value cannot be constructed.
[14 Jun 2007 19:00] Bugs System
Pushed into 5.1.20-beta
[14 Jun 2007 19:00] Bugs System
Pushed into 5.0.44
[18 Jun 2007 15:35] Paul Dubois
Noted in 5.0.44, 5.1.20 changelogs.