Skip to content

fix(ses): plug implicit NaN side-channel#3153

Merged
erights merged 5 commits intomasterfrom
markm-no-implicit-NaN-leak
Apr 7, 2026
Merged

fix(ses): plug implicit NaN side-channel#3153
erights merged 5 commits intomasterfrom
markm-no-implicit-NaN-leak

Conversation

@erights
Copy link
Copy Markdown
Contributor

@erights erights commented Mar 31, 2026

Closes: #XXXX
Refs: #XXXX

  • TODO cite Nikita's NaN side-channel demonstration.

Description

The JavaScript language can leak the bit encoding of a NaN via shared TypedArray views of an common ArrayBuffer. Although the JavaScript language has only one NaN value, the underlying IEEE 754 double-precision floating-point representation has many different bit patterns that represent NaN. This can be exploited as a side-channel to leak information. This actually happens on some platforms such as v8.

@ChALkeR explains at tc39/ecma262#758 (comment) the behavior of this side-channel on v8. At https://junk.rray.org/poc/nani.html he demonstrates it, and it indeed even worse than I expected.

To plug this side-channel, we make two coordinated changes.

  • We stop listing the Float*Array constructors as universal globals. This prevents them from being implicitly endowed to created compartments, because they are not harmless. However, we still keep them on the start compartment (the original global), consider them intrinsics, and still repair and harden them on lockdown(). Thus, they can be explicitly endowed to child compartments at the price of enabling code in that compartment to read the side-channel.
  • On lockdown(), we repair the DataView.prototype.setFloat* methods so that they only write canonical NaNs into the underlying ArrayBuffer.

The @endo.marshal package's encodePassable encodings need to obtain the bit representation of floating point values. It had used Float64Array for that. However, sometimes the @endo/marshal package is evaluated in a created compartment that would now lack that constructor. (This reevaluation typically occurs when bundling bundles in that package.) So instead, encodePassable now uses the DataView methods which are now safe.

Security Considerations

The point. This NaN side-channel in ses had been implicit, easily forgotten, and hard to plug in user code.

Scaling Considerations

Not really.

Documentation Considerations

Somewhere we need to document that the Float*Array constructors are not available in created compartments by default, and why.

Testing Considerations

New tests included.

One test newly skipped because it always hangs for me locally, which is annoying. Reviewers, feel free to ask me to unskip it.

Compatibility Considerations

The absence of the Float*Array constructors in created compartments is potentially a compat break. In fact our need to repair encodePassable demonstrates such a compat break.

Upgrade Considerations

none.

@erights erights self-assigned this Mar 31, 2026
@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Mar 31, 2026

🦋 Changeset detected

Latest commit: 10029d2

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 26 packages
Name Type
ses Major
@endo/marshal Patch
@endo/bundle-source Patch
@endo/captp Patch
@endo/check-bundle Patch
@endo/common Patch
@endo/compartment-mapper Patch
@endo/daemon Patch
@endo/errors Patch
@endo/exo Patch
@endo/far Patch
@endo/import-bundle Patch
@endo/lockdown Patch
@endo/module-source Patch
@endo/ocapn Patch
@endo/pass-style Patch
@endo/patterns Patch
@endo/ses-ava Patch
@endo/stream-types-test Patch
@endo/stream Patch
@endo/test262-runner Patch
@endo/cli Patch
@endo/lp32 Patch
@endo/stream-node Patch
@endo/init Patch
@endo/netstring Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@erights erights force-pushed the markm-no-implicit-NaN-leak branch 2 times, most recently from 692416d to 26cad3f Compare March 31, 2026 03:45
@erights erights requested a review from kriskowal March 31, 2026 03:52
@erights
Copy link
Copy Markdown
Contributor Author

erights commented Mar 31, 2026

@ChALkeR , I cannot officially make you a reviewer, but I'd appreciate it if you could take a look. Thanks!

@erights erights force-pushed the markm-no-implicit-NaN-leak branch 2 times, most recently from 2f0ddc4 to 4168d08 Compare March 31, 2026 06:57
@erights erights requested review from gibson042 and mhofman March 31, 2026 07:15
@erights erights force-pushed the markm-no-implicit-NaN-leak branch from 4168d08 to 7ed438d Compare March 31, 2026 07:51
@erights erights marked this pull request as ready for review March 31, 2026 07:58
Copy link
Copy Markdown
Member

@kriskowal kriskowal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved with the caveat that we must publish this as a major version since it will break existing applications relying on the implicit availability of Float64Array in Compartments.

@erights erights merged commit e619205 into master Apr 7, 2026
26 checks passed
@erights erights deleted the markm-no-implicit-NaN-leak branch April 7, 2026 22:37
@kriskowal kriskowal mentioned this pull request Mar 30, 2026
};

/**
* Replaces the dangerous `setFloat*` methods on `DataView.prototype`
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@erights should we also update the getFloat* methods to something like const value = apply(…); return is(value, NaN) ? NaN : value? Not all ArrayBuffers will have been populated by SES code, and if anything it is probably more common to receive contents from the outside world.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't help. Either way, get produces a an opaque NaN. Only the setting side pierces the opacity.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants