From 659bee497b0e7de22f2c7ce48391eaae37ab256d Mon Sep 17 00:00:00 2001 From: Marc Alff Date: Mon, 17 Mar 2014 17:54:08 +0100 Subject: [PATCH] Bug#18319790 QUERY TO INFORMATION_SCHEMA CRASHES SERVER Before this fix, specially crafted queries using the INFORMATION_SCHEMA could crash the server. The root cause was a buffer overflow, see the (private) bug comments for details. With this fix, the buffer overflow condition is properly handled, and the queries involved do return the expected result. --- sql/sql_show.cc | 65 +++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 58 insertions(+), 7 deletions(-) diff --git a/sql/sql_show.cc b/sql/sql_show.cc index b8e8649e1eb..dcae4c63b02 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -2394,10 +2394,38 @@ void calc_sum_of_all_status(STATUS_VAR *to) /* This is only used internally, but we need it here as a forward reference */ extern ST_SCHEMA_TABLE schema_tables[]; +/** + Condition pushdown used for INFORMATION_SCHEMA / SHOW queries. + This structure is to implement an optimization when + accessing data dictionary data in the INFORMATION_SCHEMA + or SHOW commands. + When the query contain a TABLE_SCHEMA or TABLE_NAME clause, + narrow the search for data based on the constraints given. +*/ typedef struct st_lookup_field_values { - LEX_STRING db_value, table_value; - bool wild_db_value, wild_table_value; + /** + Value of a TABLE_SCHEMA clause. + Note that this value length may exceed @c NAME_LEN. + @sa wild_db_value + */ + LEX_STRING db_value; + /** + Value of a TABLE_NAME clause. + Note that this value length may exceed @c NAME_LEN. + @sa wild_table_value + */ + LEX_STRING table_value; + /** + True when @c db_value is a LIKE clause, + false when @c db_value is an '=' clause. + */ + bool wild_db_value; + /** + True when @c table_value is a LIKE clause, + false when @c table_value is an '=' clause. + */ + bool wild_table_value; } LOOKUP_FIELD_VALUES; @@ -2801,14 +2829,22 @@ int make_db_list(THD *thd, List *files, /* - If we have db lookup vaule we just add it to list and + If we have db lookup value we just add it to list and exit from the function. We don't do this for database names longer than the maximum - path length. + name length. */ - if (lookup_field_vals->db_value.str && - lookup_field_vals->db_value.length < FN_REFLEN) + if (lookup_field_vals->db_value.str) { + if (lookup_field_vals->db_value.length > NAME_LEN) + { + /* + Impossible value for a database name, + found in a WHERE DATABASE_NAME = 'xxx' clause. + */ + return 0; + } + if (is_infoschema_db(lookup_field_vals->db_value.str, lookup_field_vals->db_value.length)) { @@ -2945,6 +2981,15 @@ make_table_name_list(THD *thd, List *table_names, LEX *lex, if (!lookup_field_vals->wild_table_value && lookup_field_vals->table_value.str) { + if (lookup_field_vals->table_value.length > NAME_LEN) + { + /* + Impossible value for a table name, + found in a WHERE TABLE_NAME = 'xxx' clause. + */ + return 0; + } + if (with_i_schema) { LEX_STRING *name; @@ -3411,6 +3456,9 @@ static int fill_schema_table_from_frm(THD *thd, TABLE_LIST *tables, bzero((char*) &table_list, sizeof(TABLE_LIST)); bzero((char*) &tbl, sizeof(TABLE)); + DBUG_ASSERT(db_name->length <= NAME_LEN); + DBUG_ASSERT(table_name->length <= NAME_LEN); + if (lower_case_table_names) { /* @@ -3742,6 +3790,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) it.rewind(); /* To get access to new elements in basis list */ while ((db_name= it++)) { + DBUG_ASSERT(db_name->length <= NAME_LEN); #ifndef NO_EMBEDDED_ACCESS_CHECKS if (!(check_access(thd, SELECT_ACL, db_name->str, &thd->col_access, NULL, 0, 1) || @@ -3763,6 +3812,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) List_iterator_fast it_files(table_names); while ((table_name= it_files++)) { + DBUG_ASSERT(table_name->length <= NAME_LEN); restore_record(table, s->default_values); table->field[schema_table->idx_field1]-> store(db_name->str, db_name->length, system_charset_info); @@ -3909,6 +3959,7 @@ int fill_schema_schemata(THD *thd, TABLE_LIST *tables, COND *cond) List_iterator_fast it(db_names); while ((db_name=it++)) { + DBUG_ASSERT(db_name->length <= NAME_LEN); if (with_i_schema) // information schema name is always first in list { if (store_schema_shemata(thd, table, db_name,