Attachment "tm-safe-base.patch" to
ticket [1999119fff]
added by
andreas_kupries
2008-06-25 22:57:34.
--- tcl85.orig/library/init.tcl 2008-06-24 10:26:11.000000000 -0700
+++ tcl85/library/init.tcl 2008-06-24 13:23:30.000000000 -0700
@@ -156,7 +156,7 @@
if {[interp issafe]} {
- package unknown ::tclPkgUnknown
+ package unknown {::tcl::tm::UnknownHandler ::tclPkgUnknown}
} else {
# Set up search for Tcl Modules (TIP #189).
# and setup platform specific unknown package handlers
--- tcl85.orig/library/safe.tcl 2008-06-24 10:26:11.000000000 -0700
+++ tcl85/library/safe.tcl 2008-06-24 15:16:57.000000000 -0700
@@ -369,6 +369,18 @@
lappend slave_auto_path "\$[PathToken $i]"
incr i
}
+ # Extend the access list with the paths used to look for Tcl
+ # Modules. We safe the virtual form separately as well, as
+ # syncing it with the slave has to be defered until the
+ # necessary commands are present for setup.
+ foreach dir [::tcl::tm::list] {
+ lappend access_path $dir
+ Set [PathToken $i $slave] $dir
+ lappend slave_auto_path "\$[PathToken $i]"
+ lappend slave_tm_path "\$[PathToken $i]"
+ incr i
+ }
+ Set [TmPathListName $slave] $slave_tm_path
Set $nname $i
Set [PathListName $slave] $access_path
Set [VirtualPathListName $slave] $slave_auto_path
@@ -448,6 +460,10 @@
::interp alias $slave encoding {} [namespace current]::AliasEncoding \
$slave
+ # Handling Tcl Modules, we need a restricted form of Glob.
+ ::interp alias $slave glob {} [namespace current]::AliasGlob \
+ $slave
+
# This alias lets the slave have access to a subset of the 'file'
# command functionality.
@@ -463,8 +479,8 @@
# by Tcl_MakeSafe(3)
- # Source init.tcl into the slave, to get auto_load and other
- # procedures defined:
+ # Source init.tcl and tm.tcl into the slave, to get auto_load
+ # and other procedures defined:
if {[catch {::interp eval $slave\
{source [file join $tcl_library init.tcl]}} msg]} {
@@ -472,6 +488,16 @@
error "can't source init.tcl into slave $slave ($msg)"
}
+ if {[catch {::interp eval $slave \
+ {source [file join $tcl_library tm.tcl]}} msg]} {
+ Log $slave "can't source tm.tcl ($msg)"
+ error "can't source tm.tcl into slave $slave ($msg)"
+ }
+
+ # Sync the paths used to search for Tcl modules. This can be
+ # done only now, after tm.tcl was loaded.
+ ::interp eval $slave [list ::tcl::tm::add {*}[Set [TmPathListName $slave]]]
+
return $slave
}
@@ -610,6 +636,10 @@
proc VirtualPathListName {slave} {
return "[InterpStateName $slave](access_path_slave)"
}
+ # returns the variable name of the complete tm path list
+ proc TmPathListName {slave} {
+ return "[InterpStateName $slave](tm_path_slave)"
+ }
# returns the variable name of the number of items
proc PathNumberName {slave} {
return "[InterpStateName $slave](access_path,n)"
@@ -707,19 +737,96 @@
}
}
+ # AliasGlob is the target of the "glob" alias in safe interpreters.
+
+ proc AliasGlob {slave args} {
+ Log $slave "GLOB ! $args" NOTICE
+ set cmd {}
+ set at 0
+
+ set dir {}
+ set virtualdir {}
+
+ while {$at < [llength $args]} {
+ switch -glob -- [set opt [lindex $args $at]] {
+ -nocomplain -
+ -join { lappend cmd $opt ; incr at }
+ -directory {
+ lappend cmd $opt ; incr at
+ set virtualdir [lindex $args $at]
+
+ # get the real path from the virtual one.
+ if {[catch {set dir [TranslatePath $slave $virtualdir]} msg]} {
+ Log $slave $msg
+ return -code error "permission denied"
+ }
+ # check that the path is in the access path of that slave
+ if {[catch {DirInAccessPath $slave $dir} msg]} {
+ Log $slave $msg
+ return -code error "permission denied"
+ }
+ lappend cmd $dir ; incr at
+ }
+ pkgIndex.tcl {
+ # Oops, this is globbing a subdirectory in regular
+ # package search. That is not wanted. Abort,
+ # handler does catch already (because glob was not
+ # defined before). See package.tcl, lines 484ff in
+ # tclPkgUnknown.
+ error "unknown command glob"
+ }
+ -* {
+ Log $slave "Safe base rejecting glob option '$opt'"
+ error "Safe base rejecting glob option '$opt'"
+ }
+ default {
+ lappend cmd $opt ; incr at
+ }
+ }
+ }
+
+ Log $slave "GLOB = $cmd" NOTICE
+
+ if {[catch {::interp invokehidden $slave glob {*}$cmd} msg]} {
+ Log $slave $msg
+ return -code error "script error"
+ }
+
+ Log $slave "GLOB @ $msg" NOTICE
+
+ # Translate path back to what the slave should see.
+ set res {}
+ foreach p $msg {
+ regsub -- ^$dir $p $virtualdir p
+ lappend res $p
+ }
+
+ Log $slave "GLOB @ $res" NOTICE
+ return $res
+ }
# AliasSource is the target of the "source" alias in safe interpreters.
proc AliasSource {slave args} {
set argc [llength $args]
- # Allow only "source filename"
+ # Extended for handling of Tcl Modules to allow not only
+ # "source filename", but "source -encoding E filename" as
+ # well.
+ if {[lindex $args 0] eq "-encoding"} {
+ incr argc -2
+ set encoding [lrange $args 0 1]
+ set at 2
+ } else {
+ set at 0
+ set encoding {}
+ }
if {$argc != 1} {
- set msg "wrong # args: should be \"source fileName\""
+ set msg "wrong # args: should be \"source ?-encoding E? fileName\""
Log $slave "$msg ($args)"
return -code error $msg
}
- set file [lindex $args 0]
+ set file [lindex $args $at]
# get the real path from the virtual one.
if {[catch {set file [TranslatePath $slave $file]} msg]} {
@@ -740,7 +847,7 @@
}
# passed all the tests , lets source it:
- if {[catch {::interp invokehidden $slave source $file} msg]} {
+ if {[catch {::interp invokehidden $slave source {*}$encoding $file} msg]} {
Log $slave $msg
return -code error "script error"
}
@@ -840,6 +947,25 @@
}
}
+ proc DirInAccessPath {slave dir} {
+ set access_path [GetAccessPath $slave]
+
+ if {[file isfile $dir]} {
+ error "\"$dir\": is a file"
+ }
+
+ # Normalize paths for comparison since lsearch knows nothing of
+ # potential pathname anomalies.
+ set norm_dir [file normalize $dir]
+ foreach path $access_path {
+ lappend norm_access_path [file normalize $path]
+ }
+
+ if {[lsearch -exact $norm_access_path $norm_dir] == -1} {
+ error "\"$dir\": not in access_path"
+ }
+ }
+
# This procedure enables access from a safe interpreter to only a subset of
# the subcommands of a command:
--- tcl85.orig/library/tm.tcl 2008-06-24 10:26:10.000000000 -0700
+++ tcl85/library/tm.tcl 2008-06-24 14:37:02.000000000 -0700
@@ -214,11 +214,11 @@
set satisfied 0
foreach path $paths {
- if {![file exists $path]} {
+ if {![interp issafe] && ![file exists $path]} {
continue
}
set currentsearchpath [file join $path $pkgroot]
- if {![file exists $currentsearchpath]} {
+ if {![interp issafe] && ![file exists $currentsearchpath]} {
continue
}
set strip [llength [file split $path]]
@@ -352,9 +352,13 @@
foreach pa $paths {
set p [file join $pa tcl$major]
for {set n $minor} {$n >= 0} {incr n -1} {
- path add [file normalize [file join $p ${major}.${n}]]
- }
- path add [file normalize [file join $p site-tcl]]
+ set px [file join $p ${major}.${n}]
+ if {![interp issafe]} { set px [file normalize $px] }
+ path add $px
+ }
+ set px [file join $p site-tcl]
+ if {![interp issafe]} { set px [file normalize $px] }
+ path add $px
}
return
}
@@ -362,4 +366,4 @@
# Initialization. Set up the default paths, then insert the new
# handler into the chain.
-::tcl::tm::Defaults
+if {![interp issafe]} { ::tcl::tm::Defaults }