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; argv0 = "/tclkit"; if (execv(argv0, 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. -jcw
CliC 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.