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(
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
......@@ -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
......@@ -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;
}
......
......@@ -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);
};
......
......@@ -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 */
......
......@@ -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
......
......@@ -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;
}
......
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