Description: A very large database name causes buffer
overflow in functions acl_get() and
check_grant_db() in sql_acl.cc. It happens
due to an unguarded string copy operation.
This puts required sanity checks before
copying db string to destination buffer.
PRIVILEGES
Description: (user,host) pair from security context is used
privilege checking at the time of granting or
revoking proxy privileges. This creates problem
when server is started with
--skip-name-resolve option because host will not
contain any value. Checks should be dependent on
consistent values regardless the way server is
started. Further, privilege check should use
(priv_user,priv_host) pair rather than values
obtained from inbound connection because
this pair represents the correct account context
obtained from mysql.user table.
CONSISTENT SNAPSHOT OPTION
A transaction is started with a consistent snapshot. After
the transaction is started new indexes are added to the
table. Now when we issue an update statement, the optimizer
chooses an index. When the index scan is being initialized
via ha_innobase::change_active_index(), InnoDB reports
the error code HA_ERR_TABLE_DEF_CHANGED, with message
stating that "insufficient history for index".
This error message is propagated up to the SQL layer. But
the my_error() api is never called. The statement level
diagnostics area is not updated with the correct error
status (it remains in Diagnostics_area::DA_EMPTY).
Hence the following check in the Protocol::end_statement()
fails.
516 case Diagnostics_area::DA_EMPTY:
517 default:
518 DBUG_ASSERT(0);
519 error= send_ok(thd->server_status, 0, 0, 0, NULL);
520 break;
The fix is to backport the fix of bugs 14365043, 11761652
and 11746399.
14365043 PROTOCOL::END_STATEMENT(): ASSERTION `0' FAILED
11761652 HA_RND_INIT() RESULT CODE NOT CHECKED
11746399 RETURN VALUES OF HA_INDEX_INIT() AND INDEX_INIT() IGNORED
rb://1227 approved by guilhem and mattiasj.
BACKGROUND:
In certain situations DROP USER fails to remove all privileges
belonging to user being dropped from in-memory structures.
Current workaround is to do DROP USER twice in scenario below
OR doing FLUSH PRIVILEGES after doing DROP USER.
ANALYSIS:
In MySQL, When we grant some stored routines privileges to a
user they are stored in their respective hash.
When doing DROP USER all the stored routine privilege entries
associated with that user has to be deleted from its respective
hash.
The root cause for this bug is some entries from the hash
are not getting deleted.
The problem is that code that deletes entries from the hash tries
to do so while iterating over it, without taking enough measures
to address the fact that such deletion can reshuffle elements in
the hash. If the user/administrator creates the same user again
he is thrown an error 'Error 1396 ER_CANNOT_USER' from MySQL.
This prompts the user to either do FLUSH PRIVILEGES or do DROP USER
again. This behaviour is not desirable as it is a workaround and
does not solves the problem mentioned above.
FIX:
This bug is fixed by introducing a dynamic array to store the
pointersto all stored routine privilege objects that either have
to be deleted or updated. This is done in 3 steps.
Step 1: Fetching the element from the hash and checking whether
it is to be deleted or updated.
Step 2: Storing the pointer to that privilege object in dynamic array.
Step 3: Traversing the dynamic array to perform the appropriate action
either delete or update.
This is a much cleaner way to delete or update the privilege entries
associated with some user and solves the problem mentioned above.
Also the code has been refactored a bit by introducing an enum
instead of hard coded numbers used for respective dynamic arrays
and hashes in handle_grant_struct() function.
BACKGROUND:
In certain situations DROP USER fails to remove all privileges
belonging to user being dropped from in-memory structures.
Current workaround is to do DROP USER twice in scenario below
OR doing FLUSH PRIVILEGES after doing DROP USER.
ANALYSIS:
In MySQL, When we grant some stored routines privileges to a
user they are stored in their respective hash.
When doing DROP USER all the stored routine privilege entries
associated with that user has to be deleted from its respective
hash.
The root cause for this bug is some entries from the hash
are not getting deleted.
The problem is that code that deletes entries from the hash tries
to do so while iterating over it, without taking enough measures
to address the fact that such deletion can reshuffle elements in
the hash. If the user/administrator creates the same user again
he is thrown an error 'Error 1396 ER_CANNOT_USER' from MySQL.
This prompts the user to either do FLUSH PRIVILEGES or do DROP USER
again. This behaviour is not desirable as it is a workaround and
does not solves the problem mentioned above.
FIX:
This bug is fixed by introducing a dynamic array to store the
pointersto all stored routine privilege objects that either have
to be deleted or updated. This is done in 3 steps.
Step 1: Fetching the element from the hash and checking whether
it is to be deleted or updated.
Step 2: Storing the pointer to that privilege object in dynamic array.
Step 3: Traversing the dynamic array to perform the appropriate action
either delete or update.
This is a much cleaner way to delete or update the privilege entries
associated with some user and solves the problem mentioned above.
Also the code has been refactored a bit by introducing an enum
instead of hard coded numbers used for respective dynamic arrays
and hashes in handle_grant_struct() function.
Analysis:
-------------
If server is started with limit of MAX_CONNECTIONS and
MAX_USER_CONNECTIONS then only MAX_USER_CONNECTIONS of any particular
users can be connected to server and total MAX_CONNECTIONS of client can
be connected to server.
Server maintains a counter for total CONNECTIONS and total CONNECTIONS
from particular user.
Here, MAX_CONNECTIONS of connections are created to server. Out of this
MAX_CONNECTIONS, connections from particular user (say USER1) are
also created. The connections from USER1 is lesser than
MAX_USER_CONNECTIONS. After that there was one more connection request from
USER1. Since USER1 can still create connections as he havent reached
MAX_USER_CONNECTIONS, server increments counter of CONNECTIONS per user.
As server already has MAX_CONNECTIONS of connections, next check to total
CONNECTION count fails. In this case control is returned WITHOUT
decrementing the CONNECTIONS per user. So the counter per user CONNECTIONS goes
on incrementing for each attempt until current connections are closed.
And because of this counter per CONNECTIONS reached MAX_USER_CONNECTIONS.
So, next connections form USER1 user always returns with MAX_USER_CONNECTION
limit error, even when total connection to sever are less than MAX_CONNECTIONS.
Fix:
-------------
This issue is occurred because of not handling counters properly in the
server. Changed the code to handle per user connection counters properly.
sql/sql_insert.cc:
CREATE ... IF NOT EXISTS may do nothing, but
it is still not a failure. don't forget to my_ok it.
******
CREATE ... IF NOT EXISTS may do nothing, but
it is still not a failure. don't forget to my_ok it.
sql/sql_table.cc:
small cleanup
******
small cleanup
One can set @@global.max_user_connections to -1 to block anyone, except SUPER user, to login.
If max_user_connection is 0, one can't change it without a restart (needed to get user connections counting to work correctly)
mysql-test/r/system_mysql_db.result:
Changed max_user_connections to handle negative numbers.
mysql-test/r/user_limits-2.result:
New test case that one can't change max_user_connection if it was 0
mysql-test/r/user_limits.result:
Fixed wrong error messages.
mysql-test/r/variables.result:
Store / restore max_user_connections (needed as there is now a --master.opt file that changes it)
mysql-test/t/subselect_mat_cost-master.opt:
Enable slow query log (as this test found some errors in slow query logging)
mysql-test/t/user_limits-2.test:
New test case that one can't change max_user_connection if it was 0
mysql-test/t/user_limits-master.opt:
Set max_user_connections (as one can't change it if it was 0)
mysql-test/t/user_limits.test:
Test max_user_connections -1
mysql-test/t/variables-master.opt:
Set max_user_connections (as one can't change it if it was 0)
mysql-test/t/variables.test:
Set/restore max_user_connections
scripts/Makefile.am:
Add a text message to mysql_fix_privilege_tables.sql that it's automaticly generated
scripts/mysql_system_tables.sql:
Change max_user_connections to signed
scripts/mysql_system_tables_fix.sql:
Change max_user_connections to signed
sql/item_func.cc:
Change SHOW_INT to be signed.
(Needed for max_user_connections and it's probably a bug that it was not originally signed)
sql/log.cc:
Remove some code that was not needed (All these variables are reset at start of query)
sql/mysql_priv.h:
Made max_user_connections signed.
Added max_user_connections_checking
sql/mysqld.cc:
Added max_user_connections_checking so that we know if max_user_connections was 0 at startup
(Which means that we will not do connection counting for accounts that don't have user resource limits)
Set thd->start_utime at same time as thr_create_utime. (Before start_utime could be < thr_create_utime which lead to wrong query counting)
sql/set_var.cc:
Don't allow one to change 'max_user_connections' if it was 0 at startup.
sql/sql_acl.cc:
Change user_connection counting to be negative.
sql/sql_connect.cc:
If max_user_connections is < 0 then only SUPER user can login.
Fixed wrong variable names for error messages.
Fixed wrong initial value for questions.
Set thd->start_utime and thd->thr_create_utime at startup. Needed to get time_out_user_resource_limits() to work.
sql/sql_show.cc:
SHOW_INT is now negative
sql/sql_yacc.yy:
Support negative values for MAX_USER_CONNECTIONS
sql/structs.h:
Make user connect counting work with signed numbers.
FROM OK PACKET
There's no reliable way (without knowing the protocol variants that each
plugin pair implements) to find out when does the authentication exchange
end.
The server is changed to send all the extra authentication packets that
server plugins need to send prefixed with the \x1 command.
The client-server protocol has left some room for interpretation
which this patch fixes by introducing byte counters and
enforced logic for SSL handshakes.