-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
MDEV-36871 mariadb-backup incremental segfault querying mariadb_backup_history #4112
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: 10.11
Are you sure you want to change the base?
Conversation
|
c4bce03
to
9b875d0
Compare
d9df59d
to
8af87eb
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code looks good to me. Please squash two commits into one and fix the commit header, it should correspond to Jira's ticket header.
I would also propose the following fix to avoid buffer overflow:
--- a/extra/mariabackup/backup_mysql.cc
+++ b/extra/mariabackup/backup_mysql.cc
@@ -610,12 +610,27 @@ select_incremental_lsn_from_history(lsn_t *incremental_lsn)
{
MYSQL_RES *mysql_result;
char query[1000];
- char buf[100];
+ char buf[NAME_LEN*2+3];
+
+ unsigned long opt_incremental_history_name_len=
+ strlen(opt_incremental_history_name);
+ unsigned long opt_incremental_history_uuid_len=
+ strlen(opt_incremental_history_uuid);
+ if (opt_incremental_history_name_len*2 > sizeof(buf))
+ die("Incremental history table name '%s' is too long.",
+ opt_incremental_history_name);
+ if (opt_incremental_history_uuid_len*2 > sizeof(buf))
+ die("Incremental history uuid '%s' is too long.",
+ opt_incremental_history_uuid);
+ if (opt_incremental_history_name && opt_incremental_history_name[0]
+ && opt_incremental_history_uuid && opt_incremental_history_uuid[0])
+ die("It is allowed to use either --incremental-history-name "
+ "or --incremental-history-uuid, but not both.");
if (opt_incremental_history_name) {
mysql_real_escape_string(mysql_connection, buf,
opt_incremental_history_name,
- (unsigned long)strlen(opt_incremental_history_name));
+ opt_incremental_history_name_len);
snprintf(query, sizeof(query),
"SELECT innodb_to_lsn "
"FROM PERCONA_SCHEMA.xtrabackup_history "
@@ -624,11 +639,10 @@ select_incremental_lsn_from_history(lsn_t *incremental_lsn)
"ORDER BY innodb_to_lsn DESC LIMIT 1",
buf);
}
-
- if (opt_incremental_history_uuid) {
+ else if (opt_incremental_history_uuid) {
mysql_real_escape_string(mysql_connection, buf,
opt_incremental_history_uuid,
- (unsigned long)strlen(opt_incremental_history_uuid));
+ opt_incremental_history_uuid_len);
snprintf(query, sizeof(query),
"SELECT innodb_to_lsn "
"FROM PERCONA_SCHEMA.xtrabackup_history "
@@ -638,7 +652,9 @@ select_incremental_lsn_from_history(lsn_t *incremental_lsn)
buf);
}
- mysql_result = xb_mysql_query(mysql_connection, query, true);
+ /* xb_mysql_query(..., ..., true) will die on error, so
+ mysql_result can't be nullptr */
+ mysql_result= xb_mysql_query(mysql_connection, query, true);
ut_ad(mysql_num_fields(mysql_result) == 1);
const MYSQL_ROW row = mysql_fetch_row(mysql_result);
I didn't check and tested the above code.
…p_history Problem: ========= (1) Mariabackup tries to read the history data from mysql.mariadb_backup_history and fails with segfault. Reason is that mariabackup does force innodb_log_checkpoint_now from commit 652f33e(MDEV-30000). Mariabackup sends the "innodb_log_checkpoint_now=1" query to server and reads the result set for the query later in the code because the query may trigger the page thread to flush the pages. But before reading the query result for innodb_log_checkpoint_now=1, mariabackup does execute the select query for the history table (mysql.mariadb_backup_history) and wrongly reads the query result of innodb_log_checkpoint_now. This leads to assertion in mariabackup. (2) The recording of incremental backups has the format as "tar" when mbstream was used. The xb_stream_fmt_t only had XB_STREAM_FMT_NONE and XB_STREAM_FMT_XBSTREAM and hence in the mysql.mariadb_backup_history table the format was recorded as "tar" for the "mbstream" due to the offset in the xb_stream_name array within mariadb-backup. (3) Also under Windows the full path of mariabackup was recorded in the the history. (4) select_incremental_lsn_from_history(): Name of the backup and UUID of the history record variable could lead to buffer overflow while copying the variable value from global variable. Solution: ========= (1) Move the reading of history data from mysql.mariadb_backup_history after reading the result of innodb_log_checkpoint_now=1 query (2) We've removed the "tar" element from the xb_stream_name. As the "xbstream" was never used, the format name is changed to mbstream. As the table needs alteration the "mbstream" appended instead of the unused xbstream in the table. "tar" is left in the enum as the previous recordings are still possible. (3) The Windows path separator is used to store just the executable name as the tool in the mariadb_backup_history table. (4) select_incremental_lsn_from_history(): Check and validate the length of incremental history name and incremental history uuid before copying into temporary buffer Thanks to Daniel black for contributing the code for solution (2) and (3)
8af87eb
to
47416da
Compare
Description
Problem:
Mariabackup tries to read the history data from mysql.mariadb_backup_history and fails with segfault. Reason is that mariabackup does force innodb_log_checkpoint_now from commit 652f33e(MDEV-30000).
Mariabackup sends the "innodb_log_checkpoint_now=1" query to server and reads the result set for the query later in the code because the query may trigger the page thread to flush the pages. But before reading the query result for innodb_log_checkpoint_now=1, mariabackup does execute the select query for the history table (mysql.mariadb_backup_history) and wrongly reads the query result of innodb_log_checkpoint_now. This leads to assertion in mariabackup
Solution:
How can this PR be tested?
./mtr mariabackup.xbstream
Basing the PR against the correct MariaDB version
main
branch.PR quality check