CVE-2016-0546: Insufficient Information (NVD-CWE-noinfo)
value: Unspecified vulnerability in Oracle MySQL 5.5.46 and earlier, 5.6.27 and earlier, and 5.7.9 and MariaDB before 5.5.47, 10.0.x before 10.0.23, and 10.1.x before 10.1.10 allows local users to affect confidentiality, integrity, and availability via unknown vectors related to Client.  NOTE: the previous information is from the January 2016 CPU. Oracle has not commented on third-party claims that these are multiple buffer overflows in the mysqlshow tool that allow remote database servers to have unspecified impact via a long table or database name.
CWE description: There is insufficient information about the issue to classify it; details are unkown or unspecified.
Published: 2016-01-21T03:01Z
Repository: https://github.com/mysql/mysql-server
Language: C
Files changed: client/mysql_plugin.c, client/mysqlshow.c, libmysql/conf_to_src.c, regex/main.c
Commit date: 2015-11-06 16:41:55 +0530
Commit message: Bug#21973610: BUFFER OVERFLOW ISSUES

Description : Incorrect usage of sprintf/strcpy caused
              possible buffer overflow issues at various
              places.

Solution : - Fixed mysql_plugin and mysqlshow
           - Fixed regex library issues

Reviewed-By : Georgi Kodinov <georgi.kodinov@oracle.com>
Reviewed-By : Venkata S Murthy Sidagam <venkata.sidagam@oracle.com>

Diff: diff --git a/client/mysql_plugin.c b/client/mysql_plugin.c
index cf212b16f24..293bd6727cf 100644
--- a/client/mysql_plugin.c
+++ b/client/mysql_plugin.c
@@ -1,7 +1,7 @@
 /*
-   Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+   Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; version 2 of the License.
 
@@ -404,11 +404,11 @@ exit:
 */
 
 static void usage(void)
 {
   PRINT_VERSION;
-  puts("Copyright (c) 2011, Oracle and/or its affiliates. "
+  puts("Copyright (c) 2011, 2015, Oracle and/or its affiliates. "
        "All rights reserved.\n");
   puts("Enable or disable plugins.");
   printf("\nUsage: %s [options] <plugin> ENABLE|DISABLE\n\nOptions:\n",
      my_progname);
   my_print_help(my_long_options);
@@ -755,10 +755,15 @@ static int check_options(int argc, char **argv, char *operation)
       num_found++;
     }
     /* read the plugin config file and check for match against argument */
     else
     {
+      if (strlen(argv[i]) + 4 + 1 > FN_REFLEN)
+      {
+        fprintf(stderr, "ERROR: argument is too long.\n");
+        return 1;
+      }
       strcpy(plugin_name, argv[i]);
       strcpy(config_file, argv[i]);
       strcat(config_file, ".ini");
     }
   }
@@ -846,10 +851,11 @@ static int process_options(int argc, char *argv[], char *operation)
   {
     i= (int)strlength(opt_basedir);
     if (opt_basedir[i-1] != FN_LIBCHAR || opt_basedir[i-1] != FN_LIBCHAR2)
     {
       char buff[FN_REFLEN];
+      memset(buff, 0, sizeof(buff));
       
       strncpy(buff, opt_basedir, sizeof(buff) - 1);
 #ifdef __WIN__
       strncat(buff, "/", sizeof(buff) - strlen(buff) - 1);
 #else
diff --git a/client/mysqlshow.c b/client/mysqlshow.c
index a6705548bcb..6cbbc5e2463 100644
--- a/client/mysqlshow.c
+++ b/client/mysqlshow.c
@@ -375,11 +375,11 @@ list_dbs(MYSQL *mysql,const char *wild)
 {
   const char *header;
   uint length, counter = 0;
   ulong rowcount = 0L;
   char tables[NAME_LEN+1], rows[NAME_LEN+1];
-  char query[255];
+  char query[NAME_LEN + 100];
   MYSQL_FIELD *field;
   MYSQL_RES *result;
   MYSQL_ROW row= NULL, rrow;
 
   if (!(result=mysql_list_dbs(mysql,wild)))
@@ -442,11 +442,12 @@ list_dbs(MYSQL *mysql,const char *wild)
 	  {
             /* Print the count of tables and rows for each database */
             MYSQL_ROW trow;
 	    while ((trow = mysql_fetch_row(tresult)))
 	    {
-	      sprintf(query,"SELECT COUNT(*) FROM `%s`",trow[0]);
+              my_snprintf(query, sizeof(query),
+                          "SELECT COUNT(*) FROM `%s`", trow[0]);
 	      if (!(mysql_query(mysql,query)))
 	      {
 		MYSQL_RES *rresult;
 		if ((rresult = mysql_store_result(mysql)))
 		{
@@ -498,11 +499,11 @@ list_dbs(MYSQL *mysql,const char *wild)
 static int
 list_tables(MYSQL *mysql,const char *db,const char *table)
 {
   const char *header;
   uint head_length, counter = 0;
-  char query[255], rows[NAME_LEN], fields[16];
+  char query[NAME_LEN + 100], rows[NAME_LEN], fields[16];
   MYSQL_FIELD *field;
   MYSQL_RES *result;
   MYSQL_ROW row, rrow;
 
   if (mysql_select_db(mysql,db))
@@ -583,11 +584,12 @@ list_tables(MYSQL *mysql,const char *db,const char *table)
 	  mysql_free_result(rresult);
 
 	  if (opt_verbose > 1)
 	  {
             /* Print the count of rows for each table */
-	    sprintf(query,"SELECT COUNT(*) FROM `%s`",row[0]);
+            my_snprintf(query, sizeof(query), "SELECT COUNT(*) FROM `%s`",
+                        row[0]);
 	    if (!(mysql_query(mysql,query)))
 	    {
 	      if ((rresult = mysql_store_result(mysql)))
 	      {
 		rrow = mysql_fetch_row(rresult);
@@ -643,17 +645,19 @@ list_tables(MYSQL *mysql,const char *db,const char *table)
 
 
 static int
 list_table_status(MYSQL *mysql,const char *db,const char *wild)
 {
-  char query[1024],*end;
+  char query[NAME_LEN + 100];
+  int len;
   MYSQL_RES *result;
   MYSQL_ROW row;
 
-  end=strxmov(query,"show table status from `",db,"`",NullS);
-  if (wild && wild[0])
-    strxmov(end," like '",wild,"'",NullS);
+  len= sizeof(query);
+  len-= my_snprintf(query, len, "show table status from `%s`", db);
+  if (wild && wild[0] && len)
+    strxnmov(query + strlen(query), len, " like '", wild, "'", NullS);
   if (mysql_query(mysql,query) || !(result=mysql_store_result(mysql)))
   {
     fprintf(stderr,"%s: Cannot get status for db: %s, table: %s: %s\n",
 	    my_progname,db,wild ? wild : "",mysql_error(mysql));
     if (mysql_errno(mysql) == ER_PARSE_ERROR)
@@ -681,11 +685,12 @@ list_table_status(MYSQL *mysql,const char *db,const char *wild)
 
 static int
 list_fields(MYSQL *mysql,const char *db,const char *table,
 	    const char *wild)
 {
-  char query[1024],*end;
+  char query[NAME_LEN + 100];
+  int len;
   MYSQL_RES *result;
   MYSQL_ROW row;
   ulong UNINIT_VAR(rows);
 
   if (mysql_select_db(mysql,db))
@@ -695,11 +700,11 @@ list_fields(MYSQL *mysql,const char *db,const char *table,
     return 1;
   }
 
   if (opt_count)
   {
-    sprintf(query,"select count(*) from `%s`", table);
+    my_snprintf(query, sizeof(query), "select count(*) from `%s`", table);
     if (mysql_query(mysql,query) || !(result=mysql_store_result(mysql)))
     {
       fprintf(stderr,"%s: Cannot get record count for db: %s, table: %s: %s\n",
               my_progname,db,table,mysql_error(mysql));
       return 1;
@@ -707,13 +712,15 @@ list_fields(MYSQL *mysql,const char *db,const char *table,
     row= mysql_fetch_row(result);
     rows= (ulong) strtoull(row[0], (char**) 0, 10);
     mysql_free_result(result);
   }
 
-  end=strmov(strmov(strmov(query,"show /*!32332 FULL */ columns from `"),table),"`");
-  if (wild && wild[0])
-    strxmov(end," like '",wild,"'",NullS);
+  len= sizeof(query);
+  len-= my_snprintf(query, len, "show /*!32332 FULL */ columns from `%s`",
+                    table);
+  if (wild && wild[0] && len)
+    strxnmov(query + strlen(query), len, " like '", wild, "'", NullS);
   if (mysql_query(mysql,query) || !(result=mysql_store_result(mysql)))
   {
     fprintf(stderr,"%s: Cannot list columns in db: %s, table: %s: %s\n",
 	    my_progname,db,table,mysql_error(mysql));
     return 1;
@@ -730,11 +737,11 @@ list_fields(MYSQL *mysql,const char *db,const char *table,
   while ((row=mysql_fetch_row(result)))
     print_res_row(result,row);
   print_res_top(result);
   if (opt_show_keys)
   {
-    end=strmov(strmov(strmov(query,"show keys from `"),table),"`");
+    my_snprintf(query, sizeof(query), "show keys from `%s`", table);
     if (mysql_query(mysql,query) || !(result=mysql_store_result(mysql)))
     {
       fprintf(stderr,"%s: Cannot list keys in db: %s, table: %s: %s\n",
 	      my_progname,db,table,mysql_error(mysql));
       return 1;
diff --git a/libmysql/conf_to_src.c b/libmysql/conf_to_src.c
index a5a7d23db0b..0e92388c93c 100644
--- a/libmysql/conf_to_src.c
+++ b/libmysql/conf_to_src.c
@@ -1,6 +1,6 @@
-/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation.
 
@@ -116,11 +116,11 @@ print_array(FILE *f, const char *set, const char *name, int n)
 void
 print_arrays_for(char *set)
 {
   FILE *f;
 
-  sprintf(buf, "%s.conf", set);
+  snprintf(buf, sizeof(buf), "%s.conf", set);
 
   if ((f = fopen(buf, "r")) == NULL) {
     fprintf(stderr, "%s: can't read conf file for charset %s\n", prog, set);
     exit(EXIT_FAILURE);
   }
diff --git a/regex/main.c b/regex/main.c
index f5b591907cf..d35d5a93734 100644
--- a/regex/main.c
+++ b/regex/main.c
@@ -423,11 +423,12 @@ char *should;
 	/* check rm_so and rm_eo for consistency */
 	if (sub.rm_so > sub.rm_eo || (sub.rm_so == -1 && sub.rm_eo != -1) ||
 				(sub.rm_so != -1 && sub.rm_eo == -1) ||
 				(sub.rm_so != -1 && sub.rm_so < 0) ||
 				(sub.rm_eo != -1 && sub.rm_eo < 0) ) {
-		sprintf(grump, "start %ld end %ld", (long)sub.rm_so,
+		snprintf(grump, sizeof(grump),
+			 "start %ld end %ld", (long)sub.rm_so,
 							(long)sub.rm_eo);
 		return(grump);
 	}
 
 	/* check for no match */
@@ -436,28 +437,31 @@ char *should;
 	if (sub.rm_so == -1)
 		return((char*) "did not match");
 
 	/* check for in range */
 	if ((int) sub.rm_eo > (int) strlen(str)) {
-		sprintf(grump, "start %ld end %ld, past end of string",
+		snprintf(grump, sizeof(grump),
+			 "start %ld end %ld, past end of string",
 					(long)sub.rm_so, (long)sub.rm_eo);
 		return(grump);
 	}
 
 	len = (int)(sub.rm_eo - sub.rm_so);
 	shlen = (int)strlen(should);
 	p = str + sub.rm_so;
 
 	/* check for not supposed to match */
 	if (should == NULL) {
-		sprintf(grump, "matched `%.*s'", len, p);
+		snprintf(grump, sizeof(grump),
+			 "matched `%.*s'", len, p);
 		return(grump);
 	}
 
 	/* check for wrong match */
 	if (len != shlen || strncmp(p, should, (size_t)shlen) != 0) {
-		sprintf(grump, "matched `%.*s' instead", len, p);
+		snprintf(grump, sizeof(grump),
+			 "matched `%.*s' instead", len, p);
 		return(grump);
 	}
 	if (shlen > 0)
 		return(NULL);
 
@@ -466,11 +470,12 @@ char *should;
 		return(NULL);
 	shlen = strlen(at);
 	if (shlen == 0)
 		shlen = 1;	/* force check for end-of-string */
 	if (strncmp(p, at, shlen) != 0) {
-		sprintf(grump, "matched null at `%.20s'", p);
+		snprintf(grump, sizeof(grump),
+			 "matched null at `%.20s'", p);
 		return(grump);
 	}
 	return(NULL);
 }
 
@@ -499,11 +504,11 @@ efind(name)
 char *name;
 {
 	static char efbuf[100];
 	my_regex_t re;
 
-	sprintf(efbuf, "REG_%s", name);
+	snprintf(efbuf, sizeof(efbuf), "REG_%s", name);
 	assert(strlen(efbuf) < sizeof(efbuf));
 	re.re_endp = efbuf;
 	(void) my_regerror(REG_ATOI, &re, efbuf, sizeof(efbuf));
 	return(atoi(efbuf));
 }

Vulnerable code:    Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
  puts("Copyright (c) 2011, Oracle and/or its affiliates. "
  char query[255];
	      sprintf(query,"SELECT COUNT(*) FROM `%s`",trow[0]);
  char query[255], rows[NAME_LEN], fields[16];
	    sprintf(query,"SELECT COUNT(*) FROM `%s`",row[0]);
  char query[1024],*end;
  end=strxmov(query,"show table status from `",db,"`",NullS);
  if (wild && wild[0])
    strxmov(end," like '",wild,"'",NullS);
  char query[1024],*end;
    sprintf(query,"select count(*) from `%s`", table);
  end=strmov(strmov(strmov(query,"show /*!32332 FULL */ columns from `"),table),"`");
  if (wild && wild[0])
    strxmov(end," like '",wild,"'",NullS);
    end=strmov(strmov(strmov(query,"show keys from `"),table),"`");
/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
  sprintf(buf, "%s.conf", set);
		sprintf(grump, "start %ld end %ld", (long)sub.rm_so,
		sprintf(grump, "start %ld end %ld, past end of string",
		sprintf(grump, "matched `%.*s'", len, p);
		sprintf(grump, "matched `%.*s' instead", len, p);
		sprintf(grump, "matched null at `%.20s'", p);
	sprintf(efbuf, "REG_%s", name);
Fixed code:    Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
  puts("Copyright (c) 2011, 2015, Oracle and/or its affiliates. "
      if (strlen(argv[i]) + 4 + 1 > FN_REFLEN)
      {
        fprintf(stderr, "ERROR: argument is too long.\n");
        return 1;
      }
      memset(buff, 0, sizeof(buff));
  char query[NAME_LEN + 100];
              my_snprintf(query, sizeof(query),
                          "SELECT COUNT(*) FROM `%s`", trow[0]);
  char query[NAME_LEN + 100], rows[NAME_LEN], fields[16];
            my_snprintf(query, sizeof(query), "SELECT COUNT(*) FROM `%s`",
                        row[0]);
  char query[NAME_LEN + 100];
  int len;
  len= sizeof(query);
  len-= my_snprintf(query, len, "show table status from `%s`", db);
  if (wild && wild[0] && len)
    strxnmov(query + strlen(query), len, " like '", wild, "'", NullS);
  char query[NAME_LEN + 100];
  int len;
    my_snprintf(query, sizeof(query), "select count(*) from `%s`", table);
  len= sizeof(query);
  len-= my_snprintf(query, len, "show /*!32332 FULL */ columns from `%s`",
                    table);
  if (wild && wild[0] && len)
    strxnmov(query + strlen(query), len, " like '", wild, "'", NullS);
    my_snprintf(query, sizeof(query), "show keys from `%s`", table);
/* Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
  snprintf(buf, sizeof(buf), "%s.conf", set);
		snprintf(grump, sizeof(grump),
			 "start %ld end %ld", (long)sub.rm_so,
		snprintf(grump, sizeof(grump),
			 "start %ld end %ld, past end of string",
		snprintf(grump, sizeof(grump),
			 "matched `%.*s'", len, p);
		snprintf(grump, sizeof(grump),
			 "matched `%.*s' instead", len, p);
		snprintf(grump, sizeof(grump),
			 "matched null at `%.20s'", p);
	snprintf(efbuf, sizeof(efbuf), "REG_%s", name);