diff -Naurp mysql-5.0.45/libmysql/libmysql.c mysql-5.0.45.oden/libmysql/libmysql.c --- mysql-5.0.45/libmysql/libmysql.c 2007-07-04 15:05:53.000000000 +0200 +++ mysql-5.0.45.oden/libmysql/libmysql.c 2008-01-25 13:22:03.000000000 +0100 @@ -693,7 +693,8 @@ int cli_read_change_user_result(MYSQL *m my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user, const char *passwd, const char *db) { - char buff[512],*end=buff; + char buff[USERNAME_LENGTH+SCRAMBLED_PASSWORD_CHAR_LENGTH+NAME_LEN+2]; + char *end= buff; int rc; DBUG_ENTER("mysql_change_user"); @@ -703,7 +704,7 @@ my_bool STDCALL mysql_change_user(MYSQL passwd=""; /* Store user into the buffer */ - end=strmov(end,user)+1; + end= strmake(end, user, USERNAME_LENGTH) + 1; /* write scrambled password according to server capabilities */ if (passwd[0]) @@ -723,7 +724,7 @@ my_bool STDCALL mysql_change_user(MYSQL else *end++= '\0'; /* empty password */ /* Add database if needed */ - end= strmov(end, db ? db : "") + 1; + end= strmake(end, db ? db : "", NAME_LEN) + 1; /* Write authentication package */ simple_command(mysql,COM_CHANGE_USER, buff,(ulong) (end-buff),1); diff -Naurp mysql-5.0.45/tests/mysql_client_test.c mysql-5.0.45.oden/tests/mysql_client_test.c --- mysql-5.0.45/tests/mysql_client_test.c 2007-07-04 15:05:54.000000000 +0200 +++ mysql-5.0.45.oden/tests/mysql_client_test.c 2008-01-25 13:29:36.000000000 +0100 @@ -15680,6 +15680,99 @@ static void test_bug28934() } + +/** + Bug#31669 Buffer overflow in mysql_change_user() +*/ + +#define LARGE_BUFFER_SIZE 2048 + +static void test_bug31669() +{ + int rc; + static char buff[LARGE_BUFFER_SIZE+1]; +#ifndef EMBEDDED_LIBRARY + static char user[USERNAME_LENGTH+1]; + static char db[NAME_LEN+1]; + static char query[LARGE_BUFFER_SIZE*2]; +#endif + + DBUG_ENTER("test_bug31669"); + myheader("test_bug31669"); + + rc= mysql_change_user(mysql, NULL, NULL, NULL); + DIE_UNLESS(rc); + + rc= mysql_change_user(mysql, "", "", ""); + DIE_UNLESS(rc); + + memset(buff, 'a', sizeof(buff)); + + rc= mysql_change_user(mysql, buff, buff, buff); + DIE_UNLESS(rc); + + rc = mysql_change_user(mysql, opt_user, opt_password, current_db); + DIE_UNLESS(!rc); + +#ifndef EMBEDDED_LIBRARY + memset(db, 'a', sizeof(db)); + db[NAME_LEN]= 0; + strxmov(query, "CREATE DATABASE IF NOT EXISTS ", db, NullS); + rc= mysql_query(mysql, query); + myquery(rc); + + memset(user, 'b', sizeof(user)); + user[USERNAME_LENGTH]= 0; + memset(buff, 'c', sizeof(buff)); + buff[LARGE_BUFFER_SIZE]= 0; + strxmov(query, "GRANT ALL PRIVILEGES ON *.* TO '", user, "'@'%' IDENTIFIED BY " + "'", buff, "' WITH GRANT OPTION", NullS); + rc= mysql_query(mysql, query); + myquery(rc); + + rc= mysql_query(mysql, "FLUSH PRIVILEGES"); + myquery(rc); + + rc= mysql_change_user(mysql, user, buff, db); + DIE_UNLESS(!rc); + + user[USERNAME_LENGTH-1]= 'a'; + rc= mysql_change_user(mysql, user, buff, db); + DIE_UNLESS(rc); + + user[USERNAME_LENGTH-1]= 'b'; + buff[LARGE_BUFFER_SIZE-1]= 'd'; + rc= mysql_change_user(mysql, user, buff, db); + DIE_UNLESS(rc); + + buff[LARGE_BUFFER_SIZE-1]= 'c'; + db[NAME_LEN-1]= 'e'; + rc= mysql_change_user(mysql, user, buff, db); + DIE_UNLESS(rc); + + db[NAME_LEN-1]= 'a'; + rc= mysql_change_user(mysql, user, buff, db); + DIE_UNLESS(!rc); + + rc= mysql_change_user(mysql, user + 1, buff + 1, db + 1); + DIE_UNLESS(rc); + + rc = mysql_change_user(mysql, opt_user, opt_password, current_db); + DIE_UNLESS(!rc); + + strxmov(query, "DROP DATABASE ", db, NullS); + rc= mysql_query(mysql, query); + myquery(rc); + + strxmov(query, "DELETE FROM mysql.user WHERE User='", user, "'", NullS); + rc= mysql_query(mysql, query); + myquery(rc); + DIE_UNLESS(mysql_affected_rows(mysql) == 1); +#endif + + DBUG_VOID_RETURN; +} + /* Read and parse arguments and MySQL options from my.cnf */ @@ -15963,6 +16056,7 @@ static struct my_tests_st my_tests[]= { { "test_bug27876", test_bug27876 }, { "test_bug28505", test_bug28505 }, { "test_bug28934", test_bug28934 }, + { "test_bug31669", test_bug31669 }, { 0, 0 } }; diff -Naurp mysql-5.0.45/tests/mysql_client_test.c.diff mysql-5.0.45.oden/tests/mysql_client_test.c.diff --- mysql-5.0.45/tests/mysql_client_test.c.diff 1970-01-01 01:00:00.000000000 +0100 +++ mysql-5.0.45.oden/tests/mysql_client_test.c.diff 2008-01-25 13:25:00.000000000 +0100 @@ -0,0 +1,115 @@ +diff -Naurp mysql-5.0.45/tests/mysql_client_test.c mysql-5.0.45.oden/tests/mysql_client_test.c +--- mysql-5.0.45/tests/mysql_client_test.c 2007-07-04 15:05:54.000000000 +0200 ++++ mysql-5.0.45.oden/tests/mysql_client_test.c 2008-01-25 13:25:17.000000000 +0100 +@@ -15680,6 +15680,99 @@ static void test_bug28934() + } + + ++ ++/** ++ Bug#31669 Buffer overflow in mysql_change_user() ++*/ ++ ++#define LARGE_BUFFER_SIZE 2048 ++ ++static void test_bug31669() ++{ ++ int rc; ++ static char buff[LARGE_BUFFER_SIZE+1]; ++#ifndef EMBEDDED_LIBRARY ++ static char user[USERNAME_LENGTH+1]; ++ static char db[NAME_LEN+1]; ++ static char query[LARGE_BUFFER_SIZE*2]; ++#endif ++ ++ DBUG_ENTER("test_bug31669"); ++ myheader("test_bug31669"); ++ ++ rc= mysql_change_user(mysql, NULL, NULL, NULL); ++ DIE_UNLESS(rc); ++ ++ rc= mysql_change_user(mysql, "", "", ""); ++ DIE_UNLESS(rc); ++ ++ memset(buff, 'a', sizeof(buff)); ++ ++ rc= mysql_change_user(mysql, buff, buff, buff); ++ DIE_UNLESS(rc); ++ ++ rc = mysql_change_user(mysql, opt_user, opt_password, current_db); ++ DIE_UNLESS(!rc); ++ ++#ifndef EMBEDDED_LIBRARY ++ memset(db, 'a', sizeof(db)); ++ db[NAME_LEN]= 0; ++ strxmov(query, "CREATE DATABASE IF NOT EXISTS ", db, NullS); ++ rc= mysql_query(mysql, query); ++ myquery(rc); ++ ++ memset(user, 'b', sizeof(user)); ++ user[USERNAME_LENGTH]= 0; ++ memset(buff, 'c', sizeof(buff)); ++ buff[LARGE_BUFFER_SIZE]= 0; ++ strxmov(query, "GRANT ALL PRIVILEGES ON *.* TO '", user, "'@'%' IDENTIFIED BY " ++ "'", buff, "' WITH GRANT OPTION", NullS); ++ rc= mysql_query(mysql, query); ++ myquery(rc); ++ ++ rc= mysql_query(mysql, "FLUSH PRIVILEGES"); ++ myquery(rc); ++ ++ rc= mysql_change_user(mysql, user, buff, db); ++ DIE_UNLESS(!rc); ++ ++ user[USERNAME_LENGTH-1]= 'a'; ++ rc= mysql_change_user(mysql, user, buff, db); ++ DIE_UNLESS(rc); ++ ++ user[USERNAME_LENGTH-1]= 'b'; ++ buff[LARGE_BUFFER_SIZE-1]= 'd'; ++ rc= mysql_change_user(mysql, user, buff, db); ++ DIE_UNLESS(rc); ++ ++ buff[LARGE_BUFFER_SIZE-1]= 'c'; ++ db[NAME_LEN-1]= 'e'; ++ rc= mysql_change_user(mysql, user, buff, db); ++ DIE_UNLESS(rc); ++ ++ db[NAME_LEN-1]= 'a'; ++ rc= mysql_change_user(mysql, user, buff, db); ++ DIE_UNLESS(!rc); ++ ++ rc= mysql_change_user(mysql, user + 1, buff + 1, db + 1); ++ DIE_UNLESS(rc); ++ ++ rc = mysql_change_user(mysql, opt_user, opt_password, current_db); ++ DIE_UNLESS(!rc); ++ ++ strxmov(query, "DROP DATABASE ", db, NullS); ++ rc= mysql_query(mysql, query); ++ myquery(rc); ++ ++ strxmov(query, "DELETE FROM mysql.user WHERE User='", user, "'", NullS); ++ rc= mysql_query(mysql, query); ++ myquery(rc); ++ DIE_UNLESS(mysql_affected_rows(mysql) == 1); ++#endif ++ ++ DBUG_VOID_RETURN; ++} ++ + /* + Read and parse arguments and MySQL options from my.cnf + */ +@@ -15963,10 +16056,10 @@ static struct my_tests_st my_tests[]= { + { "test_bug27876", test_bug27876 }, + { "test_bug28505", test_bug28505 }, + { "test_bug28934", test_bug28934 }, ++ { "test_bug31669", test_bug31669 }, + { 0, 0 } + }; + +- + static my_bool + get_one_option(int optid, const struct my_option *opt __attribute__((unused)), + char *argument)