[racket-users] Questions about module encapsulation guarantees
If I make a symbol with `gensym` (or do anything else that creates a new value that's not `eq?` to any other value) in some module, what are the absolute upper limits on my ability to use that symbol within the module without allowing any other modules to get ahold of the symbol? What do code inspectors, namespaces, sandboxes, eval, `unsafe` APIs, the FFI, etc. make possible for malicious code in external modules? Context: I'm exploring a "contract witness" idea whose implementation currently relies on the eq?-ness of opaque struct instances for security. But I vaguely recall hearing once that the The Only Way To Be Sure when it comes to struct encapsulation is to put the definition of a struct inside a lambda, otherwise some sort of nebulous "bad things" are possible in external code that wants to break the invariants of a struct type. -- You received this message because you are subscribed to the Google Groups "Racket Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: [racket-users] Questions about module encapsulation guarantees
At Sun, 9 Sep 2018 18:52:57 -0700 (PDT), Jack Firth wrote: > If I make a symbol with `gensym` (or do anything else that creates a new > value that's not `eq?` to any other value) in some module, what are the > absolute upper limits on my ability to use that symbol within the module > without allowing any other modules to get ahold of the symbol? What do code > inspectors, namespaces, sandboxes, eval, `unsafe` APIs, the FFI, etc. make > possible for malicious code in external modules? If you don't change the code inspector, than a third party can get into the module body's namespace. So, if you bind the gensym with a definition, that will be easy to see. If you retain the symbol only through a closure, as cwebber shows, then getting to the gensym is trickier, but it's still possible via unsafe APIs. Setting the code inspector should prevent access to unsafe APIs or anything else that can inspect arbitrary data --- modulo bugs in the runtime system, of course, but also any bugs in a module that might make use of unsafe features and get loaded before the code inspector is changed. > Context: I'm exploring a "contract witness" idea whose implementation > currently relies on the eq?-ness of opaque struct instances for security. > But I vaguely recall hearing once that the The Only Way To Be Sure when it > comes to struct encapsulation is to put the definition of a struct inside a > lambda, otherwise some sort of nebulous "bad things" are possible in > external code that wants to break the invariants of a struct type. The only difference between being under a `lambda` and not should be whether the relevant module or top-level namespace is accessible to the code that you don't trust. Changing the code inspector disables `module->namespace`. Meanwhile, access to the struct content otherwise would need a more powerful inspector (i.e., you don't have to change the inspector, but merely refrain from changing it to an ancestor of the one used to create the structure type). -- You received this message because you are subscribed to the Google Groups "Racket Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Sealers/unsealers in Racket (Re: [racket-users] Questions about module encapsulation guarantees)
Jack Firth writes: > If I make a symbol with `gensym` (or do anything else that creates a new > value that's not `eq?` to any other value) in some module, what are the > absolute upper limits on my ability to use that symbol within the module > without allowing any other modules to get ahold of the symbol? What do code > inspectors, namespaces, sandboxes, eval, `unsafe` APIs, the FFI, etc. make > possible for malicious code in external modules? > > Context: I'm exploring a "contract witness" idea whose implementation > currently relies on the eq?-ness of opaque struct instances for security. > But I vaguely recall hearing once that the The Only Way To Be Sure when it > comes to struct encapsulation is to put the definition of a struct inside a > lambda, otherwise some sort of nebulous "bad things" are possible in > external code that wants to break the invariants of a struct type. Struct inside a function is certainly a way to do it. You may be interested in the idea of sealer/unsealer pairs from the object capability world. I borrowed the implementation of this from Jonathan Rees' W7 code. Consider this waived into the public domain, under CC0, but also with any potential patents waived under the same terms. Imagine the ability to make a magical canning kit and a can opener, where the cans produced can only be opened by the respective can opener. ; Create a new sealer / unsealer pair and sealed? predicate ; sealer-name is optional and just for debugging help (define (new-seal [sealer-name #f]) (define struct-name (if sealer-name (string->symbol (string-append "sealed-by-" (symbol->string sealer-name))) 'sealed)) (define-values (struct:seal seal sealed? seal-ref seal-set!) (make-struct-type struct-name #f 1 0)) (define unseal (make-struct-field-accessor seal-ref 0)) (values seal unseal sealed?)) Now let's try using it: (define-values (can-sealer can-unseal can-seal?) (new-seal 'canning-factory)) The traditional ocap example is to seal tuna, but I'm vegetarian. (define lunch (seal "chickpea salad")) lunch ; # I'm in control of the sealer from my little canning factory, I don't give it to anyone else. Only someone with the matching unsealer can open this can. I can safely put it in the fridge. I can make sure this can is my lunch, in case I forgot: (can-sealed? lunch) ; #t And I can get to its contents: (can-unseal lunch) ; "chickpea salad" Not that this looks a lot like decryption, but with lexical scope only. It's possible I am okay with someone else opening my objects, in which case I might give them the can-sealed? predicate and the can-unseal procedure... then they can open it, but be sure it's from me. And with that you can more or less implement signatures. BTW, you can do powerful stuff with this... here's an example where you implement digital money: http://erights.org/elib/capability/ode/ode-capabilities.html Here's the same example from that article, written in Racket code: (define (make-mint name) (define-values (sealer unsealer sealed?) (new-seal name)) (define/contract mint% (class/c [make-purse (->m nonnegative-integer? any/c)]) (class* object% (writable<%>) (super-new) (define/public (custom-display p) (display (format "#<~a mint>" name) p)) (define/public (custom-write p) (custom-display p)) (define this-mint this) (define/public (make-purse balance) (define/contract (decr amount) (-> (and/c (>=/c 0) (lambda (amt) (<= amt balance))) void?) (set! balance (- balance amount))) (define/contract purse% (class/c [get-balance (->m integer?)] [deposit (->m integer? any/c void?)]) (class* object% (writable<%>) (super-new) (define/public (custom-display p) (display (format "#" balance name) p)) (define/public (custom-write p) (custom-display p)) (define/public (get-balance) balance) (define/public (sprout) (send this-mint make-purse 0)) (define/public (get-decr) (sealer decr)) (define/public (deposit amount src) ((unsealer (send src get-decr)) amount) (set! balance (+ balance amount)) (void (new purse% (new mint%)) (module+ test (define carol-mint (make-mint 'Carol)) (define alice-main-purse (send carol-mint make-purse 1000)) (define bob (new (class object% (super-new) (define bob-main-purse (send carol-mint make-purse 0)) (define/public (go-on-ride payment) (send bob-main-purse deposit 10 payment) (displayln "Whee!
Re: Sealers/unsealers in Racket (Re: [racket-users] Questions about module encapsulation guarantees)
> On Sep 10, 2018, at 10:09 AM, Christopher Lemmer Webber > wrote: > > Jack Firth writes: > >> If I make a symbol with `gensym` (or do anything else that creates a new >> value that's not `eq?` to any other value) in some module, what are the >> absolute upper limits on my ability to use that symbol within the module >> without allowing any other modules to get ahold of the symbol? What do code >> inspectors, namespaces, sandboxes, eval, `unsafe` APIs, the FFI, etc. make >> possible for malicious code in external modules? >> >> Context: I'm exploring a "contract witness" idea whose implementation >> currently relies on the eq?-ness of opaque struct instances for security. >> But I vaguely recall hearing once that the The Only Way To Be Sure when it >> comes to struct encapsulation is to put the definition of a struct inside a >> lambda, otherwise some sort of nebulous "bad things" are possible in >> external code that wants to break the invariants of a struct type. > > Struct inside a function is certainly a way to do it. You may be > interested in the idea of sealer/unsealer pairs from the object > capability world. I borrowed the implementation of this from Jonathan > Rees' W7 code. Consider this waived into the public domain, under CC0, > but also with any potential patents waived under the same terms. > Does this really differ from Jim Morris’s sealing? -- You received this message because you are subscribed to the Google Groups "Racket Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: Sealers/unsealers in Racket (Re: [racket-users] Questions about module encapsulation guarantees)
This is a very cool thing, but may I suggest choosing a different name than 'can'? '(can-unseal lunch)' reads less like a verb and more like a predicate where someone forgot the '?' -- "Are you able to unseal lunch?" as opposed to "Unseal my lunch now". On Mon, Sep 10, 2018 at 11:09 AM, Christopher Lemmer Webber < cweb...@dustycloud.org> wrote: > Jack Firth writes: > > > If I make a symbol with `gensym` (or do anything else that creates a new > > value that's not `eq?` to any other value) in some module, what are the > > absolute upper limits on my ability to use that symbol within the module > > without allowing any other modules to get ahold of the symbol? What do > code > > inspectors, namespaces, sandboxes, eval, `unsafe` APIs, the FFI, etc. > make > > possible for malicious code in external modules? > > > > Context: I'm exploring a "contract witness" idea whose implementation > > currently relies on the eq?-ness of opaque struct instances for security. > > But I vaguely recall hearing once that the The Only Way To Be Sure when > it > > comes to struct encapsulation is to put the definition of a struct > inside a > > lambda, otherwise some sort of nebulous "bad things" are possible in > > external code that wants to break the invariants of a struct type. > > Struct inside a function is certainly a way to do it. You may be > interested in the idea of sealer/unsealer pairs from the object > capability world. I borrowed the implementation of this from Jonathan > Rees' W7 code. Consider this waived into the public domain, under CC0, > but also with any potential patents waived under the same terms. > > Imagine the ability to make a magical canning kit and a can opener, > where the cans produced can only be opened by the respective can opener. > > ; Create a new sealer / unsealer pair and sealed? predicate > ; sealer-name is optional and just for debugging help > (define (new-seal [sealer-name #f]) > (define struct-name > (if sealer-name > (string->symbol (string-append "sealed-by-" (symbol->string > sealer-name))) > 'sealed)) > (define-values (struct:seal seal sealed? seal-ref seal-set!) > (make-struct-type struct-name #f 1 0)) > (define unseal > (make-struct-field-accessor seal-ref 0)) > (values seal unseal sealed?)) > > Now let's try using it: > > (define-values (can-sealer can-unseal can-seal?) > (new-seal 'canning-factory)) > > The traditional ocap example is to seal tuna, but I'm vegetarian. > > (define lunch (seal "chickpea salad")) > > lunch ; # > > I'm in control of the sealer from my little canning factory, I don't > give it to anyone else. Only someone with the matching unsealer can > open this can. I can safely put it in the fridge. > > I can make sure this can is my lunch, in case I forgot: > > (can-sealed? lunch) ; #t > > And I can get to its contents: > > (can-unseal lunch) ; "chickpea salad" > > Not that this looks a lot like decryption, but with lexical scope only. > It's possible I am okay with someone else opening my objects, in which > case I might give them the can-sealed? predicate and the can-unseal > procedure... then they can open it, but be sure it's from me. And > with that you can more or less implement signatures. > > BTW, you can do powerful stuff with this... here's an example where > you implement digital money: > > http://erights.org/elib/capability/ode/ode-capabilities.html > > Here's the same example from that article, written in Racket code: > > (define (make-mint name) > (define-values (sealer unsealer sealed?) > (new-seal name)) > (define/contract mint% > (class/c [make-purse (->m nonnegative-integer? any/c)]) > (class* object% (writable<%>) > (super-new) > (define/public (custom-display p) > (display (format "#<~a mint>" name) p)) > (define/public (custom-write p) > (custom-display p)) > > (define this-mint this) > (define/public (make-purse balance) > (define/contract (decr amount) > (-> (and/c (>=/c 0) >(lambda (amt) > (<= amt balance))) > void?) > (set! balance (- balance amount))) > (define/contract purse% > (class/c [get-balance (->m integer?)] > [deposit (->m integer? any/c void?)]) > (class* object% (writable<%>) > (super-new) > > (define/public (custom-display p) > (display (format "#" balance name) p)) > (define/public (custom-write p) > (custom-display p)) > > (define/public (get-balance) > balance) > (define/public (sprout) > (send this-mint make-purse 0)) > (define/public (get-decr) > (sealer decr)) > > (define/public (deposit amount src) > ((un
Re: Sealers/unsealers in Racket (Re: [racket-users] Questions about module encapsulation guarantees)
Matthias Felleisen writes: >> On Sep 10, 2018, at 10:09 AM, Christopher Lemmer Webber >> wrote: >> >> Jack Firth writes: >> >>> If I make a symbol with `gensym` (or do anything else that creates a new >>> value that's not `eq?` to any other value) in some module, what are the >>> absolute upper limits on my ability to use that symbol within the module >>> without allowing any other modules to get ahold of the symbol? What do code >>> inspectors, namespaces, sandboxes, eval, `unsafe` APIs, the FFI, etc. make >>> possible for malicious code in external modules? >>> >>> Context: I'm exploring a "contract witness" idea whose implementation >>> currently relies on the eq?-ness of opaque struct instances for security. >>> But I vaguely recall hearing once that the The Only Way To Be Sure when it >>> comes to struct encapsulation is to put the definition of a struct inside a >>> lambda, otherwise some sort of nebulous "bad things" are possible in >>> external code that wants to break the invariants of a struct type. >> >> Struct inside a function is certainly a way to do it. You may be >> interested in the idea of sealer/unsealer pairs from the object >> capability world. I borrowed the implementation of this from Jonathan >> Rees' W7 code. Consider this waived into the public domain, under CC0, >> but also with any potential patents waived under the same terms. > > Does this really differ from Jim Morris’s sealing? Not only does it not differ, it's cited on the page... this is just an implementation :) >From http://erights.org/elib/capability/ode/ode-capabilities.html : > Two common forms of rights amplification are sibling communication > [Hardy, Gosling96, Shalit96] and sealer/unsealer pairs [Morris73, > Miller87, Tribble95 Appendix D, Rees96]. E primitively provides > sealer/unsealer pairs. The money example below builds sibling > communication from sealer/unsealer pairs. which links to: http://www.erights.org/history/morris73.pdf -- You received this message because you are subscribed to the Google Groups "Racket Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: Sealers/unsealers in Racket (Re: [racket-users] Questions about module encapsulation guarantees)
Good call, I'll be careful about that in future examples. David Storrs writes: > This is a very cool thing, but may I suggest choosing a different name than > 'can'? '(can-unseal lunch)' reads less like a verb and more like a > predicate where someone forgot the '?' -- "Are you able to unseal lunch?" > as opposed to "Unseal my lunch now". > > On Mon, Sep 10, 2018 at 11:09 AM, Christopher Lemmer Webber < > cweb...@dustycloud.org> wrote: > >> Jack Firth writes: >> >> > If I make a symbol with `gensym` (or do anything else that creates a new >> > value that's not `eq?` to any other value) in some module, what are the >> > absolute upper limits on my ability to use that symbol within the module >> > without allowing any other modules to get ahold of the symbol? What do >> code >> > inspectors, namespaces, sandboxes, eval, `unsafe` APIs, the FFI, etc. >> make >> > possible for malicious code in external modules? >> > >> > Context: I'm exploring a "contract witness" idea whose implementation >> > currently relies on the eq?-ness of opaque struct instances for security. >> > But I vaguely recall hearing once that the The Only Way To Be Sure when >> it >> > comes to struct encapsulation is to put the definition of a struct >> inside a >> > lambda, otherwise some sort of nebulous "bad things" are possible in >> > external code that wants to break the invariants of a struct type. >> >> Struct inside a function is certainly a way to do it. You may be >> interested in the idea of sealer/unsealer pairs from the object >> capability world. I borrowed the implementation of this from Jonathan >> Rees' W7 code. Consider this waived into the public domain, under CC0, >> but also with any potential patents waived under the same terms. >> >> Imagine the ability to make a magical canning kit and a can opener, >> where the cans produced can only be opened by the respective can opener. >> >> ; Create a new sealer / unsealer pair and sealed? predicate >> ; sealer-name is optional and just for debugging help >> (define (new-seal [sealer-name #f]) >> (define struct-name >> (if sealer-name >> (string->symbol (string-append "sealed-by-" (symbol->string >> sealer-name))) >> 'sealed)) >> (define-values (struct:seal seal sealed? seal-ref seal-set!) >> (make-struct-type struct-name #f 1 0)) >> (define unseal >> (make-struct-field-accessor seal-ref 0)) >> (values seal unseal sealed?)) >> >> Now let's try using it: >> >> (define-values (can-sealer can-unseal can-seal?) >> (new-seal 'canning-factory)) >> >> The traditional ocap example is to seal tuna, but I'm vegetarian. >> >> (define lunch (seal "chickpea salad")) >> >> lunch ; # >> >> I'm in control of the sealer from my little canning factory, I don't >> give it to anyone else. Only someone with the matching unsealer can >> open this can. I can safely put it in the fridge. >> >> I can make sure this can is my lunch, in case I forgot: >> >> (can-sealed? lunch) ; #t >> >> And I can get to its contents: >> >> (can-unseal lunch) ; "chickpea salad" >> >> Not that this looks a lot like decryption, but with lexical scope only. >> It's possible I am okay with someone else opening my objects, in which >> case I might give them the can-sealed? predicate and the can-unseal >> procedure... then they can open it, but be sure it's from me. And >> with that you can more or less implement signatures. >> >> BTW, you can do powerful stuff with this... here's an example where >> you implement digital money: >> >> http://erights.org/elib/capability/ode/ode-capabilities.html >> >> Here's the same example from that article, written in Racket code: >> >> (define (make-mint name) >> (define-values (sealer unsealer sealed?) >> (new-seal name)) >> (define/contract mint% >> (class/c [make-purse (->m nonnegative-integer? any/c)]) >> (class* object% (writable<%>) >> (super-new) >> (define/public (custom-display p) >> (display (format "#<~a mint>" name) p)) >> (define/public (custom-write p) >> (custom-display p)) >> >> (define this-mint this) >> (define/public (make-purse balance) >> (define/contract (decr amount) >> (-> (and/c (>=/c 0) >>(lambda (amt) >> (<= amt balance))) >> void?) >> (set! balance (- balance amount))) >> (define/contract purse% >> (class/c [get-balance (->m integer?)] >> [deposit (->m integer? any/c void?)]) >> (class* object% (writable<%>) >> (super-new) >> >> (define/public (custom-display p) >> (display (format "#" balance name) p)) >> (define/public (custom-write p) >> (custom-display p)) >> >> (define/public (get-balance) >> balance) >> (define/public (