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

# Mark S. Miller (8 years ago)

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

# Raul-Sebastian Mihăilă (8 years ago)

Wouldn't it be enough to prevent access from normal SES realms to the proto-SES realm's Zone primordial in order to keep SES as an ocap environment (by having the global objects from normal SES realms inherit from a proxy of the global object from proto-SES, instead of inheriting directly from the proto-SES global object)?

# Mark S. Miller (8 years ago)

On Mar 21, 2016 4:36 AM, "Raul-Sebastian Mihăilă" <raul.mihaila at gmail.com>

wrote:

Wouldn't it be enough to prevent access from normal SES realms to the proto-SES realm's Zone primordial in order to keep SES as an ocap environment (by having the global objects from normal SES realms inherit from a proxy of the global object from proto-SES, instead of inheriting directly from the proto-SES global object)?

Hi Raul, recall that Reflect.theProtoGlobal provides direct access to the proto-SES realm's global itself (the so-called "proto-global"). If Zone is found there, then it is pervasively available. The hard question is, is it safe for this observably mutable global to be pervasively available? At first I thought the answer was "of course not". Now, due to Dean's observation, the answer is that it may indeed be safe. This is sufficiently likely that we should consider the case seriously.

If we decide not to share a global Zone but do decide that it is safe to have on individual SES realms, then we can treat it more like eval, Function, Math, and Date: Arrange for it to be absent or crippled on the proto-global, and instead have separate Zone objects to appear on each SES realm's global. As with eval and Function, this could be by built-in initialization. Or as with Date and Math, it could be by user-level pattern. But before worrying about how to fall back to this more conservative position, let's continue to critically examine the more radical hypothesis.