Are Zones Global State? Do they provide a dangerous communications channel?


At a long meeting we had last Wednesday I gave Misko a hard time because I
thought the answers were yes and yes. I normally assume that the first
implies the second. In a wonderful hours long meeting, we came up with some
solutions to cope with the dangers I saw (ZoneRef, ...). These changes to
the API had some additional expense, but Misko and I talked ourselves into
thinking the expense was affordable. Daniel Ehrenberg then separately
expressed worry about this expense.

I was going to take the time today to record the outcome of that meeting.
After a long conversation I just had with Dean, I no longer think that is
necessary. Despite having an API that requires global state, Dean convinced
me that the answers are *yes and no*. I am tremendously surprised. Zones
does have observable global state that enables information to be
communicated "by magic" in violation of normal oo rules. But Dean also
convinced me that this does not add an ability to communicate to any
scenario that could safely be assumed free of other communications
channels. I still find this result quite bizarre, but I think I believe it.

I apologize to Misko. I now see that the big insight I got from Dean is one
that Misko tried to explain to me early in our session. For whatever
reason, I didn't see it till now. I will try to listen better next time.

The one change that is required is the one Misko was perfectly comfortable
with -- that the naming objects used to name dynamic variables be genuine
objects, not strings and not symbols. Let's say these naming objects are
NameVar objects. We could use NameVars as mere tokens as in the current
Zones API (which seems absent from <https://github.com/domenic/zones> btw),
or we could give NameVars a .get() operation to look up the value currently
bound to that dynamic variable. I return to this below.


The apparent problem I was worried about:

Zone is a global. This global has a "current" property that changes state
over time. Therefore, the Zone global is not transitively immutable.
However, it cannot be assigned to, only rebound. Alice and Bob have no
direct contact, but instead talk only through a trusted membrane-like
intermediate, Tom, that enforces *some enforceable* policy limiting
interaction between Alice and Bob. Alice wants to communicate a bit to Bob
that the trusted intermediary would wish Bob not to learn. Alice creates
two zones, x and y. She invokes Bob once through the Tom in zone x once, so
that Bob can "const x = Zone.current" during the call to remember zone x's
identity. Then, depending on the setting of the bit, she invokes him again,
still necessarily through Tom, using either x or y to indicate whether the
bit is zero or one. Bob then does

if (x === Zone.current) {

to learn the bit Alice wants to communicate. This is indeed a
communications channel using the mutable state of a global object. Similar
apparent problems arise with the dynamic variables themselves, but we'll
come back to that. This case is adequate to explain my mistake.


The observation:

Because Zone.current is unassignable, but can only be rebound in operations
like run, fork, and wrap, it can only be used to communicate forward, from
invoker to invokee, once we generalize the notion of invocation beyond
direct function call. Bob can only see a new Zone.current when invoked by
Alice. Outside of any such invocation, Alice has no magic way to
communicate to Bob. In any scenario where Alice invokes Bob, even with this
extended notion of invocation, we must assume that Alice can encode
information in the very act of invocation. She could have not invoked. Or
invoked something else. Or invoked in a different order. Once a forward
invocation path from Alice to Bob is enabled, it is a fools errand to try
to reason about limits of what Alice might encode on this path for Bob to
read. The restriction we were worried about is actually unenforceable
anyway for other reasons.

This is true for bits in the downward invocation direction, such as the
outcome of Bob's "if" test, but not true for bits in the upward direction.
I do not spot any upward communications dangers here, so I think we can put
that to bed.

NameVars

It is also not true of capabilities. Using membranes, Tom is in a position
to prevent the passing of any mutable objects that he does not wish to
cross. The key here is that we can account for the interaction between Zone
instances and NameVar instances by placing all the needed mutable state in
the NameVar, with an encapsulated weak mapping from zone identity to the
value of this variable in that zone. Usual caveat: it need not be
implemented this way as long as we preserve observational equivalence. Each
zone instance can then be considered a transitively immutable instance,
used only to look up state in NameVars by zone identity. If we refactored
the API, we could even make the zone instances be symbols with no loss of
functionality.

Misko and I also talked about cross-realm problems and solutions. I think
what we came up with is still valid, but will reexamine in light of these
new insights

Since the Zone global is both mutable and SES-safe, it breaks with the rest
of the SES document and will require a careful explanation.


-- 
    Cheers,
    --MarkM
_______________________________________________
es-discuss mailing list
[email protected]
https://mail.mozilla.org/listinfo/es-discuss

Reply via email to