Uploaded image for project: 'MariaDB Server'
  1. MariaDB Server
  2. MDEV-26228

Heap-use-after-free on indexed virtual column with ON UPDATE CASCADE

    XMLWordPrintable

    Details

      Description

      The following change to the MDEV-24041 test case triggers heap-use-after-free:

      diff --git a/mysql-test/suite/gcol/t/innodb_virtual_fk.test b/mysql-test/suite/gcol/t/innodb_virtual_fk.test
      index 24b6a4631e6..c99259531b3 100644
      --- a/mysql-test/suite/gcol/t/innodb_virtual_fk.test
      +++ b/mysql-test/suite/gcol/t/innodb_virtual_fk.test
      @@ -670,6 +670,7 @@ CREATE TABLE email_stats (
         PRIMARY KEY (id),
         KEY mautic_generated_sent_date_email_id (generated_email_id),
         FOREIGN KEY (email_id) REFERENCES emails (id) ON DELETE SET NULL
      +  ON UPDATE CASCADE
       ) ENGINE=InnoDB;
       
       
      @@ -677,6 +678,7 @@ CREATE TABLE emails_metadata (
         email_id int,
         PRIMARY KEY (email_id),
         CONSTRAINT FK FOREIGN KEY (email_id) REFERENCES emails (id) ON DELETE CASCADE
      +  ON UPDATE CASCADE
       ) ENGINE=InnoDB;
       
       
      @@ -684,6 +686,7 @@ INSERT INTO emails VALUES (1);
       INSERT INTO email_stats (id, email_id,  date_sent) VALUES (1,1,'Jan');
       INSERT INTO emails_metadata VALUES (1);
       
      +UPDATE emails SET id=2;
       DELETE FROM emails;
       
       DROP TABLE email_stats;
      

      The fix is simple:

      diff --git a/storage/innobase/row/row0ins.cc b/storage/innobase/row/row0ins.cc
      --- a/storage/innobase/row/row0ins.cc
      +++ b/storage/innobase/row/row0ins.cc
      @@ -969,8 +969,8 @@ row_ins_foreign_fill_virtual(
       		upd_field = update->fields + n_diff;
       
       		upd_field->old_v_val = static_cast<dfield_t*>(
      -				mem_heap_alloc(cascade->heap,
      -					sizeof *upd_field->old_v_val));
      +			mem_heap_alloc(update->heap,
      +				       sizeof *upd_field->old_v_val));
       
       		dfield_copy(upd_field->old_v_val, vfield);
       
      

      The failure without the fix would look like this:

      10.2 742b3a0d39875584f994f4bd01d57cc31d1dddca

      ==1699592==ERROR: AddressSanitizer: heap-use-after-free on address 0x616000389070 at pc 0x0000017603bb bp 0x7fac625c7290 sp 0x7fac625c7288
      READ of size 8 at 0x616000389070 thread T27
          #0 0x17603ba in dfield_copy_data(dfield_t*, dfield_t const*) /mariadb/10.2o/storage/innobase/include/data0data.ic:143:25
          #1 0x17603ba in row_upd_store_v_row(upd_node_t*, upd_t const*, THD*, TABLE*) /mariadb/10.2o/storage/innobase/row/row0upd.cc:2139:5
          #2 0x17603ba in row_upd_store_row(upd_node_t*, THD*, TABLE*) /mariadb/10.2o/storage/innobase/row/row0upd.cc:2238:13
          #3 0x17549a5 in row_upd_clust_step(upd_node_t*, que_thr_t*) /mariadb/10.2o/storage/innobase/row/row0upd.cc:3187:7
          #4 0x17549a5 in row_upd(upd_node_t*, que_thr_t*) /mariadb/10.2o/storage/innobase/row/row0upd.cc:3281:9
          #5 0x1752b06 in row_upd_step(que_thr_t*) /mariadb/10.2o/storage/innobase/row/row0upd.cc:3427:8
          #6 0x167b1c5 in row_update_cascade_for_mysql(que_thr_t*, upd_node_t*, dict_table_t*) /mariadb/10.2o/storage/innobase/row/row0mysql.cc:2106:4
          #7 0x161ec00 in row_ins_foreign_check_on_constraint(que_thr_t*, dict_foreign_t*, btr_pcur_t*, dtuple_t*, mtr_t*) /mariadb/10.2o/storage/innobase/row/row0ins.cc:1360:8
          #8 0x161ec00 in row_ins_check_foreign_constraint(unsigned long, dict_foreign_t*, dict_table_t*, dtuple_t*, que_thr_t*) /mariadb/10.2o/storage/innobase/row/row0ins.cc:1749:12
          #9 0x1760f20 in row_upd_check_references_constraints(upd_node_t*, btr_pcur_t*, dict_table_t*, dict_index_t*, unsigned short*, que_thr_t*, mtr_t*) /mariadb/10.2o/storage/innobase/row/row0upd.cc:323:10
          #10 0x1758dc3 in row_upd_clust_rec_by_insert(upd_node_t*, dict_index_t*, que_thr_t*, bool, bool, mtr_t*) /mariadb/10.2o/storage/innobase/row/row0upd.cc:2787:10
          #11 0x1758dc3 in row_upd_clust_step(upd_node_t*, que_thr_t*) /mariadb/10.2o/storage/innobase/row/row0upd.cc:3207:9
          #12 0x1758dc3 in row_upd(upd_node_t*, que_thr_t*) /mariadb/10.2o/storage/innobase/row/row0upd.cc:3281:9
          #13 0x1752b06 in row_upd_step(que_thr_t*) /mariadb/10.2o/storage/innobase/row/row0upd.cc:3427:8
          #14 0x167740f in row_update_for_mysql(row_prebuilt_t*) /mariadb/10.2o/storage/innobase/row/row0mysql.cc:1822:3
          #15 0x13b7101 in ha_innobase::update_row(unsigned char const*, unsigned char*) /mariadb/10.2o/storage/innobase/handler/ha_innodb.cc:9019:10
          #16 0xe0ad05 in handler::ha_update_row(unsigned char const*, unsigned char*) /mariadb/10.2o/sql/handler.cc:6150:3
          #17 0xab8865 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*) /mariadb/10.2o/sql/sql_update.cc:823:24
          #18 0x87286a in mysql_execute_command(THD*) /mariadb/10.2o/sql/sql_parse.cc:4056:21
          #19 0x866cfc in mysql_parse(THD*, char*, unsigned int, Parser_state*, bool, bool) /mariadb/10.2o/sql/sql_parse.cc:7793:18
          #20 0x85d321 in dispatch_command(enum_server_command, THD*, char*, unsigned int, bool, bool) /mariadb/10.2o/sql/sql_parse.cc:1827:7
          #21 0x863cc7 in do_command(THD*) /mariadb/10.2o/sql/sql_parse.cc:1381:17
          #22 0xb77d90 in do_handle_one_connection(CONNECT*) /mariadb/10.2o/sql/sql_connect.cc:1336:11
          #23 0xb777f5 in handle_one_connection /mariadb/10.2o/sql/sql_connect.cc:1241:3
          #24 0x7fac75703ea6 in start_thread nptl/pthread_create.c:477:8
          #25 0x7fac74d49dee in clone misc/../sysdeps/unix/sysv/linux/x86_64/clone.S:95
       
      0x616000389070 is located 496 bytes inside of 640-byte region [0x616000388e80,0x616000389100)
      freed by thread T27 here:
          #0 0x62b2b2 in free (/dev/shm/10.2a/sql/mysqld+0x62b2b2)
          #1 0x175d0ef in mem_heap_free_heap_top(mem_block_info_t*, unsigned char*) /mariadb/10.2o/storage/innobase/include/mem0mem.ic:259:3
          #2 0x175d0ef in mem_heap_empty(mem_block_info_t*) /mariadb/10.2o/storage/innobase/include/mem0mem.ic:289:2
       
      previously allocated by thread T27 here:
          #0 0x62b51d in malloc (/dev/shm/10.2a/sql/mysqld+0x62b51d)
          #1 0x152f7fd in mem_heap_create_block_func(mem_block_info_t*, unsigned long, char const*, unsigned int, unsigned long) /mariadb/10.2o/storage/innobase/mem/mem0mem.cc:289:37
          #2 0x152fe9b in mem_heap_add_block(mem_block_info_t*, unsigned long) /mariadb/10.2o/storage/innobase/mem/mem0mem.cc:390:14
      

        Attachments

          Issue Links

            Activity

              People

              Assignee:
              marko Marko Mäkelä
              Reporter:
              marko Marko Mäkelä
              Votes:
              0 Vote for this issue
              Watchers:
              1 Start watching this issue

                Dates

                Created:
                Updated:
                Resolved:

                  Git Integration