diff options
author | Alexander Barkov <bar@mariadb.com> | 2019-04-30 10:53:59 +0400 |
---|---|---|
committer | Alexander Barkov <bar@mariadb.com> | 2019-04-30 10:53:59 +0400 |
commit | 5fb6444a371a5d85c832e63c02e6e8eaec2769f7 (patch) | |
tree | 2f2ec687c2cc59375e3f43012ac939dd209623d1 /sql/sql_string.cc | |
parent | 021c7216c05f3143c5113fc9a4aea3d11b6bac48 (diff) | |
download | mariadb-git-5fb6444a371a5d85c832e63c02e6e8eaec2769f7.tar.gz |
MDEV-18738 ASAN heap-use-after-free in copy_if_not_alloced / copy_fields
copy_if_not_alloced() did not handle situations when
"from" is a constant string pointing to a substring of "to",
so this code part freed "to" but then tried to copy its old (already freed)
content to a new buffer:
if (to->realloc(from_length))
return from;
if ((to->str_length=MY_MIN(from->str_length,from_length)))
memcpy(to->Ptr,from->Ptr,to->str_length);
Adding a new code piece that catches such constant substrings
and propery reallocs "to" to preserve its important part referenced
by "from".
Diffstat (limited to 'sql/sql_string.cc')
-rw-r--r-- | sql/sql_string.cc | 21 |
1 files changed, 21 insertions, 0 deletions
diff --git a/sql/sql_string.cc b/sql/sql_string.cc index c22e33182c6..8c69bea2487 100644 --- a/sql/sql_string.cc +++ b/sql/sql_string.cc @@ -909,6 +909,27 @@ String *copy_if_not_alloced(String *to,String *from,uint32 from_length) (void) from->realloc(from_length); return from; } + if (from->uses_buffer_owned_by(to)) + { + DBUG_ASSERT(!from->alloced); + DBUG_ASSERT(to->alloced); + /* + "from" is a constant string pointing to a fragment of alloced string "to": + to= xxxFFFyyy + - FFF is the part of "to" pointed by "from" + - xxx is the part of "to" before "from" + - yyy is the part of "to" after "from" + */ + uint32 xxx_length= (uint32) (from->ptr() - to->ptr()); + uint32 yyy_length= (uint32) (to->end() - from->end()); + DBUG_ASSERT(to->length() >= yyy_length); + to->length(to->length() - yyy_length); // Remove the "yyy" part + DBUG_ASSERT(to->length() >= xxx_length); + to->replace(0, xxx_length, "", 0); // Remove the "xxx" part + to->realloc(from_length); + to->str_charset= from->str_charset; + return to; + } if (to->realloc(from_length)) return from; // Actually an error if ((to->str_length=MY_MIN(from->str_length,from_length))) |