1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402 |
- ;;; Sandboxed evaluation of Scheme code
- ;;; Copyright (C) 2017, 2018 Free Software Foundation, Inc.
- ;;;; This library is free software; you can redistribute it and/or
- ;;;; modify it under the terms of the GNU Lesser General Public
- ;;;; License as published by the Free Software Foundation; either
- ;;;; version 3 of the License, or (at your option) any later version.
- ;;;;
- ;;;; This library is distributed in the hope that it will be useful,
- ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
- ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- ;;;; Lesser General Public License for more details.
- ;;;;
- ;;;; You should have received a copy of the GNU Lesser General Public
- ;;;; License along with this library; if not, write to the Free Software
- ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- ;;; Commentary:
- ;;;
- ;;; Code:
- (define-module (ice-9 sandbox)
- #:use-module (ice-9 control)
- #:use-module (ice-9 match)
- #:use-module ((ice-9 threads) #:select (current-thread))
- #:use-module (system vm vm)
- #:export (call-with-time-limit
- call-with-allocation-limit
- call-with-time-and-allocation-limits
- eval-in-sandbox
- make-sandbox-module
- alist-bindings
- array-bindings
- bit-bindings
- bitvector-bindings
- char-bindings
- char-set-bindings
- clock-bindings
- core-bindings
- error-bindings
- fluid-bindings
- hash-bindings
- iteration-bindings
- keyword-bindings
- list-bindings
- macro-bindings
- nil-bindings
- number-bindings
- pair-bindings
- predicate-bindings
- procedure-bindings
- promise-bindings
- prompt-bindings
- regexp-bindings
- sort-bindings
- srfi-4-bindings
- string-bindings
- symbol-bindings
- unspecified-bindings
- variable-bindings
- vector-bindings
- version-bindings
- mutating-alist-bindings
- mutating-array-bindings
- mutating-bitvector-bindings
- mutating-fluid-bindings
- mutating-hash-bindings
- mutating-list-bindings
- mutating-pair-bindings
- mutating-sort-bindings
- mutating-srfi-4-bindings
- mutating-string-bindings
- mutating-variable-bindings
- mutating-vector-bindings
- all-pure-bindings
- all-pure-and-impure-bindings))
- (define (call-with-time-limit limit thunk limit-reached)
- "Call @var{thunk}, but cancel it if @var{limit} seconds of wall-clock
- time have elapsed. If the computation is cancelled, call
- @var{limit-reached} in tail position. @var{thunk} must not disable
- interrupts or prevent an abort via a @code{dynamic-wind} unwind
- handler."
- ;; FIXME: use separate thread instead of sigalrm. If rounded limit is
- ;; <= 0, make it 1 usec to signal immediately.
- (let ((limit-usecs (max (inexact->exact (round (* limit 1e6))) 1))
- (prev-sigalarm-handler #f)
- (tag (make-prompt-tag)))
- (call-with-prompt tag
- (lambda ()
- (dynamic-wind
- (lambda ()
- (set! prev-sigalarm-handler
- (sigaction SIGALRM (lambda (sig)
- ;; If signal handling is delayed
- ;; until after prompt, no worries;
- ;; the success path won the race.
- (false-if-exception
- (abort-to-prompt tag)))))
- (setitimer ITIMER_REAL 0 0 0 limit-usecs))
- thunk
- (lambda ()
- (setitimer ITIMER_REAL 0 0 0 0)
- (match prev-sigalarm-handler
- ((handler . flags)
- (sigaction SIGALRM handler flags))))))
- (lambda (k)
- (limit-reached)))))
- (define (call-with-allocation-limit limit thunk limit-reached)
- "Call @var{thunk}, but cancel it if @var{limit} bytes have been
- allocated. If the computation is cancelled, call @var{limit-reached} in
- tail position. @var{thunk} must not disable interrupts or prevent an
- abort via a @code{dynamic-wind} unwind handler.
- This limit applies to both stack and heap allocation. The computation
- will not be aborted before @var{limit} bytes have been allocated, but
- for the heap allocation limit, the check may be postponed until the next
- garbage collection.
- Note that as a current shortcoming, the heap size limit applies to all
- threads; concurrent allocation by other unrelated threads counts towards
- the allocation limit."
- (define (bytes-allocated) (assq-ref (gc-stats) 'heap-total-allocated))
- (let ((zero (bytes-allocated))
- (tag (make-prompt-tag))
- (thread (current-thread)))
- (define (check-allocation)
- (when (< limit (- (bytes-allocated) zero))
- (system-async-mark (lambda ()
- (false-if-exception (abort-to-prompt tag)))
- thread)))
- (call-with-prompt tag
- (lambda ()
- (dynamic-wind
- (lambda ()
- (add-hook! after-gc-hook check-allocation))
- (lambda ()
- (call-with-stack-overflow-handler
- ;; The limit is in "words", which used to be 4 or 8 but now
- ;; is always 8 bytes.
- (max (floor/ limit 8) 1)
- thunk
- (lambda () (abort-to-prompt tag))))
- (lambda ()
- (remove-hook! after-gc-hook check-allocation))))
- (lambda (k)
- (limit-reached)))))
- (define (call-with-time-and-allocation-limits time-limit allocation-limit
- thunk)
- "Invoke @var{thunk} in a dynamic extent in which its execution is
- limited to @var{time-limit} seconds of wall-clock time, and its
- allocation to @var{allocation-limit} bytes. @var{thunk} must not
- disable interrupts or prevent an abort via a @code{dynamic-wind} unwind
- handler.
- If successful, return all values produced by invoking @var{thunk}. Any
- uncaught exception thrown by the thunk will propagate out. If the time
- or allocation limit is exceeded, an exception will be thrown to the
- @code{limit-exceeded} key."
- (call-with-time-limit
- time-limit
- (lambda ()
- (call-with-allocation-limit
- allocation-limit
- thunk
- (lambda ()
- (scm-error 'limit-exceeded "with-resource-limits"
- "Allocation limit exceeded" '() #f))))
- (lambda ()
- (scm-error 'limit-exceeded "with-resource-limits"
- "Time limit exceeded" '() #f))))
- (define (sever-module! m)
- "Remove @var{m} from its container module."
- (match (module-name m)
- ((head ... tail)
- (let ((parent (resolve-module head #f)))
- (unless (eq? m (module-ref-submodule parent tail))
- (error "can't sever module?"))
- (hashq-remove! (module-submodules parent) tail)))))
- ;; bindings := module-binding-list ...
- ;; module-binding-list := interface-name import ...
- ;; import := name | (exported-name . imported-name)
- ;; name := symbol
- (define (make-sandbox-module bindings)
- "Return a fresh module that only contains @var{bindings}.
- The @var{bindings} should be given as a list of import sets. One import
- set is a list whose car names an interface, like @code{(ice-9 q)}, and
- whose cdr is a list of imports. An import is either a bare symbol or a
- pair of @code{(@var{out} . @var{in})}, where @var{out} and @var{in} are
- both symbols and denote the name under which a binding is exported from
- the module, and the name under which to make the binding available,
- respectively."
- (let ((m (make-fresh-user-module)))
- (purify-module! m)
- (module-use-interfaces! m
- (map (match-lambda
- ((mod-name . bindings)
- (resolve-interface mod-name
- #:select bindings)))
- bindings))
- m))
- (define* (eval-in-sandbox exp #:key
- (time-limit 0.1)
- (allocation-limit #e10e6)
- (bindings all-pure-bindings)
- (module (make-sandbox-module bindings))
- (sever-module? #t))
- "Evaluate the Scheme expression @var{exp} within an isolated
- \"sandbox\". Limit its execution to @var{time-limit} seconds of
- wall-clock time, and limit its allocation to @var{allocation-limit}
- bytes.
- The evaluation will occur in @var{module}, which defaults to the result
- of calling @code{make-sandbox-module} on @var{bindings}, which itself
- defaults to @code{all-pure-bindings}. This is the core of the
- sandbox: creating a scope for the expression that is @dfn{safe}.
- A safe sandbox module has two characteristics. Firstly, it will not
- allow the expression being evaluated to avoid being cancelled due to
- time or allocation limits. This ensures that the expression terminates
- in a timely fashion.
- Secondly, a safe sandbox module will prevent the evaluation from
- receiving information from previous evaluations, or from affecting
- future evaluations. All combinations of binding sets exported by
- @code{(ice-9 sandbox)} form safe sandbox modules.
- The @var{bindings} should be given as a list of import sets. One import
- set is a list whose car names an interface, like @code{(ice-9 q)}, and
- whose cdr is a list of imports. An import is either a bare symbol or a
- pair of @code{(@var{out} . @var{in})}, where @var{out} and @var{in} are
- both symbols and denote the name under which a binding is exported from
- the module, and the name under which to make the binding available,
- respectively. Note that @var{bindings} is only used as an input to the
- default initializer for the @var{module} argument; if you pass
- @code{#:module}, @var{bindings} is unused. If @var{sever-module?} is
- true (the default), the module will be unlinked from the global module
- tree after the evaluation returns, to allow @var{mod} to be
- garbage-collected.
- If successful, return all values produced by @var{exp}. Any uncaught
- exception thrown by the expression will propagate out. If the time or
- allocation limit is exceeded, an exception will be thrown to the
- @code{limit-exceeded} key."
- (dynamic-wind
- (lambda () #t)
- (lambda ()
- (call-with-time-and-allocation-limits
- time-limit allocation-limit
- (lambda ()
- (eval exp module))))
- (lambda () (when sever-module? (sever-module! module)))))
- ;; An evaluation-sandboxing facility is safe if:
- ;;
- ;; (1) every evaluation will terminate in a timely manner
- ;;
- ;; (2) no evaluation can affect future evaluations
- ;;
- ;; For (1), we impose a user-controllable time limit on the evaluation,
- ;; in wall-clock time. When that limit is reached, Guile schedules an
- ;; asynchronous interrupt in the sandbox that aborts the computation.
- ;; For this to work, the sandboxed evaluation must not disable
- ;; interrupts, and it must not prevent timely aborts via malicious "out"
- ;; guards in dynamic-wind thunks.
- ;;
- ;; The sandbox also has an allocation limit that uses a similar cancel
- ;; mechanism, but this limit is less precise as it only runs at
- ;; garbage-collection time.
- ;;
- ;; The sandbox sets the allocation limit as the stack limit as well.
- ;;
- ;; For (2), the only way an evaluation can affect future evaluations is
- ;; if it causes a side-effect outside its sandbox. That side effect
- ;; could change the way the host or future sandboxed evaluations
- ;; operate, or it could leak information to future evaluations.
- ;;
- ;; One means of information leakage would be the file system. Although
- ;; one can imagine "safe" ways to access a file system, in practice we
- ;; just prevent all access to this and other operating system facilities
- ;; by not exposing the Guile primitives that access the file system,
- ;; connect to networking hosts, etc. If we chose our set of bindings
- ;; correctly and it is impossible to access host values other than those
- ;; given to the evaluation, then we have succeeded in granting only a
- ;; limited set of capabilities to the guest.
- ;;
- ;; To prevent information leakage we also limit other information about
- ;; the host, like its hostname or the Guile build information.
- ;;
- ;; The guest must also not have the capability to mutate a location used
- ;; by the host or by future sandboxed evaluations. Either you expose no
- ;; primitives to the evaluation that can mutate locations, or you expose
- ;; no mutable locations. In this sandbox we opt for a combination of
- ;; the two, though the selection of bindings is up to the user. "set!"
- ;; is always excluded, as Guile doesn't have a nice way to prevent set!
- ;; on imported bindings. But variable-set! is included, as no set of
- ;; bindings from this module includes a variable or a capability to a
- ;; variable. It's possible though to build sandbox modules with no
- ;; mutating primitives. As far as we know, all possible combinations of
- ;; the binding sets listed below are safe.
- ;;
- (define core-bindings
- '(((guile)
- else => _ ...
- and
- begin
- apply
- call-with-values
- values
- case
- case-lambda
- case-lambda*
- cond
- define
- define*
- define-values
- do
- if
- lambda
- lambda*
- let
- let*
- letrec
- letrec*
- or
- quasiquote
- quote
- ;; Can't allow mutation to globals.
- ;; set!
- unless
- unquote
- unquote-splicing
- when
- while
- λ)))
- (define macro-bindings
- '(((guile)
- bound-identifier=?
- ;; Although these have "current" in their name, they are lexically
- ;; scoped, not dynamically scoped.
- current-filename
- current-source-location
- datum->syntax
- define-macro
- define-syntax
- define-syntax-parameter
- define-syntax-rule
- defmacro
- free-identifier=?
- generate-temporaries
- gensym
- identifier-syntax
- identifier?
- let-syntax
- letrec-syntax
- macroexpand
- macroexpanded?
- quasisyntax
- start-stack
- syntax
- syntax->datum
- syntax-case
- syntax-error
- syntax-parameterize
- syntax-rules
- syntax-source
- syntax-violation
- unsyntax
- unsyntax-splicing
- with-ellipsis
- with-syntax
- make-variable-transformer)))
- (define iteration-bindings
- '(((guile)
- compose
- for-each
- identity
- iota
- map
- map-in-order
- const
- noop)))
- (define clock-bindings
- '(((guile)
- get-internal-real-time
- internal-time-units-per-second
- sleep
- usleep)))
- (define procedure-bindings
- '(((guile)
- procedure-documentation
- procedure-minimum-arity
- procedure-name
- procedure?
- thunk?)))
- (define version-bindings
- '(((guile)
- effective-version
- major-version
- micro-version
- minor-version
- version
- version-matches?)))
- (define nil-bindings
- '(((guile)
- nil?)))
- (define unspecified-bindings
- '(((guile)
- unspecified?
- *unspecified*)))
- (define predicate-bindings
- '(((guile)
- ->bool
- and-map
- and=>
- boolean?
- eq?
- equal?
- eqv?
- negate
- not
- or-map)))
- ;; The current ports (current-input-port et al) are dynamically scoped,
- ;; which is a footgun from a sandboxing perspective. It's too easy for
- ;; a procedure that is the result of a sandboxed evaluation to be later
- ;; invoked in a different context and thereby be implicitly granted
- ;; capabilities to whatever port is then current. This is compounded by
- ;; the fact that most Scheme i/o primitives allow the port to be omitted
- ;; and thereby default to whatever's current. For now, sadly, we avoid
- ;; exposing any i/o primitive to the sandbox.
- #;
- (define i/o-bindings
- '(((guile)
- display
- eof-object?
- force-output
- format
- make-soft-port
- newline
- read
- simple-format
- write
- write-char)
- ((ice-9 ports)
- %make-void-port
- char-ready?
- ;; Note that these are mutable parameters.
- current-error-port
- current-input-port
- current-output-port
- current-warning-port
- drain-input
- eof-object?
- file-position
- force-output
- ftell
- input-port?
- output-port?
- peek-char
- port-closed?
- port-column
- port-conversion-strategy
- port-encoding
- port-filename
- port-line
- port-mode
- port?
- read-char
- the-eof-object
- ;; We don't provide open-output-string because it needs
- ;; get-output-string, and get-output-string provides a generic
- ;; capability on any output string port. For consistency then we
- ;; don't provide open-input-string either; call-with-input-string
- ;; is sufficient.
- call-with-input-string
- call-with-output-string
- with-error-to-port
- with-error-to-string
- with-input-from-port
- with-input-from-string
- with-output-to-port
- with-output-to-string)))
- ;; If two evaluations are called with the same input port, unread-char
- ;; and unread-string can use a port as a mutable channel to pass
- ;; information from one to the other.
- #;
- (define mutating-i/o-bindings
- '(((guile)
- set-port-encoding!)
- ((ice-9 ports)
- close-input-port
- close-output-port
- close-port
- file-set-position
- seek
- set-port-column!
- set-port-conversion-strategy!
- set-port-encoding!
- set-port-filename!
- set-port-line!
- setvbuf
- unread-char
- unread-string)))
- (define error-bindings
- '(((guile)
- error
- throw
- with-throw-handler
- catch
- ;; false-if-exception can cause i/o if the #:warning arg is passed.
- ;; false-if-exception
- ;; See notes on i/o-bindings.
- ;; peek
- ;; pk
- ;; print-exception
- ;; warn
- strerror
- scm-error
- )))
- ;; FIXME: Currently we can't expose anything that works on the current
- ;; module to the sandbox. It could be that the sandboxed evaluation
- ;; returns a procedure, and that procedure may later be invoked in a
- ;; different context with a different current-module and it is unlikely
- ;; that the later caller will consider themselves as granting a
- ;; capability on whatever module is then current. Likewise export (and
- ;; by extension, define-public and the like) also operate on the current
- ;; module.
- ;;
- ;; It could be that we could expose a statically scoped eval to the
- ;; sandbox.
- #;
- (define eval-bindings
- '(((guile)
- current-module
- module-name
- module?
- define-once
- define-private
- define-public
- defined?
- export
- defmacro-public
- ;; FIXME: single-arg eval?
- eval
- primitive-eval
- eval-string
- self-evaluating?
- ;; Can we?
- set-current-module)))
- (define sort-bindings
- '(((guile)
- sort
- sorted?
- stable-sort
- sort-list)))
- ;; These can only form part of a safe binding set if no mutable pair or
- ;; vector is exposed to the sandbox.
- (define mutating-sort-bindings
- '(((guile)
- sort!
- stable-sort!
- sort-list!
- restricted-vector-sort!)))
- (define regexp-bindings
- '(((guile)
- make-regexp
- regexp-exec
- regexp/basic
- regexp/extended
- regexp/icase
- regexp/newline
- regexp/notbol
- regexp/noteol
- regexp?)))
- (define alist-bindings
- '(((guile)
- acons
- assoc
- assoc-ref
- assq
- assq-ref
- assv
- assv-ref
- sloppy-assoc
- sloppy-assq
- sloppy-assv)))
- ;; These can only form part of a safe binding set if no mutable pair
- ;; is exposed to the sandbox. Unfortunately all charsets in Guile are
- ;; mutable, currently, including the built-in charsets, so we can't
- ;; expose these primitives.
- (define mutating-alist-bindings
- '(((guile)
- assoc-remove!
- assoc-set!
- assq-remove!
- assq-set!
- assv-remove!
- assv-set!)))
- (define number-bindings
- '(((guile)
- *
- +
- -
- /
- 1+
- 1-
- <
- <=
- =
- >
- >=
- abs
- acos
- acosh
- angle
- asin
- asinh
- atan
- atanh
- ceiling
- ceiling-quotient
- ceiling-remainder
- ceiling/
- centered-quotient
- centered-remainder
- centered/
- complex?
- cos
- cosh
- denominator
- euclidean-quotient
- euclidean-remainder
- euclidean/
- even?
- exact->inexact
- exact-integer-sqrt
- exact-integer?
- exact?
- exp
- expt
- finite?
- floor
- floor-quotient
- floor-remainder
- floor/
- gcd
- imag-part
- inf
- inf?
- integer-expt
- integer-length
- integer?
- lcm
- log
- log10
- magnitude
- make-polar
- make-rectangular
- max
- min
- modulo
- modulo-expt
- most-negative-fixnum
- most-positive-fixnum
- nan
- nan?
- negative?
- numerator
- odd?
- positive?
- quotient
- rational?
- rationalize
- real-part
- real?
- remainder
- round
- round-quotient
- round-remainder
- round/
- sin
- sinh
- sqrt
- tan
- tanh
- truncate
- truncate-quotient
- truncate-remainder
- truncate/
- zero?
- number?
- number->string
- string->number)))
- (define char-set-bindings
- '(((guile)
- ->char-set
- char-set
- char-set->list
- char-set->string
- char-set-adjoin
- char-set-any
- char-set-complement
- char-set-contains?
- char-set-copy
- char-set-count
- char-set-cursor
- char-set-cursor-next
- char-set-delete
- char-set-diff+intersection
- char-set-difference
- char-set-every
- char-set-filter
- char-set-fold
- char-set-for-each
- char-set-hash
- char-set-intersection
- char-set-map
- char-set-ref
- char-set-size
- char-set-unfold
- char-set-union
- char-set-xor
- char-set:ascii
- char-set:blank
- char-set:designated
- char-set:digit
- char-set:empty
- char-set:full
- char-set:graphic
- char-set:hex-digit
- char-set:iso-control
- char-set:letter
- char-set:letter+digit
- char-set:lower-case
- char-set:printing
- char-set:punctuation
- char-set:symbol
- char-set:title-case
- char-set:upper-case
- char-set:whitespace
- char-set<=
- char-set=
- char-set?
- end-of-char-set?
- list->char-set
- string->char-set
- ucs-range->char-set)))
- ;; These can only form part of a safe binding set if no mutable char-set
- ;; is exposed to the sandbox. Unfortunately all charsets in Guile are
- ;; mutable, currently, including the built-in charsets, so we can't
- ;; expose these primitives.
- #;
- (define mutating-char-set-bindings
- '(((guile)
- char-set-adjoin!
- char-set-complement!
- char-set-delete!
- char-set-diff+intersection!
- char-set-difference!
- char-set-filter!
- char-set-intersection!
- char-set-unfold!
- char-set-union!
- char-set-xor!
- list->char-set!
- string->char-set!
- ucs-range->char-set!)))
- (define array-bindings
- '(((guile)
- array->list
- array-cell-ref
- array-contents
- array-dimensions
- array-equal?
- array-for-each
- array-in-bounds?
- array-length
- array-rank
- array-ref
- array-shape
- array-slice
- array-slice-for-each
- array-slice-for-each-in-order
- array-type
- array-type-code
- array?
- list->array
- list->typed-array
- make-array
- make-shared-array
- make-typed-array
- shared-array-increments
- shared-array-offset
- shared-array-root
- transpose-array
- typed-array?)))
- ;; These can only form part of a safe binding set if no mutable vector,
- ;; bitvector, bytevector, srfi-4 vector, or array is exposed to the
- ;; sandbox.
- (define mutating-array-bindings
- '(((guile)
- array-cell-set!
- array-copy!
- array-copy-in-order!
- array-fill!
- array-index-map!
- array-map!
- array-map-in-order!
- array-set!)))
- (define hash-bindings
- '(((guile)
- doubly-weak-hash-table?
- hash
- hash-count
- hash-fold
- hash-for-each
- hash-for-each-handle
- hash-get-handle
- hash-map->list
- hash-ref
- hash-table?
- hashq
- hashq-get-handle
- hashq-ref
- hashv
- hashv-get-handle
- hashv-ref
- hashx-get-handle
- hashx-ref
- make-doubly-weak-hash-table
- make-hash-table
- make-weak-key-hash-table
- make-weak-value-hash-table
- weak-key-hash-table?
- weak-value-hash-table?)))
- ;; These can only form part of a safe binding set if no hash table is
- ;; exposed to the sandbox.
- (define mutating-hash-bindings
- '(((guile)
- hash-clear!
- hash-create-handle!
- hash-remove!
- hash-set!
- hashq-create-handle!
- hashq-remove!
- hashq-set!
- hashv-create-handle!
- hashv-remove!
- hashv-set!
- hashx-create-handle!
- hashx-remove!
- hashx-set!)))
- (define variable-bindings
- '(((guile)
- make-undefined-variable
- make-variable
- variable-bound?
- variable-ref
- variable?)))
- ;; These can only form part of a safe binding set if no mutable variable
- ;; is exposed to the sandbox; this applies particularly to variables
- ;; that are module bindings.
- (define mutating-variable-bindings
- '(((guile)
- variable-set!
- variable-unset!)))
- (define string-bindings
- '(((guile)
- absolute-file-name?
- file-name-separator-string
- file-name-separator?
- in-vicinity
- basename
- dirname
- list->string
- make-string
- object->string
- reverse-list->string
- string
- string->list
- string-any
- string-any-c-code
- string-append
- string-append/shared
- string-capitalize
- string-ci<
- string-ci<=
- string-ci<=?
- string-ci<>
- string-ci<?
- string-ci=
- string-ci=?
- string-ci>
- string-ci>=
- string-ci>=?
- string-ci>?
- string-compare
- string-compare-ci
- string-concatenate
- string-concatenate-reverse
- string-concatenate-reverse/shared
- string-concatenate/shared
- string-contains
- string-contains-ci
- string-copy
- string-count
- string-delete
- string-downcase
- string-drop
- string-drop-right
- string-every
- string-every-c-code
- string-filter
- string-fold
- string-fold-right
- string-for-each
- string-for-each-index
- string-hash
- string-hash-ci
- string-index
- string-index-right
- string-join
- string-length
- string-map
- string-normalize-nfc
- string-normalize-nfd
- string-normalize-nfkc
- string-normalize-nfkd
- string-null?
- string-pad
- string-pad-right
- string-prefix-ci?
- string-prefix-length
- string-prefix-length-ci
- string-prefix?
- string-ref
- string-replace
- string-reverse
- string-rindex
- string-skip
- string-skip-right
- string-split
- string-suffix-ci?
- string-suffix-length
- string-suffix-length-ci
- string-suffix?
- string-tabulate
- string-take
- string-take-right
- string-titlecase
- string-tokenize
- string-trim
- string-trim-both
- string-trim-right
- string-unfold
- string-unfold-right
- string-upcase
- string-utf8-length
- string<
- string<=
- string<=?
- string<>
- string<?
- string=
- string=?
- string>
- string>=
- string>=?
- string>?
- string?
- substring
- substring/copy
- substring/read-only
- substring/shared
- xsubstring)))
- ;; These can only form part of a safe binding set if no mutable string
- ;; is exposed to the sandbox.
- (define mutating-string-bindings
- '(((guile)
- string-capitalize!
- string-copy!
- string-downcase!
- string-fill!
- string-map!
- string-reverse!
- string-set!
- string-titlecase!
- string-upcase!
- string-xcopy!
- substring-fill!
- substring-move!)))
- (define symbol-bindings
- '(((guile)
- string->symbol
- string-ci->symbol
- symbol->string
- list->symbol
- make-symbol
- symbol
- symbol-append
- symbol-hash
- symbol-interned?
- symbol?)))
- (define keyword-bindings
- '(((guile)
- keyword?
- keyword->symbol
- symbol->keyword)))
- ;; These can only form part of a safe binding set if no valid prompt tag
- ;; is ever exposed to the sandbox, or can be constructed by the sandbox.
- (define prompt-bindings
- '(((guile)
- abort-to-prompt
- abort-to-prompt*
- call-with-prompt
- make-prompt-tag)))
- (define bit-bindings
- '(((guile)
- ash
- round-ash
- logand
- logcount
- logior
- lognot
- logtest
- logxor
- logbit?)))
- (define bitvector-bindings
- '(((guile)
- bitvector-count
- bitvector-position
- bitvector-count-bits
- bit-extract
- bitvector
- bitvector->list
- bitvector-length
- bitvector-bit-set?
- bitvector-bit-clear?
- bitvector?
- list->bitvector
- make-bitvector)))
- ;; These can only form part of a safe binding set if no mutable
- ;; bitvector is exposed to the sandbox.
- (define mutating-bitvector-bindings
- '(((guile)
- bitvector-clear-bit!
- bitvector-clear-bits!
- bitvector-set-all-bits!
- bitvector-clear-all-bits!
- bitvector-flip-all-bits!
- bitvector-set-bit!
- bitvector-set-bits!)))
- (define fluid-bindings
- '(((guile)
- fluid-bound?
- fluid-ref
- ;; fluid-ref* could escape the sandbox and is not allowed.
- fluid-thread-local?
- fluid?
- make-fluid
- make-thread-local-fluid
- make-unbound-fluid
- with-fluid*
- with-fluids
- with-fluids*
- make-parameter
- parameter?
- parameterize)))
- ;; These can only form part of a safe binding set if no fluid is
- ;; directly exposed to the sandbox.
- (define mutating-fluid-bindings
- '(((guile)
- fluid-set!
- fluid-unset!
- fluid->parameter)))
- (define char-bindings
- '(((guile)
- char-alphabetic?
- char-ci<=?
- char-ci<?
- char-ci=?
- char-ci>=?
- char-ci>?
- char-downcase
- char-general-category
- char-is-both?
- char-lower-case?
- char-numeric?
- char-titlecase
- char-upcase
- char-upper-case?
- char-whitespace?
- char<=?
- char<?
- char=?
- char>=?
- char>?
- char?
- char->integer
- integer->char)))
- (define list-bindings
- '(((guile)
- list
- list-cdr-ref
- list-copy
- list-head
- list-index
- list-ref
- list-tail
- list?
- null?
- make-list
- append
- delete
- delq
- delv
- filter
- length
- member
- memq
- memv
- merge
- reverse)))
- ;; These can only form part of a safe binding set if no mutable
- ;; pair is exposed to the sandbox.
- (define mutating-list-bindings
- '(((guile)
- list-cdr-set!
- list-set!
- append!
- delete!
- delete1!
- delq!
- delq1!
- delv!
- delv1!
- filter!
- merge!
- reverse!)))
- (define pair-bindings
- '(((guile)
- last-pair
- pair?
- caaaar
- caaadr
- caaar
- caadar
- caaddr
- caadr
- caar
- cadaar
- cadadr
- cadar
- caddar
- cadddr
- caddr
- cadr
- car
- cdaaar
- cdaadr
- cdaar
- cdadar
- cdaddr
- cdadr
- cdar
- cddaar
- cddadr
- cddar
- cdddar
- cddddr
- cdddr
- cddr
- cdr
- cons
- cons*)))
- ;; These can only form part of a safe binding set if no mutable
- ;; pair is exposed to the sandbox.
- (define mutating-pair-bindings
- '(((guile)
- set-car!
- set-cdr!)))
- (define vector-bindings
- '(((guile)
- list->vector
- make-vector
- vector
- vector->list
- vector-copy
- vector-length
- vector-ref
- vector?)))
- ;; These can only form part of a safe binding set if no mutable
- ;; vector is exposed to the sandbox.
- (define mutating-vector-bindings
- '(((guile)
- vector-fill!
- vector-move-left!
- vector-move-right!
- vector-set!)))
- (define promise-bindings
- '(((guile)
- force
- delay
- make-promise
- promise?)))
- (define srfi-4-bindings
- '(((srfi srfi-4)
- f32vector
- f32vector->list
- f32vector-length
- f32vector-ref
- f32vector?
- f64vector
- f64vector->list
- f64vector-length
- f64vector-ref
- f64vector?
- list->f32vector
- list->f64vector
- list->s16vector
- list->s32vector
- list->s64vector
- list->s8vector
- list->u16vector
- list->u32vector
- list->u64vector
- list->u8vector
- make-f32vector
- make-f64vector
- make-s16vector
- make-s32vector
- make-s64vector
- make-s8vector
- make-u16vector
- make-u32vector
- make-u64vector
- make-u8vector
- s16vector
- s16vector->list
- s16vector-length
- s16vector-ref
- s16vector?
- s32vector
- s32vector->list
- s32vector-length
- s32vector-ref
- s32vector?
- s64vector
- s64vector->list
- s64vector-length
- s64vector-ref
- s64vector?
- s8vector
- s8vector->list
- s8vector-length
- s8vector-ref
- s8vector?
- u16vector
- u16vector->list
- u16vector-length
- u16vector-ref
- u16vector?
- u32vector
- u32vector->list
- u32vector-length
- u32vector-ref
- u32vector?
- u64vector
- u64vector->list
- u64vector-length
- u64vector-ref
- u64vector?
- u8vector
- u8vector->list
- u8vector-length
- u8vector-ref
- u8vector?)))
- ;; These can only form part of a safe binding set if no mutable
- ;; bytevector is exposed to the sandbox.
- (define mutating-srfi-4-bindings
- '(((srfi srfi-4)
- f32vector-set!
- f64vector-set!
- s16vector-set!
- s32vector-set!
- s64vector-set!
- s8vector-set!
- u16vector-set!
- u32vector-set!
- u64vector-set!
- u8vector-set!)))
- (define all-pure-bindings
- (append alist-bindings
- array-bindings
- bit-bindings
- bitvector-bindings
- char-bindings
- char-set-bindings
- clock-bindings
- core-bindings
- error-bindings
- fluid-bindings
- hash-bindings
- iteration-bindings
- keyword-bindings
- list-bindings
- macro-bindings
- nil-bindings
- number-bindings
- pair-bindings
- predicate-bindings
- procedure-bindings
- promise-bindings
- prompt-bindings
- regexp-bindings
- sort-bindings
- srfi-4-bindings
- string-bindings
- symbol-bindings
- unspecified-bindings
- variable-bindings
- vector-bindings
- version-bindings))
- (define all-pure-and-impure-bindings
- (append all-pure-bindings
- mutating-alist-bindings
- mutating-array-bindings
- mutating-bitvector-bindings
- mutating-fluid-bindings
- mutating-hash-bindings
- mutating-list-bindings
- mutating-pair-bindings
- mutating-sort-bindings
- mutating-srfi-4-bindings
- mutating-string-bindings
- mutating-variable-bindings
- mutating-vector-bindings))
|