[MDEV-28315] ASAN stack-buffer-overflow in String::copy_aligned Created: 2022-04-14  Updated: 2022-08-10  Resolved: 2022-08-01

Status: Closed
Project: MariaDB Server
Component/s: Server
Affects Version/s: 10.6, 10.7, 10.8
Fix Version/s: 10.6.9, 10.7.5, 10.8.4, 10.9.2, 10.10.1

Type: Bug Priority: Major
Reporter: Elena Stepanova Assignee: Nayuta Yanagisawa (Inactive)
Resolution: Fixed Votes: 0
Labels: None

Issue Links:
Relates
relates to MDEV-28646 Binary_string::alloc allocates redund... Open

 Description   

CREATE TABLE t1 (a VARBINARY(128)) CHARACTER SET utf32;
INSERT INTO t1 VALUES ('South Carolina, Vermont, New Jersey, New Mexico, Wisconsin, Missouri, Delaware');
 
CREATE TABLE t2 (b SET('South Carolina', 'Vermont', 'Texas', 'New Mexico', 'Wisconsin', 'Missouri', 'Delaware', 'Wyoming', 'New Jersey', 'Maryland', 'Illinois', 'New York')) CHARACTER SET utf32;
--error WARN_DATA_TRUNCATED
INSERT INTO t2 SELECT * FROM t1;
 
# Cleanup
DROP TABLE t1, t2;

10.6 f7f0bc748e

==1253837==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7fd121fbdc50 at pc 0x56071a534531 bp 0x7fd121fbd9d0 sp 0x7fd121fbd9c8
WRITE of size 1 at 0x7fd121fbdc50 thread T5
    #0 0x56071a534530 in String::copy_aligned(char const*, unsigned long, unsigned long, charset_info_st const*) /data/src/10.6-bug/sql/sql_string.cc:411
    #1 0x56071a53492d in String::copy(char const*, unsigned long, charset_info_st const*, charset_info_st const*, unsigned int*) /data/src/10.6-bug/sql/sql_string.cc:460
    #2 0x56071aacbc14 in Field_set::store(char const*, unsigned long, charset_info_st const*) /data/src/10.6-bug/sql/field.cc:9386
    #3 0x56071a6daa70 in Field::save_in_field_str(Field*) /data/src/10.6-bug/sql/field.h:749
    #4 0x56071a6ddcde in Field_str::save_in_field(Field*) /data/src/10.6-bug/sql/field.h:2101
    #5 0x56071aae9048 in Field_set::store_field(Field*) /data/src/10.6-bug/sql/field.h:4861
    #6 0x56071aaf3bea in field_conv_incompatible /data/src/10.6-bug/sql/field_conv.cc:850
    #7 0x56071aaf3c87 in field_conv(Field*, Field*) /data/src/10.6-bug/sql/field_conv.cc:863
    #8 0x56071ab9c96c in save_field_in_field /data/src/10.6-bug/sql/item.cc:6674
    #9 0x56071ab9d061 in Item_field::save_in_field(Field*, bool) /data/src/10.6-bug/sql/item.cc:6724
    #10 0x56071a165f35 in fill_record(THD*, TABLE*, Field**, List<Item>&, bool, bool) /data/src/10.6-bug/sql/sql_base.cc:8866
    #11 0x56071a1663cd in fill_record_n_invoke_before_triggers(THD*, TABLE*, Field**, List<Item>&, bool, trg_event_type) /data/src/10.6-bug/sql/sql_base.cc:8921
    #12 0x56071a231ceb in select_insert::store_values(List<Item>&) /data/src/10.6-bug/sql/sql_insert.cc:4156
    #13 0x56071a230ead in select_insert::send_data(List<Item>&) /data/src/10.6-bug/sql/sql_insert.cc:4088
    #14 0x56071a474c34 in select_result_sink::send_data_with_check(List<Item>&, st_select_lex_unit*, unsigned long long) /data/src/10.6-bug/sql/sql_class.h:5643
    #15 0x56071a42f976 in end_send /data/src/10.6-bug/sql/sql_select.cc:22337
    #16 0x56071a423d97 in do_select /data/src/10.6-bug/sql/sql_select.cc:20585
    #17 0x56071a3b2182 in JOIN::exec_inner() /data/src/10.6-bug/sql/sql_select.cc:4753
    #18 0x56071a3af696 in JOIN::exec() /data/src/10.6-bug/sql/sql_select.cc:4531
    #19 0x56071a3b3a9b in mysql_select(THD*, TABLE_LIST*, List<Item>&, Item*, unsigned int, st_order*, st_order*, Item*, st_order*, unsigned long long, select_result*, st_select_lex_unit*, st_select_lex*) /data/src/10.6-bug/sql/sql_select.cc:5010
    #20 0x56071a3845aa in handle_select(THD*, LEX*, select_result*, unsigned long) /data/src/10.6-bug/sql/sql_select.cc:545
    #21 0x56071a2e1570 in mysql_execute_command(THD*, bool) /data/src/10.6-bug/sql/sql_parse.cc:4726
    #22 0x56071a2f80de in mysql_parse(THD*, char*, unsigned int, Parser_state*) /data/src/10.6-bug/sql/sql_parse.cc:8045
    #23 0x56071a2cea1d in dispatch_command(enum_server_command, THD*, char*, unsigned int, bool) /data/src/10.6-bug/sql/sql_parse.cc:1912
    #24 0x56071a2cb5f5 in do_command(THD*, bool) /data/src/10.6-bug/sql/sql_parse.cc:1409
    #25 0x56071a71e9d2 in do_handle_one_connection(CONNECT*, bool) /data/src/10.6-bug/sql/sql_connect.cc:1418
    #26 0x56071a71e297 in handle_one_connection /data/src/10.6-bug/sql/sql_connect.cc:1312
    #27 0x56071b33e177 in pfs_spawn_thread /data/src/10.6-bug/storage/perfschema/pfs.cc:2201
    #28 0x7fd12b78dea6 in start_thread nptl/pthread_create.c:477
    #29 0x7fd12b38adee in __clone (/lib/x86_64-linux-gnu/libc.so.6+0xfddee)
 
Address 0x7fd121fbdc50 is located in stack of thread T5 at offset 320 in frame
    #0 0x56071aacb987 in Field_set::store(char const*, unsigned long, charset_info_st const*) /data/src/10.6-bug/sql/field.cc:9373
 
  This frame has 8 object(s):
    [48, 49) 'got_warning' (line 9375)
    [64, 68) 'err' (line 9376)
    [80, 84) 'not_used2' (line 9378)
    [96, 100) 'dummy_errors' (line 9385)
    [112, 120) 'not_used' (line 9377)
    [144, 152) 'end' (line 9395)
    [176, 208) 'tmpstr' (line 9380)
    [240, 320) 'buff' (line 9379) <== Memory access at offset 320 overflows this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
      (longjmp and C++ exceptions *are* supported)
Thread T5 created by T0 here:
    #0 0x7fd12bccd2a2 in __interceptor_pthread_create ../../../../src/libsanitizer/asan/asan_interceptors.cpp:214
    #1 0x56071b339eea in my_thread_create /data/src/10.6-bug/storage/perfschema/my_thread.h:52
    #2 0x56071b33e566 in pfs_spawn_thread_v1 /data/src/10.6-bug/storage/perfschema/pfs.cc:2252
    #3 0x560719fcb589 in inline_mysql_thread_create /data/src/10.6-bug/include/mysql/psi/mysql_thread.h:1139
    #4 0x560719fe23bb in create_thread_to_handle_connection(CONNECT*) /data/src/10.6-bug/sql/mysqld.cc:5940
    #5 0x560719fe2a01 in create_new_thread(CONNECT*) /data/src/10.6-bug/sql/mysqld.cc:5999
    #6 0x560719fe2d43 in handle_accepted_socket(st_mysql_socket, st_mysql_socket) /data/src/10.6-bug/sql/mysqld.cc:6061
    #7 0x560719fe36cf in handle_connections_sockets() /data/src/10.6-bug/sql/mysqld.cc:6185
    #8 0x560719fe1c2a in mysqld_main(int, char**) /data/src/10.6-bug/sql/mysqld.cc:5835
    #9 0x560719fca8d4 in main /data/src/10.6-bug/sql/main.cc:34
    #10 0x7fd12b2b3d09 in __libc_start_main ../csu/libc-start.c:308
 
SUMMARY: AddressSanitizer: stack-buffer-overflow /data/src/10.6-bug/sql/sql_string.cc:411 in String::copy_aligned(char const*, unsigned long, unsigned long, charset_info_st const*)
Shadow bytes around the buggy address:
  0x0ffaa43efb30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0ffaa43efb40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 f1 f1
  0x0ffaa43efb50: f1 f1 04 f3 f3 f3 00 00 00 00 00 00 00 00 00 00
  0x0ffaa43efb60: 00 00 f1 f1 f1 f1 f1 f1 01 f2 04 f2 04 f2 00 00
  0x0ffaa43efb70: 00 f2 00 00 00 f2 f2 f2 00 00 00 00 f2 f2 f2 f2
=>0x0ffaa43efb80: 00 00 00 00 00 00 00 00 00 00[f3]f3 f3 f3 00 00
  0x0ffaa43efb90: 00 00 00 00 00 00 00 00 00 00 f1 f1 f1 f1 00 00
  0x0ffaa43efba0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0ffaa43efbb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0ffaa43efbc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0ffaa43efbd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
  Shadow gap:              cc
==1253837==ABORTING
220414 14:58:55 [ERROR] mysqld got signal 6 ;
This could be because you hit a bug. It is also possible that this binary
or one of the libraries it was linked against is corrupt, improperly built,
or misconfigured. This error can also be caused by malfunctioning hardware.
 
To report this bug, see https://mariadb.com/kb/en/reporting-bugs
 
We will try our best to scrape up some info that will hopefully help
diagnose the problem, but since we have already crashed, 
something is definitely wrong and this may fail.
 
Server version: 10.6.8-MariaDB-debug-log
key_buffer_size=1048576
read_buffer_size=131072
max_used_connections=1
max_threads=153
thread_count=1
It is possible that mysqld could use up to 
key_buffer_size + (read_buffer_size + sort_buffer_size)*max_threads = 63859 K  bytes of memory
Hope that's ok; if not, decrease some variables in the equation.
 
Thread pointer: 0x62b00007e288
Attempting backtrace. You can use the following information to find out
where mysqld died. If you see no messages after this, something went
terribly wrong...
stack_bottom = 0x7fd121fc0d70 thread_stack 0x100000
sanitizer_common/sanitizer_common_interceptors.inc:4101(__interceptor_backtrace.part.0)[0x7fd12bcbbdf1]
mysys/stacktrace.c:212(my_print_stacktrace)[0x56071bf0960b]
sql/signal_handler.cc:226(handle_fatal_signal)[0x56071ab10f98]
sigaction.c:0(__restore_rt)[0x7fd12b799140]
linux/raise.c:51(__GI_raise)[0x7fd12b2c8ce1]
stdlib/abort.c:81(__GI_abort)[0x7fd12b2b2537]
sanitizer_common/sanitizer_posix_libcdep.cpp:149(__sanitizer::Abort())[0x7fd12bd3d11b]
sanitizer_common/sanitizer_termination.cpp:59(__sanitizer::Die())[0x7fd12bd47ce8]
asan/asan_report.cpp:186(__asan::ScopedInErrorReport::~ScopedInErrorReport())[0x7fd12bd2a44c]
asan/asan_report.cpp:474(__asan::ReportGenericError(unsigned long, unsigned long, unsigned long, unsigned long, bool, unsigned long, unsigned int, bool))[0x7fd12bd29d47]
asan/asan_rtl.cpp:122(__asan_report_store1)[0x7fd12bd2aa5b]
sql/sql_string.cc:411(String::copy_aligned(char const*, unsigned long, unsigned long, charset_info_st const*))[0x56071a534531]
sql/sql_string.cc:460(String::copy(char const*, unsigned long, charset_info_st const*, charset_info_st const*, unsigned int*))[0x56071a53492e]
sql/field.cc:9387(Field_set::store(char const*, unsigned long, charset_info_st const*))[0x56071aacbc15]
sql/field.h:749(Field::save_in_field_str(Field*))[0x56071a6daa71]
sql/field.h:2101(Field_str::save_in_field(Field*))[0x56071a6ddcdf]
sql/field.h:4861(Field_set::store_field(Field*))[0x56071aae9049]
sql/field_conv.cc:851(field_conv_incompatible(Field*, Field*))[0x56071aaf3beb]
sql/field_conv.cc:864(field_conv(Field*, Field*))[0x56071aaf3c88]
sql/item.cc:6674(save_field_in_field(Field*, bool*, Field*, bool))[0x56071ab9c96d]
sql/item.cc:6725(Item_field::save_in_field(Field*, bool))[0x56071ab9d062]
sql/sql_base.cc:8866(fill_record(THD*, TABLE*, Field**, List<Item>&, bool, bool))[0x56071a165f36]
sql/sql_base.cc:8921(fill_record_n_invoke_before_triggers(THD*, TABLE*, Field**, List<Item>&, bool, trg_event_type))[0x56071a1663ce]
sql/sql_insert.cc:4159(select_insert::store_values(List<Item>&))[0x56071a231cec]
sql/sql_insert.cc:4089(select_insert::send_data(List<Item>&))[0x56071a230eae]
sql/sql_class.h:5643(select_result_sink::send_data_with_check(List<Item>&, st_select_lex_unit*, unsigned long long))[0x56071a474c35]
sql/sql_select.cc:22337(end_send(JOIN*, st_join_table*, bool))[0x56071a42f977]
sql/sql_select.cc:20585(do_select(JOIN*, Procedure*))[0x56071a423d98]
sql/sql_select.cc:4753(JOIN::exec_inner())[0x56071a3b2183]
sql/sql_select.cc:4532(JOIN::exec())[0x56071a3af697]
sql/sql_select.cc:5012(mysql_select(THD*, TABLE_LIST*, List<Item>&, Item*, unsigned int, st_order*, st_order*, Item*, st_order*, unsigned long long, select_result*, st_select_lex_unit*, st_select_lex*))[0x56071a3b3a9c]
sql/sql_select.cc:545(handle_select(THD*, LEX*, select_result*, unsigned long))[0x56071a3845ab]
sql/sql_parse.cc:4726(mysql_execute_command(THD*, bool))[0x56071a2e1571]
sql/sql_parse.cc:8045(mysql_parse(THD*, char*, unsigned int, Parser_state*))[0x56071a2f80df]
sql/sql_parse.cc:1914(dispatch_command(enum_server_command, THD*, char*, unsigned int, bool))[0x56071a2cea1e]
sql/sql_parse.cc:1409(do_command(THD*, bool))[0x56071a2cb5f6]
sql/sql_connect.cc:1418(do_handle_one_connection(CONNECT*, bool))[0x56071a71e9d3]
sql/sql_connect.cc:1314(handle_one_connection)[0x56071a71e298]
perfschema/pfs.cc:2203(pfs_spawn_thread)[0x56071b33e178]
nptl/pthread_create.c:478(start_thread)[0x7fd12b78dea7]
x86_64/clone.S:97(__GI___clone)[0x7fd12b38adef]
 
Trying to get some variables.
Some pointers may be invalid and cause the dump to abort.
Query (0x62b0000852a8): INSERT INTO t2 SELECT * FROM t1
 
Connection ID (thread ID): 4
Status: NOT_KILLED
 
Optimizer switch: index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=on,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on,condition_pushdown_for_subquery=on,rowid_filter=on,condition_pushdown_from_having=on,not_null_range_scan=off
 
The manual page at https://mariadb.com/kb/en/how-to-produce-a-full-stack-trace-for-mysqld/ contains
information that should help you find out what is causing the crash.
Writing a core file...
Working directory at /dev/shm/var_auto_ZYGh/mysqld.1/data
Resource Limits:
Limit                     Soft Limit           Hard Limit           Units     
Max cpu time              unlimited            unlimited            seconds   
Max file size             unlimited            unlimited            bytes     
Max data size             unlimited            unlimited            bytes     
Max stack size            8388608              unlimited            bytes     
Max core file size        unlimited            unlimited            bytes     
Max resident set          unlimited            unlimited            bytes     
Max processes             385901               385901               processes 
Max open files            1024                 1024                 files     
Max locked memory         12659513856          12659513856          bytes     
Max address space         unlimited            unlimited            bytes     
Max file locks            unlimited            unlimited            locks     
Max pending signals       385901               385901               signals   
Max msgqueue size         819200               819200               bytes     
Max nice priority         0                    0                    
Max realtime priority     0                    0                    
Max realtime timeout      unlimited            unlimited            us        
Core pattern: core

The failure started happening in 10.6 after this commit:

commit 36cdd5c3cdb06d8538f64c0b312ffe4672a92e75
Author: Monty
Date:   Wed Sep 16 11:23:50 2020 +0300
 
    Optimize usage of c_ptr(), c_ptr_quick() and String::alloc()



 Comments   
Comment by Nayuta Yanagisawa (Inactive) [ 2022-05-12 ]

monty We got a pull request for the present issue. https://github.com/MariaDB/server/pull/2106

Comment by Norio Akagi [ 2022-05-19 ]

With the modification of the pull request above, the test case looks like below to pass

  • test file

CREATE TABLE t1 (a VARBINARY(128)) CHARACTER SET utf32;
INSERT INTO t1 VALUES ('South Carolina, Vermont, New Jersey, New Mexico, Wisconsin, Missouri, Delaware');
CREATE TABLE t2 (b SET('South Carolina', 'Vermont', 'Texas', 'New Mexico', 'Wisconsin', 'Missouri', 'Delaware', 'Wyoming', 'New Jersey', 'Maryland', 'Illinois', 'New York')) CHARACTER SET utf32;
--error WARN_DATA_TRUNCATED
INSERT INTO t2 SELECT * FROM t1;
SELECT * FROM t2;
DROP TABLE t1;
DROP TABLE t2;

  • result file

CREATE TABLE t1 (a VARBINARY(128)) CHARACTER SET utf32;
INSERT INTO t1 VALUES ('South Carolina, Vermont, New Jersey, New Mexico, Wisconsin, Missouri, Delaware');
CREATE TABLE t2 (b SET('South Carolina', 'Vermont', 'Texas', 'New Mexico', 'Wisconsin', 'Missouri', 'Delaware', 'Wyoming', 'New Jersey', 'Maryland', 'Illinois', 'New York')) CHARACTER SET utf32;
INSERT INTO t2 SELECT * FROM t1;
ERROR 01000: Data truncated for column 'b' at row 1
SELECT * FROM t2;
b
DROP TABLE t1;
DROP TABLE t2;

Does b as a result of SELECT make sense here ? I am not sure how the data is expected to be truncated after the INSERT.

Comment by Norio Akagi [ 2022-05-23 ]

Talked with @nayuta-yanagisawa and concluded that the line b represents the header which means t2 does not contain any data (expected due to the truncation).

Comment by Nayuta Yanagisawa (Inactive) [ 2022-08-01 ]

https://github.com/MariaDB/server/commit/84d26f98c7f2007d9414c33dcbfdddd3a24c9a60

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