diff --git a/mysql-test/r/func_crypt.result b/mysql-test/r/func_crypt.result index afdec0f4d06b0dadb34f7734f98925b1770d576c..42fa18b17b248236ca4cccfdec3e986ecc8ae8b3 100644 --- a/mysql-test/r/func_crypt.result +++ b/mysql-test/r/func_crypt.result @@ -95,3 +95,14 @@ Note 1003 select password(_latin1'idkfa ') AS `password('idkfa ')`,old_password( select encrypt('1234','_.'); encrypt('1234','_.') # +# +# Bug #44767: invalid memory reads in password() and old_password() +# functions +# +CREATE TABLE t1(c1 MEDIUMBLOB); +INSERT INTO t1 VALUES (REPEAT('a', 1024)); +SELECT OLD_PASSWORD(c1), PASSWORD(c1) FROM t1; +OLD_PASSWORD(c1) PASSWORD(c1) +77023ffe214c04ff *82E58A2C08AAFE72C8EB523069CD8ADB33F78F58 +DROP TABLE t1; +End of 5.0 tests diff --git a/mysql-test/t/func_crypt.test b/mysql-test/t/func_crypt.test index cc3cdb9564d2cb51b10c6b7bbce9e14e9d6d1e67..6dedeaa0fefee8d8b9dae39ba57d5219eda68538 100644 --- a/mysql-test/t/func_crypt.test +++ b/mysql-test/t/func_crypt.test @@ -56,3 +56,15 @@ explain extended select password('idkfa '), old_password('idkfa'); select encrypt('1234','_.'); # End of 4.1 tests + +--echo # +--echo # Bug #44767: invalid memory reads in password() and old_password() +--echo # functions +--echo # + +CREATE TABLE t1(c1 MEDIUMBLOB); +INSERT INTO t1 VALUES (REPEAT('a', 1024)); +SELECT OLD_PASSWORD(c1), PASSWORD(c1) FROM t1; +DROP TABLE t1; + +--echo End of 5.0 tests diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 4941f42773175f6211caa537cdd2bbf020c97006..e3fe67f4324f9886ff9f0600c0ae7e509e4689d2 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -1554,16 +1554,17 @@ String *Item_func_password::val_str(String *str) return 0; if (res->length() == 0) return &my_empty_string; - make_scrambled_password(tmp_value, res->c_ptr()); + my_make_scrambled_password(tmp_value, res->ptr(), res->length()); str->set(tmp_value, SCRAMBLED_PASSWORD_CHAR_LENGTH, res->charset()); return str; } -char *Item_func_password::alloc(THD *thd, const char *password) +char *Item_func_password::alloc(THD *thd, const char *password, + size_t pass_len) { char *buff= (char *) thd->alloc(SCRAMBLED_PASSWORD_CHAR_LENGTH+1); if (buff) - make_scrambled_password(buff, password); + my_make_scrambled_password(buff, password, pass_len); return buff; } @@ -1577,16 +1578,17 @@ String *Item_func_old_password::val_str(String *str) return 0; if (res->length() == 0) return &my_empty_string; - make_scrambled_password_323(tmp_value, res->c_ptr()); + my_make_scrambled_password_323(tmp_value, res->ptr(), res->length()); str->set(tmp_value, SCRAMBLED_PASSWORD_CHAR_LENGTH_323, res->charset()); return str; } -char *Item_func_old_password::alloc(THD *thd, const char *password) +char *Item_func_old_password::alloc(THD *thd, const char *password, + size_t pass_len) { char *buff= (char *) thd->alloc(SCRAMBLED_PASSWORD_CHAR_LENGTH_323+1); if (buff) - make_scrambled_password_323(buff, password); + my_make_scrambled_password_323(buff, password, pass_len); return buff; } diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index 1c5346ab0743d3983acd67d30b2d14673ac674db..f2cb4d2d32ad0d6e0caf0acd292204137c0399ba 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -281,7 +281,7 @@ class Item_func_password :public Item_str_func String *val_str(String *str); void fix_length_and_dec() { max_length= SCRAMBLED_PASSWORD_CHAR_LENGTH; } const char *func_name() const { return "password"; } - static char *alloc(THD *thd, const char *password); + static char *alloc(THD *thd, const char *password, size_t pass_len); }; @@ -300,7 +300,7 @@ class Item_func_old_password :public Item_str_func String *val_str(String *str); void fix_length_and_dec() { max_length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323; } const char *func_name() const { return "old_password"; } - static char *alloc(THD *thd, const char *password); + static char *alloc(THD *thd, const char *password, size_t pass_len); }; diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 9768668f103f33f2751349e2c4ecd2f739223df0..55bcd30999d84fee54237e8c15f2d2107d25aff4 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1677,6 +1677,12 @@ extern void turn_parser_debug_on(); SQL_CRYPT *get_crypt_for_frm(void); #endif +/* password.c */ +extern "C" void my_make_scrambled_password_323(char *to, const char *password, + size_t pass_len); +extern "C" void my_make_scrambled_password(char *to, const char *password, + size_t pass_len); + #include "sql_view.h" /* Some inline functions for more speed */ diff --git a/sql/password.c b/sql/password.c index 57ed3e6ab0f817bfb308028279000a352081a3f3..e12074549a4414c5dea9db8a17459028ab506f4b 100644 --- a/sql/password.c +++ b/sql/password.c @@ -137,19 +137,38 @@ void hash_password(ulong *result, const char *password, uint password_len) Create password to be stored in user database from raw string Used for pre-4.1 password handling SYNOPSIS - make_scrambled_password_323() + my_make_scrambled_password_323() to OUT store scrambled password here password IN user-supplied password + pass_len IN length of password string */ -void make_scrambled_password_323(char *to, const char *password) +void my_make_scrambled_password_323(char *to, const char *password, + size_t pass_len) { ulong hash_res[2]; - hash_password(hash_res, password, (uint) strlen(password)); + hash_password(hash_res, password, (uint) pass_len); sprintf(to, "%08lx%08lx", hash_res[0], hash_res[1]); } +/* + Wrapper around my_make_scrambled_password_323() to maintain client lib ABI + compatibility. + In server code usage of my_make_scrambled_password_323() is preferred to + avoid strlen(). + SYNOPSIS + make_scrambled_password_323() + to OUT store scrambled password here + password IN NULL-terminated string with user-supplied password +*/ + +void make_scrambled_password_323(char *to, const char *password) +{ + my_make_scrambled_password_323(to, password, strlen(password)); +} + + /* Scramble string with password. Used in pre 4.1 authentication phase. @@ -383,20 +402,21 @@ my_crypt(char *to, const uchar *s1, const uchar *s2, uint len) The result of this function is used as return value from PASSWORD() and is stored in the database. SYNOPSIS - make_scrambled_password() + my_make_scrambled_password() buf OUT buffer of size 2*SHA1_HASH_SIZE + 2 to store hex string - password IN NULL-terminated password string + password IN password string + pass_len IN length of password string */ -void -make_scrambled_password(char *to, const char *password) +void my_make_scrambled_password(char *to, const char *password, + size_t pass_len) { SHA1_CONTEXT sha1_context; uint8 hash_stage2[SHA1_HASH_SIZE]; mysql_sha1_reset(&sha1_context); /* stage 1: hash password */ - mysql_sha1_input(&sha1_context, (uint8 *) password, (uint) strlen(password)); + mysql_sha1_input(&sha1_context, (uint8 *) password, (uint) pass_len); mysql_sha1_result(&sha1_context, (uint8 *) to); /* stage 2: hash stage1 output */ mysql_sha1_reset(&sha1_context); @@ -409,6 +429,23 @@ make_scrambled_password(char *to, const char *password) } +/* + Wrapper around my_make_scrambled_password() to maintain client lib ABI + compatibility. + In server code usage of my_make_scrambled_password() is preferred to + avoid strlen(). + SYNOPSIS + make_scrambled_password() + buf OUT buffer of size 2*SHA1_HASH_SIZE + 2 to store hex string + password IN NULL-terminated password string +*/ + +void make_scrambled_password(char *to, const char *password) +{ + my_make_scrambled_password(to, password, strlen(password)); +} + + /* Produce an obscure octet sequence from password and random string, recieved from the server. This sequence corresponds to the diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 61020a3eed05c9878b8f9a635d43a723af6182e8..b6a215a2306686723164cacd7ff2ea3d487cc479 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -10092,15 +10092,16 @@ text_or_password: | PASSWORD '(' TEXT_STRING ')' { $$= $3.length ? YYTHD->variables.old_passwords ? - Item_func_old_password::alloc(YYTHD, $3.str) : - Item_func_password::alloc(YYTHD, $3.str) : + Item_func_old_password::alloc(YYTHD, $3.str, $3.length) : + Item_func_password::alloc(YYTHD, $3.str, $3.length) : $3.str; if ($$ == NULL) MYSQL_YYABORT; } | OLD_PASSWORD '(' TEXT_STRING ')' { - $$= $3.length ? Item_func_old_password::alloc(YYTHD, $3.str) : + $$= $3.length ? Item_func_old_password::alloc(YYTHD, $3.str, + $3.length) : $3.str; if ($$ == NULL) MYSQL_YYABORT; @@ -10545,7 +10546,7 @@ grant_user: (char *) YYTHD->alloc(SCRAMBLED_PASSWORD_CHAR_LENGTH_323+1); if (buff == NULL) MYSQL_YYABORT; - make_scrambled_password_323(buff, $4.str); + my_make_scrambled_password_323(buff, $4.str, $4.length); $1->password.str= buff; $1->password.length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323; } @@ -10555,7 +10556,7 @@ grant_user: (char *) YYTHD->alloc(SCRAMBLED_PASSWORD_CHAR_LENGTH+1); if (buff == NULL) MYSQL_YYABORT; - make_scrambled_password(buff, $4.str); + my_make_scrambled_password(buff, $4.str, $4.length); $1->password.str= buff; $1->password.length= SCRAMBLED_PASSWORD_CHAR_LENGTH; }