Bug #91603 stack-use-after-scope in reinit_io_cache() detected by ASan
Submitted: 11 Jul 2018 17:54 Modified: 18 Feb 2021 9:29
Reporter: Yura Sorokin (OCA) Email Updates:
Status: Duplicate Impact on me:
None 
Category:MySQL Server: Compiling Severity:S2 (Serious)
Version:5.5.60, 5.6.40 OS:Any
Assigned to: CPU Architecture:Any
Tags: Contribution

[11 Jul 2018 17:54] Yura Sorokin
Description:
Address Sanitizer from GCC 7.3 and 8.0 detects the following problem in a number of MTR test cases in 5.5 and 5.6 branches.

==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

How to repeat:
Compile MySQL 5.5 branch on Ubuntu Bionic (GCC 7.3)

Run
./mysql-test/mtr --debug-server innodb_bug12661768

Suggested fix:
See the attached patches
[11 Jul 2018 17:56] Yura Sorokin
The problem is already known 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.
[11 Jul 2018 17:58] Yura Sorokin
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;
  }

Suggested fix:
call
setup_io_cache(&select->file);
after that assignment.
[11 Jul 2018 18:05] Yura Sorokin
A patch to make 5.5 code compilable with GCC 7.3/8.0

(*) I confirm the code being submitted is offered under the terms of the OCA, and that I am authorized to contribute it.

Contribution: mysql_5_5_gcc_7_3_asan_fix.diff (application/octet-stream, text), 1.33 KiB.

[11 Jul 2018 18:08] Yura Sorokin
5.5 patch

(*) I confirm the code being submitted is offered under the terms of the OCA, and that I am authorized to contribute it.

Contribution: bug91603_5_5.diff (application/octet-stream, text), 421 bytes.

[11 Jul 2018 18:10] Yura Sorokin
5.6 patch

(*) I confirm the code being submitted is offered under the terms of the OCA, and that I am authorized to contribute it.

Contribution: bug91603_5_6.diff (application/octet-stream, text), 443 bytes.

[12 Jul 2018 8:00] MySQL Verification Team
Hello Yura Sorokin,

Thank you for the report and contribution.

Thanks,
Umesh
[20 Nov 2018 11:38] Dyre Tjeldvoll
Posted by developer:
 
Thank you for providing the contribution! As you can see from earlier comments this issue has been fixed in newer versions, and we have chosen not to backport the fix to earlier versions.
[18 Feb 2021 9:29] Erlend Dahl
Duplicate of

Bug#82220 Read of out-of-scope (tempfile) in mysql_update()