Commit 4f02e2f3 authored by Davi Arnaut's avatar Davi Arnaut

Bug#50974: Server keeps receiving big (> max_allowed_packet) packets indefinitely.

The server could be tricked to read packets indefinitely if it
received a packet larger than the maximum size of one packet.
This problem is aggravated by the fact that it can be triggered
before authentication.

The solution is to no skip big packets for non-authenticated
sessions. If a big packet is sent before a session is authen-
ticated, a error is returned and the connection is closed.

include/mysql_com.h:
  Add skip flag. Only used in server builds.
sql/net_serv.cc:
  Control whether big packets can be skipped.
parent 5273a6b9
...@@ -219,6 +219,16 @@ typedef struct st_net { ...@@ -219,6 +219,16 @@ typedef struct st_net {
my_bool report_error; /* We should report error (we have unreported error) */ my_bool report_error; /* We should report error (we have unreported error) */
my_bool return_errno; my_bool return_errno;
#if defined(MYSQL_SERVER) && !defined(EMBEDDED_LIBRARY)
/*
Controls whether a big packet should be skipped.
Initially set to FALSE by default. Unauthenticated sessions must have
this set to FALSE so that the server can't be tricked to read packets
indefinitely.
*/
my_bool skip_big_packet;
#endif
} NET; } NET;
#define packet_error (~(unsigned long) 0) #define packet_error (~(unsigned long) 0)
......
...@@ -141,6 +141,9 @@ my_bool my_net_init(NET *net, Vio* vio) ...@@ -141,6 +141,9 @@ my_bool my_net_init(NET *net, Vio* vio)
net->query_cache_query= 0; net->query_cache_query= 0;
#endif #endif
net->report_error= 0; net->report_error= 0;
#if defined(MYSQL_SERVER) && !defined(EMBEDDED_LIBRARY)
net->skip_big_packet= FALSE;
#endif
if (vio != 0) /* If real connection */ if (vio != 0) /* If real connection */
{ {
...@@ -947,6 +950,7 @@ my_real_read(NET *net, ulong *complen) ...@@ -947,6 +950,7 @@ my_real_read(NET *net, ulong *complen)
{ {
#if defined(MYSQL_SERVER) && !defined(NO_ALARM) #if defined(MYSQL_SERVER) && !defined(NO_ALARM)
if (!net->compress && if (!net->compress &&
net->skip_big_packet &&
!my_net_skip_rest(net, (uint32) len, &alarmed, &alarm_buff)) !my_net_skip_rest(net, (uint32) len, &alarmed, &alarm_buff))
net->error= 3; /* Successfully skiped packet */ net->error= 3; /* Successfully skiped packet */
#endif #endif
......
...@@ -493,6 +493,13 @@ int check_user(THD *thd, enum enum_server_command command, ...@@ -493,6 +493,13 @@ int check_user(THD *thd, enum enum_server_command command,
} }
send_ok(thd); send_ok(thd);
thd->password= test(passwd_len); // remember for error messages thd->password= test(passwd_len); // remember for error messages
/*
Allow the network layer to skip big packets. Although a malicious
authenticated session might use this to trick the server to read
big packets indefinitely, this is a previously established behavior
that needs to be preserved as to not break backwards compatibility.
*/
thd->net.skip_big_packet= TRUE;
/* Ready to handle queries */ /* Ready to handle queries */
DBUG_RETURN(0); DBUG_RETURN(0);
} }
......
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