php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #67383 exec() leaks file and socket descriptors to called program
Submitted: 2014-06-05 11:25 UTC Modified: 2014-08-04 19:35 UTC
Votes:17
Avg. Score:4.5 ± 0.8
Reproduced:15 of 15 (100.0%)
Same Version:10 (66.7%)
Same OS:12 (80.0%)
From: langemeijer@php.net Assigned:
Status: Open Package: *General Issues
PHP Version: Irrelevant OS: linux
Private report: No CVE-ID: None
 [2014-06-05 11:25 UTC] langemeijer@php.net
Description:
------------
PHP doesn't sanitize opened file descriptors opened by PHP itself before executing a program.

This should be fixed by opening all sockets with SOCK_CLOEXEC and all run a fcntl(file, F_SETFD, FD_CLOEXEC); on all newly opened filedescriptors

SOCK_CLOEXEC and FD_CLOEXEC cause exec() to close the descriptors in the fork()ed child process.

Note that this is similar, but not identical to bug #38915, bug #15529 and  bug #20302 which are about file descriptors and sockets opened by Apache.

Note that my patch also sets SOCK_CLOEXEC on the fastcgi listening socket and other similar usages of sockets.

The patch was generated on php-src master branch. I'm happy to do some more work on it if any of you feel this is required.


Patches

SOCK_CLOEXEC-and-FD_CLOEXEC (last revision 2014-06-05 11:26 UTC by casper at langemeijer dot eu)

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2014-07-21 11:54 UTC] langemeijer@php.net
-Status: Open +Status: Duplicate
 [2014-07-21 11:54 UTC] langemeijer@php.net
This is a duplicate of bug #67383 (Which contains a patch that should be merged by someone!)
 [2014-08-04 19:35 UTC] langemeijer@php.net
-Status: Duplicate +Status: Open
 [2014-08-04 19:35 UTC] langemeijer@php.net
Obviously, this bug is not a duplicate of itself. Previous comment was a clerical error.
 [2016-01-26 16:41 UTC] brak at gameservers dot com
This issue can cause you to be unable to restart PHP-FPM.  Specifically, this leaks the webserver -> php-fpm socket to any process you execute.  This prevents PHP-FPM from cleanly restarting until the process exits, because the socket will already be in use.

Quick example:
<?php
        $p = popen('/bin/bash -c "sleep 60"','w');
        pclose($p);
?>

Now find the child process (ps aux | grep sleep) and lsof -p XXX -n:

sleep   13443 nobody    0r  FIFO      0,8      0t0 10237775 pipe
sleep   13443 nobody    1u   CHR      1,3      0t0     3920 /dev/null
sleep   13443 nobody    2u   CHR      1,3      0t0     3920 /dev/null
sleep   13443 nobody    4u  IPv4 10236693      0t0      TCP 127.0.0.1:cslistener->127.0.0.1:53151 (ESTABLISHED)
sleep   13443 nobody    9u   REG      0,9        0     3918 [eventpoll]


FD 4 there is the TCP connection from the PHP worker process to the web server.
 [2017-10-11 08:29 UTC] daverandom@php.net
It is, in my opinion, not desirable to do this blindly for all fds.

It should be possible to specify this on a per-fd basis. For streams this can be done with a context option (or multiple context options for sockets vs files), but for e.g. mysqlnd it's trickier - most likely these should default to not being inheritable, but this will need to be taken care of by the extension.

A stream context option would cover 99% of cases where it's relevant, though. I would be fine with having the context option default to setting the flag, and needing to explicitly make an fd heritable, but this would be a BC break.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Tue Dec 03 16:01:33 2024 UTC