From 3882f55a61f831b4e222487bc1c50cc21b6803df Mon Sep 17 00:00:00 2001 From: Weilin Du Date: Fri, 17 Jul 2026 04:09:02 +0800 Subject: [PATCH 1/3] ext/sockets: Fix socket_set_option() validation error messages (#22772) Fix a few incorrect socket_set_option() validation error messages. --- NEWS | 4 ++++ ext/sockets/sockets.c | 6 +++--- ext/sockets/tests/socket_cmsg_udp_segment.phpt | 4 ++-- ext/sockets/tests/socket_set_option_timeo_error.phpt | 7 +++++++ 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/NEWS b/NEWS index c35b46d24c08..d989b44146d2 100644 --- a/NEWS +++ b/NEWS @@ -5,6 +5,10 @@ PHP NEWS - Date: . Fixed leak on double DatePeriod::__construct() call. (ilutov) +- Sockets: + . Fixed socket_set_option() validation error messages for UDP_SEGMENT and + SO_LINGER options. (Weilin Du) + 30 Jul 2026, PHP 8.5.9 - Core: diff --git a/ext/sockets/sockets.c b/ext/sockets/sockets.c index 0e11280c914f..5c8ad859851f 100644 --- a/ext/sockets/sockets.c +++ b/ext/sockets/sockets.c @@ -2168,7 +2168,7 @@ PHP_FUNCTION(socket_set_option) } if (val_linger < 0 || val_linger > USHRT_MAX) { - zend_argument_value_error(4, "\"%s\" must be between 0 and %d", l_linger, USHRT_MAX); + zend_argument_value_error(4, "\"%s\" must be between 0 and %u", l_linger_key, USHRT_MAX); RETURN_THROWS(); } @@ -2332,8 +2332,8 @@ PHP_FUNCTION(socket_set_option) // UDP segmentation offload maximum size or 0 to disable it if (ov < 0 || ov > USHRT_MAX) { - zend_argument_value_error(4, "must be of between 0 and %u", USHRT_MAX); - RETURN_FALSE; + zend_argument_value_error(4, "must be between 0 and %u", USHRT_MAX); + RETURN_THROWS(); } optlen = sizeof(ov); diff --git a/ext/sockets/tests/socket_cmsg_udp_segment.phpt b/ext/sockets/tests/socket_cmsg_udp_segment.phpt index 679b246ea9d4..38a914066510 100644 --- a/ext/sockets/tests/socket_cmsg_udp_segment.phpt +++ b/ext/sockets/tests/socket_cmsg_udp_segment.phpt @@ -22,5 +22,5 @@ try { } ?> --EXPECT-- -socket_setopt(): Argument #4 ($value) must be of between 0 and 65535 -socket_setopt(): Argument #4 ($value) must be of between 0 and 65535 +socket_setopt(): Argument #4 ($value) must be between 0 and 65535 +socket_setopt(): Argument #4 ($value) must be between 0 and 65535 diff --git a/ext/sockets/tests/socket_set_option_timeo_error.phpt b/ext/sockets/tests/socket_set_option_timeo_error.phpt index 1db5e01c3622..befdfb095855 100644 --- a/ext/sockets/tests/socket_set_option_timeo_error.phpt +++ b/ext/sockets/tests/socket_set_option_timeo_error.phpt @@ -13,6 +13,7 @@ $options_2 = array("sec" => new stdClass(), "usec" => "1"); $options_3 = array("l_onoff" => "aaaa", "l_linger" => "1"); $options_4 = array("l_onoff" => "1", "l_linger" => []); $options_5 = array("l_onoff" => PHP_INT_MAX, "l_linger" => "1"); +$options_6 = array("l_onoff" => "1", "l_linger" => PHP_INT_MAX); try { socket_set_option( $socket, SOL_SOCKET, SO_RCVTIMEO, new stdClass); @@ -56,6 +57,11 @@ try { } catch (\ValueError $e) { echo $e->getMessage() . PHP_EOL; } +try { + socket_set_option( $socket, SOL_SOCKET, SO_LINGER, $options_6); +} catch (\ValueError $e) { + echo $e->getMessage() . PHP_EOL; +} ?> --EXPECTF-- socket_set_option(): Argument #4 ($value) must have key "sec" @@ -64,3 +70,4 @@ Warning: Object of class stdClass could not be converted to int in %s on line %d socket_set_option(): Argument #4 ($value) must be of type array when argument #3 ($option) is SO_RCVTIMEO, string given socket_set_option(): Argument #4 ($value) must be of type array when argument #3 ($option) is SO_LINGER, string given socket_set_option(): Argument #4 ($value) "l_onoff" must be between 0 and %d +socket_set_option(): Argument #4 ($value) "l_linger" must be between 0 and %d From 1c4bf04783b4915a908a1f7f09a4f4fe2f115ed6 Mon Sep 17 00:00:00 2001 From: Ilia Alshanetsky Date: Thu, 16 Jul 2026 08:30:45 -0400 Subject: [PATCH 2/3] ext/soap: fix NULL deref on malformed HTTP status line make_http_soap_request() looked for the reason phrase with strstr(tmp, " ") even when the first strstr() found no space, which happens for a status line carrying a version but no status code, such as "HTTP/1.1". tmp is NULL there, so strstr() dereferenced it and the client crashed. Only parse the reason phrase when a status code field was present. Closes GH-22761 --- ext/soap/php_http.c | 14 ++++----- ext/soap/tests/http_status_line_no_code.phpt | 33 ++++++++++++++++++++ 2 files changed, 40 insertions(+), 7 deletions(-) create mode 100644 ext/soap/tests/http_status_line_no_code.phpt diff --git a/ext/soap/php_http.c b/ext/soap/php_http.c index e9fd68007d26..125c92582008 100644 --- a/ext/soap/php_http.c +++ b/ext/soap/php_http.c @@ -956,14 +956,14 @@ int make_http_soap_request(zval *this_ptr, if (tmp != NULL) { tmp++; http_status = atoi(tmp); - } - tmp = strstr(tmp," "); - if (tmp != NULL) { - tmp++; - if (http_msg) { - efree(http_msg); + tmp = strstr(tmp," "); + if (tmp != NULL) { + tmp++; + if (http_msg) { + efree(http_msg); + } + http_msg = estrdup(tmp); } - http_msg = estrdup(tmp); } efree(http_version); diff --git a/ext/soap/tests/http_status_line_no_code.phpt b/ext/soap/tests/http_status_line_no_code.phpt new file mode 100644 index 000000000000..de943571a492 --- /dev/null +++ b/ext/soap/tests/http_status_line_no_code.phpt @@ -0,0 +1,33 @@ +--TEST-- +SoapClient: malformed HTTP status line without status code must not crash +--EXTENSIONS-- +soap +--FILE-- + 'http://{{ ADDR }}', + 'uri' => 'http://testuri.org', + 'connection_timeout' => 3, +]); +var_dump($client->__doRequest('', 'http://{{ ADDR }}', 'T', 1)); +CODE; + +include sprintf('%s/../../openssl/tests/ServerClientTestCase.inc', __DIR__); +ServerClientTestCase::getInstance()->run($clientCode, $serverCode); +?> +--EXPECT-- +string(0) "" From 331916c910cc43f2c156545e80f02e45cb2700d7 Mon Sep 17 00:00:00 2001 From: Ilia Alshanetsky Date: Thu, 16 Jul 2026 22:07:27 -0400 Subject: [PATCH 3/3] ext/sockets: run the AF_PACKET error test in isolation (#22773) The no-data case binds an ETH_P_ALL packet socket to lo and asserts that a non-blocking recvfrom() finds nothing, which only holds while no other test puts a frame on loopback. run-tests spawns workers in parallel and the job runs as root, so any concurrent test that talks to localhost makes the socket capture a frame and recvfrom() returns data instead of failing. Observed on LINUX_X32_DEBUG_ZTS: bool(false) where bool(true) was expected. Closes GH-22773 --- ext/sockets/tests/socket_sendto_recvfrom_afpacket_errors.phpt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ext/sockets/tests/socket_sendto_recvfrom_afpacket_errors.phpt b/ext/sockets/tests/socket_sendto_recvfrom_afpacket_errors.phpt index 775a1381506c..a63c36c4f6b0 100644 --- a/ext/sockets/tests/socket_sendto_recvfrom_afpacket_errors.phpt +++ b/ext/sockets/tests/socket_sendto_recvfrom_afpacket_errors.phpt @@ -15,6 +15,8 @@ if (!function_exists("posix_getuid") || posix_getuid() != 0) { die('SKIP AF_PACKET requires root permissions.'); } ?> +--CONFLICTS-- +all --FILE--