Bug #94394 | Absence of mysql.user leads to auto-apply of --skip-grant-tables | ||
---|---|---|---|
Submitted: | 19 Feb 2019 14:10 | Modified: | 26 Feb 2019 18:47 |
Reporter: | Ceri Williams | Email Updates: | |
Status: | Closed | Impact on me: | |
Category: | MySQL Server: Security: Privileges | Severity: | S2 (Serious) |
Version: | 8.0.14 | OS: | Any |
Assigned to: | CPU Architecture: | Any |
[19 Feb 2019 14:10]
Ceri Williams
[19 Feb 2019 14:13]
Ceri Williams
Sorry, forgot to note that in the example you need to remove "--binlog_encryption=1" from the compose file too before rerunning, or resolve: Unable to recover binlog encryption master key, please check if keyring plugin is loaded
[20 Feb 2019 9:59]
Frederic Descamps
Hi Ceri, Just a comment: if you are doing --initialize, it means you don't have any data on the system isn't it ? you are just creating the system tables... so if it breaks in the middle, I don't really see a problem of having access to a empty, non stable db. But I might be wrong...
[20 Feb 2019 10:04]
Georgi Kodinov
Thank you for the reasonable feature request. Currently --initialize is not an atomic operation. If the server fails mid-flight the results are unpredictable. So not a lot of use IMHO to shuffle initialization sequence in some way as it'll just change the way the server behaves. The good part is that --initialize doesn't open any communication channels and does shut the server down when complete. Thus I'd suggest checking the state of --initialize before putting the server online on the resulting directory as a workaround until we have an atomic --initialize process.
[20 Feb 2019 11:59]
Ceri Williams
Thanks for the feedback. > if you are doing --initialize, it means you don't have any data on the system isn't it ? you are just creating the system tables... so if it breaks in the middle, I don't really see a problem of having access to a empty, non stable db. Initialisation is kindly done for you and so not necessarily obvious to the unaware user. It is possible to make the server a slave and maintain the issue, admittedly yo-u should notice this although the error that you get at first is misleading. $ mysqldump --all-databases --ignore-table=mysql.user --single-transaction --master-data=1 will produce ERROR 1794 (HY000) at line 33: Slave is not configured or failed to initialize properly. You must at least set --server-id to enable either a master or a slave. Additional error messages can be found in the MySQL error log. If you run with --master-data=2 you obviously don't get the issue. Something like the following allows this: $ mysqldump --all-databases --ignore-table=mysql.user --single-transaction --master-data=2 | tee /tmp/dump.sql | mysql -h 10.2.1.4 -B Some people like to maintain grants locally, so could ignore this table plus the related tables, even if not best practice. $ pt-heartbeat --user=root --ask-pass --host=10.2.1.2 --update Enter password: $ pt-heartbeat --host=10.2.1.4 --check --master-server-id=2 0.00 Also, you could have this as a standalone instance and write data. Once again, you would have needed to ignore the fact that you have not created a dedicated user. It should be noted that this is a consistent issue with 8.0 and does not occur with 5.7, or at least it not reproducible with the same test; 5.7 will fail and then initialize correctly on the second start. > Thus I'd suggest checking the state of --initialize before putting the server online on the resulting directory as a workaround until we have an atomic --initialize process. A less experienced user my not realise the exact issue (or find the cause) and just see the message such as "unknown variable 'binlog_encryption=1'." - they fix that and it starts. As noted above, 5.7 seems to behave in an expected fashion if you set an unknown variable in the config. +1 to an atomic --initiliaze though
[20 Feb 2019 12:22]
Ceri Williams
FTR the use of Docker here is just to make testing easy - the issue exists with a normal install. Also, from a trivial investigation the issue seems to stem from the change from MyISAM to InnoDB. If you remove the files for the mysql.user table in 5.7 it will abort as it can't lock the user table: 2019-02-20T12:04:18.324067Z 0 [ERROR] Fatal error: Can't open and lock privilege tables: Table 'mysql.user' doesn't exist 2019-02-20T12:04:18.324092Z 0 [ERROR] Fatal error: Failed to initialize ACL/grant/time zones structures or failed to remove temporary table files. 2019-02-20T12:04:18.324148Z 0 [ERROR] Aborting
[20 Feb 2019 13:00]
Sveta Smirnova
test case for MTR
Attachment: bug94394.test (application/octet-stream, text), 795 bytes.
[20 Feb 2019 13:06]
Sveta Smirnova
This bug is not about --initialize option, but about the fact that the server can successfully start and anyone can access user tables even if table mysql.user does not exist. See attached test case for MTR. Note it will not pass check-testcases test due to missed system tables. Run MTR with disabled option --check-testcases. Output of MTR test case: show tables from mysql like 'user'; Tables_in_mysql (user) user drop table mysql.user; select current_user(); current_user() root@localhost create table test.very_important_table( id int not null primary key, credit_card_num char(16), credit_card_owner varchar(256), credit_card_expire_month char(2), credit_card_expire_year char(2), credit_card_cvv char(3)) engine=innodb; insert into test.very_important_table values(1, '1234123412341234', 'Sveta Smirnova', '02', '20', '123'); "Restarting MySQL server" # restart "MySQL restarted" show tables from mysql like 'user'; Tables_in_mysql (user) select current_user(); current_user() skip-grants user@skip-grants host select current_user(); current_user() skip-grants user@skip-grants host select * from test.very_important_table; id credit_card_num credit_card_owner credit_card_expire_month credit_card_expire_year credit_card_cvv 1 1234123412341234 Sveta Smirnova 02 20 123 drop table test.very_important_table;
[21 Feb 2019 11:41]
Ceri Williams
I'm updating the synopsis to better reflect the issue and its severity. A perfectly healthy server can be turned into one that you wouldn't want running. To reiterate Sveta's test-case: mysql> use mysql mysql> rename table user to disabled_user; mysql> restart; mysql> select current_user(); ERROR 2006 (HY000): MySQL server has gone away mysql> select current_user(); skip-grants user@skip-grants host
[26 Feb 2019 18:47]
Paul DuBois
Posted by developer: Fixed in 8.0.16. Previously, if the grant tables were corrupted, the MySQL server wrote a message to the error log but continued as if the --skip-grant-tables option had been specified. This resulted in the server operating in an unexpected state unless --skip-grant-tables had in fact been specified. Now, the server stops after writing a message to the error log unless started with --skip-grant-tables. (Starting the server with that option enables you to connect to perform diagnostic operations.)