From fc5de4653d65c7cd4b894809c1a0156db6a2a42a Mon Sep 17 00:00:00 2001
From: unknown <knielsen@knielsen-hq.org>
Date: Thu, 29 Apr 2010 09:57:25 +0200
Subject: [PATCH] Fix buffer overflow in COM_FIELD_LIST. Fix missing bounds
 check in string conversion. Bump version number for security fix release.

---
 configure.in         |  2 +-
 sql/sql_base.cc      |  8 ++++++--
 sql/sql_parse.cc     | 30 ++++++++++++++++++++----------
 strings/ctype-utf8.c |  4 ++++
 4 files changed, 31 insertions(+), 13 deletions(-)

diff --git a/configure.in b/configure.in
index 47682c34fea..45952dbeceb 100644
--- a/configure.in
+++ b/configure.in
@@ -7,7 +7,7 @@ AC_PREREQ(2.59)
 # Remember to also update version.c in ndb.
 # When changing major version number please also check switch statement
 # in mysqlbinlog::check_master_version().
-AC_INIT([MariaDB Server], [5.1.44-MariaDB], [], [mysql])
+AC_INIT([MariaDB Server], [5.1.44a-MariaDB], [], [mysql])
 AC_CONFIG_SRCDIR([sql/mysqld.cc])
 AC_CANONICAL_SYSTEM
 # USTAR format gives us the possibility to store longer path names in
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 1da17c216f2..4416ebbc45c 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -233,8 +233,12 @@ static void check_unused(void)
 uint create_table_def_key(THD *thd, char *key, TABLE_LIST *table_list,
                           bool tmp_table)
 {
-  uint key_length= (uint) (strmov(strmov(key, table_list->db)+1,
-                                  table_list->table_name)-key)+1;
+  char *db_end= strnmov(key, table_list->db, MAX_DBKEY_LENGTH - 2);
+  *db_end++= '\0';
+  char *table_end= strnmov(db_end, table_list->table_name,
+                           key + MAX_DBKEY_LENGTH - 1 - db_end);
+  *table_end++= '\0';
+  uint key_length= (uint) (table_end-key);
   if (tmp_table)
   {
     int4store(key + key_length, thd->server_id);
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 9503e8a5d81..2eb6a190e63 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -1304,10 +1304,12 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
     break;
 #else
   {
-    char *fields, *packet_end= packet + packet_length, *arg_end;
+    char *fields, *packet_end= packet + packet_length, *wildcard;
     /* Locked closure of all tables */
     TABLE_LIST table_list;
-    LEX_STRING conv_name;
+    char db_buff[NAME_LEN+1];
+    uint32 db_length;
+    uint dummy_errors;
 
     /* used as fields initializator */
     lex_start(thd);
@@ -1319,11 +1321,22 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
     /*
       We have name + wildcard in packet, separated by endzero
     */
-    arg_end= strend(packet);
-    thd->convert_string(&conv_name, system_charset_info,
-			packet, (uint) (arg_end - packet), thd->charset());
-    table_list.alias= table_list.table_name= conv_name.str;
-    packet= arg_end + 1;
+    wildcard= strend(packet);
+    db_length= wildcard - packet;
+    wildcard++;
+    uint query_length= (uint) (packet_end - wildcard); // Don't count end \0
+    if (db_length > NAME_LEN || query_length > NAME_LEN)
+    {
+      my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
+      break;
+    }
+    db_length= copy_and_convert(db_buff, sizeof(db_buff)-1,
+                                system_charset_info, packet, db_length,
+                                thd->charset(), &dummy_errors);
+    db_buff[db_length]= '\0';
+    table_list.alias= table_list.table_name= db_buff;
+    if (!(fields= (char *) thd->memdup(wildcard, query_length + 1)))
+      break;
 
     if (is_schema_db(table_list.db, table_list.db_length))
     {
@@ -1332,9 +1345,6 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
         table_list.schema_table= schema_table;
     }
 
-    uint query_length= (uint) (packet_end - packet); // Don't count end \0
-    if (!(fields= (char *) thd->memdup(packet, query_length + 1)))
-      break;
     thd->set_query(fields, query_length);
     general_log_print(thd, command, "%s %s", table_list.table_name, fields);
     if (lower_case_table_names)
diff --git a/strings/ctype-utf8.c b/strings/ctype-utf8.c
index 91f633e45ce..a894afd71a9 100644
--- a/strings/ctype-utf8.c
+++ b/strings/ctype-utf8.c
@@ -4116,6 +4116,10 @@ my_wc_mb_filename(CHARSET_INFO *cs __attribute__((unused)),
 {
   int code;
   char hex[]= "0123456789abcdef";
+
+  if (s >= e)
+    return MY_CS_TOOSMALL;
+
   if (wc < 128 && filename_safe_char[wc])
   {
     *s= (uchar) wc;
-- 
2.30.9