Commit 3c1a0727162 for php

commit 3c1a0727162784b89d78eb494185444d75917e95
Author: lazerg <lazerg2@gmail.com>
Date:   Tue Oct 13 12:54:03 2026 +0000

    Fix GH-24293: Segfault with an empty password in MariaDB PAM (#24294)

    mysqlnd_pam_auth_get_auth_data() returned NULL for an empty password but
    reported a length of one for the trailing NUL required by bug #78680.
    After a switch to mysql_clear_password, the authentication response writer
    copied that byte from a NULL pointer and crashed.

    Always allocate the authentication buffer so an empty password is sent as
    a single NUL byte. Add a fake-server regression test that exercises the
    authentication switch without requiring a MariaDB PAM setup.

    Closes #24294

diff --git a/NEWS b/NEWS
index 98d3853e0b7..c6452c72004 100644
--- a/NEWS
+++ b/NEWS
@@ -37,6 +37,10 @@ PHP                                                                        NEWS
 - MBString:
   . Fixed bug GH-23958 (truncated encoding names resolving to full names). (Kamil Tekiela)

+- MySQLnd:
+  . Fixed bug GH-24293 (Segfault on connect with an empty password to a
+    MariaDB PAM account). (lazerg)
+
 - Opcache:
   . Fixed bug GH-20890 (Segfault in zval_undefined_cv with non-simple property
     hook with minimal tracing JIT). (ndossche)
diff --git a/ext/mysqli/tests/fake_server.inc b/ext/mysqli/tests/fake_server.inc
index 238c5db31da..2a4d17f946e 100644
--- a/ext/mysqli/tests/fake_server.inc
+++ b/ext/mysqli/tests/fake_server.inc
@@ -1185,6 +1185,23 @@ function my_mysqli_test_cached_sha2_switch_unterminated(my_mysqli_fake_server_co
     $conn->read(65536);
 }

+function my_mysqli_test_auth_switch_clear_password(my_mysqli_fake_server_conn $conn): void
+{
+    $p = new my_mysqli_fake_packet();
+    $p->packet_length = "2b0000";
+    $p->packet_number = "02";
+    $p->response_code = "fe";
+    $p->auth_plugin_name = bin2hex('mysql_clear_password' . chr(0));
+    // servers always send a fresh scramble with the switch request
+    $p->auth_plugin_data = "473e3f6047257c676c6b55463f49335f686c643100";
+
+    $conn->send_server_greetings();
+    $conn->read();
+    $conn->send($p->to_bytes(), "Auth Switch Request [mysql_clear_password]");
+    $conn->read();
+    $conn->send($conn->packet_generator->server_ok("04")->to_bytes(), "Server OK");
+}
+
 function my_mysqli_test_chg_user_response_empty(my_mysqli_fake_server_conn $conn): void
 {
     $p = $conn->packet_generator->server_ok("01");
diff --git a/ext/mysqli/tests/gh24293.phpt b/ext/mysqli/tests/gh24293.phpt
new file mode 100644
index 00000000000..01bee5126aa
--- /dev/null
+++ b/ext/mysqli/tests/gh24293.phpt
@@ -0,0 +1,32 @@
+--TEST--
+GH-24293 (Segfault on connect with an empty password to a MariaDB PAM account)
+--EXTENSIONS--
+mysqli
+--FILE--
+<?php
+require_once 'fake_server.inc';
+
+$servername = "127.0.0.1";
+$username = "root";
+$password = "";
+
+$process = run_fake_server_in_background('auth_switch_clear_password');
+$process->wait();
+
+$conn = new mysqli($servername, $username, $password, "", $process->getPort());
+$conn->close();
+
+$process->terminate(true);
+
+print "done!";
+?>
+--EXPECTF--
+[*] Server started on 127.0.0.1:%d
+[*] Connection established
+[*] Sending - Server Greeting: 580000000a352e352e352d31302e352e31382d4d6172696144420003000000473e3f6047257c6700fef7080200ff81150000000000000f0000006c6b55463f49335f686c6431006d7973716c5f6e61746976655f70617373776f7264
+[*] Received: 6900000185a21a00000000c0080000000000000000000000000000000000000000000000726f6f7400006d7973716c5f6e61746976655f70617373776f7264002c0c5f636c69656e745f6e616d65076d7973716c6e640c5f7365727665725f686f7374093132372e302e302e31
+[*] Sending - Auth Switch Request [mysql_clear_password]: 2b000002fe6d7973716c5f636c6561725f70617373776f726400473e3f6047257c676c6b55463f49335f686c643100
+[*] Received: 0100000300
+[*] Sending - Server OK: 0700000400000002000000
+[*] Server finished
+done!
diff --git a/ext/mysqlnd/mysqlnd_auth.c b/ext/mysqlnd/mysqlnd_auth.c
index ea9755c982e..69bf2abbe06 100644
--- a/ext/mysqlnd/mysqlnd_auth.c
+++ b/ext/mysqlnd/mysqlnd_auth.c
@@ -629,9 +629,7 @@ mysqlnd_pam_auth_get_auth_data(struct st_mysqlnd_authentication_plugin * self,
 	zend_uchar * ret = NULL;

 	/* copy pass*/
-	if (passwd && passwd_len) {
-		ret = (zend_uchar*) zend_strndup(passwd, passwd_len);
-	}
+	ret = (zend_uchar*) zend_strndup(passwd, passwd_len);
 	/*
 	  Trailing null required. bug#78680
 	  https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_connection_phase_authentication_methods_clear_text_password.html