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

Reply via email to