[plt-scheme] Sandbox updates
The sandbox library has had some major work done, this is a
not-too-short summary of the important changes.
* Implemented a global sandbox memory limit and added a new
`sandbox-memory-limit' parameter to control it. Previously, each
expression evaluation had a memory limit, but there was no global
limit for the whole sandbox. For example, if you construct a repl
that evaluates each expression, then user code could allocate space
that is smaller than the evaluation limit on each expression,
therefore grabbing arbitrary amount of memory overall.
* Memory accounting in MzScheme changed in a way that can potentially
affect sandbox users: an object is counted against the highest
custodian that can reach it. This means that if you're running a
sandbox and pulling out a value from it (for example, to check that
it satisfies some properties), then that object will be held against
your own custodian's memory limit (if any). To get it back under
the sandboxed custodian, you can simply release references to it.
* When the sandbox commits suicide with (kill-thread (current-thread))
or (custodian-shutdown-all (current-custodian)), then it is properly
terminated. This is possible through an improvement to
call-with-limits': it now properly propagates such suicide actions
to the caller.
* Added `sandbox-exit-handler' to control the exit handler. The
default will *not* throw an error -- instead, it kills the sandbox.
(And the "terminated" error message indicates this as a reason.)
* When the sandbox is terminated, a new exn:fail:sandbox-terminated
exception is thrown. This exception has a `reason' field which is a
symbol indicating the reason. Currently, this can be 'eof (when you
evaluate the eof value), 'evaluator-killed (when `kill-evaluator'
was used to kill it), 'thread-killed, 'custodian-shutdown, 'exited
(when `exit' is used with the default exit handler above),
'out-of-memory (when `sandbox-memory-limit' is exceeded).
* A new `evaluator-alive?' predicate can be used to determine if the
sandboxed evaluator is still alive.
* When using a 'string output, the output is created in the sandboxed
environment, so it counts against its memory limit.
* When a sandbox is created with a given initial code, the constrcuted
module expression was previously evaluated under the expression
limits, but the module was invoked outside of these limits. This is
fixed now, for example, this code throws a proper error:
(parameterize ([sandbox-eval-limits '(0.25 5)])
(make-evaluator 'scheme/base '(sleep 2)))
* The sandbox uses now a new code-inspector to avoid using protected
bindings (most notably, abusing `scheme/foreign' is impossible now,
since `unsafe!' cannot be used in sandboxed code). A new
`sandbox-make-code-inspector' parameter can be used to control this.
* There is a new access mode for `sandbox-path-permissions':
'read-bytecode. This is generally like 'read access, but in
addition it allows loading bytecode files from such paths. (This is
necessary because a lower code-inspector generally means that you
will not be able to load bytecode files.) This is used by default
for the plt collects tree and additional #:allow-read arguments.
* `sandbox-security-guard' can now be a thunk that creates a security
guard. The default value uses this, so if you happen to create a
sandbox in an already-restricted environment, the sandbox will be
further restricted.
* `call-with-trusted-sandbox-configuration' is a function that invokes
a thunk in a context where the sandbox customization parameters are
set for minimum restrictions. It is useful in cases where you want
to choose restrictions to add to an unrestricted default rather than
choose ones to remove from a restricted one.
* `sandbox-eval-handlers' is a new configuration that holds a list of
two functions that are used to impose arbitrary restrictions on
sandbox interactions. The functions are called with a thunk, and
they're expected to execute the thunk in some restricted way. The
first function is used for the initial evaluation when the sandbox
is setup, and the second is used for further interactions.
The default value is (list #f call-with-custodian-shutdown), which
means that no additional restrictions (beyond the usual ones) are
put on the setup stage, and later evaluations occur in a custodian
that is shutdown at the end of the interaction. This prevents
interactions from leaving behind running threads, open ports, etc,
but still allows doing so when setting up the sandbox. Also
provided are `call-with-killing-threads' (similar, but only kills
threads), and `set-eval-handler' (makes it possible to change the
handler in an existing sandbox).
* There is a new `call-in-sandbox-context' which invokes a thunk in
the sandboxed context. `get-namespace' is gone, since it's easy to
do with: (call-in-sandbox-context evaluator current-namespace).
Note that such code is restricted like any other evaluation, but you
can use more privileges because your own code is not inside the
sandbox. For example:
(let ([guard (current-security-guard)])
(call-in-sandbox-context
(lambda ()
(parameterize ([current-security-guard guard])
...can access anything you want here...))))
An optional second argument can be used to avoid the memory
`sandbox-eval-handlers' restrictions.
--
((lambda (x) (x x)) (lambda (x) (x x))) Eli Barzilay:
http://www.barzilay.org/ Maze is Life!