summaryrefslogtreecommitdiff
path: root/sql/field.cc
diff options
context:
space:
mode:
authorMichael Widenius <monty@askmonty.org>2012-03-13 16:38:43 +0200
committerMichael Widenius <monty@askmonty.org>2012-03-13 16:38:43 +0200
commit6f06cef02b062f240806cad555275c54fd68eba6 (patch)
tree0f0a13215822bd8fe1f0dae21d68be7e5a3accdb /sql/field.cc
parent223483aedf0c53bc66cb6833210228b46448003a (diff)
downloadmariadb-git-6f06cef02b062f240806cad555275c54fd68eba6.tar.gz
Fixed bug lp:917689 "Archive table corruption crashing MariaDB signal 11"
Added 'from_end' as extra parameter to Field::unpack() to detect wrong from data. Change ha_archive::unpack_row() to detect wrong field lengths. Replication code changed to detect wrong field information in events. mysql-test/r/archive.result: dded test case for lp:917689 sql/field.cc: Added 'from_end' as extra parameter to Field::unpack() to detect wrong from data. Removed not used 'unpack_key' functions. sql/field.h: Added 'from_end' as extra parameter to Field::unpack() to detect wrong from data. Removed not used 'unpack_key' functions. Removed some not needed unpack() functions. sql/filesort.cc: Added buffer end parameter to unpack_addon_fields() sql/log_event.h: Added end of buffer argument to unpack_row() sql/log_event_old.cc: Added end of buffer argument to unpack_row() sql/log_event_old.h: Added end of buffer argument to unpack_row() sql/records.cc: Added buffer end parameter to unpack_addon_fields() sql/rpl_record.cc: Added end of buffer argument to unpack_row() Added detection of wrong field information in events sql/rpl_record.h: Added end of buffer argument to unpack_row() sql/rpl_record_old.cc: Added end of buffer argument to unpack_row() Added detection of wrong field information in events sql/rpl_record_old.h: Added end of buffer argument to unpack_row() sql/table.h: Added buffer end parameter to unpack() storage/archive/ha_archive.cc: Change ha_archive::unpack_row() to detect wrong field lengths. This fixes lp:917689
Diffstat (limited to 'sql/field.cc')
-rw-r--r--sql/field.cc74
1 files changed, 61 insertions, 13 deletions
diff --git a/sql/field.cc b/sql/field.cc
index 934816ba381..aeaf1a7a21e 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -1472,11 +1472,13 @@ Field::pack(uchar *to, const uchar *from, uint max_length)
data
@return New pointer into memory based on from + length of the data
+ @return 0 if wrong data
*/
const uchar *
-Field::unpack(uchar* to, const uchar *from, uint param_data)
+Field::unpack(uchar* to, const uchar *from, const uchar *from_end,
+ uint param_data)
{
- uint length=pack_length();
+ uint length=pack_length(), len;
int from_type= 0;
/*
If from length is > 255, it has encoded data in the upper bits. Need
@@ -1492,14 +1494,19 @@ Field::unpack(uchar* to, const uchar *from, uint param_data)
(length == param_data) ||
(from_type != real_type()))
{
+ if (from + length > from_end)
+ return 0; // Error in data
+
memcpy(to, from, length);
return from+length;
}
- uint len= (param_data && (param_data < length)) ?
- param_data : length;
+ len= (param_data && (param_data < length)) ? param_data : length;
- memcpy(to, from, param_data > length ? length : len);
+ if (from + len > from_end)
+ return 0; // Error in data
+
+ memcpy(to, from, len);
return from+len;
}
@@ -2916,10 +2923,11 @@ uint Field_new_decimal::is_equal(Create_field *new_field)
@return New pointer into memory based on from + length of the data
*/
const uchar *
-Field_new_decimal::unpack(uchar* to, const uchar *from, uint param_data)
+Field_new_decimal::unpack(uchar* to, const uchar *from, const uchar *from_end,
+ uint param_data)
{
if (param_data == 0)
- return Field::unpack(to, from, param_data);
+ return Field::unpack(to, from, from_end, param_data);
uint from_precision= (param_data & 0xff00) >> 8U;
uint from_decimal= param_data & 0x00ff;
@@ -2949,7 +2957,11 @@ Field_new_decimal::unpack(uchar* to, const uchar *from, uint param_data)
decimal2bin(&dec_val, to, precision, decimals());
}
else
+ {
+ if (from + len > from_end)
+ return 0; // Wrong data
memcpy(to, from, len); // Sizes are the same, just copy the data.
+ }
return from+len;
}
@@ -6542,7 +6554,8 @@ uchar *Field_string::pack(uchar *to, const uchar *from, uint max_length)
@return New pointer into memory based on from + length of the data
*/
const uchar *
-Field_string::unpack(uchar *to, const uchar *from, uint param_data)
+Field_string::unpack(uchar *to, const uchar *from, const uchar *from_end,
+ uint param_data)
{
uint from_length, length;
@@ -6564,11 +6577,19 @@ Field_string::unpack(uchar *to, const uchar *from, uint param_data)
*/
if (from_length > 255)
{
+ if (from + 2 > from_end)
+ return 0;
length= uint2korr(from);
from+= 2;
}
else
+ {
+ if (from + 1 > from_end)
+ return 0;
length= (uint) *from++;
+ }
+ if (from + length > from_end || length > field_length)
+ return 0;
memcpy(to, from, length);
// Pad the string with the pad character of the fields charset
@@ -7060,6 +7081,7 @@ Field_varstring::pack_key(uchar *to, const uchar *key, uint max_length)
Pointer to end of 'key' (To the next key part if multi-segment key)
*/
+#ifdef NOT_USED
const uchar *
Field_varstring::unpack_key(uchar *to, const uchar *key, uint max_length)
{
@@ -7076,6 +7098,7 @@ Field_varstring::unpack_key(uchar *to, const uchar *key, uint max_length)
memcpy(ptr + length_bytes, key, length);
return key + length;
}
+#endif
/**
Create a packed key that will be used for storage in the index tree.
@@ -7120,11 +7143,16 @@ uchar * Field_varstring::pack_key_from_key_image(uchar *to, const uchar *from,
@return New pointer into memory based on from + length of the data
*/
const uchar *
-Field_varstring::unpack(uchar *to, const uchar *from, uint param_data)
+Field_varstring::unpack(uchar *to, const uchar *from, const uchar *from_end,
+ uint param_data)
{
uint length;
uint l_bytes= (param_data && (param_data < field_length)) ?
(param_data <= 255) ? 1 : 2 : length_bytes;
+
+ if (from + l_bytes > from_end)
+ return 0; // Error in data
+
if (l_bytes == 1)
{
to[0]= *from++;
@@ -7139,7 +7167,11 @@ Field_varstring::unpack(uchar *to, const uchar *from, uint param_data)
to[1]= *from++;
}
if (length)
+ {
+ if (from + length > from_end || length > field_length)
+ return 0; // Error in data
memcpy(to+ length_bytes, from, length);
+ }
return from+length;
}
@@ -7771,16 +7803,21 @@ uchar *Field_blob::pack(uchar *to, const uchar *from, uint max_length)
@return New pointer into memory based on from + length of the data
*/
-const uchar *Field_blob::unpack(uchar *to, const uchar *from, uint param_data)
+const uchar *Field_blob::unpack(uchar *to, const uchar *from,
+ const uchar *from_end, uint param_data)
{
DBUG_ENTER("Field_blob::unpack");
DBUG_PRINT("enter", ("to: 0x%lx; from: 0x%lx; param_data: %u",
(ulong) to, (ulong) from, param_data));
uint const master_packlength=
param_data > 0 ? param_data & 0xFF : packlength;
+ if (from + master_packlength > from_end)
+ DBUG_RETURN(0); // Error in data
uint32 const length= get_length(from, master_packlength);
DBUG_DUMP("packed", from, length + master_packlength);
bitmap_set_bit(table->write_set, field_index);
+ if (from + master_packlength + length > from_end)
+ DBUG_RETURN(0);
store(reinterpret_cast<const char*>(from) + master_packlength,
length, field_charset);
DBUG_DUMP("record", to, table->s->reclength);
@@ -7878,6 +7915,7 @@ Field_blob::pack_key(uchar *to, const uchar *from, uint max_length)
Pointer into 'from' past the last byte copied from packed key.
*/
+#ifdef NOT_USED
const uchar *
Field_blob::unpack_key(uchar *to, const uchar *from, uint max_length)
{
@@ -7898,7 +7936,7 @@ Field_blob::unpack_key(uchar *to, const uchar *from, uint max_length)
/* point to first byte of next field in 'from' */
return from + length;
}
-
+#endif
/** Create a packed key that will be used for storage from a MySQL key. */
@@ -8940,7 +8978,8 @@ Field_bit::pack(uchar *to, const uchar *from, uint max_length)
@return New pointer into memory based on from + length of the data
*/
const uchar *
-Field_bit::unpack(uchar *to, const uchar *from, uint param_data)
+Field_bit::unpack(uchar *to, const uchar *from, const uchar *from_end,
+ uint param_data)
{
uint const from_len= (param_data >> 8U) & 0x00ff;
uint const from_bit_len= param_data & 0x00ff;
@@ -8951,6 +8990,9 @@ Field_bit::unpack(uchar *to, const uchar *from, uint param_data)
if (param_data == 0 ||
((from_bit_len == bit_len) && (from_len == bytes_in_rec)))
{
+ if (from + bytes_in_rec + test(bit_len) > from_end)
+ return 0; // Error in data
+
if (bit_len > 0)
{
/*
@@ -8975,10 +9017,16 @@ Field_bit::unpack(uchar *to, const uchar *from, uint param_data)
Lastly the odd bits need to be masked out if the bytes_in_rec > 0.
Otherwise stray bits can cause spurious values.
*/
+
+ uint len= from_len + ((from_bit_len > 0) ? 1 : 0);
uint new_len= (field_length + 7) / 8;
+
+ if (from + len > from_end || new_len < len)
+ return 0; // Error in data
+
char *value= (char *)my_alloca(new_len);
bzero(value, new_len);
- uint len= from_len + ((from_bit_len > 0) ? 1 : 0);
+
memcpy(value + (new_len - len), from, len);
/*
Mask out the unused bits in the partial byte.