Req #38915 [PATCH]: Apache: system() (and similar) don't cleanup opened handles of Apache
| From: | testing@example.com | Date: | Wed, 27 Dec 2023 15:10:55 +0000 |
| Subject: | Req #38915 [PATCH]: Apache: system() (and similar) don't cleanup opened handles of Apache | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-246135@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=38915&edit=1
ID: 38915
Patch added by: testing@example.com
Reported by: dimmoborgir at gmail dot com
Summary: Apache: system() (and similar) don't cleanup opened
handles of Apache
Status: Analyzed
Type: Feature/Change Request
Package: Program Execution
Operating System: UNIX
PHP Version: 5.2.2, 4.4.7
Block user comment: N
Private report: N
New Comment:
The following patch has been added/updated:
Patch Name: tsSLAueP
Revision: 1703689855
URL: https://bugs.php.net/patch-display.php?bug=38915&patch=tsSLAueP&revision=1703689855
Previous Comments:
------------------------------------------------------------------------
[2014-03-14 13:02:42] php at braten dot be
Related To: Bug #15529
------------------------------------------------------------------------
[2013-12-03 17:23:11] brak at gameservers dot com
This same issue appears to happen with PHP-FPM (I am using nginx as the webserver, but that
shouldn't matter). PHP version 5.4.22 on Linux (CentOS 6.5)
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.
------------------------------------------------------------------------
[2012-10-31 23:56:34] oliver at realtsp dot com
we solved by passing the forked/exec'd process through a bash shell and closing
all te file
descriptors: eg: (note this is for FreeBSD using daemon, but "nohup" should work
on linux)
daemon /usr/bin/env bash -c 'exec 0<&-; exec 1> /path/to/error/log; exec 2>
/path/to/stdout/log;
eval exec {3..255}\>\&-; /usr/bin/env php /path/to/script args...'
Note we find it crucial to redirect and NOT CLOSE STDOUT and STDERR because
otherwise you will
never find out if sth is wrong with forked process. You should ensure that they
exist and are
writable before forking.
The trick with eval exec {3..255}\>\&-; is from here:
http://blog.n01se.net/blog-n01se-net-p-145.html
This works for us in a php-fastcgi situation. the fastcgi-socket and the mysql
socket are both
closed successfully. the new process opens its own mysql socket just fine...
I suspect this is similar to what Jeroen's closedexec.c does, but no need for a
c program.
Everyone should have bash.
If you redirect the stdout of above fork command to a file and check the
contents of that daemon
gives you nice messages, just append
2> /path/to/temp/stderr/file/for/daemon/messages
to the above command.
We have the construction of the fork command wrapped in a simple function, like
so:
$exec_cmd = ((php_uname('s') == 'FreeBSD') ? 'daemon' :
'nohup') .
// try to
be OS agnostic, daemon = fork, setguid etc, but don't close stderr with -f
' /usr/bin/env bash -c ' .
// wrap
actual call to new php process in a shell (use env!), so
// must escape here in case the already escaped args contain
// specials chars like single quotes (which the will!)
escapeshellarg(
'exec 0<&-; ' .
// close
STDIN
'exec 1> ' . escapeshellarg($app_log) . '; ' .
// STDOUT
> app_log
'exec 2> ' . escapeshellarg($error_log) . '; ' .
// STDOUT
> error_log
'eval exec {3..255}\>\&-; ' .
// we can
close all other fds (fastcgi, mysql, etc)..eval trick!
'/usr/bin/env php ' . BASE . $cmd . ' ' .
// call
php (with env!) don't rely on shebang or exec perms
join(' ',
// add
args separated by spaces
array_map(function ($arg) { return escapeshellarg($arg); }, $args))
// after
escaping them
);
Sorry about the formatting...
------------------------------------------------------------------------
[2010-04-16 01:31:48] crrodriguez at opensuse dot org
In linux, this should fix the issue for mail()
diff --git a/ext/standard/mail.c b/ext/standard/mail.c
index ab65f16..a8b3bf5 100644
--- a/ext/standard/mail.c
+++ b/ext/standard/mail.c
@@ -288,8 +288,12 @@ PHPAPI int php_mail(char *to, char *subject, char *message,
char *headers, char
* (e.g. the shell can't be executed) we explicitely set it to 0 to be
* sure we don't catch any older errno value. */
errno = 0;
+#if defined(__linux__) && defined(__GLIBC__) && __GLIBC_PREREQ(2, 9)
+ sendmail = popen(sendmail_cmd, "we");
+#else
sendmail = popen(sendmail_cmd, "w");
#endif
+#endif
if (extra_cmd != NULL) {
efree (sendmail_cmd);
}
Note that you need glibc 2.9 though.
------------------------------------------------------------------------
[2010-02-22 19:16:37] ionut dot dumitru at webland dot ro
the problem is still there in 5.2 just with php not involving apache.
so i write a cli daemon A which uses a listener socket , at some point it starts another daemon B
with any of exec/system/popen etc. 'A' works as a sort of supervisor for B so i can't
shut it down. but at some point i need to restart A, well I can't cause it won't bind to
the same listener address anymore because B is keeping the handles open. spent a lot of time but i
guess i have to go the file/cron way since php can't clean itself.
------------------------------------------------------------------------
The remainder of the comments for this report are too long. To view
the rest of the comments, please view the bug report online at
https://bugs.php.net/bug.php?id=38915
--
Edit this bug report at https://bugs.php.net/bug.php?id=38915&edit=1