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