From 35309ed0ec0fcc8494645bb3fe4f97ceafc6d38c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ey=C3=BCp=20Can=20Akman?= Date: Fri, 6 Nov 2026 20:03:56 +0300 Subject: [PATCH] Fix php-cgi -b accepting ports above 65535 fcgi_listen() read the port with atoi() into a short and did not check its range, so a port above 65535 or below 0 wrapped to another port. php-cgi -b 70000 listened on port 4464. Reject such ports, as GH-24616 did for socket transports. The -b error exits in main() returned without shutting the module down, which leaked. Jump to parent_out instead, like the error paths further down. --- main/fastcgi.c | 12 ++++++++--- sapi/cgi/cgi_main.c | 14 ++++++------ sapi/cgi/tests/bind_port_range.phpt | 33 +++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 11 deletions(-) create mode 100644 sapi/cgi/tests/bind_port_range.phpt diff --git a/main/fastcgi.c b/main/fastcgi.c index f63210a59d97..d00e457a2af7 100644 --- a/main/fastcgi.c +++ b/main/fastcgi.c @@ -644,7 +644,7 @@ int fcgi_listen(const char *path, int backlog) const char *s; int tcp = 0; char host[MAXPATHLEN]; - short port = 0; + zend_long port = 0; int listen_socket; sa_t sa; socklen_t sock_len; @@ -657,14 +657,20 @@ int fcgi_listen(const char *path, int backlog) #endif if ((s = strchr(path, ':'))) { - port = atoi(s+1); + port = ZEND_STRTOL(s+1, NULL, 10); + if (port < 0 || port > 65535) { + return -1; + } if (port != 0 && (s-path) < MAXPATHLEN) { strncpy(host, path, s-path); host[s-path] = '\0'; tcp = 1; } } else if (is_port_number(path)) { - port = atoi(path); + port = ZEND_STRTOL(path, NULL, 10); + if (port > 65535) { + return -1; + } if (port != 0) { host[0] = '\0'; tcp = 1; diff --git a/sapi/cgi/cgi_main.c b/sapi/cgi/cgi_main.c index 0e7b3009c602..7e1cddfd0679 100644 --- a/sapi/cgi/cgi_main.c +++ b/sapi/cgi/cgi_main.c @@ -1937,18 +1937,16 @@ consult the installation file that came with this distribution, or visit \n\ } if (backlog < -1 || backlog > SOMAXCONN) { fprintf(stderr, "Invalid backlog %d, needs to be between -1 and %d\n", backlog, SOMAXCONN); -#ifdef ZTS - tsrm_shutdown(); -#endif - return FAILURE; + free(bindpath); + exit_status = FAILURE; + goto parent_out; } fcgi_fd = fcgi_listen(bindpath, backlog); if (fcgi_fd < 0) { fprintf(stderr, "Couldn't create FastCGI listen socket on port %s\n", bindpath); -#ifdef ZTS - tsrm_shutdown(); -#endif - return FAILURE; + free(bindpath); + exit_status = FAILURE; + goto parent_out; } fastcgi = fcgi_is_fastcgi(); } diff --git a/sapi/cgi/tests/bind_port_range.phpt b/sapi/cgi/tests/bind_port_range.phpt new file mode 100644 index 000000000000..998598f8babd --- /dev/null +++ b/sapi/cgi/tests/bind_port_range.phpt @@ -0,0 +1,33 @@ +--TEST-- +php-cgi -b rejects ports outside 0-65535 +--SKIPIF-- + +--FILE-- + ['pipe', 'w'], 2 => ['pipe', 'w']], $pipes); + for ($i = 0; $i < 50 && proc_get_status($proc)['running']; $i++) { + usleep(100000); + } + if (proc_get_status($proc)['running']) { + proc_terminate($proc); + echo "$bind: still listening\n"; + } else { + echo trim(stream_get_contents($pipes[2])), "\n"; + } + proc_close($proc); +} + +?> +--EXPECT-- +Couldn't create FastCGI listen socket on port 127.0.0.1:70000 +Couldn't create FastCGI listen socket on port 127.0.0.1:-1 +Couldn't create FastCGI listen socket on port 70000