stack-use-after-scope in reinit_io_cache() detected by ASan

Description

Address Sanitizer from GCC 7.3 and 8.0 detects the following problem in a number of MTR test cases.
The easiest way to reproduce it is

./mysql-test/mtr --debug-server innodb_bug12661768
==11845==ERROR: AddressSanitizer: stack-use-after-scope on address 0x7f6f48198250 at pc 0x5642cb4ab9c7 bp 0x7f6f48197950 sp 0x7f6f48197940 READ of size 8 at 0x7f6f48198250 thread T17 #0 0x5642cb4ab9c6 in reinit_io_cache /mnt/hgfs/repos/percona-server/mysys/mf_iocache.c:342 #1 0x5642cb39a502 in init_read_record(READ_RECORD*, THD*, TABLE*, SQL_SELECT*, int, bool, bool) /mnt/hgfs/repos/percona-server/sql/records.cc:232 #2 0x5642caea11cd in 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*) /mnt/hgfs/repos/percona-server/sql/sql_update.cc:621 #3 0x5642cacd168c in mysql_execute_command(THD*) /mnt/hgfs/repos/percona-server/sql/sql_parse.cc:3098 #4 0x5642cace2114 in mysql_parse(THD*, char*, unsigned int, Parser_state*) /mnt/hgfs/repos/percona-server/sql/sql_parse.cc:6116 #5 0x5642cace7a2e in dispatch_command(enum_server_command, THD*, char*, unsigned int) /mnt/hgfs/repos/percona-server/sql/sql_parse.cc:1112 #6 0x5642cacecfd4 in do_command(THD*) /mnt/hgfs/repos/percona-server/sql/sql_parse.cc:792 #7 0x5642caf64d35 in do_handle_one_connection(THD*) /mnt/hgfs/repos/percona-server/sql/sql_connect.cc:1478 #8 0x5642caf6503a in handle_one_connection /mnt/hgfs/repos/percona-server/sql/sql_connect.cc:1385 #9 0x5642cb525c79 in pfs_spawn_thread /mnt/hgfs/repos/percona-server/storage/perfschema/pfs.cc:1015 #10 0x7f6f580516da in start_thread (/lib/x86_64-linux-gnu/libpthread.so.0+0x76da) #11 0x7f6f56b3088e in __clone (/lib/x86_64-linux-gnu/libc.so.6+0x12188e) Address 0x7f6f48198250 is located in stack of thread T17 at offset 1328 in frame #0 0x5642cae9f10b in 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*) /mnt/hgfs/repos/percona-server/sql/sql_update.cc:260 This frame has 20 object(s): [32, 33) 'need_sort' [96, 97) 'reverse' [160, 164) 'error' [224, 228) 'dup_key_found' [288, 292) 'table_count' [352, 356) 'cond_value' [416, 420) 'length' [480, 488) 'old_covering_keys' [544, 552) 'table' [608, 616) 'examined_rows' [672, 680) 'prelocking_strategy' [736, 744) 'tmp' [800, 808) 'table_list' [864, 872) 'conds' [928, 952) 'all_fields' [992, 1024) '_db_stack_frame_' [1056, 1088) '_db_stack_frame_' [1120, 1280) 'info' [1312, 1592) 'tempfile' <== Memory access at offset 1328 is inside this variable [1632, 2144) 'buff' HINT: this may be a false positive if your program uses some custom stack unwind mechanism or swapcontext (longjmp and C++ exceptions *are* supported) Thread T17 created by T0 here: #0 0x7f6f586d3043 in pthread_create (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x4b043) #1 0x5642cb529535 in spawn_thread_v1 /mnt/hgfs/repos/percona-server/storage/perfschema/pfs.cc:1038 #2 0x5642cab14c56 in inline_mysql_thread_create /mnt/hgfs/repos/percona-server/include/mysql/psi/mysql_thread.h:1049 #3 0x5642cab14c56 in create_thread_to_handle_connection(THD*) /mnt/hgfs/repos/percona-server/sql/mysqld.cc:5334 #4 0x5642cab16964 in create_new_thread /mnt/hgfs/repos/percona-server/sql/mysqld.cc:5432 #5 0x5642cab16964 in handle_connections_sockets() /mnt/hgfs/repos/percona-server/sql/mysqld.cc:5692 #6 0x5642cab1dc04 in mysqld_main(int, char**) /mnt/hgfs/repos/percona-server/sql/mysqld.cc:4946 #7 0x5642cab02351 in main /mnt/hgfs/repos/percona-server/sql/main.cc:25 #8 0x7f6f56a30b96 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21b96) SUMMARY: AddressSanitizer: stack-use-after-scope /mnt/hgfs/repos/percona-server/mysys/mf_iocache.c:342 in reinit_io_cache Shadow bytes around the buggy address: 0x0fee6902aff0: 00 f2 f2 f2 f2 f2 f2 f2 f8 f2 f2 f2 f2 f2 f2 f2 0x0fee6902b000: 00 f2 f2 f2 f2 f2 f2 f2 00 f2 f2 f2 f2 f2 f2 f2 0x0fee6902b010: 00 f2 f2 f2 f2 f2 f2 f2 00 00 00 f2 f2 f2 f2 f2 0x0fee6902b020: 00 00 00 00 f2 f2 f2 f2 00 00 00 00 f2 f2 f2 f2 0x0fee6902b030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 =>0x0fee6902b040: 00 00 00 00 f2 f2 f2 f2 f8 f8[f8]f8 f8 f8 f8 f8 0x0fee6902b050: f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 0x0fee6902b060: f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f2 f2 f2 f2 f2 0x0fee6902b070: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0fee6902b080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0fee6902b090: 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 ==11845==ABORTING

Environment

None

Smart Checklist

Activity

Show:

Yura Sorokin July 5, 2018 at 9:14 PM

Although 'IO_CACHE tempfile' declared inside an inner block in 'mysql_update()' function is copied by value to 'select->file'

select->file=tempfile

this operation is not safe as some of the members inside IO_CACHE struct were initialized with addresses of other data members.

In particular, in 'setup_io_cache()', called from 'init_functions()', called from 'init_io_cache()', called from 'open_cached_file()'
'current_pos' and 'current_end' are initialized with such addresses.

/* Ensure that my_b_tell() and my_b_bytes_in_cache works */ if (info->type == WRITE_CACHE) { info->current_pos= &info->write_pos; info->current_end= &info->write_end; } else { info->current_pos= &info->read_pos; info->current_end= &info->read_end; }

Yura Sorokin July 3, 2018 at 3:00 PM

The problem is known to Oracle as
Bug #24343330 "READ OF OUT-OF-SCOPE (TEMPFILE) IN MYSQL_UPDATE()"
and was fixed in 8.0.4 (https://github.com/mysql/mysql-server/commit/4d5ff7bfbf8)
and 5.7.21 (https://github.com/mysql/mysql-server/commit/e49e52a5de7) but never
backported to 5.6 and 5.5.

Yura Sorokin July 3, 2018 at 2:57 PM

The problem seems to be with the

IO_CACHE tempfile;

declared inside of the one of the inner blocks in 'mysql_update()' function but used in the

init_read_record(&info, thd, table, select, 0, 1, FALSE);

outside of this block via 'select' parameter

select->file=tempfile; // Read row ptrs from this file
Done

Details

Assignee

Reporter

Time tracking

1d 3h logged

Priority

Smart Checklist

Created July 2, 2018 at 11:44 AM
Updated March 6, 2024 at 1:05 PM
Resolved July 11, 2018 at 6:49 PM

Flag notifications