MariaDB · Report #3766217
libmariadb ( mariadb-connector-c ): stack overflow via server-controlled field->length in prepared-statement codec
How it was found
MariaDB Connector/C (libmariadb) calls alloca() with a length value read directly from the server's column-definition packet without any upper bound. A malicious MariaDB/MySQL server, or a MITM attacker on a non-TLS connection, can set field->length to a value exceeding the process stack size, causing an immediate stack overflow and process crash ( SIGSEGV ).
Vulnerable Code
File: libmariadb/ma_stmt_codec.c, function convert_from_long, line 677
static void convert_from_long(MYSQL_BIND *r_param, const MYSQL_FIELD *field,
long long val)
{
// ...
default:
{
char *buffer;
buffer = alloca(MAX(field->length, 22)); // <-- no upper bound
// ...
}
}
Source of field->length: libmariadb/mariadb_lib.c, line 1171
field->length = (uint) uint4korr(p); // 4-byte read from server packet, no clamp
The server's column-definition packet contains a 4-byte field->length value that is read verbatim with uint4korr() and stored without any validation. When this value reaches convert_from_long() via the prepared-statement fetch path, alloca() attempts to reserve that many bytes on the stack. Any value exceeding the thread's stack limit (~8MB default) causes SIGSEGV.
Call Chain
mysql_stmt_fetch()
--> stmt_buffered_fetch() or ma_stmt_execute_packet_read()
--> madb_update_stmt_fields()
--> field->length = uint4korr(p) // server-controlled, no clamp
--> ma_stmt_fetch_column_as_bind()
--> field->fetch_func() --> ps_fetch_long()
--> convert_from_long()
--> alloca(MAX(field->length, 22)) // BOOM if > stack size
Steps to Reproduce
Prerequisites
- GCC, libmariadb-dev (any version with prepared-statement support)
- Python 3 (for the malicious server)
Step 1 - Build the C client
unzip mariadb-c.zip
cd poc
gcc -o client client.c $(mariadb_config --cflags --libs)
Step 2 - Start the malicious server (field_length = 16MB)
python3 malicious_server.py 33995 &
The server implements the minimum MariaDB wire protocol: handshake, auth OK, COM_STMT_PREPARE response with field->length = 0x1000000 (16MB), and COM_STMT_EXECUTE response with a single integer row.
Step 3 - Run the client
./client 33995
Step 4 - Observe the crash
Segmentation fault (core dumped)
Exit code: 139
Step 5 - Control run (field_length = 100)
# Edit malicious_server.py: FIELD_LENGTH = 100
python3 malicious_server.py 33996 &
./client 33996
[client] connecting to 127.0.0.1:33996
[client] connected, server: 5.7.30-malicious
[client] prepared
[client] executed, fetching...
[client] fetch returned 0, value='7' len=1
Exit code: 0
Clean execution - confirms the threshold matches the stack size.
Exploitation conditions:
- The attacker controls or can impersonate the database server (malicious server, DNS poisoning, ARP spoofing, or MITM on non-TLS connections)
- No authentication or credentials are required - the malicious field metadata is sent after the handshake in response to COM_STMT_PREPARE
- No user interaction is required
Affected versions:
- libmariadb 11.8.6 (Debian/Kali system package) - confirmed
- MariaDB Connector/C HEAD of 3.4 branch (6ffb335, version 3.4.10-dev) - same vulnerable code
- MariaDB Connector/C v3.4.9 (64e9fe0) - same vulnerable code
- All prior versions with prepared-statement support
Suggested Fix
Clamp field->length before it reaches alloca():
// Option 1: clamp at parse time (mariadb_lib.c:1171)
field->length = MIN((uint)uint4korr(p), MAX_FIELD_LENGTH);
// Option 2: clamp at alloca site (ma_stmt_codec.c:677)
size_t buf_len = MAX(field->length, 22);
if (buf_len > MAX_ALLOCA_SIZE)
buffer = malloc(buf_len);
else
buffer = alloca(buf_len);
Environment
- libmariadb 11.8.6 (Debian 1:11.8.6-2)
- GCC 14.2.0, Linux x86_64
- Stack limit: 8192 KB (default)
- Reproduction: 2/2 successful
Impact
A malicious MariaDB/MySQL server, or a network attacker performing MITM on a non-TLS database connection, can crash any application linked against libmariadb that uses prepared statements (mysql_stmt_* API). The crash occurs when the client fetches query results - after the connection is established and the query is executed.
Confirmed impact:
- Denial of Service: The client process crashes with SIGSEGV (exit 139). Any application using libmariadb prepared statements is terminated immediately.
Reach - affected downstream consumers:
- PHP
mysqliin prepared-statement mode - Perl
DBD::MariaDB - Ruby
mysql2gem - Direct C/C++ applications using
mysql_stmt_fetch() - MariaDB Connector/Python is NOT affected ( uses
STMT_ATTR_FIELD_FETCH_CALLBACKoverride that bypasses this code path )