Re: [racket-users] Creating truly unique instances of structure types?

2018-11-08 Thread Matthew Flatt
At Mon, 5 Nov 2018 16:26:16 -0600, Alexis King wrote:
> To provide an example, `racket/contract` exports a value called 
> `the-unsupplied-arg`, which is created using the usual structure type 
> generativity trick:
> 
> (define-struct the-unsupplied-arg ())
> (define the-unsupplied-arg (make-the-unsupplied-arg))
> (provide the-unsupplied-arg)
> 
> The constructor is not exported, and this value is intended to be unique. 
> However, if we can arrange for the contract library to be loaded on our 
> terms, 
> we can thwart this encapsulation by supplying it with a weaker inspector:
> 
> #lang racket/base
> 
> (define the-unsupplied-arg
>   (parameterize ([current-inspector (make-inspector)])
> (dynamic-require 'racket/contract 'the-unsupplied-arg)))
> 
> (define-values [info skipped?] (struct-info the-unsupplied-arg))
> 
> (define another-unsupplied-arg ((struct-type-make-constructor info)))
> 
> (equal? the-unsupplied-arg another-unsupplied-arg) ; => #t
> (eq? the-unsupplied-arg another-unsupplied-arg); => #f

Later parts of the thread have touched on this, but the general rule is
that if you control the environment where code is loaded, then you can
do anything to that code. After all, if you get to pick the
environment, then you could use an interpreter that you wrote from
scratch and that gives you whatever capabilities you want.[*]

If you don't control the environment of `racket/contract`, then you
might not be able to break in this way. It depends on how the
environment is set up, though. If `racket/contract` is loaded before
your code, then it's too late to change the inspector, but maybe you
can load `ffi/unsafe` and still do whatever you want. Or maybe your
code is prevented from loading `ffi/unsafe` directly due to a
code-inspector change, but some sandbox bug or a bug in a trusted
library lets you get access to unsafe operations anyway.

Chaperones and inspectors provide a set of ground rules for access, and
`the-unsupplied-arg` is unique for a setting that respects those rules.
A program can subvert the rules through outside control or through
environment weaknesses. We've tried to build mechanisms that absolutely
enforce the rules, and it works well enough for some purposes, but
offering real guarantees turns out to be impractical for now.

It seems possible that if a sandbox is working right and if unsafe
operations are truly inaccessible, then maybe currently a chaperone is
enough to guard against even a superior inspector. But that doesn't
seem like a good solution to me. Instead, it makes me think that there
should be an operation that lets a sufficiently powerful inspector pull
apart chaperones.

[*] There's some work on encrypted computation where the environment
executing some code can't know everything about the code. I'm guess
that's not where you're trying to go, though.

-- 
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] Creating truly unique instances of structure types?

2018-11-06 Thread Ryan Culpepper

On 11/6/18 11:31 AM, Alexis King wrote:

On Nov 5, 2018, at 20:01, Ryan Culpepper  wrote:

You could use a chaperone to prohibit `struct-info`


Good point! I had forgotten that `struct-info` is a chaperoneable operation. 
This isn’t ideal, though, since I don’t think `struct-info` is ever actually 
supposed to raise an error, it’s just supposed to return #f, instead. It’s 
possible to call `struct-info` on absolutely anything, even things like 
numbers, and get a result:

> (struct-info 3)
#f
#t

If I understand correctly, this is because all values in Racket are “morally 
structures”, and reflective operations on values that are not actually 
implemented with structures should behave identically to reflective operations 
on values for which you do not have a sufficiently powerful inspector to 
inspect.

Unfortunately, it isn’t possible to regain this behavior with 
`impersonate-struct`, since `impersonate-struct` does not allow you to 
impersonate `struct-info`.


One solution is to delay the error by having `struct-info` return a 
chaperoned struct-type (using `chaperone-struct-type`) that makes 
`struct-type-make-constructor` raise an error. The struct-type chaperone 
should also prevent the creation of substruct instances (say, by adding 
a guard that always raises an error).


It seems like it should also be reasonable to let the `struct-info` 
interposition replace a struct type with #f, since that represents less 
information at the level of the *interpretation* of the operation. So 
it's morally a projection wrt the information ordering for the 
`struct-info` operation, even though it's not a projection wrt the 
generic information ordering for Racket values.


Ryan

--
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] Creating truly unique instances of structure types?

2018-11-06 Thread Alexis King
> On Nov 5, 2018, at 20:01, Ryan Culpepper  wrote:
> 
> You could use a chaperone to prohibit `struct-info`

Good point! I had forgotten that `struct-info` is a chaperoneable operation. 
This isn’t ideal, though, since I don’t think `struct-info` is ever actually 
supposed to raise an error, it’s just supposed to return #f, instead. It’s 
possible to call `struct-info` on absolutely anything, even things like 
numbers, and get a result:

> (struct-info 3)
#f
#t

If I understand correctly, this is because all values in Racket are “morally 
structures”, and reflective operations on values that are not actually 
implemented with structures should behave identically to reflective operations 
on values for which you do not have a sufficiently powerful inspector to 
inspect.

Unfortunately, it isn’t possible to regain this behavior with 
`impersonate-struct`, since `impersonate-struct` does not allow you to 
impersonate `struct-info`.

> On Nov 6, 2018, at 02:47, Philip McGrath  wrote:
> 
> A variant on Alexis' example lets you circumvent Typed Racket's protections:
> 
> [snip]
> 
> Maybe this is well-known to everyone who's thought about it before, but I 
> hadn't. Though I guess, while I don't think about inspectors very often, I 
> think of them as a way for one module to put others under its control, in 
> which case maybe the module with the more powerful inspector should be able 
> to break subordinate modules' invariants.

I’m not sure, either. Personally, I feel like it should be possible to have 
invariants that truly cannot be broken, but maybe there are use cases I don’t 
understand. Anyway, in the case of Typed Racket, this is clearly a soundness 
hole, but a fixable one — either Typed Racket or the contract system is not 
applying `chaperone-struct-type` where it ought to be. I’ll file a bug.

Alexis

-- 
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] Creating truly unique instances of structure types?

2018-11-06 Thread Philip McGrath
A variant on Alexis' example lets you circumvent Typed Racket's protections:

#lang racket

(module typed typed/racket
  (provide wrapper use)
  (struct wrapper ([v : Integer]))
  (: use (-> wrapper Integer))
  (define (use w)
(add1 (wrapper-v w

(require racket/runtime-path)

(define-runtime-module-path typed
  (submod "." typed))

(define-values {wrapper use}
  (parameterize ([current-inspector (make-inspector)])
(values (dynamic-require typed 'wrapper)
(dynamic-require typed 'use

(define unchecked-wrapper
  (let-values ([(info skipped?)
(struct-info (wrapper 0))])
(struct-type-make-constructor info)))

(use (unchecked-wrapper 'nonsense))

Maybe this is well-known to everyone who's thought about it before, but I
hadn't. Though I guess, while I don't think about inspectors very often, I
think of them as a way for one module to put others under its control, in
which case maybe the module with the more powerful inspector *should* be
able to break subordinate modules' invariants.

-Philip


On Mon, Nov 5, 2018 at 9:01 PM Ryan Culpepper  wrote:

> On 11/5/18 5:26 PM, Alexis King wrote:
> > To my knowledge, there are two main techniques for creating unique
> values in Racket: `gensym` and structure type generativity. The former
> seems to be bulletproof — a value created with `gensym` will never be
> `equal?` to anything except itself – but the latter isn’t. Using reflective
> operations, it’s possible to circumvent the encapsulation afforded by the
> module system.
> >
> > To provide an example, `racket/contract` exports a value called
> `the-unsupplied-arg`, which is created using the usual structure type
> generativity trick:
> >
> > (define-struct the-unsupplied-arg ())
> > (define the-unsupplied-arg (make-the-unsupplied-arg))
> > (provide the-unsupplied-arg)
> >
> > The constructor is not exported, and this value is intended to be
> unique. However, if we can arrange for the contract library to be loaded on
> our terms, we can thwart this encapsulation by supplying it with a weaker
> inspector:
> >
> > #lang racket/base
> >
> > (define the-unsupplied-arg
> >   (parameterize ([current-inspector (make-inspector)])
> > (dynamic-require 'racket/contract 'the-unsupplied-arg)))
> >
> > (define-values [info skipped?] (struct-info the-unsupplied-arg))
> >
> > (define another-unsupplied-arg ((struct-type-make-constructor info)))
> >
> > (equal? the-unsupplied-arg another-unsupplied-arg) ; => #t
> > (eq? the-unsupplied-arg another-unsupplied-arg); => #f
> >
> > Perhaps this isn’t the end of the world, as after all, we can’t do
> anything especially nefarious with this value, and we wouldn’t be able to
> do it in the first place if we didn’t have complete control of the
> inspector hierarchy. Still, it seems a little unsatisfying.
> >
> > So, my question: is there any way to create a structure type for which
> there can truly ever only be one instance? If not, is there a fundamental
> reason why not?
>
> You could use a chaperone to prohibit `struct-info`:
>
>(define the-unsupplied-arg
>  (chaperone-struct (make-the-unsupplied-arg)
>struct:unsupplied-arg
>struct-info (lambda _ (error "not allowed"
>
> Ryan
>
> --
> 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.
>

-- 
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] Creating truly unique instances of structure types?

2018-11-05 Thread Ryan Culpepper

On 11/5/18 5:26 PM, Alexis King wrote:

To my knowledge, there are two main techniques for creating unique values in 
Racket: `gensym` and structure type generativity. The former seems to be 
bulletproof — a value created with `gensym` will never be `equal?` to anything 
except itself – but the latter isn’t. Using reflective operations, it’s 
possible to circumvent the encapsulation afforded by the module system.

To provide an example, `racket/contract` exports a value called 
`the-unsupplied-arg`, which is created using the usual structure type 
generativity trick:

(define-struct the-unsupplied-arg ())
(define the-unsupplied-arg (make-the-unsupplied-arg))
(provide the-unsupplied-arg)

The constructor is not exported, and this value is intended to be unique. 
However, if we can arrange for the contract library to be loaded on our terms, 
we can thwart this encapsulation by supplying it with a weaker inspector:

#lang racket/base

(define the-unsupplied-arg
  (parameterize ([current-inspector (make-inspector)])
(dynamic-require 'racket/contract 'the-unsupplied-arg)))

(define-values [info skipped?] (struct-info the-unsupplied-arg))

(define another-unsupplied-arg ((struct-type-make-constructor info)))

(equal? the-unsupplied-arg another-unsupplied-arg) ; => #t
(eq? the-unsupplied-arg another-unsupplied-arg); => #f

Perhaps this isn’t the end of the world, as after all, we can’t do anything 
especially nefarious with this value, and we wouldn’t be able to do it in the 
first place if we didn’t have complete control of the inspector hierarchy. 
Still, it seems a little unsatisfying.

So, my question: is there any way to create a structure type for which there 
can truly ever only be one instance? If not, is there a fundamental reason why 
not?


You could use a chaperone to prohibit `struct-info`:

  (define the-unsupplied-arg
(chaperone-struct (make-the-unsupplied-arg)
  struct:unsupplied-arg
  struct-info (lambda _ (error "not allowed"

Ryan

--
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.


[racket-users] Creating truly unique instances of structure types?

2018-11-05 Thread Alexis King
To my knowledge, there are two main techniques for creating unique values in 
Racket: `gensym` and structure type generativity. The former seems to be 
bulletproof — a value created with `gensym` will never be `equal?` to anything 
except itself – but the latter isn’t. Using reflective operations, it’s 
possible to circumvent the encapsulation afforded by the module system.

To provide an example, `racket/contract` exports a value called 
`the-unsupplied-arg`, which is created using the usual structure type 
generativity trick:

(define-struct the-unsupplied-arg ())
(define the-unsupplied-arg (make-the-unsupplied-arg))
(provide the-unsupplied-arg)

The constructor is not exported, and this value is intended to be unique. 
However, if we can arrange for the contract library to be loaded on our terms, 
we can thwart this encapsulation by supplying it with a weaker inspector:

#lang racket/base

(define the-unsupplied-arg
  (parameterize ([current-inspector (make-inspector)])
(dynamic-require 'racket/contract 'the-unsupplied-arg)))

(define-values [info skipped?] (struct-info the-unsupplied-arg))

(define another-unsupplied-arg ((struct-type-make-constructor info)))

(equal? the-unsupplied-arg another-unsupplied-arg) ; => #t
(eq? the-unsupplied-arg another-unsupplied-arg); => #f

Perhaps this isn’t the end of the world, as after all, we can’t do anything 
especially nefarious with this value, and we wouldn’t be able to do it in the 
first place if we didn’t have complete control of the inspector hierarchy. 
Still, it seems a little unsatisfying.

So, my question: is there any way to create a structure type for which there 
can truly ever only be one instance? If not, is there a fundamental reason why 
not?

Alexis

-- 
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.