Skip to content

Commit e50602b

Browse files
committed
WL#8077 Extend mysql_real_escape() to be aware of the string type it's escaping for.
mysql_real_escape_string() function was found insecure when sql_mode was set to NO_BACKSLASH_ESCAPES. mysql_real_escape_string() function reports error when sql_mode is set to NO_BACKSLASH_ESCAPES. Newly introduced API function mysql_real_escape_string_quote() should be used instead. Additional char type parameter allows to specify, which character should be doubled. Doubled character is a quote character of the identifier or a string within a SQL query. client/mysql_secure_installation.cc client/mysqldump.c client/mysqlimport.c client/mysqlshow.c Every occurrence of mysql_real_escape_string() replaced with mysql_real_escape_string_quote(). include/errmsg.h Insecure API error message code added (CR_INSECURE_API_ERR / 2062). libmysql/errmsg.cc Insecure API error message text added. include/my_sys.h mysys/charset.c escape_quotes_for_mysql() extended to support additional parameter (char quote). include/mysql.h include/mysql.h.pp mysql_real_escape_string_quote() function declaration added. libmysql/CMakeLists.txt mysql_real_escape_string_quote() function added to the client API set. libmysql/libmysql.cc mysql_real_escape_string_quote() function definition added. libmysql/libmysql.def libmysqld/libmysqld.def mysql_real_escape_string_quote() function added to the lib exports. mysql-test/r/mysqlshow.result mysql-test/t/mysqlshow.test MTR test extended to support grave accent (`) table name tests. sql/sql_initialize.cc escape_quotes_for_mysql() call replaced with escape_string_for_mysql(). tests/mysql_client_test.c Tests of the mysql_real_escape_string_quote() function added.
1 parent 047f457 commit e50602b

File tree

18 files changed

+342
-54
lines changed

18 files changed

+342
-54
lines changed

client/mysql_secure_installation.cc

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -373,7 +373,7 @@ int install_password_validation_plugin()
373373
MYF(MY_WME));
374374
end= my_stpcpy(query, "SET GLOBAL validate_password_policy = ");
375375
*end++ = '\'';
376-
end+= mysql_real_escape_string(&mysql, end, strength, strength_length);
376+
end+= mysql_real_escape_string_quote(&mysql, end, strength, strength_length, '\'');
377377
*end++ = '\'';
378378
if (!execute_query((const char **) &query,(unsigned int) (end-query)))
379379
DBUG_PRINT("info", ("query success!"));
@@ -406,7 +406,7 @@ void estimate_password_strength(char *password_string)
406406
MYF(MY_WME));
407407
end= my_stpcpy(query, "SELECT validate_password_strength(");
408408
*end++ = '\'';
409-
end+= mysql_real_escape_string(&mysql, end, password_string, password_length);
409+
end+= mysql_real_escape_string_quote(&mysql, end, password_string, password_length, '\'');
410410
*end++ = '\'';
411411
*end++ = ')';
412412
if (!execute_query((const char **) &query,(unsigned int) (end-query)))
@@ -442,7 +442,7 @@ my_bool mysql_set_password(MYSQL *mysql, char *password)
442442
char *query, *end;
443443
query= (char *)my_malloc(PSI_NOT_INSTRUMENTED, password_len+50, MYF(MY_WME));
444444
end= my_stpmov(query, "SET PASSWORD= PASSWORD('");
445-
end += mysql_real_escape_string(mysql, end, password, password_len);
445+
end+= mysql_real_escape_string_quote(mysql, end, password, password_len, '\'');
446446
*end++ = '\'';
447447
*end++ = ')';
448448
if (mysql_real_query(mysql, query, (unsigned int) (end - query)))
@@ -551,7 +551,7 @@ static void set_root_password(int plugin_set)
551551
(pass_length*2 + tmp)*sizeof(char), MYF(MY_WME));
552552
end= my_stpcpy(query, "SET PASSWORD=PASSWORD(");
553553
*end++ = '\'';
554-
end+= mysql_real_escape_string(&mysql, end, password1, pass_length);
554+
end+= mysql_real_escape_string_quote(&mysql, end, password1, pass_length, '\'');
555555
*end++ = '\'';
556556
*end++ = ')';
557557
my_free(password1);
@@ -705,11 +705,11 @@ void drop_users(MYSQL_RES *result)
705705
sizeof(char), MYF(MY_WME));
706706
end= my_stpcpy(query, "DROP USER ");
707707
*end++ = '\'';
708-
end+= mysql_real_escape_string(&mysql, end, user_tmp, user_length);
708+
end+= mysql_real_escape_string_quote(&mysql, end, user_tmp, user_length, '\'');
709709
*end++ = '\'';
710710
*end++ = '@';
711711
*end++ = '\'';
712-
end+= mysql_real_escape_string(&mysql, end, host_tmp, host_length);
712+
end+= mysql_real_escape_string_quote(&mysql, end, host_tmp, host_length, '\'');
713713
*end++ = '\'';
714714
if (!execute_query((const char **) &query, (unsigned int) (end-query)))
715715
DBUG_PRINT("info", ("query success!"));

client/mysqldump.c

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
2+
Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
33
44
This program is free software; you can redistribute it and/or modify
55
it under the terms of the GNU General Public License as published by
@@ -1707,7 +1707,7 @@ static void unescape(FILE *file,char *pos,uint length)
17071707
length*2+1, MYF(MY_WME))))
17081708
die(EX_MYSQLERR, "Couldn't allocate memory");
17091709

1710-
mysql_real_escape_string(&mysql_connection, tmp, pos, length);
1710+
mysql_real_escape_string_quote(&mysql_connection, tmp, pos, length, '\'');
17111711
fputc('\'', file);
17121712
fputs(tmp, file);
17131713
fputc('\'', file);
@@ -2194,8 +2194,8 @@ static uint dump_events_for_db(char *db)
21942194
DBUG_ENTER("dump_events_for_db");
21952195
DBUG_PRINT("enter", ("db: '%s'", db));
21962196

2197-
mysql_real_escape_string(mysql, db_name_buff, db, (ulong)strlen(db));
2198-
2197+
mysql_real_escape_string_quote(mysql, db_name_buff,
2198+
db, (ulong)strlen(db), '\'');
21992199
/* nice comments */
22002200
print_comment(sql_file, 0,
22012201
"\n--\n-- Dumping events for database '%s'\n--\n", db);
@@ -2406,8 +2406,8 @@ static uint dump_routines_for_db(char *db)
24062406
DBUG_ENTER("dump_routines_for_db");
24072407
DBUG_PRINT("enter", ("db: '%s'", db));
24082408

2409-
mysql_real_escape_string(mysql, db_name_buff, db, (ulong)strlen(db));
2410-
2409+
mysql_real_escape_string_quote(mysql, db_name_buff,
2410+
db, (ulong)strlen(db), '\'');
24112411
/* nice comments */
24122412
print_comment(sql_file, 0,
24132413
"\n--\n-- Dumping routines for database '%s'\n--\n", db);
@@ -3764,9 +3764,10 @@ static void dump_table(char *table, char *db)
37643764
{
37653765
dynstr_append_checked(&extended_row,"'");
37663766
extended_row.length +=
3767-
mysql_real_escape_string(&mysql_connection,
3768-
&extended_row.str[extended_row.length],
3769-
row[i],length);
3767+
mysql_real_escape_string_quote(&mysql_connection,
3768+
&extended_row.str[extended_row.length],
3769+
row[i],length,
3770+
'\'');
37703771
extended_row.str[extended_row.length]='\0';
37713772
dynstr_append_checked(&extended_row,"'");
37723773
}
@@ -3999,7 +4000,7 @@ static int dump_tablespaces_for_tables(char *db, char **table_names, int tables)
39994000
int i;
40004001
char name_buff[NAME_LEN*2+3];
40014002

4002-
mysql_real_escape_string(mysql, name_buff, db, (ulong)strlen(db));
4003+
mysql_real_escape_string_quote(mysql, name_buff, db, (ulong)strlen(db), '\'');
40034004

40044005
init_dynamic_string_checked(&where, " AND TABLESPACE_NAME IN ("
40054006
"SELECT DISTINCT TABLESPACE_NAME FROM"
@@ -4011,8 +4012,8 @@ static int dump_tablespaces_for_tables(char *db, char **table_names, int tables)
40114012

40124013
for (i=0 ; i<tables ; i++)
40134014
{
4014-
mysql_real_escape_string(mysql, name_buff,
4015-
table_names[i], (ulong)strlen(table_names[i]));
4015+
mysql_real_escape_string_quote(mysql, name_buff,
4016+
table_names[i], (ulong)strlen(table_names[i]), '\'');
40164017

40174018
dynstr_append_checked(&where, "'");
40184019
dynstr_append_checked(&where, name_buff);
@@ -4042,8 +4043,8 @@ static int dump_tablespaces_for_databases(char** databases)
40424043
for (i=0 ; databases[i]!=NULL ; i++)
40434044
{
40444045
char db_name_buff[NAME_LEN*2+3];
4045-
mysql_real_escape_string(mysql, db_name_buff,
4046-
databases[i], (ulong)strlen(databases[i]));
4046+
mysql_real_escape_string_quote(mysql, db_name_buff,
4047+
databases[i], (ulong)strlen(databases[i]), '\'');
40474048
dynstr_append_checked(&where, "'");
40484049
dynstr_append_checked(&where, db_name_buff);
40494050
dynstr_append_checked(&where, "',");

client/mysqlimport.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -369,8 +369,8 @@ static int write_to_table(char *filename, MYSQL *mysql)
369369
fprintf(stdout, "Loading data from SERVER file: %s into %s\n",
370370
hard_path, tablename);
371371
}
372-
mysql_real_escape_string(mysql, escaped_name, hard_path,
373-
(unsigned long) strlen(hard_path));
372+
mysql_real_escape_string_quote(mysql, escaped_name, hard_path,
373+
(unsigned long) strlen(hard_path), '\'');
374374
sprintf(sql_statement, "LOAD DATA %s %s INFILE '%s'",
375375
opt_low_priority ? "LOW_PRIORITY" : "",
376376
opt_local_file ? "LOCAL" : "", escaped_name);

client/mysqlshow.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
2+
Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
33
44
This program is free software; you can redistribute it and/or modify
55
it under the terms of the GNU General Public License as published by
@@ -539,7 +539,8 @@ list_tables(MYSQL *mysql,const char *db,const char *table)
539539
We just hijack the 'rows' variable for a bit to store the escaped
540540
table name
541541
*/
542-
mysql_real_escape_string(mysql, rows, table, (unsigned long)strlen(table));
542+
mysql_real_escape_string_quote(mysql, rows, table,
543+
(unsigned long)strlen(table), '\'');
543544
my_snprintf(query, sizeof(query), "show%s tables like '%s'",
544545
opt_table_type ? " full" : "", rows);
545546
}

include/errmsg.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#ifndef ERRMSG_INCLUDED
22
#define ERRMSG_INCLUDED
33

4-
/* Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
4+
/* Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
55
66
This program is free software; you can redistribute it and/or modify
77
it under the terms of the GNU General Public License as published by
@@ -106,7 +106,8 @@ extern const char *client_errors[]; /* Error messages */
106106
#define CR_AUTH_PLUGIN_CANNOT_LOAD 2059
107107
#define CR_DUPLICATE_CONNECTION_ATTR 2060
108108
#define CR_AUTH_PLUGIN_ERR 2061
109-
#define CR_ERROR_LAST /*Copy last error nr:*/ 2061
109+
#define CR_INSECURE_API_ERR 2062
110+
#define CR_ERROR_LAST /*Copy last error nr:*/ 2062
110111
/* Add error numbers before CR_ERROR_LAST and change it accordingly. */
111112

112113
#endif /* ERRMSG_INCLUDED */

include/my_sys.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -881,9 +881,8 @@ extern size_t escape_string_for_mysql(const CHARSET_INFO *charset_info,
881881
extern CHARSET_INFO *fs_character_set(void);
882882
#endif
883883
extern size_t escape_quotes_for_mysql(CHARSET_INFO *charset_info,
884-
char *to, size_t to_length,
885-
const char *from, size_t length);
886-
884+
char *to, size_t to_length,
885+
const char *from, size_t length, char quote);
887886
#ifdef _WIN32
888887
extern my_bool have_tcpip; /* Is set if tcpip is used */
889888

include/mysql.h

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
1+
/* Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
22
33
This program is free software; you can redistribute it and/or modify
44
it under the terms of the GNU General Public License as published by
@@ -483,12 +483,15 @@ unsigned long STDCALL mysql_hex_string(char *to,const char *from,
483483
unsigned long STDCALL mysql_real_escape_string(MYSQL *mysql,
484484
char *to,const char *from,
485485
unsigned long length);
486-
void STDCALL mysql_debug(const char *debug);
487-
void STDCALL myodbc_remove_escape(MYSQL *mysql,char *name);
488-
unsigned int STDCALL mysql_thread_safe(void);
489-
my_bool STDCALL mysql_embedded(void);
490-
my_bool STDCALL mysql_read_query_result(MYSQL *mysql);
491-
int STDCALL mysql_reset_connection(MYSQL *mysql);
486+
unsigned long STDCALL mysql_real_escape_string_quote(MYSQL *mysql,
487+
char *to, const char *from,
488+
unsigned long length, char quote);
489+
void STDCALL mysql_debug(const char *debug);
490+
void STDCALL myodbc_remove_escape(MYSQL *mysql,char *name);
491+
unsigned int STDCALL mysql_thread_safe(void);
492+
my_bool STDCALL mysql_embedded(void);
493+
my_bool STDCALL mysql_read_query_result(MYSQL *mysql);
494+
int STDCALL mysql_reset_connection(MYSQL *mysql);
492495

493496
/*
494497
The following definitions are added for the enhanced

include/mysql.h.pp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -557,6 +557,9 @@
557557
unsigned long mysql_real_escape_string(MYSQL *mysql,
558558
char *to,const char *from,
559559
unsigned long length);
560+
unsigned long mysql_real_escape_string_quote(MYSQL *mysql,
561+
char *to, const char *from,
562+
unsigned long length, char quote);
560563
void mysql_debug(const char *debug);
561564
void myodbc_remove_escape(MYSQL *mysql,char *name);
562565
unsigned int mysql_thread_safe(void);

libmysql/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright (c) 2006, 2014, Oracle and/or its affiliates. All rights reserved.
1+
# Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved.
22
#
33
# This program is free software; you can redistribute it and/or modify
44
# it under the terms of the GNU General Public License as published by
@@ -87,6 +87,7 @@ mysql_query
8787
mysql_read_query_result
8888
mysql_real_connect
8989
mysql_real_escape_string
90+
mysql_real_escape_string_quote
9091
mysql_real_query
9192
mysql_refresh
9293
mysql_rollback

libmysql/errmsg.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ const char *client_errors[]=
8787
"Authentication plugin '%s' cannot be loaded: %s",
8888
"There is an attribute with the same name already",
8989
"Authentication plugin '%s' reported error: %s",
90+
"Insecure API function call: '%s' Use instead: '%s'",
9091
""
9192
};
9293

0 commit comments

Comments
 (0)