[MDEV-27080] Malicious data type overflow in joint query leads to service coredump Created: 2021-11-18  Updated: 2022-06-22  Resolved: 2022-06-22

Status: Closed
Project: MariaDB Server
Component/s: Server
Affects Version/s: 10.3.30, 10.3.31, 10.3.32, 10.2, 10.3, 10.4, 10.5, 10.6, 10.7
Fix Version/s: 10.3.36, 10.4.26, 10.5.17, 10.6.9, 10.7.5, 10.8.4, 10.9.2

Type: Bug Priority: Critical
Reporter: willcao Assignee: Oleksandr Byelkin
Resolution: Duplicate Votes: 0
Labels: None
Environment:

x86 mariadb server环境


Issue Links:
Duplicate
duplicates MDEV-25994 Crash with union of my_decimal type i... Closed
Relates
relates to MDEV-23850 Server crash with SIGFPE in decimal2b... Closed

 Description   

create table tb1 ( col1 int unique,col2 int unique);
insert into tb1 (col1,col2) values (100,200);
update tb1 set col1= case 11 when 0 then 'x' when 'x' then 'x' end order by col1,(select 2555555555.5555555555 union select 0 union select -1),col2 desc,col2,col1;
ERROR 2013 (HY000): Lost connection to MySQL server during query

Program terminated with signal SIGSEGV, Segmentation fault.

#0  __pthread_kill (threadid=<optimized out>, signo=11) at ../sysdeps/unix/sysv/linux/pthread_kill.c:56
56      ../sysdeps/unix/sysv/linux/pthread_kill.c: 没有那个文件或目录.
[Current thread is 1 (Thread 0x7ff1fc236700 (LWP 30208))]
(gdb) bt
#0  __pthread_kill (threadid=<optimized out>, signo=11) at ../sysdeps/unix/sysv/linux/pthread_kill.c:56
#1  0x0000557666840dc8 in handle_fatal_signal ()
#2  <signal handler called>
#3  0x000055766693773f in my_decimal2binary(unsigned int, my_decimal const*, unsigned char*, int, int) ()
#4  0x000055766683da7b in Type_handler_decimal_result::make_sort_key(unsigned char*, Item*, SORT_FIELD_ATTR const*, Sort_param*) const ()
#5  0x000055766683cd65 in ?? ()
#6  0x000055766683fc9f in filesort(THD*, TABLE*, Filesort*, Filesort_tracker*, JOIN*, unsigned long long) ()
#7  0x000055766670938f in mysql_update(THD*, TABLE_LIST*, List<Item>&, List<Item>&, Item*, unsigned int, st_order*, unsigned long long, bool, unsigned long long*, unsigned long long*) ()
#8  0x0000557666664e31 in mysql_execute_command(THD*) ()
#9  0x000055766666aca9 in mysql_parse(THD*, char*, unsigned int, Parser_state*, bool, bool) ()
#10 0x000055766666cb45 in dispatch_command(enum_server_command, THD*, char*, unsigned int, bool, bool) ()
#11 0x000055766666e342 in do_command(THD*) ()
#12 0x0000557666745ad6 in do_handle_one_connection(CONNECT*) ()
#13 0x0000557666745c4d in handle_one_connection ()
#14 0x00007ff206f06fa3 in start_thread (arg=<optimized out>) at pthread_create.c:486
#15 0x00007ff20698e60f in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95



 Comments   
Comment by willcao [ 2021-11-18 ]

Incorporating the following patches can solve this problem

From 04dac63d71302e4f7140202732f395aa328ce986 Mon Sep 17 00:00:00 2001
From: root <root@localhost.localdomain>
Date: Wed, 27 Oct 2021 17:55:45 +0800
Subject: [PATCH] case2
 
---
 sql/my_decimal.cc | 4 ++++
 1 file changed, 4 insertions(+)
 
diff --git a/sql/my_decimal.cc b/sql/my_decimal.cc
index 338f78d8..c6a3f2d1 100644
--- a/sql/my_decimal.cc
+++ b/sql/my_decimal.cc
@@ -204,6 +204,10 @@ int my_decimal2binary(uint mask, const my_decimal *d, uchar *bin, int prec,
 {
   int err1= E_DEC_OK, err2;
   my_decimal rounded;
+  if ((void*)0 == d)
+  {
+    return check_result(mask, E_DEC_TRUNCATED);
+  }
   my_decimal2decimal(d, &rounded);
   rounded.frac= decimal_actual_fraction(&rounded);
   if (scale < rounded.frac)
--
2.27.0

Comment by Anel Husakovic [ 2021-11-18 ]

Hi willcao, thanks for reporting the bug.
Can you please make a pull request (https://github.com/MariaDB/server/pulls) with your patch, so other developers could take a look too?

Comment by Alice Sherepa [ 2021-11-18 ]

THank you! I repeated as described on 10.2-10.7

10.2 81d7adb1e2cdfb1064279b

Version: '10.2.42-MariaDB-debug-log'  
211118 13:50:03 [ERROR] mysqld got signal 11 ;
 
Server version: 10.2.42-MariaDB-debug-log
 
sigaction.c:0(__restore_rt)[0x7fc50ae233c0]
sql/my_decimal.h:106(my_decimal::operator=(my_decimal const&))[0x55c6258faec7]
sql/my_decimal.h:271(my_decimal2decimal(my_decimal const*, my_decimal*))[0x55c6258fb21c]
sql/my_decimal.cc:208(my_decimal2binary(unsigned int, my_decimal const*, unsigned char*, int, int))[0x55c625bac4f5]
sql/filesort.cc:1159(Type_handler_decimal_result::make_sort_key(unsigned char*, Item*, SORT_FIELD_ATTR const*, Sort_param*) const)[0x55c62585ef58]
sql/item.h:939(Item::make_sort_key(unsigned char*, Item*, SORT_FIELD_ATTR const*, Sort_param*) const)[0x55c62500fec0]
sql/filesort.cc:1206(make_sortkey(Sort_param*, unsigned char*, unsigned char*))[0x55c62585f39f]
sql/filesort.cc:885(find_all_keys(THD*, Sort_param*, SQL_SELECT*, SORT_INFO*, st_io_cache*, st_io_cache*, Bounded_queue<unsigned char, unsigned char>*, unsigned long long*))[0x55c62585cc4f]
sql/filesort.cc:275(filesort(THD*, TABLE*, Filesort*, Filesort_tracker*, JOIN*, unsigned long long))[0x55c625858820]
sql/sql_update.cc:572(mysql_update(THD*, TABLE_LIST*, List<Item>&, List<Item>&, Item*, unsigned int, st_order*, unsigned long long, enum_duplicates, bool, unsigned long long*, unsigned long long*))[0x55c6254af6ac]
sql/sql_parse.cc:4056(mysql_execute_command(THD*))[0x55c62522b742]
sql/sql_parse.cc:7793(mysql_parse(THD*, char*, unsigned int, Parser_state*, bool, bool))[0x55c625244e16]
sql/sql_parse.cc:1830(dispatch_command(enum_server_command, THD*, char*, unsigned int, bool, bool))[0x55c62521e01b]
sql/sql_parse.cc:1381(do_command(THD*))[0x55c62521ade6]
sql/sql_connect.cc:1336(do_handle_one_connection(CONNECT*))[0x55c6255a6e48]
sql/sql_connect.cc:1242(handle_one_connection)[0x55c6255a670b]
perfschema/pfs.cc:1871(pfs_spawn_thread)[0x55c6269461f2]
nptl/pthread_create.c:478(start_thread)[0x7fc50ae17609]
/lib/x86_64-linux-gnu/libc.so.6(clone+0x43)[0x7fc50a9f0293]
 
Query (0x62b000000290): update tb1 set col1= case 11 when 0 then 'x' when 'x' then 'x' end order by col1,(select 2555555555.5555555555 union select 0 union select -1),col2 desc,col2,col1

Comment by Oleksandr Byelkin [ 2022-06-22 ]

For me it return an error:

mysqltest: At line 3: query 'update tb1 set col1= case 11 when 0 then 'x' when 'x' then 'x' end order by col1,(select 2555555555.5555555555 union select 0 union select -1),col2 desc,col2,col1' failed: 1242: Subquery returns more than 1 row

Comment by Oleksandr Byelkin [ 2022-06-22 ]

with fixed query:

create table tb1 ( col1 int unique,col2 int unique);
insert into tb1 (col1,col2) values (100,200);
update tb1 set col1= case 11 when 0 then 'x' when 'x' then 'x' end order by
col1,(select 2555555555.5555555555 union select 0 union select -1 limit 1),col2 desc,col2,col1;

it return an error

mysqltest: At line 3: query 'update tb1 set col1= case 11 when 0 then 'x' when 'x' then 'x' end order by
col1,(select 2555555555.5555555555 union select 0 union select -1 limit 1),col2 desc,col2,col1' failed: 1292: Truncated incorrect DOUBLE value: 'x'

Comment by Oleksandr Byelkin [ 2022-06-22 ]

I rewind to the point when it was repeatable and found that cause of the bug is that a field which can not be NULL get a NULL value due to a bug fixed in https://jira.mariadb.org/browse/MDEV-25994. Of course the code can be done more robust with a patch like this:

sanja@SanjasLaptop:~/maria/git/10.3/mysql-test$ vim log
sanja@SanjasLaptop:~/maria/git/10.3/mysql-test$ git diff
diff --git a/sql/filesort.cc b/sql/filesort.cc
index 8b019caf8f5..186700a1215 100644
--- a/sql/filesort.cc
+++ b/sql/filesort.cc
@@ -1147,13 +1147,13 @@ Type_handler_decimal_result::make_sort_key(uchar *to, Item *item,
                                            Sort_param *param) const
 {
   my_decimal dec_buf, *dec_val= item->val_decimal_result(&dec_buf);
-  if (item->maybe_null)
-  {
     if (item->null_value)
     {
       memset(to, 0, sort_field->length + 1);
       return;
     }
+  if (item->maybe_null)
+  {
     *to++= 1;
   }
   my_decimal2binary(E_DEC_FATAL_ERROR, dec_val, to,

but IMHO it is overkill to check for NULL where NULL is impossible.

Generated at Thu Feb 08 09:50:11 UTC 2024 using Jira 8.20.16#820016-sha1:9d11dbea5f4be3d4cc21f03a88dd11d8c8687422.