[MDEV-4664] mysql_upgrade crashes if root's password contains an apostrophe/single quotation mark Created: 2013-06-15  Updated: 2016-02-06  Resolved: 2016-02-06

Status: Closed
Project: MariaDB Server
Component/s: Scripts & Clients
Affects Version/s: 10.0.3, 5.5.31, 5.1.67, 5.2.14, 5.3.12
Fix Version/s: 5.5.48, 10.0.24, 10.1.12

Type: Bug Priority: Minor
Reporter: Joe MacMahon Assignee: Sergei Golubchik
Resolution: Fixed Votes: 2
Labels: mysql_upgrade, upstream
Environment:

Using Arch Linux x86_64


Issue Links:
Relates
relates to MDEV-7414 Debian package installation of MariaD... Confirmed

 Description   

Expected behaviour: mysql_upgrade completes successfully when using a password containing a single quotation mark (').

Actual behaviour mysql_upgrade crashes with the following:

root:~ # mysql_upgrade -p
Enter password: 
sh: -c: line 0: unexpected EOF while looking for matching `''
sh: -c: line 1: syntax error: unexpected end of file
Phase 1/3: Fixing table and database names
sh: -c: line 0: unexpected EOF while looking for matching `''
sh: -c: line 1: syntax error: unexpected end of file
FATAL ERROR: Upgrade failed



 Comments   
Comment by Elena Stepanova [ 2013-06-15 ]

Also reproducible on all of MySQL 5.1-5.7

Comment by Jean Weisbuch [ 2015-01-06 ]

Here is a patch for this bug :

--- ./mysys/string.c	2014-09-25 00:29:46.000000000 +0200
+++ ./mysys/string.c	2015-01-06 19:21:29.677750456 +0100
@@ -145,13 +145,13 @@
   const char *quote_str= "\"";
   const uint  quote_len= 1;
 #else
-  const char *quote_str= "\'";
-  const uint  quote_len= 1;
+  const char *quote_str= "\'\"\'\"\'";
+  const uint  quote_len= 5;
 #endif /* __WIN__ */
   my_bool ret= TRUE;
   va_list dirty_text;
 
-  ret&= dynstr_append_mem(str, quote_str, quote_len); /* Leading quote */
+  ret&= dynstr_append_mem(str, quote_str, 1); /* Leading quote */
   va_start(dirty_text, append);
   while (append != NullS)
   {
@@ -162,7 +162,9 @@
     while(*(next_pos= strcend(cur_pos, quote_str[0])) != '\0')
     {
       ret&= dynstr_append_mem(str, cur_pos, (uint) (next_pos - cur_pos));
-      ret&= dynstr_append_mem(str ,"\\", 1);
+      #ifdef __WIN__
+        ret&= dynstr_append_mem(str ,"\\", 1);
+      #endif
       ret&= dynstr_append_mem(str, quote_str, quote_len);
       cur_pos= next_pos + 1;
     }
@@ -170,7 +172,7 @@
     append= va_arg(dirty_text, char *);
   }
   va_end(dirty_text);
-  ret&= dynstr_append_mem(str, quote_str, quote_len); /* Trailing quote */
+  ret&= dynstr_append_mem(str, quote_str, 1); /* Trailing quote */
 
   return ret;
 }

Before patching, if the provided password has a quote (maria'db on the example), the command executed using popen() on mysql_upgrade.c on the function run_command() looks like this :

'./mysql' '--no-defaults' '--port=3306' '--socket=/var/run/mysqld/mysqld.sock' '--user=*user defined in ~/.my.cnf*' '--password=*password defined in ~/.my.cnf*' '--socket=/var/run/mysqld/mysqld.sock' '--password=maria\'db' '--user=*user defined in ~/.my.cnf*'  '--database=mysql' '--batch' '--skip-force' '--silent' < /tmp/sqls8IHkR 2>&1

The issue is that on a POSIX shell, you cannot escape anything on simple quoted string not even a simple quote, to do so you must close the simple quote, open a double quotes, put your simple quote on it then close the double quotes, for example :

$ echo 'simple quotes: '"'"'here'"'"''
simple quotes: 'here'

After applying the patch, the resulting executed command looks like :

'./mysql' '--no-defaults' '--port=3306' '--socket=/var/run/mysqld/mysqld.sock' '--user=*user defined in ~/.my.cnf*' '--password=*password defined in ~/.my.cnf*' '--socket=/var/run/mysqld/mysqld.sock' '--password=maria'"'"'db' '--user=*user defined in ~/.my.cnf*'  '--database=mysql' '--batch' '--skip-force' '--silent' < /tmp/sqlG8Ftqz 2>&1

I only tested the patch on Linux but to mimic the Windows behavior i inverted the quote_str and quote_len values from the Windows and Linux values and it worked fine too with double quotes instead of simple ones but i wasnt on a Windows OS so i am not 100% sure it wouldnt require a real test on it.
The function seems to be also used on ./client/mysqltest.cc and ./libmysql/libmysql_exports_file.cc.

ps: another small "bug" is that even if i didnt specify the user on the command line, it is passed twice on the mysql client.

Generated at Thu Feb 08 06:58:11 UTC 2024 using Jira 8.20.16#820016-sha1:9d11dbea5f4be3d4cc21f03a88dd11d8c8687422.