php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #67905 proc_open leaks file descriptors on error
Submitted: 2014-08-26 07:59 UTC Modified: 2014-09-18 14:21 UTC
Votes:1
Avg. Score:3.0 ± 0.0
Reproduced:1 of 1 (100.0%)
Same Version:1 (100.0%)
Same OS:1 (100.0%)
From: jille at hexon dot cx Assigned:
Status: Verified Package: Program Execution
PHP Version: master-Git-2014-08-26 (Git) OS: n/a
Private report: No CVE-ID: None
Have you experienced this issue?
Rate the importance of this bug to you:

 [2014-08-26 07:59 UTC] jille at hexon dot cx
Description:
------------
proc_open leaks file descriptors when leaving via the exit_fail label. There is some code to clean them up, but it is only executed when fork() fails instead of opening one of the descriptors.

References:
https://github.com/php/php-src/blob/c3e3c98/ext/standard/proc_open.c#L512 (goto)
https://github.com/php/php-src/blob/c3e3c98/ext/standard/proc_open.c#L952 (label)
https://github.com/php/php-src/blob/c3e3c98/ext/standard/proc_open.c#L852 (fork failed)

Test script:
---------------
<?php
  $descr = array(
    0 => array('file', '/dev/null', 'r'),
    1 => array('file', '/nonexistent', 'r'),
  );
  for($i = 0; 1025 > $i; $i++) {
    $ph = proc_open('true', $descr, $pipes);
  }
?>



Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2014-09-18 14:21 UTC] gwynne@php.net
-Status: Open +Status: Verified
 [2014-09-18 14:21 UTC] gwynne@php.net
Confirmed that this bug still stands. A test which shows the failure directly:

<?php
// This test requires a /dev/fd filesystem (OS X for example) to show the error.
// There should only be 4 descriptors (stdin, stdout, stderr, readdir of /dev/fd) open after the failed proc_open().
proc_open("/bin/true", [0 => ['pipe', 'r'], 1 => ['INVALID']], $pipes);
print_r(scandir("/dev/fd"));
?>

Correct fix is to move this code from the fork() failure case to the error_exit case:

for (i = 0; i < ndesc; i++) {
	close(descriptors[i].childend);
	if (descriptors[i].parentend >= 0)
		close(descriptors[i].parentend);
}

(Please note - the fork() failure case does not check >= 0, which can cause a leaked descriptor if stdin was closed before proc_open() was called.)
 
PHP Copyright © 2001-2019 The PHP Group
All rights reserved.
Last updated: Thu May 23 09:01:32 2019 UTC