From 4aa8eac799368632152c3c711935239d444214eb Mon Sep 17 00:00:00 2001 From: Johan Wikman Date: Fri, 3 May 2019 08:58:56 +0300 Subject: [PATCH] MXS-2457 Allow strings to be treated as fields Before this change, if the firewall was configured to block the use of certain columns, it could be be bypassed simply by > set @@sql_mode='ANSI_QUOTES'; > select "ssn" from person; The reason is that as the query classifier is not aware of whether 'ANSI_QUOTES' is on or not, it will not know that what above appears to be the string "ssn", actually is the field name `ssn`. Consequently, the select will not be blocked and the result returned in cleartext. It's now possible to instruct the query classifier to report all strings as fields, which will prevent the above. However, it will also mean that there may be false positives. --- include/maxscale/query_classifier.h | 3 +- .../qc_mysqlembedded/qc_mysqlembedded.cc | 30 +++++++++++++++++-- query_classifier/qc_sqlite/qc_sqlite.cc | 19 ++++++++++++ 3 files changed, 48 insertions(+), 4 deletions(-) diff --git a/include/maxscale/query_classifier.h b/include/maxscale/query_classifier.h index d05c97bbe..6ce242303 100644 --- a/include/maxscale/query_classifier.h +++ b/include/maxscale/query_classifier.h @@ -36,9 +36,10 @@ typedef enum qc_init_kind enum qc_option_t { QC_OPTION_STRING_ARG_AS_FIELD = (1 << 0), /*< Report a string argument to a function as a field. */ + QC_OPTION_STRING_AS_FIELD = (1 << 1), /*< Report strings as fields. */ }; -const uint32_t QC_OPTION_MASK = QC_OPTION_STRING_ARG_AS_FIELD; +const uint32_t QC_OPTION_MASK = QC_OPTION_STRING_ARG_AS_FIELD | QC_OPTION_STRING_AS_FIELD; /** * qc_sql_mode_t specifies what should be assumed of the statements diff --git a/query_classifier/qc_mysqlembedded/qc_mysqlembedded.cc b/query_classifier/qc_mysqlembedded/qc_mysqlembedded.cc index ad2c1e2fd..7689c99d1 100644 --- a/query_classifier/qc_mysqlembedded/qc_mysqlembedded.cc +++ b/query_classifier/qc_mysqlembedded/qc_mysqlembedded.cc @@ -2268,7 +2268,6 @@ static void unalias_names(st_select_lex* select, } static void add_field_info(parsing_info_t* info, - st_select_lex* select, const char* database, const char* table, const char* column, @@ -2276,8 +2275,6 @@ static void add_field_info(parsing_info_t* info, { mxb_assert(column); - unalias_names(select, database, table, &database, &table); - QC_FIELD_INFO item = {(char*)database, (char*)table, (char*)column}; size_t i; @@ -2353,6 +2350,20 @@ static void add_field_info(parsing_info_t* info, } } +static void add_field_info(parsing_info_t* info, + st_select_lex* select, + const char* database, + const char* table, + const char* column, + List* excludep) +{ + mxb_assert(column); + + unalias_names(select, database, table, &database, &table); + + add_field_info(info, database, table, column, excludep); +} + static void add_function_field_usage(const char* database, const char* table, const char* column, @@ -3063,6 +3074,19 @@ static void update_field_infos(parsing_info_t* pi, } break; + case Item::STRING_ITEM: + if (this_thread.options & QC_OPTION_STRING_AS_FIELD) + { + String* s = item->val_str(); + int len = s->length(); + char tmp[len + 1]; + memcpy(tmp, s->ptr(), len); + tmp[len] = 0; + + add_field_info(pi, nullptr, nullptr, tmp, excludep); + } + break; + default: break; } diff --git a/query_classifier/qc_sqlite/qc_sqlite.cc b/query_classifier/qc_sqlite/qc_sqlite.cc index f0f2e6323..ca8545eff 100644 --- a/query_classifier/qc_sqlite/qc_sqlite.cc +++ b/query_classifier/qc_sqlite/qc_sqlite.cc @@ -832,6 +832,14 @@ public: update_field_infos_from_expr(pAliases, context, pExpr, pExclude); break; + case TK_STRING: // select "a" ..., for @@sql_mode containing 'ANSI_QUOTES' + if (this_thread.options & QC_OPTION_STRING_AS_FIELD) + { + const char* zColumn = pExpr->u.zToken; + update_field_infos_from_column(pAliases, context, zColumn, pExclude); + } + break; + case TK_VARIABLE: { if (zToken[0] == '@') @@ -1184,6 +1192,17 @@ public: } } + void update_field_infos_from_column(QcAliases* pAliases, + uint32_t context, + const char* zColumn, + const ExprList* pExclude) + { + if (must_check_sequence_related_functions() || must_collect_fields()) + { + update_field_info(pAliases, context, nullptr, nullptr, zColumn, pExclude); + } + } + void update_field_infos_from_exprlist(QcAliases* pAliases, uint32_t context, const ExprList* pEList,