This SRFI is currently in final status. Here is an explanation of each status that a SRFI can hold. To provide input on this SRFI, please send email to srfi-172@nospamsrfi.schemers.org
. To subscribe to the list, follow these instructions. You can access previous messages via the mailing list archive.
This SRFI provides two libraries for use with R7RS that provide a
way to sandbox the eval
procedure to make it safer to use
in evaluating Scheme expressions of doubtful provenance. The intention
is to call eval
, passing it an S-expression representing a
Scheme procedure and the environment defined by one of these libraries.
Since code evaluated by eval
runs in a null lexical
environment, the resulting procedure can then be invoked with less
concern about possible side effects.
Use of these libraries does not provide any sort of safety guarantee. There are still many loopholes uncaught, including attempts to process circular structure and over-allocation of memory. The claim is only that the probability of such an attack is reduced, not that it is eliminated. However, using these libraries is a simple provision that is easy to implement and easy to use. For higher safety, it can readily be combined with other provisions.
The Scheme eval
procedure, though part of the language
since R5RS and commonplace in Scheme implementations long before that,
has always been considered radically unsafe. In the R6RS and R7RS,
this is not entirely true.
With the help of the environment
procedure,
code can be evaluated in an immutable global environment
containing only specified libraries. This SRFI provides
two such environments, structured as R6RS or R7RS libraries.
The intention is that the programmer call
(eval s (environment '(srfi 172)))
,
where s is an S-expression
representing a procedure (typically a list whose
car is lambda
or case-lambda
).
The resulting procedure can be called with increased assurance that it
will not gain access to or modify any Scheme object except those that
are reachable from whatever is passed in as an argument.
If (srfi 172 functional)
is passed to eval
in place of (srfi 172)
,
the procedure most likely cannot mutate anything at all.
Note that while some I/O operations are provided by these libraries, the only kinds of ports that can be created are string and bytevector ports.
Warning: If an implementation coalesces two constants (quoted
or self-evaluating) that are the same in the sense of equal?
so that they also become constant in the sense of eq?, then a mutation
of one constant will affect the value of the other unless they are marked
immutable when read in; Scheme allows this but does not require it:
(define (foo x) (set-car! '(a . b) x) (car '(a . b))) ; compile the file with MIT Scheme and load it (foo 5) => 5 ; instead of a because the two (a . b) constants are coalesced
Such changes provide a covert channel between the sandbox and an object outside it that has been made the same object under the covers, and there is nothing this SRFI can do about it. (Example due to Taylor Campbell.)
The library (srfi 172)
includes the following 284 variables
and syntax keywords from R7RS-small. They are believed to be safe in the
sense that they cannot affect or be affected by the outside world except
through the arguments passed to them.
No distinctions are
made between the individual R7RS-small libraries, though implementations
that lack one or more libraries would have to bind the missing names
to calls on error
or syntax-error
.
This SRFI does not require that the procedures and syntax definitions it exports are exactly the same as those exported by the various R7RS standard libraries. In particular, wrappers or alternative versions that signal errors on implementation-specified behavior are recommended.
-
*
/
+
<
<=
=
=>
>
>=
abs
acos
and
angle
append
apply
asin
assoc
assq
assv
atan
begin
boolean?
boolean=?
bytevector
bytevector?
bytevector-append
bytevector-copy
bytevector-copy!
bytevector-length
bytevector-u8-ref
bytevector-u8-set!
caaaar
caaadr
caaar
caadar
caaddr
caadr
caar
cadaar
cadadr
cadar
caddar
cadddr
caddr
cadr
call/cc
call-with-current-continuation
call-with-port
call-with-values
car
case
case-lambda
cdaaar
cdaadr
cdaar
cdadar
cdaddr
cdadr
cdar
cddaar
cddadr
cddar
cdddar
cddddr
cdddr
cddr
cdr
ceiling
char?
char<?
char<=?
char=?
char>?
char>=?
char->integer
char-alphabetic?
char-ci<?
char-ci<=?
char-ci=?
char-ci>?
char-ci>=?
char-downcase
char-foldcase
char-lower-case?
char-numeric?
char-upcase
char-upper-case?
char-whitespace?
close-input-port
close-output-port
close-port
complex?
cond
cond-expand
cons
cos
delay
delay-force
denominator
digit-value
do
dynamic-wind
else
eof-object
eof-object?
eq?
equal?
eqv?
error
error-object?
error-object-irritants
error-object-message
even?
exact
exact?
exact-integer?
exact-integer-sqrt
exp
expt
finite?
floor
floor/
floor-quotient
floor-remainder
force
for-each
gcd
get-output-bytevector
get-output-string
guard
if
imag-part
inexact
inexact?
infinite?
input-port?
integer?
integer->char
lambda
lcm
length
let
let*
let*-values
letrec
letrec*
let-values
list
list?
list->string
list->vector
list-copy
list-ref
list-set!
list-tail
log
magnitude
make-bytevector
make-list
make-parameter
make-polar
make-promise
make-rectangular
make-string
make-vector
map
max
member
memq
memv
min
modulo
nan?
negative?
newline
not
null?
number?
number->string
numerator
odd?
open-input-bytevector
open-input-string
open-output-bytevector
open-output-string
or
output-port?
pair?
peek-char
peek-u8
parameterize
port?
positive?
procedure?
promise?
quasiquote
quote
quotient
raise
raise-continuable
rational?
rationalize
read-bytevector
read-bytevector!
read-char
read-error?
read-line
read-string
read-u8
real?
real-part
remainder
reverse
round
set!
set-car!
set-cdr!
sin
sqrt
square
string
string?
string<?
string<=?
string=?
string>?
string>=?
string->list
string->number
string->utf8
string->vector
string-append
string-ci<?
string-ci<=?
string-ci=?
string-ci>?
string-ci>=?
string-copy
string-copy!
string-downcase
string-fill!
string-foldcase
string-for-each
string-length
string-map
string-ref
string-set!
string-upcase
substring
symbol?
symbol=?
symbol->string
tan
textual-port?
truncate
truncate/
truncate-quotient
truncate-remainder
unless
unquote
unquote-splicing
utf8->string
values
vector
vector?
vector->list
vector->string
vector-append
vector-copy
vector-copy!
vector-fill!
vector-for-each
vector-length
vector-map
vector-ref
vector-set!
when
with-exception-handler
write-bytevector
write-char
write-string
write-u8
zero?
The library (srfi 172 functional)
exports all of
the exports of (srfi 172)
except for:
set!
syntax keyword!
port
read
peek
write
It therefore exports 251 identifiers.
A conforming implementation could be created entirely from this description.
Implementations of the two libraries for Chibi can be found in the repository of this SRFI and in srfi-172.tgz.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.