Commit 2aeb3287 authored by Vadim Zeitlin's avatar Vadim Zeitlin

Fix reading from unallocated memory in ODBC with MySQL

ODBC documentation[1] states that "StrLen_or_IndPtr" parameter may
contain the length of the parameter value being bound and that this
length is "ignored except for character or binary C data", however MySQL
ODBC driver[2] misinterprets this and considers that if the value of
this parameter is SQL_NTS, it must still find the parameter length as if
it were a nul-terminated string, i.e. by using strlen() which, of
course, fails horribly when the data is binary, resulting in accessing
data beyond the allocated heap block and possibly crashing -- and, at
the very least, tripping address sanitizer checks.

Work around this apparent MySQL driver bug by explicitly _not_ passing
SQL_NTS for non-character data. This is enough to fix the problem for it
as length is really not used in this case, and shouldn't have any
negative implications for the other databases.

[1]: https://docs.microsoft.com/en-us/sql/odbc/reference/syntax/sqlbindparameter-function
[2]: https://github.com/mysql/mysql-connector-odbc
parent dc05c8e8
......@@ -290,14 +290,18 @@ void odbc_vector_use_type_backend::bind_by_name(
void odbc_vector_use_type_backend::pre_use(indicator const *ind)
{
// first deal with data
SQLLEN non_null_indicator = 0;
switch (type_)
{
case x_short:
case x_integer:
case x_double:
// Length of the parameter value is ignored for these types.
break;
case x_char:
case x_stdstring:
// Nothing special to do.
non_null_indicator = SQL_NTS;
break;
case x_stdtm:
......@@ -340,6 +344,8 @@ void odbc_vector_use_type_backend::pre_use(indicator const *ind)
snprintf(pos, max_bigint_length, "%" LL_FMT_FLAGS "d", v[i]);
pos += max_bigint_length;
}
non_null_indicator = SQL_NTS;
}
break;
......@@ -357,6 +363,8 @@ void odbc_vector_use_type_backend::pre_use(indicator const *ind)
snprintf(pos, max_bigint_length, "%" LL_FMT_FLAGS "u", v[i]);
pos += max_bigint_length;
}
non_null_indicator = SQL_NTS;
}
break;
......@@ -387,7 +395,7 @@ void odbc_vector_use_type_backend::pre_use(indicator const *ind)
// for strings we have already set the values
if (type_ != x_stdstring)
{
indHolderVec_[i] = SQL_NTS; // value is OK
indHolderVec_[i] = non_null_indicator;
}
}
}
......@@ -401,7 +409,7 @@ void odbc_vector_use_type_backend::pre_use(indicator const *ind)
// for strings we have already set the values
if (type_ != x_stdstring)
{
indHolderVec_[i] = SQL_NTS; // value is OK
indHolderVec_[i] = non_null_indicator;
}
}
}
......
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