Sometimes, one needs to run tcl scripts in a secure environment. One of the ways to do this is to use the unix
chroot() call to block out all access to the local file system. With
tclkit, a static executable which carries a complete runtime with it, this is very easy to do. -
jcw
/*
* SafeKit - Running Tclkit inside a secure sandbox.
*
* This wrapper launches tclkit after calling "chroot()" to limit
* access to the filesystem to the current subtree. This approach
* guarantees that scripts run within this context cannot access a
* file outside this environment, not even through external programs.
*
* Since chroot can only be done by the superuser, this wrapper program
* has to be "setuid root". On startup, it does a chroot("."), and
* then reduces permissions to the original ones. Then, tclkit is
* launched, passing all arguments on to it.
*
* To use this sandbox, you need to place all scripts and data that
* are needed in a single directory area, along with a copy of tclkit
* and this safekit wrapper. Nothing else is needed, provided that
* tclkit and safekit are both compiled as fully static executables.
* If extensions are to be dynamically loaded, you will also need to
* create a /lib area with all necessary shared runtime libraries.
*
* For example, to run "myscript.tcl" safely, set up the following:
* $ ls -la
* total 3334
* drwxr-xr-x 2 jcw users 108 Apr 7 22:44 .
* drwxr-xr-x 8 jcw users 536 Apr 7 22:35 ..
* -rw-r--r-- 1 jcw users 126 Apr 7 22:37 myscript.tcl
* -rwsr-xr-x 1 root users 368376 Apr 7 21:57 safekit
* -rwxr-xr-x 1 jcw users 3035383 Apr 6 01:42 tclkit
* $
*
* The contents of "myscript.tcl" in the following example is:
* puts "pwd = pwd"
* catch { exec ls } err
* puts "exec ls -> [split $err \n]"
* puts "glob * -> [glob *]"
* cd ..
* puts "pwd = pwd"
*
* When run with a normal tclkit, this is the output:
* $ ./tclkit myscript.tcl
* pwd = /home/jcw/safexample
* exec ls -> myscript.tcl safekit tclkit
* glob * -> safekit tclkit myscript.tcl
* pwd = /home/jcw
* $
*
* When run through the safekit wrapper, it will be different:
* $ ./safekit myscript.tcl
* pwd = /
* exec ls -> {couldn't execute "ls": no such file or directory}
* glob * -> safekit tclkit myscript.tcl
* pwd = /
* $
*
* As you can see, there is no way out, and things like "ls" are not
* accessible.
*
* jcw, 07-04-2002
*/
#include <unistd.h>
#include <sys/types.h>
int main(int argc, char** argv)
{
if (chroot(".") != 0)
return 1;
if (seteuid(getuid()) != 0)
return 2;
argv[0] = "/tclkit";
if (execv(argv[0], argv) != 0)
return 3;
return 0;
}
SEH -- How portable is this? Isn't the command on BSD "jail" or something like that?
Well, it's a dozen lines of C with 3 system calls. Standard Unix, AFAICT. The *BSD "jail" is a considerably more sophisticated mechanism. This just brings chroot() functionality to tclkit. -jcwCliC jails are a FreeBSD- and DragonFlyBSD-specific mechanism (DragonFly is a fork of FreeBSD). OpenBSD and NetBSD do not have jail(8). AFAIK, FreeBSD and DragonFlyBSD support chroot as well.
I like the concept, though -- something I never thought about really but is quite straightforward.