diff --git a/README.md b/README.md index 5fa7cda88a4a7cb66aa468a70682274ea2186901..dc1b140374cde5bdc533b6f5379be63801e1929b 100644 --- a/README.md +++ b/README.md @@ -5,9 +5,9 @@ A slightly improved (and massively simplified) *suexec* wrapper for Apache [mod_suexec](https://httpd.apache.org/docs/2.4/suexec.html). It's meant for a very specific and narrow use case: multi-tenant large -scale website hosting of PHP websites. It drops some of the standard -*suexec* features that we weren't using anyway (namely, user home -directory support). +scale website hosting of PHP websites using FastCGI. It drops some of +the standard *suexec* features that we weren't using anyway (namely, +user home directory support). It also gets rid of the somewhat arbitrary assumption made by the default Apache suexec wrapper on document root layout, in favor of a @@ -53,3 +53,63 @@ The wrapper does not use libnss or interact with the user/group databases in any way, so you **MUST** use numeric UIDs and GIDs in your Apache configuration. +# Usage with FastCGI + +The overall suexec workflow is the following: upon receiving a request +for a suexec-wrapped CGI, Apache will: + +* cd to the directory containing the file, which will be somewhere + below the DocumentRoot of the site; +* launch the */usr/lib/apache2/suexec* wrapper with the arguments + *uid* *gid* *file*. + +Here *uid* and *gid* will be the user and group ID specified in the +SuexecUserGroup *mod_suexec* configuration directive. + +In this case, the standard suexec wrapper will perform a number of +safety checks, including verifying that the file to execute is indeed +owned by the specified user and group. + +In a FastCGI setting, which we're more interested in, things are +slightly different: when using FastCGI, suexec does not get invoked on +every request, but it is only used to start the FastCGI process, a +long-running server that will handle many requests. Therefore, the +file being executed isn't the target PHP file, but rather the PHP +interpreter itself (e.g. */usr/lib/cgi-bin/php5.fcgi*), so it is not +going to be owned by the target user and it wouldn't make sense to +perform ownership checks. Furthermore, the directory suexec will be +invoked from will always be */usr/lib/cgi-bin*, losing any relation +with the site's document root. + +Combining suexec and FastCGI is thus less effective from a security +standpoint, as many checks are unavailable and we're forced to rely +more on UNIX-level permissions and features. On the other hand, since +FastCGI processes are long-lived, setup latency isn't as critical +anymore, and we can do more complex initialization of the process +space. + +## Checks + +The wrapper performs the following safety checks: + +* it fetches the full path of the command using realpath(3) +* the command is checked against a list of allowed commands +* the current directory is checked against a list of allowed path + prefixes +* the command has the current directory as its prefix +* *uid* is greater than `min_uid` +* *gid* is greater than `min_gid` + +If the checks pass successfully, the wrapper will: + +* spawn a child in an isolated user namespace, with its own usermap, + process space, etc. and optionally an entirely different filesystem + root (similarly to a chroot); +* filter out dangerous system calls with *seccomp* +* drop all privileges; +* switch to the specified *uid* and *gid* +* execute the target command + +The namespace isolation is lifted, with minor modifications, from +https://blog.lizzie.io/linux-containers-in-500-loc.html so you can +check that page for the gory details.