summaryrefslogtreecommitdiff
path: root/sql/sql_prepare.cc
diff options
context:
space:
mode:
authorunknown <konstantin@mysql.com>2004-03-15 20:20:47 +0300
committerunknown <konstantin@mysql.com>2004-03-15 20:20:47 +0300
commitef44fb9af3ee729de5897f290c13437bbbc09da5 (patch)
tree794ffd419d2fa1e7a821b2cfd61ad9a1e799cc43 /sql/sql_prepare.cc
parent5148b005111200b45672f1de30a16f7d902cc8ca (diff)
downloadmariadb-git-ef44fb9af3ee729de5897f290c13437bbbc09da5.tar.gz
Fixes for bugs #2274 "mysqld gets SIGSEGV during processing of malformed
COM_EXECUTE packet" and #2795 "prepare + execute without bind_param crashes server" and #2473 "seg fault running tests/client_test.c": - length checking added to packet parser - default impelemntation of Item_param::set_param_func will work in case of malformed packet. No test cases are possible in our test suite, as there are no tests operating on protocol layer. sql/item.cc: Default set_param function implemented: this is to not sigsegv in case of malformed packet with no parameters data. sql/item.h: - Item_param constructor moved to .cc to be able to assign set_param_func. - now embedded and ordinary versions of set_param have the same signature. sql/mysql_priv.h: mysql_stmt_execute now requires packet_length sql/sql_parse.cc: mysql_stmt_execute now requires packet length. sql/sql_prepare.cc: - length checking added to all functions working with network packet. - set_param_func's in embedded and ordinary version now have the same signature
Diffstat (limited to 'sql/sql_prepare.cc')
-rw-r--r--sql/sql_prepare.cc115
1 files changed, 76 insertions, 39 deletions
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index ac5b7847647..ab136668cfb 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -94,7 +94,8 @@ public:
bool long_data_used;
bool log_full_query;
#ifndef EMBEDDED_LIBRARY
- bool (*set_params)(Prepared_statement *st, uchar *pos, uchar *read_pos);
+ bool (*set_params)(Prepared_statement *st, uchar *data, uchar *data_end,
+ uchar *read_pos);
#else
bool (*set_params_data)(Prepared_statement *st);
#endif
@@ -117,14 +118,6 @@ inline bool is_param_null(const uchar *pos, ulong param_no)
enum { STMT_QUERY_LOG_LENGTH= 8192 };
-#ifdef EMBEDDED_LIBRARY
-#define SET_PARAM_FUNCTION(fn_name) \
-static void fn_name(Item_param *param, uchar **pos, ulong data_len)
-#else
-#define SET_PARAM_FUNCTION(fn_name) \
-static void fn_name(Item_param *param, uchar **pos)
-#endif
-
enum enum_send_error { DONT_SEND_ERROR= 0, SEND_ERROR };
/*
@@ -186,29 +179,38 @@ static bool send_prep_stmt(Prepared_statement *stmt,
*/
#ifndef EMBEDDED_LIBRARY
-static ulong get_param_length(uchar **packet)
+static ulong get_param_length(uchar **packet, ulong len)
{
reg1 uchar *pos= *packet;
+ if (len < 1)
+ return 0;
if (*pos < 251)
{
(*packet)++;
return (ulong) *pos;
}
+ if (len < 3)
+ return 0;
if (*pos == 252)
{
(*packet)+=3;
return (ulong) uint2korr(pos+1);
}
+ if (len < 4)
+ return 0;
if (*pos == 253)
{
(*packet)+=4;
return (ulong) uint3korr(pos+1);
}
+ if (len < 5)
+ return 0;
(*packet)+=9; // Must be 254 when here
+ /* TODO: why uint4korr here? (should be uint8korr) */
return (ulong) uint4korr(pos+1);
}
#else
-#define get_param_length(A) data_len
+#define get_param_length(packet, len) len
#endif /*!EMBEDDED_LIBRARY*/
/*
@@ -230,55 +232,80 @@ static ulong get_param_length(uchar **packet)
none
*/
-SET_PARAM_FUNCTION(set_param_tiny)
+void set_param_tiny(Item_param *param, uchar **pos, ulong len)
{
+#ifndef EMBEDDED_LIBRARY
+ if (len < 1)
+ return;
+#endif
param->set_int((longlong)(**pos));
*pos+= 1;
}
-SET_PARAM_FUNCTION(set_param_short)
+void set_param_short(Item_param *param, uchar **pos, ulong len)
{
+#ifndef EMBEDDED_LIBRARY
+ if (len < 2)
+ return;
+#endif
param->set_int((longlong)sint2korr(*pos));
*pos+= 2;
}
-SET_PARAM_FUNCTION(set_param_int32)
+void set_param_int32(Item_param *param, uchar **pos, ulong len)
{
+#ifndef EMBEDDED_LIBRARY
+ if (len < 4)
+ return;
+#endif
param->set_int((longlong)sint4korr(*pos));
*pos+= 4;
}
-SET_PARAM_FUNCTION(set_param_int64)
+void set_param_int64(Item_param *param, uchar **pos, ulong len)
{
+#ifndef EMBEDDED_LIBRARY
+ if (len < 8)
+ return;
+#endif
param->set_int((longlong)sint8korr(*pos));
*pos+= 8;
}
-SET_PARAM_FUNCTION(set_param_float)
+void set_param_float(Item_param *param, uchar **pos, ulong len)
{
+#ifndef EMBEDDED_LIBRARY
+ if (len < 4)
+ return;
+#endif
float data;
float4get(data,*pos);
param->set_double((double) data);
*pos+= 4;
}
-SET_PARAM_FUNCTION(set_param_double)
+void set_param_double(Item_param *param, uchar **pos, ulong len)
{
+#ifndef EMBEDDED_LIBRARY
+ if (len < 8)
+ return;
+#endif
double data;
float8get(data,*pos);
param->set_double((double) data);
*pos+= 8;
}
-SET_PARAM_FUNCTION(set_param_time)
+void set_param_time(Item_param *param, uchar **pos, ulong len)
{
ulong length;
- if ((length= get_param_length(pos)))
+ if ((length= get_param_length(pos, len)) >= 8)
{
uchar *to= *pos;
TIME tm;
+ /* TODO: why length is compared with 8 here? */
tm.second_part= (length > 8 ) ? (ulong) sint4korr(to+7): 0;
tm.day= (ulong) sint4korr(to+1);
@@ -294,11 +321,11 @@ SET_PARAM_FUNCTION(set_param_time)
*pos+= length;
}
-SET_PARAM_FUNCTION(set_param_datetime)
+void set_param_datetime(Item_param *param, uchar **pos, ulong len)
{
uint length;
- if ((length= get_param_length(pos)))
+ if ((length= get_param_length(pos, len)) >= 4)
{
uchar *to= *pos;
TIME tm;
@@ -324,11 +351,11 @@ SET_PARAM_FUNCTION(set_param_datetime)
*pos+= length;
}
-SET_PARAM_FUNCTION(set_param_date)
+void set_param_date(Item_param *param, uchar **pos, ulong len)
{
ulong length;
- if ((length= get_param_length(pos)))
+ if ((length= get_param_length(pos, len)) >= 4)
{
uchar *to= *pos;
TIME tm;
@@ -346,11 +373,11 @@ SET_PARAM_FUNCTION(set_param_date)
*pos+= length;
}
-SET_PARAM_FUNCTION(set_param_str)
+void set_param_str(Item_param *param, uchar **pos, ulong len)
{
- ulong len= get_param_length(pos);
- param->set_value((const char *)*pos, len);
- *pos+= len;
+ ulong length= get_param_length(pos, len);
+ param->set_value((const char *)*pos, length);
+ *pos+= length;
}
static void setup_one_conversion_function(Item_param *param, uchar param_type)
@@ -405,8 +432,8 @@ static void setup_one_conversion_function(Item_param *param, uchar param_type)
and if binary/update log is set, generate the valid query.
*/
-static bool insert_params_withlog(Prepared_statement *stmt, uchar *pos,
- uchar *read_pos)
+static bool insert_params_withlog(Prepared_statement *stmt, uchar *null_array,
+ uchar *read_pos, uchar *data_end)
{
THD *thd= stmt->thd;
Item_param **begin= stmt->param_array;
@@ -428,7 +455,7 @@ static bool insert_params_withlog(Prepared_statement *stmt, uchar *pos,
res= param->query_val_str(&str);
else
{
- if (is_param_null(pos, it - begin))
+ if (is_param_null(null_array, it - begin))
{
param->maybe_null= param->null_value= 1;
res= &my_null_string;
@@ -436,7 +463,9 @@ static bool insert_params_withlog(Prepared_statement *stmt, uchar *pos,
else
{
param->maybe_null= param->null_value= 0;
- param->set_param_func(param, &read_pos);
+ if (read_pos >= data_end)
+ DBUG_RETURN(1);
+ param->set_param_func(param, &read_pos, data_end - read_pos);
res= param->query_val_str(&str);
}
}
@@ -452,8 +481,8 @@ static bool insert_params_withlog(Prepared_statement *stmt, uchar *pos,
}
-static bool insert_params(Prepared_statement *stmt, uchar *pos,
- uchar *read_pos)
+static bool insert_params(Prepared_statement *stmt, uchar *null_array,
+ uchar *read_pos, uchar *data_end)
{
Item_param **begin= stmt->param_array;
Item_param **end= begin + stmt->param_count;
@@ -465,20 +494,23 @@ static bool insert_params(Prepared_statement *stmt, uchar *pos,
Item_param *param= *it;
if (!param->long_data_supplied)
{
- if (is_param_null(pos, it - begin))
+ if (is_param_null(null_array, it - begin))
param->maybe_null= param->null_value= 1;
else
{
param->maybe_null= param->null_value= 0;
- param->set_param_func(param, &read_pos);
+ if (read_pos >= data_end)
+ DBUG_RETURN(1);
+ param->set_param_func(param, &read_pos, data_end - read_pos);
}
}
}
DBUG_RETURN(0);
}
+
static bool setup_conversion_functions(Prepared_statement *stmt,
- uchar **data)
+ uchar **data, uchar *data_end)
{
/* skip null bits */
uchar *read_pos= *data + (stmt->param_count+7) / 8;
@@ -495,6 +527,8 @@ static bool setup_conversion_functions(Prepared_statement *stmt,
Item_param **end= it + stmt->param_count;
for (; it < end; ++it)
{
+ if (read_pos >= data_end)
+ DBUG_RETURN(1);
setup_one_conversion_function(*it, *read_pos);
read_pos+= 2;
}
@@ -1072,7 +1106,7 @@ static void reset_stmt_for_execute(Prepared_statement *stmt)
*/
-void mysql_stmt_execute(THD *thd, char *packet)
+void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
{
ulong stmt_id= uint4korr(packet);
Prepared_statement *stmt;
@@ -1097,10 +1131,11 @@ void mysql_stmt_execute(THD *thd, char *packet)
#ifndef EMBEDDED_LIBRARY
if (stmt->param_count)
{
+ uchar *packet_end= (uchar *) packet + packet_length - 1;
packet+= 4;
uchar *null_array= (uchar *) packet;
- if (setup_conversion_functions(stmt, (uchar **) &packet) ||
- stmt->set_params(stmt, null_array, (uchar *) packet))
+ if (setup_conversion_functions(stmt, (uchar **) &packet, packet_end) ||
+ stmt->set_params(stmt, null_array, (uchar *) packet, packet_end))
goto set_params_data_err;
}
#else
@@ -1159,6 +1194,7 @@ set_params_data_err:
void mysql_stmt_reset(THD *thd, char *packet)
{
+ /* There is always space for 4 bytes in buffer */
ulong stmt_id= uint4korr(packet);
Prepared_statement *stmt;
@@ -1189,6 +1225,7 @@ void mysql_stmt_reset(THD *thd, char *packet)
void mysql_stmt_free(THD *thd, char *packet)
{
+ /* There is always space for 4 bytes in packet buffer */
ulong stmt_id= uint4korr(packet);
Prepared_statement *stmt;