CGI apps in C?

Brian Candler B.Candler at pobox.com
Tue Jul 18 12:46:03 UTC 2006


On Sun, Jul 16, 2006 at 06:19:35PM -0400, Mark Bucciarelli wrote:
> "fork a shell"
> 
> This would be used if you want to run "find" or some other shell
> utility from your C code.  Correct?

Yes, if you call system(), or popen(), or something else which invokes a
command via a shell.

If you explictly fork() and in the child do
execl("/usr/bin/find",arg1,arg2...) then you don't have this problem, as
you're running the program directly.

Silly example: don't write things like

    snprintf(buf, sizeof(buf), "rm /tmp/sessions/%s", sessionid);
    system(str);

when the user could present a sessionid of

    ../../etc/passwd

or worse something like

    1234;echo "foobar"|passwd root

> Yes, I did a bunch of reading when setting up my first FreeBSD
> server and settled on running PHP apps using fastcgi + suexec.
> Very RAM-heavy, as each client get's their own php interpreter
> resident.  They time out pretty fast, which is good for RAM but
> bad for the next time someone visits the site.  There is no
> better solution I have found for performance + security with PHP.
> And I don't like it much ... hence my initial post.

Well, the Unix security model is that once a process has switched to user id
X, it cannot switch to another userid (at least not unless it exec's a
setuid binary and hence becomes a new program). That's the basis of the
security model; if you assume that an attacker comes across a process
running as X where they can substitute their own code, there should be no
way they can switch to user Y.

So if you have 1000 users, then either you need 1000 processes floating
around, each running as one of those userids, or you need to start a new
process for each request.

In the limiting case, you could run 1000 webservers under different uids
listening on different ports, and have a front-end webserver answering on
port 80 and relaying the requests to those other servers (e.g. using
mod_proxy under Apache). It will eat RAM, but perhaps not as much as you
might expect due to shared code pages (especially for those sites which
don't have mod_php and the like loaded)

Since in my experience the vast number of websites are either (a) idle, or
(b) completely static content, then having a split where the majority of
sites run on a single process with suexec for the odd CGI request, and a
small number of "premium" servers where each user has their own httpd server
process, seems to make sense. Each user can then customise their config,
e.g. those who want mod_perl or mod_ruby can have it.

Of course, "super premium" customers can have their own operating system
too, running under Xen or VMware :-)

> > Another thing I did was to modify suexec so
> > that it would fork(), wait4(), and then log the rusage
> > information for each CGI execution. Analysing these logs lets
> > you work out, site by site, which are the CGI hogs. 
> 
> That sounds pretty interesting.  Did you publish your work?

Unfortunately not - it belongs to my ex-employer. However I did suggest that
this functionality could easily be included in mod_cgi, with an outline
patch you might be able to use here:

http://mail-archives.apache.org/mod_mbox/httpd-dev/200512.mbox/%3C20051205091812.GA90189@uk.tiscali.com%3E
(point 2)

You replace the existing wait/waitpid call with wait4(). It's more efficient
to do it there anyway. In our case it was more important to avoid touching
the base code, which is why I moved this into suexec, which we had to
customise for other reasons anyway.

A quick google search suggests that maybe cgiwrap can do this:

http://cgiwrap.sourceforge.net/changes.html
"New in version 3.6.2:
...
    * Added support for reporting rusage/return code after executing script."

But I've not used cgiwrap myself.

Regards,

Brian.


More information about the freebsd-isp mailing list