Apache httpd’s “suexec” feature has always been relatively safe but still slightly annoying. The /usr/sbin/suexec binary is installed setuid root, allowing a non-root user to execute it under root’s privileges. The binary is implemented to very carefully ensure that this is only possible in very specific circumstances: when the “apache” user is trying to execute a CGI script owned by a user. The documentation explains the twenty different steps necessary to make this process as secure as possible.
A recent Fedora initiative to get rid of setuid binaries prompted me to add support for using suexec with Linux capabilites instead. A “setuid root” binary is all-powerful; the binary executes with the complete permissions of the superuser. With capabilities we can instead allow setuid to run only with the specific permissions required.
It turns out two separate features were required here.
1. Making suexec itself use capabilities was actually very simple. The two capability bits which suexec needs are CAP_SETGID and CAP_SETUID – this allows arbitrary use of setuid() and setgid() as required. So I added a new configure option –enable-suexec-capabilities to httpd which switches “make install” to use:
setcap 'cap_setuid,cap_setgid+pe' /path/to/suexec
Instead of “chmod 4755”. (You can read the setcap(7) man page for more information about that command.)
That was committed in r1342065.
2. But using only that change, the suexec binary then stops working. Why? Because suexec wants to write to its log file (in Fedora/RHEL at /var/log/suexec.log) every time it is executed, and fails if it cannot. And of course that log file must be only writable by root.
We could work around that by giving suexec an extra capability bit, CAP_DAC_OVERRIDE which will override the permissions checks when writing to the log file. But that defeats the point of this exercise, which is to limit capabilities as much as possible. There was another way – syslog! We can write to syslog without needing superuser privileges. So part two was to adapt suexec to use syslog. This was added in a second commit, r1341905, using a separate configure option (since the feature is independently useful), –with-suexec-syslog.
The complete set of suexec configure options used in the current Fedora httpd.spec is as follows:
./configure ... \ --enable-suexec --with-suexec \ --enable-suexec-capabilities \ --with-suexec-caller=apache \ --with-suexec-docroot=/var/www \ --without-suexec-logfile \ --with-suexec-syslog \ --with-suexec-bin=/usr/sbin/suexec \ --with-suexec-uidmin=500 --with-suexec-gidmin=100
Bingo! All done. suexec is no longer setuid root. The new code is available in httpd trunk, patched into Fedora httpd, and I should really propose it for backport to 2.4.x.