Version 3 of safely source a file

Updated 2003-03-19 11:13:18

Arjen Markus I do not usually worry about safety too much, but sometimes, it is necessary or useful to think about ways in which to prevent stupid mistakes to do harm.

Configuration files are one way of introduction safety and security problems into your applications. So, I decided to do a small experiment. Here is the result.


The script below sources a configuration file "myconf.tcl" that may contain any valid Tcl code, e.g. "file delete -force *" (I did not experiment with that one though :), like:

 # Unsafe configuration file
 set ::myvar [exit]

 # Should have been:
 #set ::myvar 2 

The script sources this file via a safe interpreter and then updates any or all global variables that were set in the calling interpreter. This temporary interpreter being safe, it does not have the possibility to set important variables like tcl_precision and so on, but I remove this type of variables anyway.


 # Attempt to make configuration files safe to source
 #

 # safesource --
 #    Source a configuration file in a safe environment and copy the
 #    results back
 # Arguments:
 #    srcname    Name of the external file to be sourced
 #    vars       (Optional) list of variables to be considered
 # Result:
 #    0 if everything okay, possible error if unsafe commands used
 # Side effect:
 #    Variables in the caller's namespace set
 # Note:
 #    No provision yet for arrays!
 #
 proc safesource {srcname {vars *}} {
    #
    # Create a safe interpreter and source the file
    #
    set cnf _ConfSrc_
    interp create -safe $cnf
    interp invokehidden $cnf source $srcname

    #
    # Copy back those variables we are interested in
    # (never do tcl_platform, argv0, argv or env)
    #

    set srcvars {}
    foreach v $vars {
       set srcvars [interp eval $cnf info vars $v]
    }

    foreach v {tcl_platform tcl_version tcl_patchLevel tcl_interactive argv0 argv env} {
       set idx [lsearch $srcvars $v]
       set srcvars [lreplace $srcvars $idx $idx]
    }

    #
    # NOTE: Assume scalars for the moment!
    #
    foreach v $srcvars {
       set ::$v [interp eval $cnf set $v]
    }

    interp delete $cnf

    return 0
 }

 set myvar 1

 safesource "myconf.tcl"

 puts "Myvar: $myvar"

RS: Instead of explicitly enumerating "taboo" variables, you might get that list as follows:

 set taboo [$cnf eval info vars] ;# before sourcing
 ...
 foreach v $taboo {...

Experiments show only these variables - argc, argv, argv0, env seem to be considered unsafe:

 tcl_interactive tcl_version tcl_patchLevel tcl_platform

AM Good idea. I noticed that tcl_precision can not be changed in a safe interpreter. This does not show up?