[php-src] Issue #24293: mysqlnd: segfault on connect with an empty password to a MariaDB PAM account
| From: | clamy54 | Date: | Tue, 13 Oct 2026 12:38:17 +0000 |
| Subject: | [php-src] Issue #24293: mysqlnd: segfault on connect with an empty password to a MariaDB PAM account | ||
| Groups: | php.bugs | ||
| Request: | Send a blank email to php-bugs+get-252984@lists.php.net to get a copy of this message | ||
Issue: https://github.com/php/php-src/issues/24293
Author: clamy54
### Description
### Description
Connecting with mysqli to a MariaDB account that authenticates through PAM with
pam_use_cleartext_plugin=ON crashes the PHP process (SIGSEGV) when the
password is empty. The server sends an auth switch request to
mysql_clear_password; with an empty password mysqlnd dereferences a NULL
buffer instead of sending a single NUL byte. With a non-empty password the same
connection works.
It showed up with Adminer 6, which reconnects with an empty password right
after login. Every MySQL login ended with the php-fpm worker exiting on
signal 11 and nginx answering 502.
Reproducer:
```php
<?php
mysqli_report(MYSQLI_REPORT_OFF);
$m = mysqli_init();
$r = @$m->real_connect('db', 'pamuser', '', null, 3306);
echo $r ? "connected\n" : "error: {$m->connect_error}\n";
```
Server side (MariaDB official image, tested with pam_permit):
```
# /etc/mysql/conf.d/pam.cnf
[mariadbd]
plugin-load-add = auth_pam.so
pam_use_cleartext_plugin = ON
# /etc/pam.d/mariadb
auth required pam_permit.so
account required pam_permit.so
CREATE USER 'pamuser'@'%' IDENTIFIED VIA pam USING 'mariadb';
```
Resulted in this output:
```
(no output, exit code 139)
Program received signal SIGSEGV, Segmentation fault.
#0 0x00007ffff746185a in ?? () from /lib/x86_64-linux-gnu/libc.so.6
#1-#7 ?? () in the php binary (no symbols)
#8 mysqlnd_connection_connect ()
#9 mysqli_common_connect () from .../mysqli.so
```
But I expected this output instead:
```
error: Access denied for user 'pamuser'@'...' (using password: NO)
```
### Code
mysql_clear_password goes through mysqlnd_pam_auth_get_auth_data():
https://github.com/php/php-src/blob/8db886e419a6aba1903ec97754b0548051b55f9c/ext/mysqlnd/mysqlnd_auth.c#L620-L627
```c
if (passwd && passwd_len) {
ret = (zend_uchar*) zend_strndup(passwd, passwd_len);
}
*auth_data_len = passwd_len + 1;
```
Empty password: ret stays NULL, auth_data_len is 1.
On the write side, php_mysqlnd_change_auth_response_write() copies
auth_data_len bytes from auth_data:
https://github.com/php/php-src/blob/8db886e419a6aba1903ec97754b0548051b55f9c/ext/mysqlnd/mysqlnd_wireprotocol.c#L867-L868
For comparison, the sha256 clear text path (L903-L906, changed in GH-11440)
allocates the buffer whatever the password length.
### PHP Version
```plain
PHP 8.3.35, 8.4.26 and 8.5.11 (official docker images php:8.x-cli and php:8.3-fpm-bookworm)
MariaDB 10.11.19 and 11.4.13
```
### Operating System
Debian (official PHP docker images)