Commit 877d60a2 authored by Alexey Kopytov's avatar Alexey Kopytov

Bug #44767: invalid memory reads in password() and

            old_password() functions   
The PASSWORD() and OLD_PASSWORD() functions could lead to   
memory reads outside of an internal buffer when used with BLOB   
arguments.   
  
String::c_ptr() assumes there is at least one extra byte  
in the internally allocated buffer when adding the trailing  
'\0'.  This, however, may not be the case when a String object  
was initialized with externally allocated buffer.  
  
The bug was fixed by adding an additional "length" argument to  
make_scrambled_password_323() and make_scrambled_password() in  
order to avoid String::c_ptr() calls for  
PASSWORD()/OLD_PASSWORD().  
  
However, since the make_scrambled_password[_323] functions are  
a part of the client library ABI, the functions with the new  
interfaces were implemented with the 'my_' prefix in their  
names, with the old functions changed to be wrappers around  
the new ones to maintain interface compatibility.  

mysql-test/r/func_crypt.result:
  Added a test case for bug #44767.
mysql-test/t/func_crypt.test:
  Added a test case for bug #44767.
sql/item_strfunc.cc:
  Use the new my_make_scrambled_password*() to avoid 
  String::c_ptr().
sql/item_strfunc.h:
  Changed Item_func[_old]_password::alloc() interfaces so that
  we can use the new my_make_scrambled_password*() functions.
sql/mysql_priv.h:
  Added declarations for the new my_make_scrambled_password*() 
  functions.
sql/password.c:
  Added new my_make_scrambled_password*() functions with an
  additional "length" argument. Changed ones to be wrappers
  around the new ones to maintain interface compatibility.
sql/sql_yacc.yy:
  Utilize the new password hashing functions with additional length
  argument.
parent 355c28a5
...@@ -95,3 +95,14 @@ Note 1003 select password(_latin1'idkfa ') AS `password('idkfa ')`,old_password( ...@@ -95,3 +95,14 @@ Note 1003 select password(_latin1'idkfa ') AS `password('idkfa ')`,old_password(
select encrypt('1234','_.'); select encrypt('1234','_.');
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
...@@ -56,3 +56,15 @@ explain extended select password('idkfa '), old_password('idkfa'); ...@@ -56,3 +56,15 @@ explain extended select password('idkfa '), old_password('idkfa');
select encrypt('1234','_.'); select encrypt('1234','_.');
# End of 4.1 tests # 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
...@@ -1554,16 +1554,17 @@ String *Item_func_password::val_str(String *str) ...@@ -1554,16 +1554,17 @@ String *Item_func_password::val_str(String *str)
return 0; return 0;
if (res->length() == 0) if (res->length() == 0)
return &my_empty_string; 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()); str->set(tmp_value, SCRAMBLED_PASSWORD_CHAR_LENGTH, res->charset());
return str; 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); char *buff= (char *) thd->alloc(SCRAMBLED_PASSWORD_CHAR_LENGTH+1);
if (buff) if (buff)
make_scrambled_password(buff, password); my_make_scrambled_password(buff, password, pass_len);
return buff; return buff;
} }
...@@ -1577,16 +1578,17 @@ String *Item_func_old_password::val_str(String *str) ...@@ -1577,16 +1578,17 @@ String *Item_func_old_password::val_str(String *str)
return 0; return 0;
if (res->length() == 0) if (res->length() == 0)
return &my_empty_string; 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()); str->set(tmp_value, SCRAMBLED_PASSWORD_CHAR_LENGTH_323, res->charset());
return str; 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); char *buff= (char *) thd->alloc(SCRAMBLED_PASSWORD_CHAR_LENGTH_323+1);
if (buff) if (buff)
make_scrambled_password_323(buff, password); my_make_scrambled_password_323(buff, password, pass_len);
return buff; return buff;
} }
......
...@@ -281,7 +281,7 @@ class Item_func_password :public Item_str_func ...@@ -281,7 +281,7 @@ class Item_func_password :public Item_str_func
String *val_str(String *str); String *val_str(String *str);
void fix_length_and_dec() { max_length= SCRAMBLED_PASSWORD_CHAR_LENGTH; } void fix_length_and_dec() { max_length= SCRAMBLED_PASSWORD_CHAR_LENGTH; }
const char *func_name() const { return "password"; } 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 ...@@ -300,7 +300,7 @@ class Item_func_old_password :public Item_str_func
String *val_str(String *str); String *val_str(String *str);
void fix_length_and_dec() { max_length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323; } void fix_length_and_dec() { max_length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323; }
const char *func_name() const { return "old_password"; } 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);
}; };
......
...@@ -1677,6 +1677,12 @@ extern void turn_parser_debug_on(); ...@@ -1677,6 +1677,12 @@ extern void turn_parser_debug_on();
SQL_CRYPT *get_crypt_for_frm(void); SQL_CRYPT *get_crypt_for_frm(void);
#endif #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" #include "sql_view.h"
/* Some inline functions for more speed */ /* Some inline functions for more speed */
......
...@@ -137,19 +137,38 @@ void hash_password(ulong *result, const char *password, uint password_len) ...@@ -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 Create password to be stored in user database from raw string
Used for pre-4.1 password handling Used for pre-4.1 password handling
SYNOPSIS SYNOPSIS
make_scrambled_password_323() my_make_scrambled_password_323()
to OUT store scrambled password here to OUT store scrambled password here
password IN user-supplied password 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]; 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]); 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. Scramble string with password.
Used in pre 4.1 authentication phase. Used in pre 4.1 authentication phase.
...@@ -383,20 +402,21 @@ my_crypt(char *to, const uchar *s1, const uchar *s2, uint len) ...@@ -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 The result of this function is used as return value from PASSWORD() and
is stored in the database. is stored in the database.
SYNOPSIS SYNOPSIS
make_scrambled_password() my_make_scrambled_password()
buf OUT buffer of size 2*SHA1_HASH_SIZE + 2 to store hex string 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 void my_make_scrambled_password(char *to, const char *password,
make_scrambled_password(char *to, const char *password) size_t pass_len)
{ {
SHA1_CONTEXT sha1_context; SHA1_CONTEXT sha1_context;
uint8 hash_stage2[SHA1_HASH_SIZE]; uint8 hash_stage2[SHA1_HASH_SIZE];
mysql_sha1_reset(&sha1_context); mysql_sha1_reset(&sha1_context);
/* stage 1: hash password */ /* 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); mysql_sha1_result(&sha1_context, (uint8 *) to);
/* stage 2: hash stage1 output */ /* stage 2: hash stage1 output */
mysql_sha1_reset(&sha1_context); mysql_sha1_reset(&sha1_context);
...@@ -409,6 +429,23 @@ make_scrambled_password(char *to, const char *password) ...@@ -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 Produce an obscure octet sequence from password and random
string, recieved from the server. This sequence corresponds to the string, recieved from the server. This sequence corresponds to the
......
...@@ -10092,15 +10092,16 @@ text_or_password: ...@@ -10092,15 +10092,16 @@ text_or_password:
| PASSWORD '(' TEXT_STRING ')' | PASSWORD '(' TEXT_STRING ')'
{ {
$$= $3.length ? YYTHD->variables.old_passwords ? $$= $3.length ? YYTHD->variables.old_passwords ?
Item_func_old_password::alloc(YYTHD, $3.str) : Item_func_old_password::alloc(YYTHD, $3.str, $3.length) :
Item_func_password::alloc(YYTHD, $3.str) : Item_func_password::alloc(YYTHD, $3.str, $3.length) :
$3.str; $3.str;
if ($$ == NULL) if ($$ == NULL)
MYSQL_YYABORT; MYSQL_YYABORT;
} }
| OLD_PASSWORD '(' TEXT_STRING ')' | 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; $3.str;
if ($$ == NULL) if ($$ == NULL)
MYSQL_YYABORT; MYSQL_YYABORT;
...@@ -10545,7 +10546,7 @@ grant_user: ...@@ -10545,7 +10546,7 @@ grant_user:
(char *) YYTHD->alloc(SCRAMBLED_PASSWORD_CHAR_LENGTH_323+1); (char *) YYTHD->alloc(SCRAMBLED_PASSWORD_CHAR_LENGTH_323+1);
if (buff == NULL) if (buff == NULL)
MYSQL_YYABORT; 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.str= buff;
$1->password.length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323; $1->password.length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323;
} }
...@@ -10555,7 +10556,7 @@ grant_user: ...@@ -10555,7 +10556,7 @@ grant_user:
(char *) YYTHD->alloc(SCRAMBLED_PASSWORD_CHAR_LENGTH+1); (char *) YYTHD->alloc(SCRAMBLED_PASSWORD_CHAR_LENGTH+1);
if (buff == NULL) if (buff == NULL)
MYSQL_YYABORT; MYSQL_YYABORT;
make_scrambled_password(buff, $4.str); my_make_scrambled_password(buff, $4.str, $4.length);
$1->password.str= buff; $1->password.str= buff;
$1->password.length= SCRAMBLED_PASSWORD_CHAR_LENGTH; $1->password.length= SCRAMBLED_PASSWORD_CHAR_LENGTH;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment