TOCTTOU issue in Proxy invariant checks

# Tom Van Cutsem (11 years ago)

While reviewing some changes to the Proxy spec in the latest revision, it occurred to me there is a potential time-of-check-to-time-of-use (TOCTTOU) issue in the Proxy invariant checks.

Concretely, take revision 26, section 9.5.12 [[OwnPropertyKeys]]:

  • step 11 checks whether the target object is extensible
  • this result then gets used in step 21 and 28 (if the target was non-extensible, more invariant checks are made)
  • in between steps 11 and 21/28, control is transferred to internal methods of the target, which may itself be a Proxy and so trigger arbitrary user code to run.
  • hence, the extensibility state checked in step 11 might have changed before being used in steps 21/28

I think the issue is benign, because extensibility can only ever change from 'true' to 'false' but not vice versa. This means we can end up in the following scenario:

  • assume a proxy and its target are extensible when [[OwnPropertyKeys]] is invoked
  • step 11 checks the extensibility state and stores 'true'
  • assume user code runs between steps 11 and 21 that calls Object.preventExtensions on the target, so the extensibility state is now really 'false'
  • Then, in step 21, even though the target is now non-extensible, the algorithm terminates early and doesn't perform the invariant checks for non-extensible objects.

I think this is benign because the caller of the internal method, at the time it made the call, had no reason to assume strong invariants on the proxy/target.

Basically, the way to think of this is that invariant checks are made based upon the state of the target object when the internal method is first invoked. While that internal method call is suspended, the target's state may change, but invariant checks may still be based on the target's state upon entry.

While I'm fairly confident the issue is benign, the reasoning is subtle and could use more braincells to check if I missed anything.

This issue may appear for other Proxy internal methods, I haven't yet checked. But generally I think they will also be benign for the same reasons. An attacker can only modify the target to have stronger, not weaker, invariants. Suspended calls that only assume weak invariants cannot get confused if eventually more invariant checks are made.

# Mark S. Miller (11 years ago)

your reasoning seems good to me.