diff --git a/libmariadb/mariadb_stmt.c b/libmariadb/mariadb_stmt.c index dfc7f0a0..516b8016 100644 --- a/libmariadb/mariadb_stmt.c +++ b/libmariadb/mariadb_stmt.c @@ -1645,6 +1645,7 @@ my_bool mthd_stmt_read_prepare_response(MYSQL_STMT *stmt) if (stmt->prebind_params != stmt->param_count) { SET_CLIENT_STMT_ERROR(stmt, CR_INVALID_PARAMETER_NO, SQLSTATE_UNKNOWN, 0); + stmt->param_count= stmt->prebind_params; return 1; } } else { @@ -1931,6 +1932,13 @@ int mthd_stmt_read_execute_response(MYSQL_STMT *stmt) { SET_CLIENT_STMT_ERROR(stmt, mysql->net.last_errno, mysql->net.sqlstate, mysql->net.last_error); + /* if mariadb_stmt_execute_direct was used, we need to send the number + of parameters to the specified prebinded value to prevent possible + memory overrun */ + if (stmt->prebind_params) + { + stmt->param_count= stmt->prebind_params; + } stmt->state= MYSQL_STMT_PREPARED; return(1); } diff --git a/plugins/auth/my_auth.c b/plugins/auth/my_auth.c index 2fd1ba12..2423294c 100644 --- a/plugins/auth/my_auth.c +++ b/plugins/auth/my_auth.c @@ -85,6 +85,7 @@ static int native_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql) if (mysql && mysql->passwd[0]) { char scrambled[SCRAMBLE_LENGTH + 1]; + memset(scrambled, 0, SCRAMBLE_LENGTH + 1); ma_scramble_41((uchar *)scrambled, (char*)pkt, mysql->passwd); if (vio->write_packet(vio, (uchar*)scrambled, SCRAMBLE_LENGTH)) return CR_ERROR; diff --git a/unittest/libmariadb/async.c b/unittest/libmariadb/async.c index 079f19d8..4c1a30e3 100644 --- a/unittest/libmariadb/async.c +++ b/unittest/libmariadb/async.c @@ -37,7 +37,7 @@ static int test_async(MYSQL *mysql) if (type > MARIADB_CONNECTION_TCP) { skip_async= 1; - diag("Asnyc IO not supported"); + diag("Async IO not supported"); } return OK; } diff --git a/unittest/libmariadb/bulk1.c b/unittest/libmariadb/bulk1.c index d220aa31..e1c31eaa 100644 --- a/unittest/libmariadb/bulk1.c +++ b/unittest/libmariadb/bulk1.c @@ -925,7 +925,7 @@ static int bulk_null_null(MYSQL *mysql) rc= mysql_stmt_prepare(stmt, "INSERT INTO bulk_null VALUES (?,?,?,?,?)", -1); check_stmt_rc(rc, stmt); - memset(bind, 0, sizeof(MYSQL_BIND)*2); + memset(bind, 0, sizeof(MYSQL_BIND)*5); rc= mysql_stmt_attr_set(stmt, STMT_ATTR_ARRAY_SIZE, &array_size); check_stmt_rc(rc, stmt); @@ -1011,6 +1011,7 @@ static int test_mdev16593(MYSQL *mysql) diag("waiting for server fix"); return SKIP; + memset(&bind, 0, 2 * sizeof(MYSQL_BIND)); for (i=0; i < 3; i++) { MYSQL_RES *res; @@ -1018,8 +1019,6 @@ static int test_mdev16593(MYSQL *mysql) MYSQL_STMT *stmt= mysql_stmt_init(mysql); rc= mysql_query(mysql, "CREATE OR REPLACE TABLE t1 (a int not null auto_increment primary key, b int)"); check_mysql_rc(rc, mysql); - - memset(&bind, 0, sizeof(MYSQL_BIND)); switch (i) { case 0: bind[0].buffer_type= MYSQL_TYPE_LONG; diff --git a/unittest/libmariadb/misc.c b/unittest/libmariadb/misc.c index 8d80c7a7..496619da 100644 --- a/unittest/libmariadb/misc.c +++ b/unittest/libmariadb/misc.c @@ -1063,7 +1063,7 @@ static int test_read_timeout(MYSQL *unused __attribute__((unused))) return OK; } - +#if __has_feature(memory_sanitizer) #ifdef HAVE_REMOTEIO void *remote_plugin; static int test_remote1(MYSQL *mysql) @@ -1131,6 +1131,7 @@ static int test_remote2(MYSQL *my) return OK; } #endif +#endif #ifndef _WIN32 static int test_mdev12965(MYSQL *unused __attribute__((unused))) @@ -1499,6 +1500,7 @@ static int test_sslenforce(MYSQL *unused __attribute__((unused))) } #endif +#if !__has_feature(memory_sanitizer) static int test_conc457(MYSQL *mysql) { MYSQL_RES *result; @@ -1511,6 +1513,7 @@ static int test_conc457(MYSQL *mysql) mysql_free_result(result); return OK; } +#endif static int test_conc458(MYSQL *my __attribute__((unused))) { @@ -1618,7 +1621,9 @@ struct my_tests_st my_tests[] = { {"test_ext_field_attr", test_ext_field_attr, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"test_conc533", test_conc533, TEST_CONNECTION_NEW, 0, NULL, NULL}, {"test_conc458", test_conc458, TEST_CONNECTION_NONE, 0, NULL, NULL}, +#if !__has_feature(memory_sanitizer) {"test_conc457", test_conc457, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, +#endif {"test_conc384", test_conc384, TEST_CONNECTION_NONE, 0, NULL, NULL}, #ifndef _WIN32 {"test_mdev12965", test_mdev12965, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, @@ -1629,9 +1634,11 @@ struct my_tests_st my_tests[] = { {"test_server_status", test_server_status, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"test_read_timeout", test_read_timeout, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"test_zerofill", test_zerofill, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, +#if !__has_feature(memory_sanitizer) #ifdef HAVE_REMOTEIO {"test_remote1", test_remote1, TEST_CONNECTION_NEW, 0, NULL, NULL}, {"test_remote2", test_remote2, TEST_CONNECTION_NEW, 0, NULL, NULL}, +#endif #endif {"test_get_info", test_get_info, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"test_conc117", test_conc117, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, diff --git a/unittest/libmariadb/ps_bugs.c b/unittest/libmariadb/ps_bugs.c index 17ca0419..933a969e 100644 --- a/unittest/libmariadb/ps_bugs.c +++ b/unittest/libmariadb/ps_bugs.c @@ -5410,7 +5410,146 @@ static int test_conc566(MYSQL *mysql) return OK; } +#define MDEV19838_MAX_PARAM_COUNT 32 +#define MDEV19838_FIELDS_COUNT 17 + +static int test_mdev19838(MYSQL *mysql) +{ + int rc; + MYSQL_BIND bind[MDEV19838_MAX_PARAM_COUNT]; + unsigned int i, paramCount = 1; + char charvalue[] = "012345678901234567890123456789012345"; + MYSQL_STMT *stmt; + + rc = mysql_query(mysql, "CREATE temporary TABLE mdev19838(" + "f1 char(36)," + "f2 char(36)," + "f3 char(36)," + "f4 char(36)," + "f5 char(36)," + "f6 char(36)," + "f7 char(36)," + "f8 char(36)," + "f9 char(36)," + "f10 char(36)," + "f11 char(36)," + "f12 char(36)," + "f13 char(36)," + "f14 char(36)," + "f15 char(36)," + "f16 char(36)," + "f17 char(36)" + ")"); + check_mysql_rc(rc, mysql); + + stmt = mysql_stmt_init(mysql); + + memset(bind, 0, sizeof(bind)); + + for (i = 0; i < MDEV19838_MAX_PARAM_COUNT; ++i) + { + bind[i].buffer = charvalue; + bind[i].buffer_type = MYSQL_TYPE_STRING; + bind[i].buffer_length = strlen(charvalue) + 1; + bind[i].length = &bind[i].length_value; + bind[i].length_value = bind[i].buffer_length - 1; + } + + for (paramCount = 1; paramCount < MDEV19838_FIELDS_COUNT; ++paramCount) + { + mysql_stmt_attr_set(stmt, STMT_ATTR_PREBIND_PARAMS, ¶mCount); + + rc = mysql_stmt_bind_param(stmt, bind); + check_stmt_rc(rc, stmt); + + rc = mariadb_stmt_execute_direct(stmt, "INSERT INTO mdev19838" + "(f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17)" + " VALUES " + "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", -1); + + /* Expecting an error */ + FAIL_UNLESS(rc != 0, "rc!=0"); + + mysql_stmt_close(stmt); + stmt = mysql_stmt_init(mysql); + } + + paramCount = 0; + mysql_stmt_attr_set(stmt, STMT_ATTR_PREBIND_PARAMS, ¶mCount); + rc = mariadb_stmt_execute_direct(stmt, "INSERT INTO mdev19838(f1)" + " VALUES (?)", -1); + /* Expecting an error */ + FAIL_UNLESS(rc != 0, "rc!=0"); + mysql_stmt_close(stmt); + + stmt = mysql_stmt_init(mysql); + /* Correct number of parameters */ + paramCount = MDEV19838_FIELDS_COUNT; + mysql_stmt_attr_set(stmt, STMT_ATTR_PREBIND_PARAMS, ¶mCount); + mysql_stmt_bind_param(stmt, bind); + + rc = mariadb_stmt_execute_direct(stmt, "INSERT INTO mdev19838" + "(f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17)" + " VALUES " + "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", -1); + check_stmt_rc(rc, stmt); + + /* MYSQL_TYPE_TINY = 1. This parameter byte can be read as "parameters send" flag byte. + Checking that wrong packet is still detected */ + bind[0].buffer_type = MYSQL_TYPE_TINY; + bind[0].length_value = 1; + bind[0].buffer_length = 1; + + for (paramCount = 8; paramCount > 0; --paramCount) + { + mysql_stmt_close(stmt); + stmt = mysql_stmt_init(mysql); + + mysql_stmt_attr_set(stmt, STMT_ATTR_PREBIND_PARAMS, ¶mCount); + + rc = mysql_stmt_bind_param(stmt, bind); + + rc = mariadb_stmt_execute_direct(stmt, "INSERT INTO mdev19838" + "(f1, f2, f3, f4, f5, f6, f7, f8, f9)" + " VALUES " + "(?, ?, ?, ?, ?, ?, ?, ?, ?)", -1); + + /* Expecting an error */ + FAIL_UNLESS(rc != 0, "rc"); + } + + /* Test of query w/out parameters, with parameter sent and not sent */ + for (paramCount = MDEV19838_MAX_PARAM_COUNT; paramCount != (unsigned int)-1; --paramCount) + { + mysql_stmt_close(stmt); + stmt = mysql_stmt_init(mysql); + + mysql_stmt_attr_set(stmt, STMT_ATTR_PREBIND_PARAMS, ¶mCount); + + if (paramCount > 0) + { + rc = mysql_stmt_bind_param(stmt, bind); + check_stmt_rc(rc, stmt); + } + + rc = mariadb_stmt_execute_direct(stmt, "INSERT INTO mdev19838" + "(f1)" + " VALUES " + "(0x1111111111111111)", -1); + + /* + We allow junk at the end of the packet in case of + no parameters. So it will succeed. + */ + FAIL_UNLESS(rc == 0, ""); + } + + mysql_stmt_close(stmt); + return OK; +} + struct my_tests_st my_tests[] = { + {"test_mdev19838", test_mdev19838, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"test_conc525", test_conc525, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"test_conc566", test_conc566, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"test_conc512", test_conc512, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, diff --git a/unittest/libmariadb/view.c b/unittest/libmariadb/view.c index 10d6f3ef..1cf4c862 100644 --- a/unittest/libmariadb/view.c +++ b/unittest/libmariadb/view.c @@ -206,7 +206,7 @@ static int test_view_2where(MYSQL *mysql) " AENAME,T0001.DEPENDVARS AS DEPENDVARS,T0001.INACTIVE AS " " INACTIVE from LTDX T0001 where (T0001.SRTF2 = 0)"); check_mysql_rc(rc, mysql); - memset(my_bind, '\0', sizeof(MYSQL_BIND)); + memset(my_bind, '\0', 8 * sizeof(MYSQL_BIND)); for (i=0; i < 8; i++) { strcpy(params[i], "1"); my_bind[i].buffer_type = MYSQL_TYPE_VAR_STRING; @@ -257,7 +257,7 @@ static int test_view_star(MYSQL *mysql) check_mysql_rc(rc, mysql); rc= mysql_query(mysql, "CREATE VIEW vt1 AS SELECT a FROM t1"); check_mysql_rc(rc, mysql); - memset(my_bind, '\0', sizeof(MYSQL_BIND)); + memset(my_bind, '\0', 8 * sizeof(MYSQL_BIND)); for (i= 0; i < 2; i++) { sprintf((char *)¶ms[i], "%d", i); my_bind[i].buffer_type = MYSQL_TYPE_VAR_STRING; @@ -438,7 +438,7 @@ static int test_view_insert_fields(MYSQL *mysql) memset(my_bind, '\0', sizeof(my_bind)); for (i= 0; i < 11; i++) { - l[i]= 20; + l[i]= 2; my_bind[i].buffer_type= MYSQL_TYPE_STRING; my_bind[i].is_null= 0; my_bind[i].buffer= (char *)&parm[i];