Speeding up MPM-itk

A few days ago I added support for MPM-itk ("mpm-itk" USE flag) to our Apache 2.0 packages. MPM-itk is a user-switching MPM, that is, it switches to an assigned user when processing the requests, instead of processing everything as user apache (MPM-perchild, metux-MPM and MPM-peruser are other examples of this).
In its original form it accomplishes this by doing the following:

  • apache process as root, interpret the request
  • fork() new process and switch (setuid(unprivuid) / setgid(unprivgid)) to unprivileged user for it, process the request
  • kill of the setuid/setgid process, with the next request it will redo the process

Now, this is foolproof, but provokes an immense performance hit, especially on static pages. Benchmarks done with ab2 showed that a normal Apache2 (MPM-prefork) can process about 240 PHP req/sec and 4000 HTML req/seq, while the MPM-itk patched Apache 2.0 managed about 110 PHP req/sec and 240 HTML req/sec, so you see, the peformance hit is enormous, and it's obiously due to the overhead of always having to fork() a new Apache process and then kill it off, for every request!
I managed to successfully change the way the MPM works, and thus managed to bring its speed to normal Apache levels, by changing the "worfklow" like this:

  • apache process as root, interpret the request
  • switch (setresuid(unprivuid, unprivuid, 0) / setresgid(unprivgid, unprivgid, 0)) to unprivileged user, process the request
  • switch back to root (setresuid(0, 0, 0) / setresgid(0, 0, 0)), with the next request it will redo the process

Now this solves the performance problems, as it doesn't anymore do the extra fork(), and fully reuses the process with the next request, but it introduces a new problem: a gaping security hole. :(
Since the processed request cannot be trusted, everything in there can simply setuid/setgid to root and do operations as root! A simple call to, for example, the posix_setuid/posix_setgid functions of the PHP POSIX extensio are enough to switch the user back to root and let the rest of the PHP script just work as root... This is totally unacceptable for security. So, now my call for help: has anyone got any idea how it's possible to realize this in a secure manner??? I can't think of any way to securely switch the process from root to unpriv user and back to root, without giving the untrusted code executed in the request processing phase the same ability (that is, to switch back to root).
Ideas and comments are very appreciated. ;)

Posted by Luca Longinotti on 11 Jul 2006 at 13:00
Categories: Apache, Gentoo Comments


blog comments powered by Disqus