Commit 21e6836b authored by unknown's avatar unknown

Fix for BUG#16899: Possible buffer overflow in handling of DEFINER-clause

    
User name (host name) has limit on length. The server code relies on these
limits when storing the names. The problem was that sometimes these limits
were not checked properly, so that could lead to buffer overflow.
  
The fix is to check length of user/host name in parser and if string is too
long, throw an error.


mysql-test/r/grant.result:
  Updated result file.
mysql-test/r/sp.result:
  Updated result file.
mysql-test/r/trigger.result:
  Updated result file.
mysql-test/r/view.result:
  Updated result file.
mysql-test/t/grant.test:
  Added test for BUG#16899.
mysql-test/t/sp.test:
  Added test for BUG#16899.
mysql-test/t/trigger.test:
  Added test for BUG#16899.
mysql-test/t/view.test:
  Added test for BUG#16899.
sql/mysql_priv.h:
  Added prototype for new function.
sql/sql_acl.cc:
  Remove outdated checks.
sql/sql_parse.cc:
  Add a new function for checking string length.
sql/share/errmsg.txt:
  Added new resources.
sql/sql_yacc.yy:
  Check length of user/host name.
parent 70ad92dc
...@@ -867,3 +867,27 @@ insert into mysql.user select * from t2; ...@@ -867,3 +867,27 @@ insert into mysql.user select * from t2;
flush privileges; flush privileges;
drop table t2; drop table t2;
drop table t1; drop table t1;
GRANT CREATE ON mysqltest.* TO 1234567890abcdefGHIKL@localhost;
ERROR HY000: String '1234567890abcdefGHIKL' is too long for user name (should be no longer than 16)
GRANT CREATE ON mysqltest.* TO some_user_name@1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY;
ERROR HY000: String '1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY' is too long for host name (should be no longer than 60)
REVOKE CREATE ON mysqltest.* FROM 1234567890abcdefGHIKL@localhost;
ERROR HY000: String '1234567890abcdefGHIKL' is too long for user name (should be no longer than 16)
REVOKE CREATE ON mysqltest.* FROM some_user_name@1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY;
ERROR HY000: String '1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY' is too long for host name (should be no longer than 60)
GRANT CREATE ON t1 TO 1234567890abcdefGHIKL@localhost;
ERROR HY000: String '1234567890abcdefGHIKL' is too long for user name (should be no longer than 16)
GRANT CREATE ON t1 TO some_user_name@1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY;
ERROR HY000: String '1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY' is too long for host name (should be no longer than 60)
REVOKE CREATE ON t1 FROM 1234567890abcdefGHIKL@localhost;
ERROR HY000: String '1234567890abcdefGHIKL' is too long for user name (should be no longer than 16)
REVOKE CREATE ON t1 FROM some_user_name@1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY;
ERROR HY000: String '1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY' is too long for host name (should be no longer than 60)
GRANT EXECUTE ON PROCEDURE p1 TO 1234567890abcdefGHIKL@localhost;
ERROR HY000: String '1234567890abcdefGHIKL' is too long for user name (should be no longer than 16)
GRANT EXECUTE ON PROCEDURE p1 TO some_user_name@1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY;
ERROR HY000: String '1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY' is too long for host name (should be no longer than 60)
REVOKE EXECUTE ON PROCEDURE p1 FROM 1234567890abcdefGHIKL@localhost;
ERROR HY000: String '1234567890abcdefGHIKL' is too long for user name (should be no longer than 16)
REVOKE EXECUTE ON PROCEDURE t1 FROM some_user_name@1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY;
ERROR HY000: String '1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY' is too long for host name (should be no longer than 60)
...@@ -5072,4 +5072,17 @@ a ...@@ -5072,4 +5072,17 @@ a
1 1
use test| use test|
drop table t3| drop table t3|
DROP PROCEDURE IF EXISTS bug16899_p1|
DROP FUNCTION IF EXISTS bug16899_f1|
CREATE DEFINER=1234567890abcdefGHIKL@localhost PROCEDURE bug16899_p1()
BEGIN
SET @a = 1;
END|
ERROR HY000: String '1234567890abcdefGHIKL' is too long for user name (should be no longer than 16)
CREATE DEFINER=some_user_name@1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY
FUNCTION bug16899_f1() RETURNS INT
BEGIN
RETURN 1;
END|
ERROR HY000: String '1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY' is too long for host name (should be no longer than 60)
drop table t1,t2; drop table t1,t2;
...@@ -1089,4 +1089,17 @@ begin ...@@ -1089,4 +1089,17 @@ begin
set @a:= 1; set @a:= 1;
end| end|
ERROR HY000: Triggers can not be created on system tables ERROR HY000: Triggers can not be created on system tables
use test|
DROP TABLE IF EXISTS t1;
DROP TABLE IF EXISTS t2;
CREATE TABLE t1(c INT);
CREATE TABLE t2(c INT);
CREATE DEFINER=1234567890abcdefGHIKL@localhost
TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW SET @a = 1;
ERROR HY000: String '1234567890abcdefGHIKL' is too long for user name (should be no longer than 16)
CREATE DEFINER=some_user_name@1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY
TRIGGER t2_bi BEFORE INSERT ON t2 FOR EACH ROW SET @a = 2;
ERROR HY000: String '1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY' is too long for host name (should be no longer than 60)
DROP TABLE t1;
DROP TABLE t2;
End of 5.0 tests End of 5.0 tests
...@@ -2736,3 +2736,14 @@ m e ...@@ -2736,3 +2736,14 @@ m e
1 b 1 b
DROP VIEW v1; DROP VIEW v1;
DROP TABLE IF EXISTS t1,t2; DROP TABLE IF EXISTS t1,t2;
DROP TABLE IF EXISTS t1;
DROP VIEW IF EXISTS v1;
DROP VIEW IF EXISTS v2;
CREATE TABLE t1(a INT, b INT);
CREATE DEFINER=1234567890abcdefGHIKL@localhost
VIEW v1 AS SELECT a FROM t1;
ERROR HY000: String '1234567890abcdefGHIKL' is too long for user name (should be no longer than 16)
CREATE DEFINER=some_user_name@1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY
VIEW v2 AS SELECT b FROM t1;
ERROR HY000: String '1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY' is too long for host name (should be no longer than 60)
DROP TABLE t1;
...@@ -681,3 +681,52 @@ drop table t2; ...@@ -681,3 +681,52 @@ drop table t2;
drop table t1; drop table t1;
#
# Test for BUG#16899: Possible buffer overflow in handling of DEFINER-clause.
#
# These checks are intended to ensure that appropriate errors are risen when
# illegal user name or hostname is specified in user-clause of GRANT/REVOKE
# statements.
#
# Working with database-level privileges.
--error ER_WRONG_STRING_LENGTH
GRANT CREATE ON mysqltest.* TO 1234567890abcdefGHIKL@localhost;
--error ER_WRONG_STRING_LENGTH
GRANT CREATE ON mysqltest.* TO some_user_name@1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY;
--error ER_WRONG_STRING_LENGTH
REVOKE CREATE ON mysqltest.* FROM 1234567890abcdefGHIKL@localhost;
--error ER_WRONG_STRING_LENGTH
REVOKE CREATE ON mysqltest.* FROM some_user_name@1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY;
# Working with table-level privileges.
--error ER_WRONG_STRING_LENGTH
GRANT CREATE ON t1 TO 1234567890abcdefGHIKL@localhost;
--error ER_WRONG_STRING_LENGTH
GRANT CREATE ON t1 TO some_user_name@1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY;
--error ER_WRONG_STRING_LENGTH
REVOKE CREATE ON t1 FROM 1234567890abcdefGHIKL@localhost;
--error ER_WRONG_STRING_LENGTH
REVOKE CREATE ON t1 FROM some_user_name@1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY;
# Working with routine-level privileges.
--error ER_WRONG_STRING_LENGTH
GRANT EXECUTE ON PROCEDURE p1 TO 1234567890abcdefGHIKL@localhost;
--error ER_WRONG_STRING_LENGTH
GRANT EXECUTE ON PROCEDURE p1 TO some_user_name@1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY;
--error ER_WRONG_STRING_LENGTH
REVOKE EXECUTE ON PROCEDURE p1 FROM 1234567890abcdefGHIKL@localhost;
--error ER_WRONG_STRING_LENGTH
REVOKE EXECUTE ON PROCEDURE t1 FROM some_user_name@1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY;
...@@ -5987,6 +5987,32 @@ select * from (select 1 as a) as t1 natural join (select * from test.t3) as t2| ...@@ -5987,6 +5987,32 @@ select * from (select 1 as a) as t1 natural join (select * from test.t3) as t2|
use test| use test|
drop table t3| drop table t3|
#
# Test for BUG#16899: Possible buffer overflow in handling of DEFINER-clause.
#
# Prepare.
--disable_warnings
DROP PROCEDURE IF EXISTS bug16899_p1|
DROP FUNCTION IF EXISTS bug16899_f1|
--enable_warnings
--error ER_WRONG_STRING_LENGTH
CREATE DEFINER=1234567890abcdefGHIKL@localhost PROCEDURE bug16899_p1()
BEGIN
SET @a = 1;
END|
--error ER_WRONG_STRING_LENGTH
CREATE DEFINER=some_user_name@1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY
FUNCTION bug16899_f1() RETURNS INT
BEGIN
RETURN 1;
END|
# #
# BUG#NNNN: New bug synopsis # BUG#NNNN: New bug synopsis
# #
......
...@@ -1301,6 +1301,36 @@ create trigger wont_work after update on event for each row ...@@ -1301,6 +1301,36 @@ create trigger wont_work after update on event for each row
begin begin
set @a:= 1; set @a:= 1;
end| end|
use test|
delimiter ;| delimiter ;|
#
# Test for BUG#16899: Possible buffer overflow in handling of DEFINER-clause.
#
# Prepare.
--disable_warnings
DROP TABLE IF EXISTS t1;
DROP TABLE IF EXISTS t2;
--enable_warnings
CREATE TABLE t1(c INT);
CREATE TABLE t2(c INT);
--error ER_WRONG_STRING_LENGTH
CREATE DEFINER=1234567890abcdefGHIKL@localhost
TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW SET @a = 1;
--error ER_WRONG_STRING_LENGTH
CREATE DEFINER=some_user_name@1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY
TRIGGER t2_bi BEFORE INSERT ON t2 FOR EACH ROW SET @a = 2;
# Cleanup.
DROP TABLE t1;
DROP TABLE t2;
--echo End of 5.0 tests --echo End of 5.0 tests
...@@ -2596,3 +2596,30 @@ SELECT * FROM t2; ...@@ -2596,3 +2596,30 @@ SELECT * FROM t2;
DROP VIEW v1; DROP VIEW v1;
DROP TABLE IF EXISTS t1,t2; DROP TABLE IF EXISTS t1,t2;
#
# Test for BUG#16899: Possible buffer overflow in handling of DEFINER-clause.
#
# Prepare.
--disable_warnings
DROP TABLE IF EXISTS t1;
DROP VIEW IF EXISTS v1;
DROP VIEW IF EXISTS v2;
--enable_warnings
CREATE TABLE t1(a INT, b INT);
--error ER_WRONG_STRING_LENGTH
CREATE DEFINER=1234567890abcdefGHIKL@localhost
VIEW v1 AS SELECT a FROM t1;
--error ER_WRONG_STRING_LENGTH
CREATE DEFINER=some_user_name@1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY
VIEW v2 AS SELECT b FROM t1;
# Cleanup.
DROP TABLE t1;
...@@ -537,6 +537,7 @@ int append_query_string(CHARSET_INFO *csinfo, ...@@ -537,6 +537,7 @@ int append_query_string(CHARSET_INFO *csinfo,
void get_default_definer(THD *thd, LEX_USER *definer); void get_default_definer(THD *thd, LEX_USER *definer);
LEX_USER *create_default_definer(THD *thd); LEX_USER *create_default_definer(THD *thd);
LEX_USER *create_definer(THD *thd, LEX_STRING *user_name, LEX_STRING *host_name); LEX_USER *create_definer(THD *thd, LEX_STRING *user_name, LEX_STRING *host_name);
bool check_string_length(LEX_STRING *str, const char *err_msg, uint max_length);
enum enum_mysql_completiontype { enum enum_mysql_completiontype {
ROLLBACK_RELEASE=-2, ROLLBACK=1, ROLLBACK_AND_CHAIN=7, ROLLBACK_RELEASE=-2, ROLLBACK=1, ROLLBACK_AND_CHAIN=7,
......
...@@ -5621,3 +5621,9 @@ ER_TABLE_CANT_HANDLE_SPKEYS ...@@ -5621,3 +5621,9 @@ ER_TABLE_CANT_HANDLE_SPKEYS
eng "The used table type doesn't support SPATIAL indexes" eng "The used table type doesn't support SPATIAL indexes"
ER_NO_TRIGGERS_ON_SYSTEM_SCHEMA ER_NO_TRIGGERS_ON_SYSTEM_SCHEMA
eng "Triggers can not be created on system tables" eng "Triggers can not be created on system tables"
ER_USERNAME
eng "user name"
ER_HOSTNAME
eng "host name"
ER_WRONG_STRING_LENGTH
eng "String '%-.70s' is too long for %s (should be no longer than %d)"
...@@ -2895,14 +2895,7 @@ bool mysql_table_grant(THD *thd, TABLE_LIST *table_list, ...@@ -2895,14 +2895,7 @@ bool mysql_table_grant(THD *thd, TABLE_LIST *table_list,
{ {
int error; int error;
GRANT_TABLE *grant_table; GRANT_TABLE *grant_table;
if (Str->host.length > HOSTNAME_LENGTH ||
Str->user.length > USERNAME_LENGTH)
{
my_message(ER_GRANT_WRONG_HOST_OR_USER, ER(ER_GRANT_WRONG_HOST_OR_USER),
MYF(0));
result= TRUE;
continue;
}
/* Create user if needed */ /* Create user if needed */
error=replace_user_table(thd, tables[0].table, *Str, error=replace_user_table(thd, tables[0].table, *Str,
0, revoke_grant, create_new_users, 0, revoke_grant, create_new_users,
...@@ -3102,15 +3095,7 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc, ...@@ -3102,15 +3095,7 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc,
{ {
int error; int error;
GRANT_NAME *grant_name; GRANT_NAME *grant_name;
if (Str->host.length > HOSTNAME_LENGTH ||
Str->user.length > USERNAME_LENGTH)
{
if (!no_error)
my_message(ER_GRANT_WRONG_HOST_OR_USER, ER(ER_GRANT_WRONG_HOST_OR_USER),
MYF(0));
result= TRUE;
continue;
}
/* Create user if needed */ /* Create user if needed */
error=replace_user_table(thd, tables[0].table, *Str, error=replace_user_table(thd, tables[0].table, *Str,
0, revoke_grant, create_new_users, 0, revoke_grant, create_new_users,
...@@ -3231,14 +3216,6 @@ bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list, ...@@ -3231,14 +3216,6 @@ bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list,
int result=0; int result=0;
while ((Str = str_list++)) while ((Str = str_list++))
{ {
if (Str->host.length > HOSTNAME_LENGTH ||
Str->user.length > USERNAME_LENGTH)
{
my_message(ER_GRANT_WRONG_HOST_OR_USER, ER(ER_GRANT_WRONG_HOST_OR_USER),
MYF(0));
result= -1;
continue;
}
if (replace_user_table(thd, tables[0].table, *Str, if (replace_user_table(thd, tables[0].table, *Str,
(!db ? rights : 0), revoke_grant, create_new_users, (!db ? rights : 0), revoke_grant, create_new_users,
test(thd->variables.sql_mode & test(thd->variables.sql_mode &
...@@ -4129,14 +4106,6 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user) ...@@ -4129,14 +4106,6 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user)
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
} }
if (lex_user->host.length > HOSTNAME_LENGTH ||
lex_user->user.length > USERNAME_LENGTH)
{
my_message(ER_GRANT_WRONG_HOST_OR_USER, ER(ER_GRANT_WRONG_HOST_OR_USER),
MYF(0));
DBUG_RETURN(TRUE);
}
rw_rdlock(&LOCK_grant); rw_rdlock(&LOCK_grant);
VOID(pthread_mutex_lock(&acl_cache->lock)); VOID(pthread_mutex_lock(&acl_cache->lock));
......
...@@ -7499,3 +7499,29 @@ LEX_USER *create_definer(THD *thd, LEX_STRING *user_name, LEX_STRING *host_name) ...@@ -7499,3 +7499,29 @@ LEX_USER *create_definer(THD *thd, LEX_STRING *user_name, LEX_STRING *host_name)
return definer; return definer;
} }
/*
Check that length of a string does not exceed some limit.
SYNOPSIS
check_string_length()
str string to be checked
err_msg error message to be displayed if the string is too long
max_length max length
RETURN
FALSE the passed string is not longer than max_length
TRUE the passed string is longer than max_length
*/
bool check_string_length(LEX_STRING *str, const char *err_msg,
uint max_length)
{
if (str->length <= max_length)
return FALSE;
my_error(ER_WRONG_STRING_LENGTH, MYF(0), str->str, err_msg, max_length);
return TRUE;
}
...@@ -7479,6 +7479,9 @@ user: ...@@ -7479,6 +7479,9 @@ user:
$$->user = $1; $$->user = $1;
$$->host.str= (char *) "%"; $$->host.str= (char *) "%";
$$->host.length= 1; $$->host.length= 1;
if (check_string_length(&$$->user, ER(ER_USERNAME), USERNAME_LENGTH))
YYABORT;
} }
| ident_or_text '@' ident_or_text | ident_or_text '@' ident_or_text
{ {
...@@ -7486,6 +7489,11 @@ user: ...@@ -7486,6 +7489,11 @@ user:
if (!($$=(LEX_USER*) thd->alloc(sizeof(st_lex_user)))) if (!($$=(LEX_USER*) thd->alloc(sizeof(st_lex_user))))
YYABORT; YYABORT;
$$->user = $1; $$->host=$3; $$->user = $1; $$->host=$3;
if (check_string_length(&$$->user, ER(ER_USERNAME), USERNAME_LENGTH) ||
check_string_length(&$$->host, ER(ER_HOSTNAME),
HOSTNAME_LENGTH))
YYABORT;
} }
| CURRENT_USER optional_braces | CURRENT_USER optional_braces
{ {
...@@ -8966,15 +8974,9 @@ definer: ...@@ -8966,15 +8974,9 @@ definer:
*/ */
YYTHD->lex->definer= 0; YYTHD->lex->definer= 0;
} }
| DEFINER_SYM EQ CURRENT_USER optional_braces | DEFINER_SYM EQ user
{ {
if (! (YYTHD->lex->definer= create_default_definer(YYTHD))) YYTHD->lex->definer= $3;
YYABORT;
}
| DEFINER_SYM EQ ident_or_text '@' ident_or_text
{
if (!(YYTHD->lex->definer= create_definer(YYTHD, &$3, &$5)))
YYABORT;
} }
; ;
......
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