Commit 318077c4 authored by Sujatha Sivakumar's avatar Sujatha Sivakumar

Bug#16753869:INCORRECT TRUNCATION OF LONG SET EXPRESSION IN

LOAD DATA CAN CAUSE SQL INJECTION

Problem:
=======
A long SET expression in LOAD DATA is incorrectly truncated
when written to the binary log.

Analysis:
========
LOAD DATA statements are reconstructed once again before
they are written to the binary log. When SET clauses are
specified as part of LOAD DATA statement, these SET clause
user command strings need to be stored as it is inorder to
reconstruct the original user command.  At present these
strings are stored as part of SET clause item tree's
top most Item node's name itself which is incorrect. As an
Item::name can be of MAX_ALIAS_NAME (256) size. Hence the
name will get truncated to "255".

Because of this the rewritten LOAD DATA statement will be
terminated incorrectly.  When this statment is read back by
the mysqlbinlog tool it reads a starting single quote and
continuos to read till it finds an ending quote. Hence any
statement written post ending quote will be considered as
a new statement.

Fix:
===
As name field has length restriction the string value
should not be stored in Item::name.  A new String list is
maintained to store the SET expression values and this list
is read during reconstrution.
parent a326f974
......@@ -372,6 +372,7 @@ void lex_start(THD *thd)
/* 'parent_lex' is used in init_query() so it must be before it. */
lex->select_lex.parent_lex= lex;
lex->select_lex.init_query();
lex->load_set_str_list.empty();
lex->value_list.empty();
lex->update_list.empty();
lex->set_var_list.empty();
......
......@@ -2286,6 +2286,13 @@ struct LEX: public Query_tables_list
List<Key_part_spec> col_list;
List<Key_part_spec> ref_list;
/*
A list of strings is maintained to store the SET clause command user strings
which are specified in load data operation. This list will be used
during the reconstruction of "load data" statement at the time of writing
to binary log.
*/
List<String> load_set_str_list;
List<String> interval_list;
List<LEX_USER> users_list;
List<LEX_COLUMN> columns;
......
/*
Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
Copyright (c) 2000, 2013, 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
......@@ -672,7 +672,8 @@ static bool write_execute_load_query_log_event(THD *thd, sql_exchange* ex,
*p= NULL;
size_t pl= 0;
List<Item> fv;
Item *item, *val;
Item *item;
String *str;
String pfield, pfields;
int n;
const char *tbl= table_name_arg;
......@@ -726,18 +727,18 @@ static bool write_execute_load_query_log_event(THD *thd, sql_exchange* ex,
if (!thd->lex->update_list.is_empty())
{
List_iterator<Item> lu(thd->lex->update_list);
List_iterator<Item> lv(thd->lex->value_list);
List_iterator<String> ls(thd->lex->load_set_str_list);
pfields.append(" SET ");
n= 0;
while ((item= lu++))
{
val= lv++;
str= ls++;
if (n++)
pfields.append(", ");
append_identifier(thd, &pfields, item->name, strlen(item->name));
pfields.append(val->name);
pfields.append((char *)str->ptr());
}
}
......
......@@ -11727,10 +11727,17 @@ load_data_set_elem:
simple_ident_nospvar equal remember_name expr_or_default remember_end
{
LEX *lex= Lex;
if (lex->update_list.push_back($1) ||
lex->value_list.push_back($4))
uint length= (uint) ($5 - $3);
String *val= new (YYTHD->mem_root) String($3,
length,
YYTHD->charset());
if (val == NULL)
MYSQL_YYABORT;
if (lex->update_list.push_back($1) ||
lex->value_list.push_back($4) ||
lex->load_set_str_list.push_back(val))
MYSQL_YYABORT;
$4->set_name($3, (uint) ($5 - $3), YYTHD->charset());
$4->set_name($3, length, YYTHD->charset());
}
;
......
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