Patch for Suexec for Virtual Hosts to use PHP with FastCGI
| From: | Jason Kovacs | Date: | Fri, 07 Oct 2005 17:12:09 +0000 |
| Subject: | Patch for Suexec for Virtual Hosts to use PHP with FastCGI | ||
| Groups: | php.general | ||
| Request: | Send a blank email to php-general+get-223739@lists.php.net to get a copy of this message | ||
Hello,
I am new to this list, but I thought I might contribute a patch implementation I've come up
with and ask the other developers on the list to help me scrutinize its security implications.
I've posted this same message to fastcgi-developers list at fastcgi.org to look for feedback
from them as well.
I've been working with Apache2, SuExec, PHP5, and FastCGI recently and ran across the
seemingly-common problem of allowing Virtual Hosts to share a PHP (cgi-fcgi) binary that is
SuExec'd to their User/Group. I read everything I could find on the net about this subject,
and the fastcgi.com archives were very helpful, but I was not happy or successful with some of the
solutions presented. I thought I would end up having to copying the php binary for every Virtual
Host that existed and chown them to each user/group so that Suexec would work properly and I could
stop getting permission errors. Then I realized how it would be a nightmare to automate this
process of copying and owning the php binary to the right user/group every time a Virtual Host was
created (and I'm not that great at shell scripting). If I wanted to recompile php, I would
have to update all of the instances of php that now existed (which seemed to be getting too
complex). So I finally gave in and decided to modify suexec.c, despite the warnings from apache.org
not to do so because much thought had already been put into the conditions for suexec to work
securely. However, the fact that I wanted the php binary to be shared is a special case from all
other cgi scripts, since its user/group must be different from the target user/group of the Virtual
Host. So this is what I've come up with and it seems to fit my needs, so I thought it could
help others in the same situation.
I've created a new user/group named "php-cgi-shared", which took on a UID and GID
above 500. My virtual hosts all reside in /home/<username>/ so in my Apache2 configuration I
set '--with-suexec-docroot' to "/home" to encompass all virtual hosts and their
cgi-bin directories (this made sense to me, but maybe I don't fully understand how the suexec
docroot and userdir settings work). Then I created /home/fcgi-bin/ where I would later copy
/usr/bin/php (built as cgi-fcgi) to and chown the fcgi-bin directory and the php-fcgi binary to the
user and group of "php-cgi-shared". I've read some 3rd-party changes and patches to
suexec.c that chose to completely ignore the check for the SuexecUserGroup UID and GID to match the
UID and GID of the CGI file and its containing folder. However, I thought this was a too lenient and
allows security holes, so I left that code as it is but added a custom hack of my own. I've
hard-coded the custom user/group of "php-cgi-shared" into the suexec.h header file, and
within the code checked to see if this was a valid user/group on the system and obtained its UID and
GID. If the UID/GID of the target program and folder do not match the SuexecUserGroup (as done in
the original code), then I additionally check if they match my "safe" UID/GID obtained
from the "php-cgi-shared" user/group. If a match occurs, then I allow the suexec program
to proceed and not exit with an error. So then when FastCGI passes the SuexecUserGroup from a
Virtual Host to the Suexec wrapper, it will spawn a dynamic instance of the php-fcgi binary running
as the user/group of the virtual host. Likewise, I run a static instance of this php-fcgi using
FastCgiServer with the -user and -group set to "php-cgi-shared", and not
"apache/www/nobody" because those users are below the UID/GID of 500 that I've set as
a minimum when building Apache/Suexec. My assumption is that this fcgi-bin directory and php-fcgi
program are the only two files that are owned by "php-cgi-shared", as set by root, and no
other cgi's will ever take on this special privilege that suexec now allows. This seems to be
a valid solution, unless I don't fully understand how all of the components work together
correctly and securely. Please tell me otherwise if I am wrong. All I know is that this setup is
now working the way I want after many days of frustration, it keeps things secure as far as I can
tell, and requires little to no extra maintenance in the future.
My httpd.conf file has the following directives that apply to PHP/FastCGI/Suexec (I built Apache2
using its default directory/file layout):
User apache
Group apache
...
LoadModule fastcgi_module modules/mod_fastcgi.so
AddType application/x-httpd-php .php
<IfModule mod_fastcgi.c>
Alias /fcgi-bin/ /home/fcgi-bin/
FastCgiIpcDir /usr/local/apache2/logs/fastcgi
FastCgiWrapper /usr/local/apache2/bin/suexec
FastCgiServer /home/fcgi-bin/php-fcgi -user php-cgi-shared -group php-cgi-shared
<Directory /home/fcgi-bin/>
SetHandler fastcgi-script
Options +ExecCGI
</Directory>
AddHandler php-fastcgi .php
Action php-fastcgi /fcgi-bin/php-fcgi
</IfModule>
Please respond with your comments on my method, and if it's generally correct and others are
interested in using it, I can post my changes to suexec.c.
Thanks,
Jason Kovacs