Commit c84dde14 authored by Alexander Barkov's avatar Alexander Barkov

MDEV-19184 Crash in IS_IPV6(_ucs2 0x0031)

parent 02d9b048
...@@ -6393,5 +6393,29 @@ SELECT HEX(INET6_ATON('1::1')), HEX(INET6_ATON(CONVERT('1::1' USING ucs2))); ...@@ -6393,5 +6393,29 @@ SELECT HEX(INET6_ATON('1::1')), HEX(INET6_ATON(CONVERT('1::1' USING ucs2)));
HEX(INET6_ATON('1::1')) HEX(INET6_ATON(CONVERT('1::1' USING ucs2))) HEX(INET6_ATON('1::1')) HEX(INET6_ATON(CONVERT('1::1' USING ucs2)))
00010000000000000000000000000001 00010000000000000000000000000001 00010000000000000000000000000001 00010000000000000000000000000001
# #
# MDEV-19184 Crash in IS_IPV6(_ucs2 0x0031)
#
SET NAMES utf8;
SELECT IS_IPV6(_ucs2 0x0031);
IS_IPV6(_ucs2 0x0031)
0
SELECT IS_IPV4(_ucs2 0x0031);
IS_IPV4(_ucs2 0x0031)
0
SELECT IS_IPV6(_ucs2 0x003A003A);
IS_IPV6(_ucs2 0x003A003A)
1
SELECT IS_IPV4(_ucs2 0x00310030002E0030002E0030002E0031);
IS_IPV4(_ucs2 0x00310030002E0030002E0030002E0031)
1
SET NAMES utf8, collation_connection=ucs2_bin;
SELECT IS_IPV6('::');
IS_IPV6('::')
1
SELECT IS_IPV4('10.0.0.1');
IS_IPV4('10.0.0.1')
1
SET NAMES utf8;
#
# End of 10.4 tests # End of 10.4 tests
# #
...@@ -1105,6 +1105,21 @@ DEALLOCATE PREPARE stmt; ...@@ -1105,6 +1105,21 @@ DEALLOCATE PREPARE stmt;
SELECT HEX(INET6_ATON('1::1')), HEX(INET6_ATON(CONVERT('1::1' USING ucs2))); SELECT HEX(INET6_ATON('1::1')), HEX(INET6_ATON(CONVERT('1::1' USING ucs2)));
--echo #
--echo # MDEV-19184 Crash in IS_IPV6(_ucs2 0x0031)
--echo #
SET NAMES utf8;
SELECT IS_IPV6(_ucs2 0x0031);
SELECT IS_IPV4(_ucs2 0x0031);
SELECT IS_IPV6(_ucs2 0x003A003A);
SELECT IS_IPV4(_ucs2 0x00310030002E0030002E0030002E0031);
SET NAMES utf8, collation_connection=ucs2_bin;
SELECT IS_IPV6('::');
SELECT IS_IPV4('10.0.0.1');
SET NAMES utf8;
--echo # --echo #
--echo # End of 10.4 tests --echo # End of 10.4 tests
......
...@@ -22,9 +22,18 @@ ...@@ -22,9 +22,18 @@
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
static const size_t IN_ADDR_SIZE= 4; static const size_t IN_ADDR_SIZE= 4;
static const size_t IN_ADDR_MAX_CHAR_LENGTH= 15;
static const size_t IN6_ADDR_SIZE= 16; static const size_t IN6_ADDR_SIZE= 16;
static const size_t IN6_ADDR_NUM_WORDS= IN6_ADDR_SIZE / 2; static const size_t IN6_ADDR_NUM_WORDS= IN6_ADDR_SIZE / 2;
/**
Non-abbreviated syntax is 8 groups, up to 4 digits each,
plus 7 delimiters between the groups.
Abbreviated syntax is even shorter.
*/
static const uint IN6_ADDR_MAX_CHAR_LENGTH= 8 * 4 + 7;
static const char HEX_DIGITS[]= "0123456789abcdef"; static const char HEX_DIGITS[]= "0123456789abcdef";
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
...@@ -143,7 +152,20 @@ class Inet4 ...@@ -143,7 +152,20 @@ class Inet4
{ {
char m_buffer[IN_ADDR_SIZE]; char m_buffer[IN_ADDR_SIZE];
protected: protected:
bool str_to_ipv4(const char *str, size_t length, CHARSET_INFO *cs); bool ascii_to_ipv4(const char *str, size_t length);
bool character_string_to_ipv4(const char *str, size_t str_length,
CHARSET_INFO *cs)
{
if (cs->state & MY_CS_NONASCII)
{
char tmp[IN_ADDR_MAX_CHAR_LENGTH];
String_copier copier;
uint length= copier.well_formed_copy(&my_charset_latin1, tmp, sizeof(tmp),
cs, str, str_length);
return ascii_to_ipv4(tmp, length);
}
return ascii_to_ipv4(str, str_length);
}
bool binary_to_ipv4(const char *str, size_t length) bool binary_to_ipv4(const char *str, size_t length)
{ {
if (length != sizeof(m_buffer)) if (length != sizeof(m_buffer))
...@@ -180,7 +202,7 @@ class Inet4_null: public Inet4, public Null_flag ...@@ -180,7 +202,7 @@ class Inet4_null: public Inet4, public Null_flag
public: public:
// Initialize from a text representation // Initialize from a text representation
Inet4_null(const char *str, size_t length, CHARSET_INFO *cs) Inet4_null(const char *str, size_t length, CHARSET_INFO *cs)
:Null_flag(str_to_ipv4(str, length, cs)) :Null_flag(character_string_to_ipv4(str, length, cs))
{ } { }
Inet4_null(const String &str) Inet4_null(const String &str)
:Inet4_null(str.ptr(), str.length(), str.charset()) :Inet4_null(str.ptr(), str.length(), str.charset())
...@@ -222,7 +244,20 @@ class Inet6 ...@@ -222,7 +244,20 @@ class Inet6
char m_buffer[IN6_ADDR_SIZE]; char m_buffer[IN6_ADDR_SIZE];
protected: protected:
bool make_from_item(Item *item); bool make_from_item(Item *item);
bool str_to_ipv6(const char *str, size_t str_length, CHARSET_INFO *cs); bool ascii_to_ipv6(const char *str, size_t str_length);
bool character_string_to_ipv6(const char *str, size_t str_length,
CHARSET_INFO *cs)
{
if (cs->state & MY_CS_NONASCII)
{
char tmp[IN6_ADDR_MAX_CHAR_LENGTH];
String_copier copier;
uint length= copier.well_formed_copy(&my_charset_latin1, tmp, sizeof(tmp),
cs, str, str_length);
return ascii_to_ipv6(tmp, length);
}
return ascii_to_ipv6(str, str_length);
}
bool binary_to_ipv6(const char *str, size_t length) bool binary_to_ipv6(const char *str, size_t length)
{ {
if (length != sizeof(m_buffer)) if (length != sizeof(m_buffer))
...@@ -264,7 +299,7 @@ class Inet6_null: public Inet6, public Null_flag ...@@ -264,7 +299,7 @@ class Inet6_null: public Inet6, public Null_flag
public: public:
// Initialize from a text representation // Initialize from a text representation
Inet6_null(const char *str, size_t length, CHARSET_INFO *cs) Inet6_null(const char *str, size_t length, CHARSET_INFO *cs)
:Null_flag(str_to_ipv6(str, length, cs)) :Null_flag(character_string_to_ipv6(str, length, cs))
{ } { }
Inet6_null(const String &str) Inet6_null(const String &str)
:Inet6_null(str.ptr(), str.length(), str.charset()) :Inet6_null(str.ptr(), str.length(), str.charset())
...@@ -343,20 +378,19 @@ bool Inet6::make_from_item(Item *item) ...@@ -343,20 +378,19 @@ bool Inet6::make_from_item(Item *item)
IPv4-part differently on different platforms. IPv4-part differently on different platforms.
*/ */
bool Inet4::str_to_ipv4(const char *str, size_t str_length, CHARSET_INFO *cs) bool Inet4::ascii_to_ipv4(const char *str, size_t str_length)
{ {
DBUG_ASSERT(cs->mbminlen == 1);
if (str_length < 7) if (str_length < 7)
{ {
DBUG_PRINT("error", ("str_to_ipv4(%.*s): " DBUG_PRINT("error", ("ascii_to_ipv4(%.*s): "
"invalid IPv4 address: too short.", "invalid IPv4 address: too short.",
(int) str_length, str)); (int) str_length, str));
return true; return true;
} }
if (str_length > 15) if (str_length > IN_ADDR_MAX_CHAR_LENGTH)
{ {
DBUG_PRINT("error", ("str_to_ipv4(%.*s): " DBUG_PRINT("error", ("ascii_to_ipv4(%.*s): "
"invalid IPv4 address: too long.", "invalid IPv4 address: too long.",
(int) str_length, str)); (int) str_length, str));
return true; return true;
...@@ -380,7 +414,7 @@ bool Inet4::str_to_ipv4(const char *str, size_t str_length, CHARSET_INFO *cs) ...@@ -380,7 +414,7 @@ bool Inet4::str_to_ipv4(const char *str, size_t str_length, CHARSET_INFO *cs)
if (chars_in_group > 3) if (chars_in_group > 3)
{ {
DBUG_PRINT("error", ("str_to_ipv4(%.*s): invalid IPv4 address: " DBUG_PRINT("error", ("ascii_to_ipv4(%.*s): invalid IPv4 address: "
"too many characters in a group.", "too many characters in a group.",
(int) str_length, str)); (int) str_length, str));
return true; return true;
...@@ -390,7 +424,7 @@ bool Inet4::str_to_ipv4(const char *str, size_t str_length, CHARSET_INFO *cs) ...@@ -390,7 +424,7 @@ bool Inet4::str_to_ipv4(const char *str, size_t str_length, CHARSET_INFO *cs)
if (byte_value > 255) if (byte_value > 255)
{ {
DBUG_PRINT("error", ("str_to_ipv4(%.*s): invalid IPv4 address: " DBUG_PRINT("error", ("ascii_to_ipv4(%.*s): invalid IPv4 address: "
"invalid byte value.", "invalid byte value.",
(int) str_length, str)); (int) str_length, str));
return true; return true;
...@@ -400,7 +434,7 @@ bool Inet4::str_to_ipv4(const char *str, size_t str_length, CHARSET_INFO *cs) ...@@ -400,7 +434,7 @@ bool Inet4::str_to_ipv4(const char *str, size_t str_length, CHARSET_INFO *cs)
{ {
if (chars_in_group == 0) if (chars_in_group == 0)
{ {
DBUG_PRINT("error", ("str_to_ipv4(%.*s): invalid IPv4 address: " DBUG_PRINT("error", ("ascii_to_ipv4(%.*s): invalid IPv4 address: "
"too few characters in a group.", "too few characters in a group.",
(int) str_length, str)); (int) str_length, str));
return true; return true;
...@@ -414,14 +448,14 @@ bool Inet4::str_to_ipv4(const char *str, size_t str_length, CHARSET_INFO *cs) ...@@ -414,14 +448,14 @@ bool Inet4::str_to_ipv4(const char *str, size_t str_length, CHARSET_INFO *cs)
if (dot_count > 3) if (dot_count > 3)
{ {
DBUG_PRINT("error", ("str_to_ipv4(%.*s): invalid IPv4 address: " DBUG_PRINT("error", ("ascii_to_ipv4(%.*s): invalid IPv4 address: "
"too many dots.", (int) str_length, str)); "too many dots.", (int) str_length, str));
return true; return true;
} }
} }
else else
{ {
DBUG_PRINT("error", ("str_to_ipv4(%.*s): invalid IPv4 address: " DBUG_PRINT("error", ("ascii_to_ipv4(%.*s): invalid IPv4 address: "
"invalid character at pos %d.", "invalid character at pos %d.",
(int) str_length, str, (int) (p - str))); (int) str_length, str, (int) (p - str)));
return true; return true;
...@@ -430,14 +464,14 @@ bool Inet4::str_to_ipv4(const char *str, size_t str_length, CHARSET_INFO *cs) ...@@ -430,14 +464,14 @@ bool Inet4::str_to_ipv4(const char *str, size_t str_length, CHARSET_INFO *cs)
if (c == '.') if (c == '.')
{ {
DBUG_PRINT("error", ("str_to_ipv4(%.*s): invalid IPv4 address: " DBUG_PRINT("error", ("ascii_to_ipv4(%.*s): invalid IPv4 address: "
"ending at '.'.", (int) str_length, str)); "ending at '.'.", (int) str_length, str));
return true; return true;
} }
if (dot_count != 3) if (dot_count != 3)
{ {
DBUG_PRINT("error", ("str_to_ipv4(%.*s): invalid IPv4 address: " DBUG_PRINT("error", ("ascii_to_ipv4(%.*s): invalid IPv4 address: "
"too few groups.", "too few groups.",
(int) str_length, str)); (int) str_length, str));
return true; return true;
...@@ -445,7 +479,7 @@ bool Inet4::str_to_ipv4(const char *str, size_t str_length, CHARSET_INFO *cs) ...@@ -445,7 +479,7 @@ bool Inet4::str_to_ipv4(const char *str, size_t str_length, CHARSET_INFO *cs)
ipv4_bytes[3]= (unsigned char) byte_value; ipv4_bytes[3]= (unsigned char) byte_value;
DBUG_PRINT("info", ("str_to_ipv4(%.*s): valid IPv4 address: %d.%d.%d.%d", DBUG_PRINT("info", ("ascii_to_ipv4(%.*s): valid IPv4 address: %d.%d.%d.%d",
(int) str_length, str, (int) str_length, str,
ipv4_bytes[0], ipv4_bytes[1], ipv4_bytes[0], ipv4_bytes[1],
ipv4_bytes[2], ipv4_bytes[3])); ipv4_bytes[2], ipv4_bytes[3]));
...@@ -468,20 +502,18 @@ bool Inet4::str_to_ipv4(const char *str, size_t str_length, CHARSET_INFO *cs) ...@@ -468,20 +502,18 @@ bool Inet4::str_to_ipv4(const char *str, size_t str_length, CHARSET_INFO *cs)
IPv4-part differently on different platforms. IPv4-part differently on different platforms.
*/ */
bool Inet6::str_to_ipv6(const char *str, size_t str_length, CHARSET_INFO *cs) bool Inet6::ascii_to_ipv6(const char *str, size_t str_length)
{ {
DBUG_ASSERT(cs->mbminlen == 1);
if (str_length < 2) if (str_length < 2)
{ {
DBUG_PRINT("error", ("str_to_ipv6(%.*s): invalid IPv6 address: too short.", DBUG_PRINT("error", ("ascii_to_ipv6(%.*s): invalid IPv6 address: too short.",
(int) str_length, str)); (int) str_length, str));
return true; return true;
} }
if (str_length > 8 * 4 + 7) if (str_length > IN6_ADDR_MAX_CHAR_LENGTH)
{ {
DBUG_PRINT("error", ("str_to_ipv6(%.*s): invalid IPv6 address: too long.", DBUG_PRINT("error", ("ascii_to_ipv6(%.*s): invalid IPv6 address: too long.",
(int) str_length, str)); (int) str_length, str));
return true; return true;
} }
...@@ -496,7 +528,7 @@ bool Inet6::str_to_ipv6(const char *str, size_t str_length, CHARSET_INFO *cs) ...@@ -496,7 +528,7 @@ bool Inet6::str_to_ipv6(const char *str, size_t str_length, CHARSET_INFO *cs)
if (*p != ':') if (*p != ':')
{ {
DBUG_PRINT("error", ("str_to_ipv6(%.*s): invalid IPv6 address: " DBUG_PRINT("error", ("ascii_to_ipv6(%.*s): invalid IPv6 address: "
"can not start with ':x'.", (int) str_length, str)); "can not start with ':x'.", (int) str_length, str));
return true; return true;
} }
...@@ -522,7 +554,7 @@ bool Inet6::str_to_ipv6(const char *str, size_t str_length, CHARSET_INFO *cs) ...@@ -522,7 +554,7 @@ bool Inet6::str_to_ipv6(const char *str, size_t str_length, CHARSET_INFO *cs)
{ {
if (gap_ptr) if (gap_ptr)
{ {
DBUG_PRINT("error", ("str_to_ipv6(%.*s): invalid IPv6 address: " DBUG_PRINT("error", ("ascii_to_ipv6(%.*s): invalid IPv6 address: "
"too many gaps(::).", (int) str_length, str)); "too many gaps(::).", (int) str_length, str));
return true; return true;
} }
...@@ -533,14 +565,14 @@ bool Inet6::str_to_ipv6(const char *str, size_t str_length, CHARSET_INFO *cs) ...@@ -533,14 +565,14 @@ bool Inet6::str_to_ipv6(const char *str, size_t str_length, CHARSET_INFO *cs)
if (!*p || p >= str_end) if (!*p || p >= str_end)
{ {
DBUG_PRINT("error", ("str_to_ipv6(%.*s): invalid IPv6 address: " DBUG_PRINT("error", ("ascii_to_ipv6(%.*s): invalid IPv6 address: "
"ending at ':'.", (int) str_length, str)); "ending at ':'.", (int) str_length, str));
return true; return true;
} }
if (dst + 2 > ipv6_bytes_end) if (dst + 2 > ipv6_bytes_end)
{ {
DBUG_PRINT("error", ("str_to_ipv6(%.*s): invalid IPv6 address: " DBUG_PRINT("error", ("ascii_to_ipv6(%.*s): invalid IPv6 address: "
"too many groups (1).", (int) str_length, str)); "too many groups (1).", (int) str_length, str));
return true; return true;
} }
...@@ -556,15 +588,16 @@ bool Inet6::str_to_ipv6(const char *str, size_t str_length, CHARSET_INFO *cs) ...@@ -556,15 +588,16 @@ bool Inet6::str_to_ipv6(const char *str, size_t str_length, CHARSET_INFO *cs)
{ {
if (dst + IN_ADDR_SIZE > ipv6_bytes_end) if (dst + IN_ADDR_SIZE > ipv6_bytes_end)
{ {
DBUG_PRINT("error", ("str_to_ipv6(%.*s): invalid IPv6 address: " DBUG_PRINT("error", ("ascii_to_ipv6(%.*s): invalid IPv6 address: "
"unexpected IPv4-part.", (int) str_length, str)); "unexpected IPv4-part.", (int) str_length, str));
return true; return true;
} }
Inet4_null tmp(group_start_ptr, (size_t) (str_end - group_start_ptr), cs); Inet4_null tmp(group_start_ptr, (size_t) (str_end - group_start_ptr),
&my_charset_latin1);
if (tmp.is_null()) if (tmp.is_null())
{ {
DBUG_PRINT("error", ("str_to_ipv6(%.*s): invalid IPv6 address: " DBUG_PRINT("error", ("ascii_to_ipv6(%.*s): invalid IPv6 address: "
"invalid IPv4-part.", (int) str_length, str)); "invalid IPv4-part.", (int) str_length, str));
return true; return true;
} }
...@@ -581,7 +614,7 @@ bool Inet6::str_to_ipv6(const char *str, size_t str_length, CHARSET_INFO *cs) ...@@ -581,7 +614,7 @@ bool Inet6::str_to_ipv6(const char *str, size_t str_length, CHARSET_INFO *cs)
if (!hdp) if (!hdp)
{ {
DBUG_PRINT("error", ("str_to_ipv6(%.*s): invalid IPv6 address: " DBUG_PRINT("error", ("ascii_to_ipv6(%.*s): invalid IPv6 address: "
"invalid character at pos %d.", "invalid character at pos %d.",
(int) str_length, str, (int) (p - str))); (int) str_length, str, (int) (p - str)));
return true; return true;
...@@ -589,7 +622,7 @@ bool Inet6::str_to_ipv6(const char *str, size_t str_length, CHARSET_INFO *cs) ...@@ -589,7 +622,7 @@ bool Inet6::str_to_ipv6(const char *str, size_t str_length, CHARSET_INFO *cs)
if (chars_in_group >= 4) if (chars_in_group >= 4)
{ {
DBUG_PRINT("error", ("str_to_ipv6(%.*s): invalid IPv6 address: " DBUG_PRINT("error", ("ascii_to_ipv6(%.*s): invalid IPv6 address: "
"too many digits in group.", "too many digits in group.",
(int) str_length, str)); (int) str_length, str));
return true; return true;
...@@ -608,7 +641,7 @@ bool Inet6::str_to_ipv6(const char *str, size_t str_length, CHARSET_INFO *cs) ...@@ -608,7 +641,7 @@ bool Inet6::str_to_ipv6(const char *str, size_t str_length, CHARSET_INFO *cs)
{ {
if (dst + 2 > ipv6_bytes_end) if (dst + 2 > ipv6_bytes_end)
{ {
DBUG_PRINT("error", ("str_to_ipv6(%.*s): invalid IPv6 address: " DBUG_PRINT("error", ("ascii_to_ipv6(%.*s): invalid IPv6 address: "
"too many groups (2).", (int) str_length, str)); "too many groups (2).", (int) str_length, str));
return true; return true;
} }
...@@ -622,7 +655,7 @@ bool Inet6::str_to_ipv6(const char *str, size_t str_length, CHARSET_INFO *cs) ...@@ -622,7 +655,7 @@ bool Inet6::str_to_ipv6(const char *str, size_t str_length, CHARSET_INFO *cs)
{ {
if (dst == ipv6_bytes_end) if (dst == ipv6_bytes_end)
{ {
DBUG_PRINT("error", ("str_to_ipv6(%.*s): invalid IPv6 address: " DBUG_PRINT("error", ("ascii_to_ipv6(%.*s): invalid IPv6 address: "
"no room for a gap (::).", (int) str_length, str)); "no room for a gap (::).", (int) str_length, str));
return true; return true;
} }
...@@ -640,7 +673,7 @@ bool Inet6::str_to_ipv6(const char *str, size_t str_length, CHARSET_INFO *cs) ...@@ -640,7 +673,7 @@ bool Inet6::str_to_ipv6(const char *str, size_t str_length, CHARSET_INFO *cs)
if (dst < ipv6_bytes_end) if (dst < ipv6_bytes_end)
{ {
DBUG_PRINT("error", ("str_to_ipv6(%.*s): invalid IPv6 address: " DBUG_PRINT("error", ("ascii_to_ipv6(%.*s): invalid IPv6 address: "
"too few groups.", (int) str_length, str)); "too few groups.", (int) str_length, str));
return true; return true;
} }
......
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