summaryrefslogtreecommitdiff
path: root/client
diff options
context:
space:
mode:
authorShishir Jaiswal <shishir.j.jaiswal@oracle.com>2016-05-16 13:46:49 +0530
committerPrashant Tekriwal <prashant.tekriwal@oracle.com>2016-05-16 11:33:57 +0200
commit9d72fb4af0d87f6a69a3ccb9202b4029acf2bd56 (patch)
treef0390f098b09894c5f8a5f42f9931d12f61d2444 /client
parent6768f80c0b1f0b82c5addbe47ce712ded14d0d8c (diff)
downloadmariadb-git-9d72fb4af0d87f6a69a3ccb9202b4029acf2bd56.tar.gz
Bug#21977380 - POSSIBLE BUFFER OVERFLOW ISSUES
DESCRIPTION =========== Buffer overflow is reported in a lot of code sections spanning across server, client programs, Regex libraries etc. If not handled appropriately, they can cause abnormal behaviour. ANALYSIS ======== The reported casea are the ones which are likely to result in SEGFAULT, MEMORY LEAK etc. FIX === - sprintf() has been replaced by my_snprintf() to avoid buffer overflow. - my_free() is done after checking if the pointer isn't NULL already and setting it to NULL thereafter at few places. - Buffer is ensured to be large enough to hold the data. - 'unsigned int' (aka 'uint') is replaced with 'size_t' to avoid wraparound. - Memory is freed (if not done so) after its alloced and used. - Inserted assert() for size check in InnoDb memcached code (from 5.6 onwards) - Other minor changes (cherry picked from commit 3487e20959c940cbd24429afa795ebfc8a01e94f)
Diffstat (limited to 'client')
-rw-r--r--client/mysqlcheck.c42
-rw-r--r--client/mysqldump.c49
-rw-r--r--client/mysqlshow.c36
3 files changed, 72 insertions, 55 deletions
diff --git a/client/mysqlcheck.c b/client/mysqlcheck.c
index a564e871281..55b941e7f1a 100644
--- a/client/mysqlcheck.c
+++ b/client/mysqlcheck.c
@@ -213,13 +213,13 @@ static int process_selected_tables(char *db, char **table_names, int tables);
static int process_all_tables_in_db(char *database);
static int process_one_db(char *database);
static int use_db(char *database);
-static int handle_request_for_tables(char *tables, uint length);
+static int handle_request_for_tables(char *tables, size_t length);
static int dbConnect(char *host, char *user,char *passwd);
static void dbDisconnect(char *host);
static void DBerror(MYSQL *mysql, const char *when);
static void safe_exit(int error);
static void print_result();
-static uint fixed_name_length(const char *name);
+static size_t fixed_name_length(const char *name);
static char *fix_table_name(char *dest, char *src);
int what_to_do = 0;
@@ -486,7 +486,7 @@ static int process_selected_tables(char *db, char **table_names, int tables)
*end++= ',';
}
*--end = 0;
- handle_request_for_tables(table_names_comma_sep + 1, (uint) (tot_length - 1));
+ handle_request_for_tables(table_names_comma_sep + 1, tot_length - 1);
my_free(table_names_comma_sep);
}
else
@@ -496,10 +496,10 @@ static int process_selected_tables(char *db, char **table_names, int tables)
} /* process_selected_tables */
-static uint fixed_name_length(const char *name)
+static size_t fixed_name_length(const char *name)
{
const char *p;
- uint extra_length= 2; /* count the first/last backticks */
+ size_t extra_length= 2; /* count the first/last backticks */
for (p= name; *p; p++)
{
@@ -508,7 +508,7 @@ static uint fixed_name_length(const char *name)
else if (*p == '.')
extra_length+= 2;
}
- return (uint) ((p - name) + extra_length);
+ return (size_t) ((p - name) + extra_length);
}
@@ -564,7 +564,7 @@ static int process_all_tables_in_db(char *database)
*/
char *tables, *end;
- uint tot_length = 0;
+ size_t tot_length = 0;
while ((row = mysql_fetch_row(res)))
tot_length+= fixed_name_length(row[0]) + 2;
@@ -622,7 +622,9 @@ static int fix_table_storage_name(const char *name)
int rc= 0;
if (strncmp(name, "#mysql50#", 9))
return 1;
- sprintf(qbuf, "RENAME TABLE `%s` TO `%s`", name, name + 9);
+ my_snprintf(qbuf, sizeof(qbuf), "RENAME TABLE `%s` TO `%s`",
+ name, name + 9);
+
rc= run_query(qbuf);
if (verbose)
printf("%-50s %s\n", name, rc ? "FAILED" : "OK");
@@ -635,7 +637,8 @@ static int fix_database_storage_name(const char *name)
int rc= 0;
if (strncmp(name, "#mysql50#", 9))
return 1;
- sprintf(qbuf, "ALTER DATABASE `%s` UPGRADE DATA DIRECTORY NAME", name);
+ my_snprintf(qbuf, sizeof(qbuf), "ALTER DATABASE `%s` UPGRADE DATA DIRECTORY "
+ "NAME", name);
rc= run_query(qbuf);
if (verbose)
printf("%-50s %s\n", name, rc ? "FAILED" : "OK");
@@ -653,7 +656,7 @@ static int rebuild_table(char *name)
ptr= strmov(query, "ALTER TABLE ");
ptr= fix_table_name(ptr, name);
ptr= strxmov(ptr, " FORCE", NullS);
- if (mysql_real_query(sock, query, (uint)(ptr - query)))
+ if (mysql_real_query(sock, query, (ulong)(ptr - query)))
{
fprintf(stderr, "Failed to %s\n", query);
fprintf(stderr, "Error: %s\n", mysql_error(sock));
@@ -702,10 +705,10 @@ static int disable_binlog()
return run_query(stmt);
}
-static int handle_request_for_tables(char *tables, uint length)
+static int handle_request_for_tables(char *tables, size_t length)
{
char *query, *end, options[100], message[100];
- uint query_length= 0;
+ size_t query_length= 0, query_size= sizeof(char)*(length+110);
const char *op = 0;
options[0] = 0;
@@ -736,10 +739,14 @@ static int handle_request_for_tables(char *tables, uint length)
return fix_table_storage_name(tables);
}
- if (!(query =(char *) my_malloc((sizeof(char)*(length+110)), MYF(MY_WME))))
+ if (!(query =(char *) my_malloc(query_size, MYF(MY_WME))))
+ {
return 1;
+ }
if (opt_all_in_1)
{
+ DBUG_ASSERT(strlen(op)+strlen(tables)+strlen(options)+8+1 <= query_size);
+
/* No backticks here as we added them before */
query_length= sprintf(query, "%s TABLE %s %s", op, tables, options);
}
@@ -750,7 +757,7 @@ static int handle_request_for_tables(char *tables, uint length)
ptr= strmov(strmov(query, op), " TABLE ");
ptr= fix_table_name(ptr, tables);
ptr= strxmov(ptr, " ", options, NullS);
- query_length= (uint) (ptr - query);
+ query_length= (size_t) (ptr - query);
}
if (mysql_real_query(sock, query, query_length))
{
@@ -834,7 +841,10 @@ static void print_result()
prev_alter[0]= 0;
}
else
- strcpy(prev_alter, alter_txt);
+ {
+ strncpy(prev_alter, alter_txt, MAX_ALTER_STR_SIZE-1);
+ prev_alter[MAX_ALTER_STR_SIZE-1]= 0;
+ }
}
}
}
@@ -978,7 +988,7 @@ int main(int argc, char **argv)
process_databases(argv);
if (opt_auto_repair)
{
- uint i;
+ size_t i;
if (!opt_silent && (tables4repair.elements || tables4rebuild.elements))
puts("\nRepairing tables");
diff --git a/client/mysqldump.c b/client/mysqldump.c
index 6c4fec313c5..00265def489 100644
--- a/client/mysqldump.c
+++ b/client/mysqldump.c
@@ -86,7 +86,7 @@
static void add_load_option(DYNAMIC_STRING *str, const char *option,
const char *option_value);
-static ulong find_set(TYPELIB *lib, const char *x, uint length,
+static ulong find_set(TYPELIB *lib, const char *x, size_t length,
char **err_pos, uint *err_len);
static char *alloc_query_str(ulong size);
@@ -852,7 +852,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
opt_set_charset= 0;
opt_compatible_mode_str= argument;
opt_compatible_mode= find_set(&compatible_mode_typelib,
- argument, (uint) strlen(argument),
+ argument, strlen(argument),
&err_ptr, &err_len);
if (err_len)
{
@@ -862,7 +862,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
}
#if !defined(DBUG_OFF)
{
- uint size_for_sql_mode= 0;
+ size_t size_for_sql_mode= 0;
const char **ptr;
for (ptr= compatible_mode_names; *ptr; ptr++)
size_for_sql_mode+= strlen(*ptr);
@@ -1138,8 +1138,8 @@ static int fetch_db_collation(const char *db_name,
break;
}
- strncpy(db_cl_name, db_cl_row[0], db_cl_size);
- db_cl_name[db_cl_size - 1]= 0; /* just in case. */
+ strncpy(db_cl_name, db_cl_row[0], db_cl_size-1);
+ db_cl_name[db_cl_size - 1]= 0;
} while (FALSE);
@@ -1150,7 +1150,7 @@ static int fetch_db_collation(const char *db_name,
static char *my_case_str(const char *str,
- uint str_len,
+ size_t str_len,
const char *token,
uint token_len)
{
@@ -1366,7 +1366,7 @@ static int switch_character_set_results(MYSQL *mysql, const char *cs_name)
*/
static char *cover_definer_clause(const char *stmt_str,
- uint stmt_length,
+ size_t stmt_length,
const char *definer_version_str,
uint definer_version_length,
const char *stmt_version_str,
@@ -1548,14 +1548,14 @@ static void dbDisconnect(char *host)
} /* dbDisconnect */
-static void unescape(FILE *file,char *pos,uint length)
+static void unescape(FILE *file,char *pos, size_t length)
{
char *tmp;
DBUG_ENTER("unescape");
if (!(tmp=(char*) my_malloc(length*2+1, MYF(MY_WME))))
die(EX_MYSQLERR, "Couldn't allocate memory");
- mysql_real_escape_string(&mysql_connection, tmp, pos, length);
+ mysql_real_escape_string(&mysql_connection, tmp, pos, (ulong)length);
fputc('\'', file);
fputs(tmp, file);
fputc('\'', file);
@@ -1669,7 +1669,7 @@ static char *quote_for_like(const char *name, char *buff)
Quote '<' '>' '&' '\"' chars and print a string to the xml_file.
*/
-static void print_quoted_xml(FILE *xml_file, const char *str, ulong len,
+static void print_quoted_xml(FILE *xml_file, const char *str, size_t len,
my_bool is_attribute_name)
{
const char *end;
@@ -1928,7 +1928,7 @@ static void print_xml_row(FILE *xml_file, const char *row_name,
squeezed to a single hyphen.
*/
-static void print_xml_comment(FILE *xml_file, ulong len,
+static void print_xml_comment(FILE *xml_file, size_t len,
const char *comment_string)
{
const char* end;
@@ -2045,7 +2045,7 @@ static uint dump_events_for_db(char *db)
DBUG_ENTER("dump_events_for_db");
DBUG_PRINT("enter", ("db: '%s'", db));
- mysql_real_escape_string(mysql, db_name_buff, db, strlen(db));
+ mysql_real_escape_string(mysql, db_name_buff, db, (ulong)strlen(db));
/* nice comments */
print_comment(sql_file, 0,
@@ -2164,6 +2164,11 @@ static uint dump_events_for_db(char *db)
(const char *) (query_str != NULL ? query_str : row[3]),
(const char *) delimiter);
+ if(query_str)
+ {
+ my_free(query_str);
+ query_str= NULL;
+ }
restore_time_zone(sql_file, delimiter);
restore_sql_mode(sql_file, delimiter);
@@ -2257,7 +2262,7 @@ static uint dump_routines_for_db(char *db)
DBUG_ENTER("dump_routines_for_db");
DBUG_PRINT("enter", ("db: '%s'", db));
- mysql_real_escape_string(mysql, db_name_buff, db, strlen(db));
+ mysql_real_escape_string(mysql, db_name_buff, db, (ulong)strlen(db));
/* nice comments */
print_comment(sql_file, 0,
@@ -2311,9 +2316,9 @@ static uint dump_routines_for_db(char *db)
if the user has EXECUTE privilege he see routine names, but NOT the
routine body of other routines that are not the creator of!
*/
- DBUG_PRINT("info",("length of body for %s row[2] '%s' is %d",
+ DBUG_PRINT("info",("length of body for %s row[2] '%s' is %zu",
routine_name, row[2] ? row[2] : "(null)",
- row[2] ? (int) strlen(row[2]) : 0));
+ row[2] ? strlen(row[2]) : 0));
if (row[2] == NULL)
{
print_comment(sql_file, 1, "\n-- insufficient privileges to %s\n",
@@ -3873,7 +3878,7 @@ static int dump_tablespaces_for_tables(char *db, char **table_names, int tables)
int i;
char name_buff[NAME_LEN*2+3];
- mysql_real_escape_string(mysql, name_buff, db, strlen(db));
+ mysql_real_escape_string(mysql, name_buff, db, (ulong)strlen(db));
init_dynamic_string_checked(&where, " AND TABLESPACE_NAME IN ("
"SELECT DISTINCT TABLESPACE_NAME FROM"
@@ -3886,7 +3891,7 @@ static int dump_tablespaces_for_tables(char *db, char **table_names, int tables)
for (i=0 ; i<tables ; i++)
{
mysql_real_escape_string(mysql, name_buff,
- table_names[i], strlen(table_names[i]));
+ table_names[i], (ulong)strlen(table_names[i]));
dynstr_append_checked(&where, "'");
dynstr_append_checked(&where, name_buff);
@@ -3917,7 +3922,7 @@ static int dump_tablespaces_for_databases(char** databases)
{
char db_name_buff[NAME_LEN*2+3];
mysql_real_escape_string(mysql, db_name_buff,
- databases[i], strlen(databases[i]));
+ databases[i], (ulong)strlen(databases[i]));
dynstr_append_checked(&where, "'");
dynstr_append_checked(&where, db_name_buff);
dynstr_append_checked(&where, "',");
@@ -4927,7 +4932,7 @@ static int start_transaction(MYSQL *mysql_con)
}
-static ulong find_set(TYPELIB *lib, const char *x, uint length,
+static ulong find_set(TYPELIB *lib, const char *x, size_t length,
char **err_pos, uint *err_len)
{
const char *end= x + length;
@@ -4985,7 +4990,7 @@ static void print_value(FILE *file, MYSQL_RES *result, MYSQL_ROW row,
fputc(' ',file);
fputs(prefix, file);
if (string_value)
- unescape(file,row[0],(uint) strlen(row[0]));
+ unescape(file,row[0], strlen(row[0]));
else
fputs(row[0], file);
check_io(file);
@@ -5238,8 +5243,8 @@ static my_bool get_view_structure(char *table, char* db)
verbose_msg("-- Retrieving view structure for table %s...\n", table);
#ifdef NOT_REALLY_USED_YET
- sprintf(insert_pat, "SET SQL_QUOTE_SHOW_CREATE=%d",
- (opt_quoted || opt_keywords));
+ dynstr_append_checked(&insert_pat, "SET SQL_QUOTE_SHOW_CREATE=");
+ dynstr_append_checked(&insert_pat, (opt_quoted || opt_keywords)? "1":"0");
#endif
result_table= quote_name(table, table_buff, 1);
diff --git a/client/mysqlshow.c b/client/mysqlshow.c
index f1f8bdaf54b..d0390ec443b 100644
--- a/client/mysqlshow.c
+++ b/client/mysqlshow.c
@@ -52,9 +52,9 @@ static int list_tables(MYSQL *mysql,const char *db,const char *table);
static int list_table_status(MYSQL *mysql,const char *db,const char *table);
static int list_fields(MYSQL *mysql,const char *db,const char *table,
const char *field);
-static void print_header(const char *header,uint head_length,...);
-static void print_row(const char *header,uint head_length,...);
-static void print_trailer(uint length,...);
+static void print_header(const char *header,size_t head_length,...);
+static void print_row(const char *header,size_t head_length,...);
+static void print_trailer(size_t length,...);
static void print_res_header(MYSQL_RES *result);
static void print_res_top(MYSQL_RES *result);
static void print_res_row(MYSQL_RES *result,MYSQL_ROW cur);
@@ -374,7 +374,8 @@ static int
list_dbs(MYSQL *mysql,const char *wild)
{
const char *header;
- uint length, counter = 0;
+ size_t length = 0;
+ uint counter = 0;
ulong rowcount = 0L;
char tables[NAME_LEN+1], rows[NAME_LEN+1];
char query[NAME_LEN + 100];
@@ -412,7 +413,7 @@ list_dbs(MYSQL *mysql,const char *wild)
printf("Wildcard: %s\n",wild);
header="Databases";
- length=(uint) strlen(header);
+ length= strlen(header);
field=mysql_fetch_field(result);
if (length < field->max_length)
length=field->max_length;
@@ -500,7 +501,8 @@ static int
list_tables(MYSQL *mysql,const char *db,const char *table)
{
const char *header;
- uint head_length, counter = 0;
+ size_t head_length;
+ uint counter = 0;
char query[NAME_LEN + 100], rows[NAME_LEN], fields[16];
MYSQL_FIELD *field;
MYSQL_RES *result;
@@ -537,7 +539,7 @@ list_tables(MYSQL *mysql,const char *db,const char *table)
putchar('\n');
header="Tables";
- head_length=(uint) strlen(header);
+ head_length= strlen(header);
field=mysql_fetch_field(result);
if (head_length < field->max_length)
head_length=field->max_length;
@@ -766,10 +768,10 @@ list_fields(MYSQL *mysql,const char *db,const char *table,
*****************************************************************************/
static void
-print_header(const char *header,uint head_length,...)
+print_header(const char *header,size_t head_length,...)
{
va_list args;
- uint length,i,str_length,pre_space;
+ size_t length,i,str_length,pre_space;
const char *field;
va_start(args,head_length);
@@ -792,10 +794,10 @@ print_header(const char *header,uint head_length,...)
putchar('|');
for (;;)
{
- str_length=(uint) strlen(field);
+ str_length= strlen(field);
if (str_length > length)
str_length=length+1;
- pre_space=(uint) (((int) length-(int) str_length)/2)+1;
+ pre_space= ((length- str_length)/2)+1;
for (i=0 ; i < pre_space ; i++)
putchar(' ');
for (i = 0 ; i < str_length ; i++)
@@ -829,11 +831,11 @@ print_header(const char *header,uint head_length,...)
static void
-print_row(const char *header,uint head_length,...)
+print_row(const char *header,size_t head_length,...)
{
va_list args;
const char *field;
- uint i,length,field_length;
+ size_t i,length,field_length;
va_start(args,head_length);
field=header; length=head_length;
@@ -842,7 +844,7 @@ print_row(const char *header,uint head_length,...)
putchar('|');
putchar(' ');
fputs(field,stdout);
- field_length=(uint) strlen(field);
+ field_length= strlen(field);
for (i=field_length ; i <= length ; i++)
putchar(' ');
if (!(field=va_arg(args,char *)))
@@ -856,10 +858,10 @@ print_row(const char *header,uint head_length,...)
static void
-print_trailer(uint head_length,...)
+print_trailer(size_t head_length,...)
{
va_list args;
- uint length,i;
+ size_t length,i;
va_start(args,head_length);
length=head_length;
@@ -902,7 +904,7 @@ static void print_res_top(MYSQL_RES *result)
mysql_field_seek(result,0);
while((field = mysql_fetch_field(result)))
{
- if ((length=(uint) strlen(field->name)) > field->max_length)
+ if ((length= strlen(field->name)) > field->max_length)
field->max_length=length;
else
length=field->max_length;