2008-07-07 16:44:14 +00:00
|
|
|
|
|
|
|
----------
|
|
|
|
OVERVIEW
|
|
|
|
----------
|
|
|
|
|
|
|
|
ExecWrap is a super-user exec wrapper for the lighttpd web-server, but it can be used in
|
|
|
|
any environment as long as arguments can be passed from the server to its children via the
|
|
|
|
environment.
|
|
|
|
|
|
|
|
ExecWrap is released under the BSD license, which may be found in the source file.
|
|
|
|
|
|
|
|
The different compile-time configuration options are explained below. For optimal security,
|
|
|
|
please review ALL of them, as default values are hard to provide in most cases. The
|
|
|
|
configuration is mainly concerned with security. Next, the run-time configuration options
|
|
|
|
are explained.
|
|
|
|
|
|
|
|
An overview of the security implications of each check the wrapper performs is then given,
|
|
|
|
along with some checks it doesn't perform and the reason for it.
|
|
|
|
|
|
|
|
Finally, the run-time configuration is explained and a usage example is given.
|
|
|
|
|
|
|
|
|
|
|
|
-------------------
|
|
|
|
COMMAND ARGUMENTS
|
|
|
|
-------------------
|
|
|
|
|
|
|
|
The super user and the user specified by the PARENT_UID parameter (see below) are allowed
|
|
|
|
to give command line options to the wrapper. These are only useful for humans, and not for
|
|
|
|
a web-server.
|
|
|
|
|
|
|
|
Argument Explanation
|
|
|
|
-------------------------------------------------------------------------------------------
|
|
|
|
-v Displays the name, i.e. ExecWrap, and version of the wrapper.
|
|
|
|
-V Displays name, version and the compile-time configuration parameters.
|
|
|
|
|
|
|
|
|
|
|
|
----------------------------
|
|
|
|
COMPILE-TIME CONFIGURATION
|
|
|
|
----------------------------
|
|
|
|
|
|
|
|
After compiling, remember that the program must be owned by the super user and have its
|
|
|
|
setuid-user bit set to work! The configuration parameters are found in the file
|
|
|
|
execwrap_config.h, except for the ones that shouldn't normally be changed. Those are found
|
|
|
|
in the main file.
|
|
|
|
|
|
|
|
Config parameter Explanation
|
|
|
|
-------------------------------------------------------------------------------------------
|
|
|
|
PARENT_UID The (numeric only) value of this parameter controls what parent UID
|
|
|
|
the wrapper will accept. If it is started by any other UID than this
|
|
|
|
or the super user, it will instantly abort.
|
|
|
|
|
|
|
|
TARGET_MIN_UID This (numeric) value sets the _minimum_ UID the wrapper can be told
|
|
|
|
to switch to. If asked to switch to a lower value, it will abort.
|
|
|
|
It is _strongly_ advised to set this value to the _minimum_ needed.
|
|
|
|
Setting it to 0 would allow the server to become root, wherefore it
|
|
|
|
is disallowed (by compile-time security checks).
|
|
|
|
|
|
|
|
TARGET_MIN_GID The same as TARGET_MIN_UID, but for the GID. The same reasons and
|
|
|
|
restrictions apply.
|
|
|
|
|
|
|
|
TARGET_PATH_PREFIX This parameter sets the prefix of any target program the wrapper is
|
|
|
|
instructed to invoke. If asked to start something _not_ under this
|
|
|
|
path, the wrapper aborts.
|
|
|
|
|
|
|
|
DEFAULT_UID The default (numeric) UID to become, if no UID is given via the
|
|
|
|
environment. It defaults to 65534, which usually maps to the nobody
|
|
|
|
user. This is recommended. At any rate, it must be at least as high
|
|
|
|
as TARGET_MIN_UID. This is ensured by compile time security checks.
|
|
|
|
|
|
|
|
DEFAULT_GID The same as DEFAULT_UID, but for the GID. The same reasons and
|
|
|
|
restrictions apply.
|
|
|
|
|
2009-10-23 08:31:22 +00:00
|
|
|
REQUIRE_PWENT If set, target users are reuired to have passwd-entries. These are
|
|
|
|
used to set the supplementary group access list. Defaults to 0.
|
2008-07-07 20:15:59 +00:00
|
|
|
|
2009-10-23 08:31:22 +00:00
|
|
|
ALLOW_CHECKGID If set, enabled the CHECK_GID feature, q.v. Defaults to 1.
|
2008-07-07 20:15:59 +00:00
|
|
|
|
2009-10-23 08:31:22 +00:00
|
|
|
USE_SYSLOG If set, log errors and (if enabled) debug messages to syslog.
|
|
|
|
Defaults to 1.
|
2008-07-07 16:44:14 +00:00
|
|
|
|
|
|
|
The following configuration parameters shouldn't normally be changed. In case you have a
|
|
|
|
clash with some other ENV arguments to the target program, they can be changed, however.
|
|
|
|
The configuration dump command line option, -V, will not output them.
|
|
|
|
|
|
|
|
|
|
|
|
ENV_UID This parameter controls the name of the environment variable used to
|
|
|
|
tell the wrapper what UID to switch to. It defaults to "UID=" and
|
|
|
|
there is usually no need to change it. If you do, remember that it
|
|
|
|
must end in "=" like the default, or it will fail to be recognised.
|
|
|
|
See the run-time configuration section below.
|
|
|
|
|
|
|
|
ENV_GID The same as ENV_UID, but controls the name of the GID parameter.
|
|
|
|
Defaults to "GID=".
|
|
|
|
|
|
|
|
ENV_TARGET The same as ENV_UID, but controls the name of the TARGET parameter.
|
|
|
|
Defaults to "TARGET=".
|
|
|
|
|
|
|
|
ENV_CHECK_GID The same as ENV_UID, but controls the name of the CHECK_GID
|
|
|
|
parameter. Defaults to "CHECK_GID=".
|
|
|
|
|
|
|
|
ENV_NON_RESIDENT The same as ENV_UID, but controls the name of the NON_RESIDENT
|
|
|
|
parameter. Defaults to "NON_RESIDENT=".
|
|
|
|
|
2009-10-23 08:31:22 +00:00
|
|
|
ENV_DEBUG Controls the name of environment variable used to enable debug
|
|
|
|
output to syslog (depends on USE_SYSLOG)
|
2008-07-07 16:44:14 +00:00
|
|
|
|
|
|
|
---------------------
|
|
|
|
COMPILE AND INSTALL
|
|
|
|
---------------------
|
|
|
|
|
|
|
|
There is no Makefile right now, but compile is as simple as:
|
|
|
|
|
2008-07-07 23:59:58 +00:00
|
|
|
> gcc -W -Wall -O2 -o execwrap execwrap.c && strip execwrap
|
2008-07-07 16:44:14 +00:00
|
|
|
|
|
|
|
Or similar, depending on taste. You need something other than an ancient compiler to make
|
|
|
|
it work, preferably C99. To install, make sure the file is owned by the super user and has
|
|
|
|
the proper modes:
|
|
|
|
|
|
|
|
> chown root execwrap
|
|
|
|
> chmod og-w,+rx,u+s execwrap
|
|
|
|
|
|
|
|
Then move it to where it's supposed to reside. That's all. If you're really fanatic about
|
|
|
|
security, you can also do something like this (before the chmod u+s):
|
|
|
|
|
|
|
|
> chgrp lighttpd execwrap # <-- Or whatever group your web-server is in.
|
|
|
|
> chmod o-rwx,g-rw execwrap
|
|
|
|
|
|
|
|
To make the command impossible to start for anyone but the super user and the server admin.
|
|
|
|
But since the first thing the wrapper does on start up is to check the parent UID, this
|
|
|
|
really isn't necessary.
|
|
|
|
|
|
|
|
|
|
|
|
------------------------
|
|
|
|
RUN TIME CONFIGURATION
|
|
|
|
------------------------
|
|
|
|
|
|
|
|
The run-time configuration is provided by environment variables, and not the command line.
|
|
|
|
Currently, command line arguments are completely ignored. The run-time arguments are
|
|
|
|
subjected to the restrictions imposed by the compile-time configuration discussed above.
|
|
|
|
|
|
|
|
Note that since the names of the parameters can be changed, the defaults are used in the
|
|
|
|
following list.
|
|
|
|
|
|
|
|
Config parameter Explanation
|
|
|
|
-------------------------------------------------------------------------------------------
|
|
|
|
UID The UID to switch to. Only numerical values are accepted currently.
|
|
|
|
|
|
|
|
GID The GID to switch to. Only numerical values are accepted currently.
|
|
|
|
|
|
|
|
TARGET The target program to start. For security, it must be absolute and
|
|
|
|
must not contain any ~ characters or ".." sub-strings. Of course the
|
|
|
|
compiled-in prefix must also be a prefix of it.
|
|
|
|
|
|
|
|
CHECK_GID If set (to anything, even the empty string), the security checks will
|
|
|
|
be slightly relaxed to allow targets owned by the target GID but not
|
|
|
|
necessarily by the target UID, as well as allowing the target to be
|
|
|
|
group-writable if owned by the target GID. Useful for projects where
|
|
|
|
several people collaborate so file ownership can vary.
|
|
|
|
|
|
|
|
NON_RESIDENT If set (to anything), the wrapper will drop privileges and become the
|
|
|
|
target process directly, instead of the default behaviour where it
|
|
|
|
forks off before becoming the target, allowing SIGTERM to propagate
|
|
|
|
from the caller of the wrapper, to the target. It is not recommended
|
|
|
|
to set this, as it will make it impossible for the caller (usually a
|
|
|
|
web-server) to terminate the target process, and thus prevents it
|
|
|
|
from effectively managing it.
|
|
|
|
|
2009-10-23 08:31:22 +00:00
|
|
|
DEBUG If set to anything, debug output to syslog is enabled.
|
2008-07-07 16:44:14 +00:00
|
|
|
|
|
|
|
-----------------------------------
|
|
|
|
SECURITY CHECKS AND THEIR REASONS
|
|
|
|
-----------------------------------
|
|
|
|
|
|
|
|
The security checks below are listed in the order they are performed.
|
|
|
|
|
|
|
|
Security check Reason it's performed
|
|
|
|
-------------------------------------------------------------------------------------------
|
|
|
|
Check parent UID Done to disallow people other than root and server admins to become
|
|
|
|
another user. The reason for this should be obvious, but given all
|
|
|
|
the other checks, this one actually isn't the most important one.
|
|
|
|
|
|
|
|
Check min. UID/GID Done to control what users the server admins can start programs as.
|
|
|
|
In particular, they can't start programs as root. Again, the reason
|
|
|
|
for checking this should be obvious. Never ever set these values to
|
|
|
|
anything at or below system services users and groups!
|
|
|
|
|
|
|
|
Target path checks We check that it's absolute and doesn't contain ~ and "..". This is
|
|
|
|
an overly careful (but also simpler) way to make sure it doesn't
|
|
|
|
lead outside of the prefix.
|
|
|
|
|
|
|
|
Target path prefix Done to prevent server admins from executing user code outside the
|
|
|
|
designated server root. This is not in itself a security enhancement
|
|
|
|
unless the system in general is kept in a tight leash, but it also
|
|
|
|
helps prevent a run-away server from causing problems.
|
|
|
|
|
|
|
|
Target given Done. This isn't for security, but without a target there is no work
|
|
|
|
to be done in the first place :-p.
|
|
|
|
|
|
|
|
Can switch UID/GID Done. Again, this is usually not a security enhancement, as the
|
|
|
|
switch should never fail. In certain environments however, additional
|
|
|
|
security measures such as MAC might prevent even the super user from
|
|
|
|
switching to certain UIDs or GIDs.
|
|
|
|
|
|
|
|
Can stat the target Done. Otherwise, we can hardly expect to become the target anyway.
|
|
|
|
Not for security as such.
|
|
|
|
|
|
|
|
Target has wrong Done to prevent users not owning the target file, or not in the same
|
|
|
|
modes or UID/GID group, from replacing it with malicious code. The following checks
|
|
|
|
are performed. If any of them fails, the wrapper aborts.
|
|
|
|
1. Target is NOT world-writable.
|
|
|
|
2. Target is owned by the UID we switched to OR, when CHECK_GID is
|
|
|
|
given, target is owned by the GID we switched to.
|
|
|
|
3. Target is NOT group-writable unless CHECK_GID was given and it
|
|
|
|
is owned by the GID we switched to.
|
|
|
|
|
|
|
|
|
|
|
|
Also, there is one common check we do not perform:
|
|
|
|
|
|
|
|
Target dir checks Not done. Checking the target directory adds no real security. True,
|
|
|
|
if someone else has write permissions he can remove the target and
|
|
|
|
replace it with something else, but this won't have the correct UID
|
|
|
|
and GID. If he can make it have the right values, he would be able to
|
|
|
|
overwrite the target in the first place. Care must be taken here if
|
|
|
|
the CHECK_GID feature is used along with the setgid bit. See below.
|
|
|
|
|
|
|
|
|
|
|
|
-------------------------------
|
|
|
|
OTHER SECURITY CONSIDERATIONS
|
|
|
|
-------------------------------
|
|
|
|
|
|
|
|
Even though several steps are taken to prevent abuse, care must be taken when setting up
|
|
|
|
any system involving a super-user executable. In particular, consider the following:
|
|
|
|
|
|
|
|
1. Make sure the wrapper is safe. It should at most be user-writable.
|
|
|
|
2. Make sure the group setup for the web server is sane. If the setgid bit is enabled for
|
|
|
|
the web root, which is useful in many cases and is the reason for the CHECK_GID
|
|
|
|
feature, make SURE that ALL members of the group in question are accounted for, since
|
|
|
|
they might be able to replace files in any directory at and below the web root.
|
|
|
|
|
|
|
|
|
|
|
|
-----------------------
|
|
|
|
CONFIGURATION EXAMPLE
|
|
|
|
-----------------------
|
|
|
|
|
|
|
|
|
|
|
|
Compile-time configuration (the <- parts are comments, obviously):
|
|
|
|
-------------------------------------------------------------------------------------------
|
|
|
|
PARENT_UID 104 <- My lighttpd UID.
|
|
|
|
TARGET_MIN_UID 1000 <- The first regular user UID.
|
|
|
|
TARGET_MIN_GID 100 <- Ditto for group.
|
|
|
|
TARGET_PATH_PREFIX "/var/www/light/" <- Site web-roots are below this.
|
|
|
|
DEFAULT_UID 65534 <- Nobody.
|
|
|
|
DEFAULT_GID 65534 <- Nobody.
|
|
|
|
|
|
|
|
|
|
|
|
Run-time configuration in lighttpd:
|
|
|
|
-------------------------------------------------------------------------------------------
|
|
|
|
fastcgi.server = (
|
|
|
|
"/dispatch.fcg" =>
|
|
|
|
( "dispatcher" =>
|
|
|
|
(
|
|
|
|
"socket" => "/tmp/fcgi.sock",
|
|
|
|
"bin-path" => "/var/www/light/execwrap", <- The wrapper.
|
|
|
|
"check-local" => "disable",
|
|
|
|
"min-procs" => 1,
|
|
|
|
"max-procs" => 1,
|
|
|
|
"bin-environment" => (
|
|
|
|
"UID" => "1000",
|
|
|
|
"GID" => "407",
|
|
|
|
"TARGET" => "/var/www/light/blah.tld/html/dispatch.fcg", <- The real script.
|
|
|
|
"CHECK_GID" => "1"
|
|
|
|
)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|