Bug #483 mysqld ignores max_user_connections
Submitted: 23 May 2003 8:59 Modified: 3 Jul 2003 0:44
Reporter: Alexey Guzeev Email Updates:
Status: Closed Impact on me:
None 
Category:MySQL Server Severity:S2 (Serious)
Version:4.0.13 OS:Any (glibc 2.2.5-based Linux)
Assigned to: CPU Architecture:Any

[23 May 2003 8:59] Alexey Guzeev
Description:
After version 4.0.1 MySQL ignores variable max_user_connections (at least 
if per-hour limits are not set), thus any user can take over all MySQL
connections - a serious DoS attack at shared hosting servers!

Looks like MySQL 3.23.x releases don't have this bug. 4.1 and 5.0 might have it.

Tracking cause of the bug a couple of other potentially serious problems were discovered, like uninitialized data, race condition.

How to repeat:
specify max_user_connections=10 variable for mysqld. The value will be correctly reflected by SHOW GLOBAL VARIABLES but mysqld will happily let opening 90+ connections for a single user.

Suggested fix:
This patch fixes all discovered problems. It made against 4.0.13, but looks like the code was not changed since 4.0.2.

--- sql/sql_parse.cc-old        2003-05-14 16:24:34.000000000 -0400
+++ sql/sql_parse.cc    2003-05-23 02:09:30.000000000 -0400
@@ -140,6 +140,7 @@
   DBUG_ASSERT(user != 0);
   DBUG_ASSERT(host != 0);
                                                                                                                              
+  memset(temp_user, 0, sizeof(temp_user));
   user_len=strlen(user);
   host_len=strlen(host);
   temp_len= (strmov(strmov(temp_user, user)+1, host) - temp_user)+1;
@@ -161,7 +162,13 @@
     uc->user_len= user_len;
     uc->host=uc->user + uc->user_len +  1;
     uc->len = temp_len;
-    uc->connections = 1;
+    /* if per-hour limits are set then initial value 1 will */
+    /* prevent object from being removed when client closes all */
+    /* connections ensuring that stats are not lost */
+    /* but if we only track maximum number of simultaneous connections */
+    /* then initial value of 0 will allow reclaiming object memory upon */
+    /* disconnect and thus keeping hashtable much smaller */
+    uc->connections = (mqh->questions || mqh->updates || mqh->connections)?1:0;
     uc->questions=uc->updates=uc->conn_per_hour=0;
     uc->user_resources=*mqh;
     if (max_user_connections && mqh->connections > max_user_connections)
@@ -257,10 +264,10 @@
                  db ? db : (char*) "");
   thd->db_access=0;
   /* Don't allow user to connect if he has done too many queries */
-  if ((ur.questions || ur.updates || ur.connections) &&
+  if ((ur.questions || ur.updates || ur.connections || max_user_connections) &&
       get_or_create_user_conn(thd,user,thd->host_or_ip,&ur))
     return -1;
-  if (thd->user_connect && thd->user_connect->user_resources.connections &&
+  if (thd->user_connect && ( max_user_connections || thd->user_connect->user_resources.connections ) &&
       check_for_max_user_connections(thd->user_connect))
     return -1;
   if (db && db[0])
@@ -314,7 +321,6 @@
     error=1;
     goto end;
   }
-  uc->connections++;
   if (uc->user_resources.connections &&
       uc->conn_per_hour++ >= uc->user_resources.connections)
   {
@@ -324,6 +330,7 @@
     error=1;
     goto end;
   }
+  uc->connections++;
 end:
   DBUG_RETURN(error);
 }
@@ -336,7 +343,9 @@
   {
     /* Last connection for user; Delete it */
     (void) pthread_mutex_lock(&LOCK_user_conn);
-    (void) hash_delete(&hash_user_connections,(byte*) uc);
+    if (!uc->connections) { /* avoid race condition by checking again with mutex held */
+      (void) hash_delete(&hash_user_connections,(byte*) uc);
+    }
     (void) pthread_mutex_unlock(&LOCK_user_conn);
   }
   DBUG_VOID_RETURN;
[31 May 2003 11:29] MySQL Verification Team
Thank you for your bug report. This issue has been fixed in the latest
development tree for that product. You can find more information about
accessing our development trees at 
    http://www.mysql.com/doc/en/Installing_source_tree.html

A patch, a bit different then yours, which helped us, will be available in one of the next releases of 4.0 and above.
[3 Jul 2003 0:44] Michael Widenius
Thank you for your bug report. This issue has been fixed in the latest
development tree for that product. You can find more information about
accessing our development trees at 
    http://www.mysql.com/doc/en/Installing_source_tree.html

The fix will be in 4.0.14