Commit 727757d2 authored by unknown's avatar unknown

Fix for BUG#27592: stack overrun when storing datetime value

using prepared statements.


sql/field.cc:
  Using MAX_DATETIME_WIDTH or MAX_DATETIME_COMPRESSED_WIDTH
  constants for the length of DATETIME fields.
  
  Using MAX_DATE_STRING_REP_LENGTH for allocating buffers
  for date/time/... string representation.
sql/item_timefunc.cc:
  Using MAX_DATETIME_WIDTH or MAX_DATETIME_COMPRESSED_WIDTH
  constants for the length of DATETIME fields.
  
  Using MAX_DATE_STRING_REP_LENGTH for allocating buffers
  for date/time/... string representation.
sql/unireg.h:
  Introduce a constant for length of datetime compressed
  format (YYYYMMDDHHMMSS).
parent e2107646
...@@ -4285,7 +4285,7 @@ Field_timestamp::Field_timestamp(char *ptr_arg, uint32 len_arg, ...@@ -4285,7 +4285,7 @@ Field_timestamp::Field_timestamp(char *ptr_arg, uint32 len_arg,
const char *field_name_arg, const char *field_name_arg,
struct st_table *table_arg, struct st_table *table_arg,
CHARSET_INFO *cs) CHARSET_INFO *cs)
:Field_str(ptr_arg, 19, null_ptr_arg, null_bit_arg, :Field_str(ptr_arg, MAX_DATETIME_WIDTH, null_ptr_arg, null_bit_arg,
unireg_check_arg, field_name_arg, table_arg, cs) unireg_check_arg, field_name_arg, table_arg, cs)
{ {
/* For 4.0 MYD and 4.0 InnoDB compatibility */ /* For 4.0 MYD and 4.0 InnoDB compatibility */
...@@ -4303,7 +4303,8 @@ Field_timestamp::Field_timestamp(char *ptr_arg, uint32 len_arg, ...@@ -4303,7 +4303,8 @@ Field_timestamp::Field_timestamp(char *ptr_arg, uint32 len_arg,
Field_timestamp::Field_timestamp(bool maybe_null_arg, Field_timestamp::Field_timestamp(bool maybe_null_arg,
const char *field_name_arg, const char *field_name_arg,
struct st_table *table_arg, CHARSET_INFO *cs) struct st_table *table_arg, CHARSET_INFO *cs)
:Field_str((char*) 0, 19, maybe_null_arg ? (uchar*) "": 0, 0, :Field_str((char*) 0, MAX_DATETIME_WIDTH,
maybe_null_arg ? (uchar*) "": 0, 0,
NONE, field_name_arg, table_arg, cs) NONE, field_name_arg, table_arg, cs)
{ {
/* For 4.0 MYD and 4.0 InnoDB compatibility */ /* For 4.0 MYD and 4.0 InnoDB compatibility */
...@@ -4834,7 +4835,7 @@ String *Field_time::val_str(String *val_buffer, ...@@ -4834,7 +4835,7 @@ String *Field_time::val_str(String *val_buffer,
String *val_ptr __attribute__((unused))) String *val_ptr __attribute__((unused)))
{ {
MYSQL_TIME ltime; MYSQL_TIME ltime;
val_buffer->alloc(19); val_buffer->alloc(MAX_DATE_STRING_REP_LENGTH);
long tmp=(long) sint3korr(ptr); long tmp=(long) sint3korr(ptr);
ltime.neg= 0; ltime.neg= 0;
if (tmp < 0) if (tmp < 0)
...@@ -5370,7 +5371,7 @@ int Field_newdate::store_time(MYSQL_TIME *ltime, timestamp_type time_type) ...@@ -5370,7 +5371,7 @@ int Field_newdate::store_time(MYSQL_TIME *ltime, timestamp_type time_type)
(MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE | (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE |
MODE_INVALID_DATES))), &error)) MODE_INVALID_DATES))), &error))
{ {
char buff[12]; char buff[MAX_DATE_STRING_REP_LENGTH];
String str(buff, sizeof(buff), &my_charset_latin1); String str(buff, sizeof(buff), &my_charset_latin1);
make_date((DATE_TIME_FORMAT *) 0, ltime, &str); make_date((DATE_TIME_FORMAT *) 0, ltime, &str);
set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED,
...@@ -5595,7 +5596,7 @@ int Field_datetime::store_time(MYSQL_TIME *ltime,timestamp_type time_type) ...@@ -5595,7 +5596,7 @@ int Field_datetime::store_time(MYSQL_TIME *ltime,timestamp_type time_type)
(MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE | (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE |
MODE_INVALID_DATES))), &error)) MODE_INVALID_DATES))), &error))
{ {
char buff[19]; char buff[MAX_DATE_STRING_REP_LENGTH];
String str(buff, sizeof(buff), &my_charset_latin1); String str(buff, sizeof(buff), &my_charset_latin1);
make_datetime((DATE_TIME_FORMAT *) 0, ltime, &str); make_datetime((DATE_TIME_FORMAT *) 0, ltime, &str);
set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED,
...@@ -5669,7 +5670,7 @@ String *Field_datetime::val_str(String *val_buffer, ...@@ -5669,7 +5670,7 @@ String *Field_datetime::val_str(String *val_buffer,
part1=(long) (tmp/LL(1000000)); part1=(long) (tmp/LL(1000000));
part2=(long) (tmp - (ulonglong) part1*LL(1000000)); part2=(long) (tmp - (ulonglong) part1*LL(1000000));
pos=(char*) val_buffer->ptr()+19; pos= (char*) val_buffer->ptr() + MAX_DATETIME_WIDTH;
*pos--=0; *pos--=0;
*pos--= (char) ('0'+(char) (part2%10)); part2/=10; *pos--= (char) ('0'+(char) (part2%10)); part2/=10;
*pos--= (char) ('0'+(char) (part2%10)); part3= (int) (part2 / 10); *pos--= (char) ('0'+(char) (part2%10)); part3= (int) (part2 / 10);
...@@ -8565,15 +8566,18 @@ bool create_field::init(THD *thd, char *fld_name, enum_field_types fld_type, ...@@ -8565,15 +8566,18 @@ bool create_field::init(THD *thd, char *fld_name, enum_field_types fld_type,
break; break;
case FIELD_TYPE_TIMESTAMP: case FIELD_TYPE_TIMESTAMP:
if (!fld_length) if (!fld_length)
length= 14; /* Full date YYYYMMDDHHMMSS */ {
else if (length != 19) /* Compressed date YYYYMMDDHHMMSS */
length= MAX_DATETIME_COMPRESSED_WIDTH;
}
else if (length != MAX_DATETIME_WIDTH)
{ {
/* /*
We support only even TIMESTAMP lengths less or equal than 14 We support only even TIMESTAMP lengths less or equal than 14
and 19 as length of 4.1 compatible representation. and 19 as length of 4.1 compatible representation.
*/ */
length= ((length+1)/2)*2; /* purecov: inspected */ length= ((length+1)/2)*2; /* purecov: inspected */
length= min(length,14); /* purecov: inspected */ length= min(length, MAX_DATETIME_COMPRESSED_WIDTH); /* purecov: inspected */
} }
flags|= ZEROFILL_FLAG | UNSIGNED_FLAG; flags|= ZEROFILL_FLAG | UNSIGNED_FLAG;
if (fld_default_value) if (fld_default_value)
...@@ -8626,7 +8630,7 @@ bool create_field::init(THD *thd, char *fld_name, enum_field_types fld_type, ...@@ -8626,7 +8630,7 @@ bool create_field::init(THD *thd, char *fld_name, enum_field_types fld_type,
length= 10; length= 10;
break; break;
case FIELD_TYPE_DATETIME: case FIELD_TYPE_DATETIME:
length= 19; length= MAX_DATETIME_WIDTH;
break; break;
case FIELD_TYPE_SET: case FIELD_TYPE_SET:
{ {
......
...@@ -51,7 +51,7 @@ static bool make_datetime(date_time_format_types format, MYSQL_TIME *ltime, ...@@ -51,7 +51,7 @@ static bool make_datetime(date_time_format_types format, MYSQL_TIME *ltime,
{ {
char *buff; char *buff;
CHARSET_INFO *cs= &my_charset_bin; CHARSET_INFO *cs= &my_charset_bin;
uint length= 30; uint length= MAX_DATE_STRING_REP_LENGTH;
if (str->alloc(length)) if (str->alloc(length))
return 1; return 1;
...@@ -1400,7 +1400,7 @@ String *Item_date::val_str(String *str) ...@@ -1400,7 +1400,7 @@ String *Item_date::val_str(String *str)
MYSQL_TIME ltime; MYSQL_TIME ltime;
if (get_date(&ltime, TIME_FUZZY_DATE)) if (get_date(&ltime, TIME_FUZZY_DATE))
return (String *) 0; return (String *) 0;
if (str->alloc(11)) if (str->alloc(MAX_DATE_STRING_REP_LENGTH))
{ {
null_value= 1; null_value= 1;
return (String *) 0; return (String *) 0;
...@@ -1449,7 +1449,7 @@ void Item_func_curdate::fix_length_and_dec() ...@@ -1449,7 +1449,7 @@ void Item_func_curdate::fix_length_and_dec()
String *Item_func_curdate::val_str(String *str) String *Item_func_curdate::val_str(String *str)
{ {
DBUG_ASSERT(fixed == 1); DBUG_ASSERT(fixed == 1);
if (str->alloc(11)) if (str->alloc(MAX_DATE_STRING_REP_LENGTH))
{ {
null_value= 1; null_value= 1;
return (String *) 0; return (String *) 0;
...@@ -1678,7 +1678,8 @@ String *Item_func_sec_to_time::val_str(String *str) ...@@ -1678,7 +1678,8 @@ String *Item_func_sec_to_time::val_str(String *str)
MYSQL_TIME ltime; MYSQL_TIME ltime;
longlong arg_val= args[0]->val_int(); longlong arg_val= args[0]->val_int();
if ((null_value=args[0]->null_value) || str->alloc(19)) if ((null_value=args[0]->null_value) ||
str->alloc(MAX_DATE_STRING_REP_LENGTH))
{ {
null_value= 1; null_value= 1;
return (String*) 0; return (String*) 0;
...@@ -1863,6 +1864,10 @@ String *Item_func_date_format::val_str(String *str) ...@@ -1863,6 +1864,10 @@ String *Item_func_date_format::val_str(String *str)
size=max_length; size=max_length;
else else
size=format_length(format); size=format_length(format);
if (size < MAX_DATE_STRING_REP_LENGTH)
size= MAX_DATE_STRING_REP_LENGTH;
if (format == str) if (format == str)
str= &value; // Save result here str= &value; // Save result here
if (str->alloc(size)) if (str->alloc(size))
...@@ -1906,13 +1911,14 @@ String *Item_func_from_unixtime::val_str(String *str) ...@@ -1906,13 +1911,14 @@ String *Item_func_from_unixtime::val_str(String *str)
if (get_date(&time_tmp, 0)) if (get_date(&time_tmp, 0))
return 0; return 0;
if (str->alloc(20*MY_CHARSET_BIN_MB_MAXLEN)) if (str->alloc(MAX_DATE_STRING_REP_LENGTH))
{ {
null_value= 1; null_value= 1;
return 0; return 0;
} }
make_datetime((DATE_TIME_FORMAT *) 0, &time_tmp, str); make_datetime((DATE_TIME_FORMAT *) 0, &time_tmp, str);
return str; return str;
} }
...@@ -1974,14 +1980,15 @@ String *Item_func_convert_tz::val_str(String *str) ...@@ -1974,14 +1980,15 @@ String *Item_func_convert_tz::val_str(String *str)
if (get_date(&time_tmp, 0)) if (get_date(&time_tmp, 0))
return 0; return 0;
if (str->alloc(20*MY_CHARSET_BIN_MB_MAXLEN)) if (str->alloc(MAX_DATE_STRING_REP_LENGTH))
{ {
null_value= 1; null_value= 1;
return 0; return 0;
} }
make_datetime((DATE_TIME_FORMAT *) 0, &time_tmp, str); make_datetime((DATE_TIME_FORMAT *) 0, &time_tmp, str);
return str; return str;
} }
...@@ -2582,6 +2589,7 @@ String *Item_datetime_typecast::val_str(String *str) ...@@ -2582,6 +2589,7 @@ String *Item_datetime_typecast::val_str(String *str)
{ {
DBUG_ASSERT(fixed == 1); DBUG_ASSERT(fixed == 1);
MYSQL_TIME ltime; MYSQL_TIME ltime;
if (!get_arg0_date(&ltime, TIME_FUZZY_DATE) && if (!get_arg0_date(&ltime, TIME_FUZZY_DATE) &&
!make_datetime(ltime.second_part ? DATE_TIME_MICROSECOND : DATE_TIME, !make_datetime(ltime.second_part ? DATE_TIME_MICROSECOND : DATE_TIME,
&ltime, str)) &ltime, str))
...@@ -2660,7 +2668,8 @@ String *Item_date_typecast::val_str(String *str) ...@@ -2660,7 +2668,8 @@ String *Item_date_typecast::val_str(String *str)
DBUG_ASSERT(fixed == 1); DBUG_ASSERT(fixed == 1);
MYSQL_TIME ltime; MYSQL_TIME ltime;
if (!get_arg0_date(&ltime, TIME_FUZZY_DATE) && !str->alloc(11)) if (!get_arg0_date(&ltime, TIME_FUZZY_DATE) &&
!str->alloc(MAX_DATE_STRING_REP_LENGTH))
{ {
make_date((DATE_TIME_FORMAT *) 0, &ltime, str); make_date((DATE_TIME_FORMAT *) 0, &ltime, str);
return str; return str;
...@@ -2713,7 +2722,7 @@ String *Item_func_makedate::val_str(String *str) ...@@ -2713,7 +2722,7 @@ String *Item_func_makedate::val_str(String *str)
{ {
null_value=0; null_value=0;
get_date_from_daynr(days,&l_time.year,&l_time.month,&l_time.day); get_date_from_daynr(days,&l_time.year,&l_time.month,&l_time.day);
if (str->alloc(11)) if (str->alloc(MAX_DATE_STRING_REP_LENGTH))
goto err; goto err;
make_date((DATE_TIME_FORMAT *) 0, &l_time, str); make_date((DATE_TIME_FORMAT *) 0, &l_time, str);
return str; return str;
...@@ -2849,6 +2858,7 @@ String *Item_func_add_time::val_str(String *str) ...@@ -2849,6 +2858,7 @@ String *Item_func_add_time::val_str(String *str)
days= (long)(seconds/86400L); days= (long)(seconds/86400L);
calc_time_from_sec(&l_time3, (long)(seconds%86400L), microseconds); calc_time_from_sec(&l_time3, (long)(seconds%86400L), microseconds);
if (!is_time) if (!is_time)
{ {
get_date_from_daynr(days,&l_time3.year,&l_time3.month,&l_time3.day); get_date_from_daynr(days,&l_time3.year,&l_time3.month,&l_time3.day);
...@@ -2964,7 +2974,7 @@ String *Item_func_maketime::val_str(String *str) ...@@ -2964,7 +2974,7 @@ String *Item_func_maketime::val_str(String *str)
args[2]->null_value || args[2]->null_value ||
minute < 0 || minute > 59 || minute < 0 || minute > 59 ||
second < 0 || second > 59 || second < 0 || second > 59 ||
str->alloc(19)))) str->alloc(MAX_DATE_STRING_REP_LENGTH))))
return 0; return 0;
bzero((char *)&ltime, sizeof(ltime)); bzero((char *)&ltime, sizeof(ltime));
......
...@@ -71,6 +71,7 @@ ...@@ -71,6 +71,7 @@
#define MAX_TIME_WIDTH 23 /* -DDDDDD HH:MM:SS.###### */ #define MAX_TIME_WIDTH 23 /* -DDDDDD HH:MM:SS.###### */
#define MAX_DATETIME_FULL_WIDTH 29 /* YYYY-MM-DD HH:MM:SS.###### AM */ #define MAX_DATETIME_FULL_WIDTH 29 /* YYYY-MM-DD HH:MM:SS.###### AM */
#define MAX_DATETIME_WIDTH 19 /* YYYY-MM-DD HH:MM:SS */ #define MAX_DATETIME_WIDTH 19 /* YYYY-MM-DD HH:MM:SS */
#define MAX_DATETIME_COMPRESSED_WIDTH 14 /* YYYYMMDDHHMMSS */
#define MAX_TABLES (sizeof(table_map)*8-3) /* Max tables in join */ #define MAX_TABLES (sizeof(table_map)*8-3) /* Max tables in join */
#define PARAM_TABLE_BIT (((table_map) 1) << (sizeof(table_map)*8-3)) #define PARAM_TABLE_BIT (((table_map) 1) << (sizeof(table_map)*8-3))
......
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