CVE-2022-31624 (published 2022-05-25T21:15Z)

MariaDB Server before 10.7 is vulnerable to Denial of Service. While executing the plugin/server_audit/server_audit.c method log_statement_ex, the held lock lock_bigbuffer is not released correctly, which allows local users to trigger a denial of service due to the deadlock.

Severity: LOW
CVSS v2 base score: 2.1 (AV:L/AC:L/Au:N/C:N/I:N/A:P)
CVSS v3 base score: 5.5, MEDIUM (CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H)

Weakness information:
cwe_id: CWE-667
cwe_name: Improper Locking
description: The product does not properly acquire or release a lock on a resource, leading to unexpected resource state changes and behaviors.
extended_description: 
	   Locking is a type of synchronization behavior that ensures that multiple independently-operating processes or threads do not interfere with each other when accessing the same resource. All processes/threads are expected to follow the same steps for locking. If these steps are not followed precisely - or if no locking is done at all - then another process/thread could modify the shared resource in a way that is not visible or predictable to the original process.  This can lead to data or memory corruption, denial of service, etc.
         

Fix information:
repo_url: https://github.com/MariaDB/server
commit_details: repo_url: https://github.com/MariaDB/server
author: Alexey Botchkov
author_date: 2021-10-21 15:11:20+04:00
msg: MDEV-26556 An improper locking bug(s) due to unreleased lock.

Get rid of the global big_buffer.
repository: repo_url: https://github.com/MariaDB/server
repo_name: MariaDB/server
description: MariaDB server is a community developed fork of MySQL server. Started by core members of the original MySQL team, MariaDB actively works with outside developers to deliver the most featureful, stable, and sanely licensed open SQL server in the industry.
repo_language: C++
owner: MariaDB
file_changes: filename: server_audit.result
change_type: ModificationType.MODIFY
diff: @@ -261,6 +261,9 @@ A	B	C	D
 A	B	C	D
 set global server_audit_query_log_limit= 1024;
 drop database sa_db;
+select length('01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789');
+length('0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456
+2750
 set global server_audit_file_path='.';
 show status like 'server_audit_current_log';
 Variable_name	Value
@@ -485,6 +488,7 @@ TIME,HOSTNAME,root,localhost,ID,ID,READ,mysql,proc,
 TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,proc,
 TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,event,
 TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'drop database sa_db',0
+TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'select length(\'012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567',0
 TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'set global server_audit_file_path=\'.\'',0
 TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'set global server_audit_file_path=\'.\'',0
 TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'show status like \'server_audit_current_log\'',0

programming_language: SQL
filename: server_audit.test
change_type: ModificationType.MODIFY
diff: @@ -210,6 +210,8 @@ select 'A', 'B', 'C', 'D';
 set global server_audit_query_log_limit= 1024;
 drop database sa_db;
 
+select length('01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789');
+
 set global server_audit_file_path='.';
 --replace_regex /\.[\\\/]/HOME_DIR\//
 show status like 'server_audit_current_log';

programming_language: SQL
filename: server_audit.c
change_type: ModificationType.MODIFY
diff: @@ -301,8 +301,6 @@ static char logging;
 static volatile int internal_stop_logging= 0;
 static char incl_user_buffer[1024];
 static char excl_user_buffer[1024];
-static char *big_buffer= NULL;
-static size_t big_buffer_alloced= 0;
 static unsigned int query_log_limit= 0;
 
 static char servhost[256];
@@ -555,20 +553,16 @@ static struct st_mysql_show_var audit_status[]=
 /* These belong to the service initialization */
 static PSI_mutex_key key_LOCK_operations;
 static PSI_mutex_key key_LOCK_atomic;
-static PSI_mutex_key key_LOCK_bigbuffer;
 static PSI_mutex_info mutex_key_list[]=
 {
   { &key_LOCK_operations, "SERVER_AUDIT_plugin::lock_operations",
     PSI_FLAG_GLOBAL},
   { &key_LOCK_atomic, "SERVER_AUDIT_plugin::lock_atomic",
     PSI_FLAG_GLOBAL},
-  { &key_LOCK_bigbuffer, "SERVER_AUDIT_plugin::lock_bigbuffer",
-    PSI_FLAG_GLOBAL}
 };
 #endif
 static mysql_mutex_t lock_operations;
 static mysql_mutex_t lock_atomic;
-static mysql_mutex_t lock_bigbuffer;
 
 /* The Percona server and partly MySQL don't support         */
 /* launching client errors in the 'update_variable' methods. */
@@ -1700,7 +1694,7 @@ static int log_statement_ex(const struct connection_info *cn,
                             int error_code, const char *type, int take_lock)
 {
   size_t csize;
-  char message_loc[1024];
+  char message_loc[2048];
   char *message= message_loc;
   size_t message_size= sizeof(message_loc);
   char *uh_buffer;
@@ -1709,6 +1703,7 @@ static int log_statement_ex(const struct connection_info *cn,
   unsigned int db_length;
   long long query_id;
   int result;
+  char *big_buffer= NULL;
 
   if ((db= cn->db))
     db_length= cn->db_length;
@@ -1791,17 +1786,9 @@ static int log_statement_ex(const struct connection_info *cn,
 
   if (query_len > (message_size - csize)/2)
   {
-    flogger_mutex_lock(&lock_bigbuffer);
-    if (big_buffer_alloced < (query_len * 2 + csize))
-    {
-      big_buffer_alloced= (query_len * 2 + csize + 4095) & ~4095L;
-      big_buffer= realloc(big_buffer, big_buffer_alloced);
-      if (big_buffer == NULL)
-      {
-        big_buffer_alloced= 0;
-        return 0;
-      }
-    }
+    size_t big_buffer_alloced= (query_len * 2 + csize + 4095) & ~4095L;
+    if(!(big_buffer= malloc(big_buffer_alloced)))
+      return 0;
 
     memcpy(big_buffer, message, csize);
     message= big_buffer;
@@ -1846,8 +1833,8 @@ static int log_statement_ex(const struct connection_info *cn,
                       "\',%d", error_code);
   message[csize]= '\n';
   result= write_log(message, csize + 1, take_lock);
-  if (message == big_buffer)
-    flogger_mutex_unlock(&lock_bigbuffer);
+  if (big_buffer)
+    free(big_buffer);
 
   return result;
 }
@@ -2496,7 +2483,6 @@ static int server_audit_init(void *p __attribute__((unused)))
 #endif
   flogger_mutex_init(key_LOCK_operations, &lock_operations, MY_MUTEX_INIT_FAST);
   flogger_mutex_init(key_LOCK_operations, &lock_atomic, MY_MUTEX_INIT_FAST);
-  flogger_mutex_init(key_LOCK_operations, &lock_bigbuffer, MY_MUTEX_INIT_FAST);
 
   coll_init(&incl_user_coll);
   coll_init(&excl_user_coll);
@@ -2581,10 +2567,8 @@ static int server_audit_deinit(void *p __attribute__((unused)))
   else if (output_type == OUTPUT_SYSLOG)
     closelog();
 
-  (void) free(big_buffer);
   flogger_mutex_destroy(&lock_operations);
   flogger_mutex_destroy(&lock_atomic);
-  flogger_mutex_destroy(&lock_bigbuffer);
 
   error_header();
   fprintf(stderr, "STOPPED\n");

programming_language: C