* modify environments to make sandboxes @ 2006-06-12 16:20 Mildred 2006-06-12 16:47 ` Ludovic Courtès 2006-06-28 4:13 ` Jon Wilson 0 siblings, 2 replies; 7+ messages in thread From: Mildred @ 2006-06-12 16:20 UTC (permalink / raw) Hi, I'm new to this mailing list and also new to the scheme language ... I'm used to Lua but I try to search about functionnal programming, and I found scheme. It looks like a good language but before using it in my projects I would like to know if tere is an easy way to create sandboxes. In lua, it is easy, you create a table containing functions ... and the table can be made environment for a function. So, you can easily create secure sandboxes by loading lua code from file and changing the environment of the loaded code. I do not know how to do that in scheme. Apparetly the function null-environment can return an environment and eval can evaluate some code in an environment. But the question is how to define a variable in an environment and also how to undefine a variable that you don't want to appear. I didn't found anything about modifying an environment. Is it possible ? If not, why not ? and is it possible to create sandboxes ? Thanks Mildred -- Mildred <xmpp:mildred@jabber.fr> <http://mildred632.free.fr/> Clef GPG : <hkp://pgp.mit.edu> ou <http://mildred632.free.fr/gpg_key> Fingerprint : 197C A7E6 645B 4299 6D37 684B 6F9D A8D6 [9A7D 2E2B] _______________________________________________ Guile-user mailing list Guile-user@gnu.org http://lists.gnu.org/mailman/listinfo/guile-user ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: modify environments to make sandboxes 2006-06-12 16:20 modify environments to make sandboxes Mildred @ 2006-06-12 16:47 ` Ludovic Courtès 2006-06-12 22:05 ` Neil Jerram 2006-06-28 4:13 ` Jon Wilson 1 sibling, 1 reply; 7+ messages in thread From: Ludovic Courtès @ 2006-06-12 16:47 UTC (permalink / raw) Cc: guile-user Hi, Mildred <ml.mildred593@online.fr> writes: > I do not know how to do that in scheme. Apparetly the function > null-environment can return an environment and eval can evaluate some > code in an environment. But the question is how to define a variable in > an environment and also how to undefine a variable that you don't want > to appear. Code confinement is indeed an interesting feature. Fortunately, Guile offers various ways to do it (AFAIK, there's no standard way to do this in R5RS Scheme). :-) Basically, in Guile, one can manipulate "modules". Modules are first-class representations of name spaces (i.e., environments with bindings). The second argument of `eval' is a module, so you can ask Guile to evaluate a piece of code within the context of a particular module. The basic way to create a module is `make-module'. However, this returns a module with absolutely no defined binding (i.e., no variable is bound within it, not even `define', `let', etc.). If you were to create a confined module to evaluate mathematical expressions, you could start from there: (define (make-pure-math-module) (let ((m (make-module))) (module-define! m '+ +) (module-define! m '- -) (module-define! m '* *) (module-define! m '/ /) (module-define! m 'let let) m)) Now, thanks to this, you will be able to catch the following: (eval '(system "rm -rf /") (make-pure-math-module)) IOW, you can safely evaluate any expression, and you know that it will fail if it's not a pure mathematical expression. Now, in the general case, you want to create a module that contains enough bindings to allow "friendly" code to evaluate, but you don't want to list all those bindings one by one. In this case, you can use `make-root-module' which returns a new module that contains all the default Guile bindings. Then, you can selectively undefine or modify various bindings within that module (using `module-remove!' and `module-set!'). In particular, you'll want to make sure that no POSIX syscall is available, and that `load' and `resolve-module' (which allows one to load a Scheme file) are either undefined or restricted (e.g., such that only specific modules can be loaded from within the confined module). Finally, another approach is to start from an empty module (returned by `make-module') and then use a set of `module-use!' calls to have it import bindings from a few specific modules. You can get more information about modules in `ice-9/boot-9.scm'. Happy hacking! Ludovic. _______________________________________________ Guile-user mailing list Guile-user@gnu.org http://lists.gnu.org/mailman/listinfo/guile-user ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: modify environments to make sandboxes 2006-06-12 16:47 ` Ludovic Courtès @ 2006-06-12 22:05 ` Neil Jerram 2006-06-22 12:34 ` Ludovic Courtès 0 siblings, 1 reply; 7+ messages in thread From: Neil Jerram @ 2006-06-12 22:05 UTC (permalink / raw) Cc: guile-user ludovic.courtes@laas.fr (Ludovic Courtès) writes: > Code confinement is indeed an interesting feature. Fortunately, Guile > offers various ways to do it (AFAIK, there's no standard way to do this > in R5RS Scheme). :-) [...] That's a very nice explanation. Is there a good place for it somewhere in the manual? (If not, perhaps we should start a "How can I do XXX" section.) Regards, Neil _______________________________________________ Guile-user mailing list Guile-user@gnu.org http://lists.gnu.org/mailman/listinfo/guile-user ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: modify environments to make sandboxes 2006-06-12 22:05 ` Neil Jerram @ 2006-06-22 12:34 ` Ludovic Courtès 2006-06-22 18:36 ` Alan Grover 0 siblings, 1 reply; 7+ messages in thread From: Ludovic Courtès @ 2006-06-22 12:34 UTC (permalink / raw) Cc: guile-user Hi, Neil Jerram <neil@ossau.uklinux.net> writes: > ludovic.courtes@laas.fr (Ludovic Courtès) writes: > >> Code confinement is indeed an interesting feature. Fortunately, Guile >> offers various ways to do it (AFAIK, there's no standard way to do this >> in R5RS Scheme). :-) [...] > > That's a very nice explanation. Is there a good place for it > somewhere in the manual? (If not, perhaps we should start a "How can > I do XXX" section.) (Sorry, I think I had skipped this message.) We don't have "how to" sections in the manual, but for this specific topic, perhaps we could add a subsection under "The Guile module system"? Note that control over a module's name space (as described in my post) is not the only thing needed to safely evaluate untrusted code. The user would also need finer control over all the resources used by the code at hand (in order to prevent DoS attacks), particularly memory (heap and stack) and CPU. Unfortunately, I don't think this can be realized using Guile, except maybe by running the untrusted code in a separate process and relying on the OS' resource accounting mechanisms (e.g., `setrlimit' --- but Guile core doesn't provide bindings for it). However, running untrusted code in a separate process would preclude, practically, resource sharing with the user's trusted code (e.g., an Xchat Scheme plug-in would be useless as a separate process because it would be unable to access the data structures of the "real" Xchat). The "ideal" solution would imply things like: * changing the evaluator so that several evaluators with different `eval-options' can be instantiated (pretty much like the `guile-reader' approach); this way, untrusted code could be evaluated with an evaluator that has custom stack limits; * having, roughly, a `current-heap' fluid that would be referred to anytime heap is allocated (hmm...); * similarly, have CPU time slice capabilities that would be passed to `eval' either explicitly or via a fluid. But, well, going back to the documentation issue at hand, perhaps we can just mention that Guile lacks certain features to allow for really safe execution of untrusted code. ;-) Thanks, Ludovic. _______________________________________________ Guile-user mailing list Guile-user@gnu.org http://lists.gnu.org/mailman/listinfo/guile-user ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: modify environments to make sandboxes 2006-06-22 12:34 ` Ludovic Courtès @ 2006-06-22 18:36 ` Alan Grover 2006-06-23 14:22 ` Ludovic Courtès 0 siblings, 1 reply; 7+ messages in thread From: Alan Grover @ 2006-06-22 18:36 UTC (permalink / raw) Ludovic Courtès wrote: > Hi, > > Neil Jerram <neil@ossau.uklinux.net> writes: > > >>ludovic.courtes@laas.fr (Ludovic Courtès) writes: >> >> >>>Code confinement is indeed an interesting feature. Fortunately, Guile >>>offers various ways to do it (AFAIK, there's no standard way to do this >>>in R5RS Scheme). :-) [...] One approach is to write your own security-manager/white-list. You scan the s-expr, check the symbols in the head of any (sub-)list, and fail if they aren't approved. The comments of http://schemecookbook.org/Cookbook/DynamicUntrustedEval gives an outline of how to do this (minus parsing). You actually have to parse a bit: so you can ignore argument-lists to lambda, the variables in "let", etc. An example parser is in your guile distribution, scripts/lint, see the detect-free-variables procedure (usually somewhere like /usr/share/guile/1.6/scripts). Of course, you don't have to parse if you don't allow let/lambda and friends. I think there is a R5RS way of doing code-confinement. The R5RS spec says that the null-environment "is empty except for the (syntactic) bindings for all syntactic keywords defined in this report that are either required or both optional and supported by the implementation." I take it to mean that you are guaranteed the required keywords, might have the optional keywords, but won't have anything else. So, you could do this: (define (safe-eval s-expr) (let* ( (lambda-expr-that-provides-some-procs ; extend null-environment with "+" `(lambda (+) ,s-expr)) (actual-lambda (eval lambda-expr-that-provides-some-procs (null-environment 5)))) (actual-lambda +))) ; provide + (safe-eval '(begin (define (x y) 1) (x 2))) (safe-eval '1) (safe-eval '(+ 1 2)) (safe-eval '(- 1 2)) ; fails, there is no "-" available You can provide more procedures where I just provided "+". The trick has two parts: * Eval the untrusted expression in null-environment. A minimum of procedures/etc. is available. * "import" the other-procedures by providing them to a lambda, which provides the lexical environment. You could "black-list" keywords, maybe like this: (define (safe-eval s-expr) (let* ( (lambda-expr-that-provides-some-procs `(lambda (+ error) ; re-bind "define" to something that won't work (let ((define (lambda args (error "Not allowed")))) ,s-expr))) (actual-lambda (eval lambda-expr-that-provides-some-procs (null-environment 5)))) (actual-lambda + error))) (safe-eval '1) (safe-eval '(+ 1 2)) (safe-eval '(begin (define (x y) 1) (x 2))) But, note that this doesn't quite fail the way you want: it will eval (x y) and then call the local "define", which means you'll get an unbound error on x. Well, at least you disabled "define". FYI, here's the list of symbols in null-environment for guile 1.6: and begin case cond define define-syntax delay do if lambda let let* let-syntax letrec letrec-syntax or quasiquote quote set! Beware, you have to provide a comprehensive black-list. Imagine if the guile 1.6 null-environment didn't include every optional-keyword, but 1.8 did. Untrusted code could take advantage of the difference. You also have to carefully consider the impact of allowing any keyword. For example, "let" would allow the untrusted code to do an infinite loop (via named-let). I can't find the place where I originally found this method, but there is another example at http://www.cap-lore.com/CapTheory/Language/Scheme/SchemeFactory.html and the preceding pages. You may want to read these pages to understand some other issues around untrusted code. And in thread: http://ecos.sourceware.org/ml/guile/1999-02/msg00233.html > Note that control over a module's name space (as described in my post) > is not the only thing needed to safely evaluate untrusted code. The > user would also need finer control over all the resources used by the > code at hand (in order to prevent DoS attacks), particularly memory > (heap and stack) and CPU. > > Unfortunately, I don't think this can be realized using Guile, except > maybe by running the untrusted code in a separate process and relying on > the OS' resource accounting mechanisms (e.g., `setrlimit' --- but Guile > core doesn't provide bindings for it). However, running untrusted code > in a separate process would preclude, practically, resource sharing with > the user's trusted code (e.g., an Xchat Scheme plug-in would be useless > as a separate process because it would be unable to access the data > structures of the "real" Xchat). > > The "ideal" solution would imply things like: > > * changing the evaluator so that several evaluators with different > `eval-options' can be instantiated (pretty much like the > `guile-reader' approach); this way, untrusted code could be > evaluated with an evaluator that has custom stack limits; > > * having, roughly, a `current-heap' fluid that would be referred to > anytime heap is allocated (hmm...); > > * similarly, have CPU time slice capabilities that would be passed > to `eval' either explicitly or via a fluid. You can also write a safe-interpreter in scheme, and thus in the same process. You solve the above issues by charging the expression each time it applies a procedure, each time it consumes heap (roughly at each "cons"), etc. This one is for chicken: http://www.call-with-current-continuation.org/eggs/sandbox.scm And, again, I can't locate a reference to the original example of this, I believe it was R5RS though. _______________________________________________ Guile-user mailing list Guile-user@gnu.org http://lists.gnu.org/mailman/listinfo/guile-user ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: modify environments to make sandboxes 2006-06-22 18:36 ` Alan Grover @ 2006-06-23 14:22 ` Ludovic Courtès 0 siblings, 0 replies; 7+ messages in thread From: Ludovic Courtès @ 2006-06-23 14:22 UTC (permalink / raw) Cc: guile-user Hi, Thanks for your comments and the nice links! Alan Grover <awgrover@mail.msen.com> writes: > One approach is to write your own security-manager/white-list. You scan > the s-expr, check the symbols in the head of any (sub-)list, and fail if > they aren't approved. I don't really like this approach, it looks quite "ugly" and impractical IMO, and it could only be made to work when one has access to the source code. Instead, evaluating untrusted code in an environment that only provides access to the necessary bindings and resources (as I suggested), thereby honoring the principle of least authority (POLA), really looks nicer. > I think there is a R5RS way of doing code-confinement. The R5RS spec > says that the null-environment "is empty except for the (syntactic) > bindings for all syntactic keywords defined in this report that are > either required or both optional and supported by the implementation." I > take it to mean that you are guaranteed the required keywords, might > have the optional keywords, but won't have anything else. Right. Then you still lack control over the resources used by the untrusted code. > Beware, you have to provide a comprehensive black-list. Imagine if the > guile 1.6 null-environment didn't include every optional-keyword, but > 1.8 did. Untrusted code could take advantage of the difference. You also > have to carefully consider the impact of allowing any keyword. For > example, "let" would allow the untrusted code to do an infinite loop > (via named-let). Good point: "black listing" is obviously more risky than "white listing" because you can always forget an important binding. > I can't find the place where I originally found this method, but there > is another example at > http://www.cap-lore.com/CapTheory/Language/Scheme/SchemeFactory.html > and the preceding pages. You may want to read these pages to understand > some other issues around untrusted code. This is a very nice reading. It also refers to Jonathan Reed's ``A Security Kernel Based on the Lambda-Calculus'' [0] which I'm going to read as soon as I can! :-) >> The "ideal" solution would imply things like: >> >> * changing the evaluator so that several evaluators with different >> `eval-options' can be instantiated (pretty much like the >> `guile-reader' approach); this way, untrusted code could be >> evaluated with an evaluator that has custom stack limits; >> >> * having, roughly, a `current-heap' fluid that would be referred to >> anytime heap is allocated (hmm...); >> >> * similarly, have CPU time slice capabilities that would be passed >> to `eval' either explicitly or via a fluid. > > You can also write a safe-interpreter in scheme, and thus in the same > process. You solve the above issues by charging the expression each time > it applies a procedure, each time it consumes heap (roughly at each > "cons"), etc. The changes I was describing are the minimal changes that look necessary to write such a "safe interpreter" (you don't need that if you run the untrusted code as a separate process: you can rely on `setrlimit' and friends). As for control over heap allocation: unfortunately, rebinding `cons' to a restricted version of `cons' (for instance, once that enforces some quota) would not be sufficient in Guile. This is because, for instance, memory for SMOBs, vectors, etc., is not allocated via `cons'. Controlling calls to `scm_cell ()' would be better, but still insufficient. And anyway, one could hardly control the heap used by SMOBs (because there's more than one way SMOBs can allocate memory)... (Of course, we are clearly not considering invocation of untrusted C code by the untrusted Scheme code!) > This one is for chicken: > http://www.call-with-current-continuation.org/eggs/sandbox.scm > And, again, I can't locate a reference to the original example of this, > I believe it was R5RS though. Hmm, I'm not sure I understand how it works. Thanks, Ludovic. [0] http://mumble.net/~jar/pubs/secureos/ _______________________________________________ Guile-user mailing list Guile-user@gnu.org http://lists.gnu.org/mailman/listinfo/guile-user ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: modify environments to make sandboxes 2006-06-12 16:20 modify environments to make sandboxes Mildred 2006-06-12 16:47 ` Ludovic Courtès @ 2006-06-28 4:13 ` Jon Wilson 1 sibling, 0 replies; 7+ messages in thread From: Jon Wilson @ 2006-06-28 4:13 UTC (permalink / raw) Cc: guile-user Hi all, How about having the ability to capture the current lexical environment and use it as an environment for eval? Something like call/cc, but I guess call/env. In essence, this would make environments useful as first class objects (perhaps). (define my-env #f) (let ((a 0) (b 1) (c 2)) (call/env (lambda (x) (set! my-env x)))) (eval '(begin (display a) (newline) (display b) (newline) (display c) (newline) (display my-env) (newline)) my-env) >> prints: 0 1 2 #<environment 0xDEADBEEF> Perhaps an unlet would also be useful. This would create a lexical environment in which several variables were unbound. (unlet (eval read load) (call/env (lambda (x) (set! my-env x)))) (eval '(eval '(+ 1 2)) my-env) => #error Hmmm, perhaps this idea (unlet) couldn't work in any kind of a sensible, simple, lexical scoping system. Maybe unlet could just set the variables given to it to #<unspecified> or #f or something. So, which extant language feature have I overlooked that provides more or less exactly this? :) Regards, Jon Mildred wrote: > Hi, > > I'm new to this mailing list and also new to the scheme language ... > I'm used to Lua but I try to search about functionnal programming, and > I found scheme. It looks like a good language but before using it in my > projects I would like to know if tere is an easy way to create > sandboxes. > > In lua, it is easy, you create a table containing functions ... and the > table can be made environment for a function. So, you can easily create > secure sandboxes by loading lua code from file and changing the > environment of the loaded code. > > I do not know how to do that in scheme. Apparetly the function > null-environment can return an environment and eval can evaluate some > code in an environment. But the question is how to define a variable in > an environment and also how to undefine a variable that you don't want > to appear. > I didn't found anything about modifying an environment. Is it > possible ? If not, why not ? and is it possible to create sandboxes ? > Thanks > > Mildred > _______________________________________________ Guile-user mailing list Guile-user@gnu.org http://lists.gnu.org/mailman/listinfo/guile-user ^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2006-06-28 4:13 UTC | newest] Thread overview: 7+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2006-06-12 16:20 modify environments to make sandboxes Mildred 2006-06-12 16:47 ` Ludovic Courtès 2006-06-12 22:05 ` Neil Jerram 2006-06-22 12:34 ` Ludovic Courtès 2006-06-22 18:36 ` Alan Grover 2006-06-23 14:22 ` Ludovic Courtès 2006-06-28 4:13 ` Jon Wilson
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).