Commit 33a36ce9 authored by Davi Arnaut's avatar Davi Arnaut

Bug#42634: % character in query can cause mysqld signal 11 segfault

The problem is that a unfiltered user query was being passed as
the format string parameter of sql_print_warning which later
performs printf-like formatting, leading to crashes if the user
query contains formatting instructions (ie: %s). Also, it was
using THD::query as the source of the user query, but this
variable is not meaningful in some situations -- in a delayed
insert, it points to the table name.

The solution is to pass the user query as a parameter for the
format string and use the function parameter query_arg as the
source of the user query.
parent 7a6c62c4
...@@ -220,3 +220,10 @@ Warning 1592 Statement is not safe to log in statement format. ...@@ -220,3 +220,10 @@ Warning 1592 Statement is not safe to log in statement format.
Warning 1592 Statement is not safe to log in statement format. Warning 1592 Statement is not safe to log in statement format.
DROP PROCEDURE p1; DROP PROCEDURE p1;
DROP TABLE t1; DROP TABLE t1;
DROP TABLE IF EXISTS t1;
CREATE TABLE t1 (a VARCHAR(100), b VARCHAR(100));
INSERT INTO t1 VALUES ('a','b');
UPDATE t1 SET b = '%s%s%s%s%s%s%s%s%s%s%s%s%s%s' WHERE a = 'a' LIMIT 1;
Warnings:
Warning 1592 Statement is not safe to log in statement format.
DROP TABLE t1;
...@@ -257,3 +257,17 @@ delimiter ;| ...@@ -257,3 +257,17 @@ delimiter ;|
CALL p1(); CALL p1();
DROP PROCEDURE p1; DROP PROCEDURE p1;
DROP TABLE t1; DROP TABLE t1;
#
# Bug#42634: % character in query can cause mysqld signal 11 segfault
#
--disable_warnings
DROP TABLE IF EXISTS t1;
--enable_warnings
CREATE TABLE t1 (a VARCHAR(100), b VARCHAR(100));
INSERT INTO t1 VALUES ('a','b');
UPDATE t1 SET b = '%s%s%s%s%s%s%s%s%s%s%s%s%s%s' WHERE a = 'a' LIMIT 1;
DROP TABLE t1;
...@@ -3660,16 +3660,14 @@ int THD::binlog_query(THD::enum_binlog_query_type qtype, char const *query_arg, ...@@ -3660,16 +3660,14 @@ int THD::binlog_query(THD::enum_binlog_query_type qtype, char const *query_arg,
if (lex->is_stmt_unsafe() && if (lex->is_stmt_unsafe() &&
variables.binlog_format == BINLOG_FORMAT_STMT) variables.binlog_format == BINLOG_FORMAT_STMT)
{ {
DBUG_ASSERT(this->query != NULL);
push_warning(this, MYSQL_ERROR::WARN_LEVEL_WARN, push_warning(this, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_BINLOG_UNSAFE_STATEMENT, ER_BINLOG_UNSAFE_STATEMENT,
ER(ER_BINLOG_UNSAFE_STATEMENT)); ER(ER_BINLOG_UNSAFE_STATEMENT));
if (!(binlog_flags & BINLOG_FLAG_UNSAFE_STMT_PRINTED)) if (!(binlog_flags & BINLOG_FLAG_UNSAFE_STMT_PRINTED))
{ {
char warn_buf[MYSQL_ERRMSG_SIZE]; sql_print_warning("%s Statement: %.*s",
my_snprintf(warn_buf, MYSQL_ERRMSG_SIZE, "%s Statement: %s", ER(ER_BINLOG_UNSAFE_STATEMENT),
ER(ER_BINLOG_UNSAFE_STATEMENT), this->query); MYSQL_ERRMSG_SIZE, query_arg);
sql_print_warning(warn_buf);
binlog_flags|= BINLOG_FLAG_UNSAFE_STMT_PRINTED; binlog_flags|= BINLOG_FLAG_UNSAFE_STMT_PRINTED;
} }
} }
......
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