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
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: jille at hexon dot cx
New email:
PHP Version: OS:

 

 [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

Pull Requests

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-2024 The PHP Group
All rights reserved.
Last updated: Thu Nov 21 17:01:32 2024 UTC