VYPR
Unrated severityNVD Advisory· Published Feb 19, 2018· Updated Aug 6, 2024

CVE-2015-9253

CVE-2015-9253

Description

PHP php-fpm master process enters infinite restart loop when child uses non-blocking STDIN with exec functions, causing CPU exhaustion and disk fill.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

PHP php-fpm master process enters infinite restart loop when child uses non-blocking STDIN with exec functions, causing CPU exhaustion and disk fill.

Vulnerability

In PHP versions 7.1.x before 7.1.20, 7.2.x before 7.2.8, and 7.3.x before 7.3.0alpha3, the php-fpm master process enters an endless restart loop when a child process uses program execution functions (e.g., exec, passthru, shell_exec, system) with a non-blocking STDIN stream [2]. The bug was originally reported in 2015 in the context of SSH multiplexing [1] and later generalized to any non-blocking STDIN scenario [2].

Exploitation

An attacker who can execute arbitrary PHP code on a server running php-fpm (e.g., a customer of a shared-hosting facility) can trigger the vulnerability by calling stream_set_blocking(fopen('php://stdin', 'r'), false) before invoking any program execution function [2]. No special network position or authentication beyond the ability to run PHP scripts is required. The child process crashes, causing the master to restart it repeatedly in an infinite loop [1][2].

Impact

Successful exploitation causes the php-fpm master process to consume 100% CPU and generate a large volume of error logs, rapidly filling disk space [2]. This results in a denial of service (DoS) for the hosting server, affecting all hosted sites. The master process may become unresponsive to stop/restart signals, requiring a SIGKILL to terminate [2].

Mitigation

The fix was included in PHP 7.1.20, 7.2.8, and 7.3.0alpha3 [2]. Ubuntu released updates in USN-3766-1 (2018) for 18.04 LTS and USN-4279-1 (2020) for other releases [3][4]. Users should upgrade to the patched versions or apply the vendor-provided updates. No workaround is documented; disabling php-fpm or restricting execution functions may reduce risk but is not a complete mitigation.

AI Insight generated on May 24, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected products

14

Patches

2
69dee5c732fe

Fixed bug #73342

https://github.com/php/php-srcNikita PopovJun 12, 2018via nvd-ref
4 files changed · +51 6
  • NEWS+4 0 modified
    @@ -5,6 +5,10 @@ PHP                                                                        NEWS
     - Date:
       . Fixed bug #76462 (Undefined property: DateInterval::$f). (Anatol)
     
    +- FPM:
    +  . Fixed bug #73342 (Vulnerability in php-fpm by changing stdin to
    +    non-blocking). (Nikita)
    +
     22 Jun 2019, PHP 7.1.19
     
     - CLI Server:
    
  • sapi/fpm/fpm/fpm_children.c+1 0 modified
    @@ -146,6 +146,7 @@ static struct fpm_child_s *fpm_child_find(pid_t pid) /* {{{ */
     static void fpm_child_init(struct fpm_worker_pool_s *wp) /* {{{ */
     {
     	fpm_globals.max_requests = wp->config->pm_max_requests;
    +	fpm_globals.listening_socket = dup(wp->listening_socket);
     
     	if (0 > fpm_stdio_init_child(wp)  ||
     	    0 > fpm_log_init_child(wp)    ||
    
  • sapi/fpm/fpm/fpm_stdio.c+0 6 modified
    @@ -103,12 +103,6 @@ int fpm_stdio_init_child(struct fpm_worker_pool_s *wp) /* {{{ */
     	fpm_globals.error_log_fd = -1;
     	zlog_set_fd(-1);
     
    -	if (wp->listening_socket != STDIN_FILENO) {
    -		if (0 > dup2(wp->listening_socket, STDIN_FILENO)) {
    -			zlog(ZLOG_SYSERROR, "failed to init child stdio: dup2()");
    -			return -1;
    -		}
    -	}
     	return 0;
     }
     /* }}} */
    
  • sapi/fpm/tests/bug73342-nonblocking-stdio.phpt+46 0 added
    @@ -0,0 +1,46 @@
    +--TEST--
    +FPM: bug73342 - Non-blocking stdin
    +--SKIPIF--
    +<?php include "skipif.inc"; ?>
    +--FILE--
    +<?php
    +
    +require_once "tester.inc";
    +
    +$cfg = <<<EOT
    +[global]
    +error_log = {{FILE:LOG}}
    +[unconfined]
    +listen = {{ADDR}}
    +pm = dynamic
    +pm.max_children = 5
    +pm.start_servers = 1
    +pm.min_spare_servers = 1
    +pm.max_spare_servers = 3
    +EOT;
    +
    +$code = <<<EOT
    +<?php
    +echo "Before\n";
    +stream_set_blocking(fopen('php://stdin', 'r'), false);
    +echo "After\n";
    +EOT;
    +
    +$tester = new FPM\Tester($cfg, $code);
    +$tester->start();
    +$tester->expectLogStartNotices();
    +$tester->request()->expectBody("Before\nAfter");
    +$tester->request()->expectBody("Before\nAfter");
    +$tester->terminate();
    +$tester->expectLogTerminatingNotices();
    +$tester->close();
    +
    +?>
    +Done
    +--EXPECT--
    +Done
    +--CLEAN--
    +<?php
    +require_once "tester.inc";
    +FPM\Tester::clean();
    +?>
    
acd652bf1eb0

Merge 36f979369026ef9a5c6a616a39ed1cd55d7a9fa0 into 5dd1ef90caec3021e6ce55c8554e695edf641eaf

https://github.com/php/php-srcNikita PopovJun 18, 2018via nvd-ref
3 files changed · +47 6
  • sapi/fpm/fpm/fpm_children.c+1 0 modified
    @@ -146,6 +146,7 @@ static struct fpm_child_s *fpm_child_find(pid_t pid) /* {{{ */
     static void fpm_child_init(struct fpm_worker_pool_s *wp) /* {{{ */
     {
     	fpm_globals.max_requests = wp->config->pm_max_requests;
    +	fpm_globals.listening_socket = dup(wp->listening_socket);
     
     	if (0 > fpm_stdio_init_child(wp)  ||
     	    0 > fpm_log_init_child(wp)    ||
    
  • sapi/fpm/fpm/fpm_stdio.c+0 6 modified
    @@ -103,12 +103,6 @@ int fpm_stdio_init_child(struct fpm_worker_pool_s *wp) /* {{{ */
     	fpm_globals.error_log_fd = -1;
     	zlog_set_fd(-1);
     
    -	if (wp->listening_socket != STDIN_FILENO) {
    -		if (0 > dup2(wp->listening_socket, STDIN_FILENO)) {
    -			zlog(ZLOG_SYSERROR, "failed to init child stdio: dup2()");
    -			return -1;
    -		}
    -	}
     	return 0;
     }
     /* }}} */
    
  • sapi/fpm/tests/bug73342-nonblocking-stdio.phpt+46 0 added
    @@ -0,0 +1,46 @@
    +--TEST--
    +Bug #73342: Vulnerability in php-fpm by changing stdin to non-blocking
    +--SKIPIF--
    +<?php include "skipif.inc"; ?>
    +--FILE--
    +<?php
    +
    +require_once "tester.inc";
    +
    +$cfg = <<<EOT
    +[global]
    +error_log = {{FILE:LOG}}
    +[unconfined]
    +listen = {{ADDR}}
    +pm = dynamic
    +pm.max_children = 5
    +pm.start_servers = 1
    +pm.min_spare_servers = 1
    +pm.max_spare_servers = 3
    +EOT;
    +
    +$code = <<<EOT
    +<?php
    +echo "Before\n";
    +stream_set_blocking(fopen('php://stdin', 'r'), false);
    +echo "After\n";
    +EOT;
    +
    +$tester = new FPM\Tester($cfg, $code);
    +$tester->start();
    +$tester->expectLogStartNotices();
    +$tester->request()->expectBody("Before\nAfter");
    +$tester->request()->expectBody("Before\nAfter");
    +$tester->terminate();
    +$tester->expectLogTerminatingNotices();
    +$tester->close();
    +
    +?>
    +Done
    +--EXPECT--
    +Done
    +--CLEAN--
    +<?php
    +require_once "tester.inc";
    +FPM\Tester::clean();
    +?>
    

Vulnerability mechanics

Root cause

"php-fpm duplicated the listening socket onto STDIN of child processes, so when a child set STDIN to non-blocking mode the master process entered an infinite restart loop."

Attack vector

An attacker who can execute PHP code on a shared-hosting server (e.g. via a web application) can call any program execution function such as `exec()`, `shell_exec()`, `passthru()`, or `system()` with a child process that sets STDIN to non-blocking mode. Because php-fpm had previously `dup2()`'d the listening socket onto STDIN, the child's non-blocking STDIN causes the master process to misinterpret the socket state, triggering an endless loop of child restarts. This consumes 100% CPU and rapidly fills the error log with "child exited" notices, potentially exhausting disk space [ref_id=1].

Affected code

The vulnerability resides in `sapi/fpm/fpm/fpm_stdio.c` in the `fpm_stdio_init_child()` function, which used `dup2()` to duplicate the listening socket onto `STDIN_FILENO`. The patch also modifies `sapi/fpm/fpm/fpm_children.c` to store a duplicated listening socket via `dup()` in `fpm_child_init()`.

What the fix does

The patch removes the `dup2(wp->listening_socket, STDIN_FILENO)` call from `fpm_stdio_init_child()` so the listening socket is no longer duplicated onto STDIN. Instead, `fpm_child_init()` now stores a separate duplicated file descriptor via `dup(wp->listening_socket)` into `fpm_globals.listening_socket`. This prevents child processes from inheriting the listening socket as STDIN, so when a child sets STDIN to non-blocking mode it no longer interferes with the master process's socket handling, breaking the infinite restart loop [patch_id=2247143][patch_id=2247142].

Preconditions

  • authAttacker must be able to execute arbitrary PHP code on a server running php-fpm (e.g., a shared-hosting customer with a web application).
  • inputThe executed PHP code must call a program execution function (exec, shell_exec, passthru, system) that launches a child process which sets STDIN to non-blocking.

Generated on May 24, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

8

News mentions

0

No linked articles in our index yet.