From e775a99afae43a8581cdeedd22545c7fa703c691 Mon Sep 17 00:00:00 2001 From: Dan Connolly Date: Wed, 13 Jan 2021 20:28:12 -0600 Subject: [PATCH] feat(xs-vat-worker): bootstrap SES shim on xsnap - add ses dependency - noop console, since xsnap no longer provides `print` - re-package XS ArrayBuffer.fromString() extension as TextEncoder.prototype.encode - use `xsStringBuffer()` C API rather than `String.fromArrayBuffer` JS API so that xsnap eval continues to work after `lockdown()`. --- packages/xs-vat-worker/package.json | 4 ++- packages/xs-vat-worker/src/bootstrap.js | 5 +++ packages/xs-vat-worker/src/console-shim.js | 9 +++++ packages/xs-vat-worker/src/console.js | 22 ------------ packages/xs-vat-worker/src/lockdown-shim.js | 5 +++ packages/xs-vat-worker/src/text-shim.js | 12 +++++++ .../xs-vat-worker/test/test-boot-lockdown.js | 36 +++++++++++++++++++ packages/xsnap/src/xsnap.c | 7 ++-- 8 files changed, 73 insertions(+), 27 deletions(-) create mode 100644 packages/xs-vat-worker/src/bootstrap.js create mode 100644 packages/xs-vat-worker/src/console-shim.js delete mode 100644 packages/xs-vat-worker/src/console.js create mode 100644 packages/xs-vat-worker/src/lockdown-shim.js create mode 100644 packages/xs-vat-worker/src/text-shim.js create mode 100644 packages/xs-vat-worker/test/test-boot-lockdown.js diff --git a/packages/xs-vat-worker/package.json b/packages/xs-vat-worker/package.json index 9552fbce648..f189b5dc438 100644 --- a/packages/xs-vat-worker/package.json +++ b/packages/xs-vat-worker/package.json @@ -52,8 +52,10 @@ "@agoric/marshal": "^0.3.0", "@agoric/promise-kit": "^0.2.0", "@agoric/swingset-vat": "^0.11.0", + "@agoric/xsnap": "^0.0.0", "anylogger": "^0.21.0", - "esm": "^3.2.5" + "esm": "^3.2.5", + "ses": "^0.11.0" }, "keywords": [], "files": [ diff --git a/packages/xs-vat-worker/src/bootstrap.js b/packages/xs-vat-worker/src/bootstrap.js new file mode 100644 index 00000000000..cd615238ba9 --- /dev/null +++ b/packages/xs-vat-worker/src/bootstrap.js @@ -0,0 +1,5 @@ +import './console-shim'; +import './text-shim'; +import './lockdown-shim'; + +harden(console); diff --git a/packages/xs-vat-worker/src/console-shim.js b/packages/xs-vat-worker/src/console-shim.js new file mode 100644 index 00000000000..7c58ec97216 --- /dev/null +++ b/packages/xs-vat-worker/src/console-shim.js @@ -0,0 +1,9 @@ +const noop = _ => undefined; + +globalThis.console = { + debug: noop, + log: noop, + info: noop, + warn: noop, + error: noop, +}; diff --git a/packages/xs-vat-worker/src/console.js b/packages/xs-vat-worker/src/console.js deleted file mode 100644 index da6d9b29211..00000000000 --- a/packages/xs-vat-worker/src/console.js +++ /dev/null @@ -1,22 +0,0 @@ -/** console for xs platform */ -const harden = x => Object.freeze(x, true); - -const text = it => (typeof it === 'object' ? JSON.stringify(it) : `${it}`); -const combine = (...things) => `${things.map(text).join(' ')}\n`; - -export function makeConsole(write_) { - const write = write_; - return harden({ - log(...things) { - write(combine(...things)); - }, - // node.js docs say this is just an alias for error - warn(...things) { - write(combine('WARNING: ', ...things)); - }, - // node docs say this goes to stderr - error(...things) { - write(combine('ERROR: ', ...things)); - }, - }); -} diff --git a/packages/xs-vat-worker/src/lockdown-shim.js b/packages/xs-vat-worker/src/lockdown-shim.js new file mode 100644 index 00000000000..79a7e30f6d8 --- /dev/null +++ b/packages/xs-vat-worker/src/lockdown-shim.js @@ -0,0 +1,5 @@ +/* global lockdown */ + +import 'ses/lockdown'; + +lockdown(); diff --git a/packages/xs-vat-worker/src/text-shim.js b/packages/xs-vat-worker/src/text-shim.js new file mode 100644 index 00000000000..1e8cff5ea1c --- /dev/null +++ b/packages/xs-vat-worker/src/text-shim.js @@ -0,0 +1,12 @@ +/* eslint-disable class-methods-use-this */ + +// Save this XS extension before SES shim deletes it. +const { fromString } = ArrayBuffer; + +class TextEncoder { + encode(s) { + return new Uint8Array(fromString(s)); + } +} + +globalThis.TextEncoder = TextEncoder; diff --git a/packages/xs-vat-worker/test/test-boot-lockdown.js b/packages/xs-vat-worker/test/test-boot-lockdown.js new file mode 100644 index 00000000000..babfd57df9e --- /dev/null +++ b/packages/xs-vat-worker/test/test-boot-lockdown.js @@ -0,0 +1,36 @@ +import test from 'ava'; +import * as childProcess from 'child_process'; +import * as os from 'os'; +import * as fs from 'fs'; +import * as path from 'path'; +import { xsnap } from '@agoric/xsnap'; + +const dist = async name => + fs.promises.readFile(path.join(__filename, '..', '..', 'dist', name)); + +const decoder = new TextDecoder(); + +const xsnapOptions = { + spawn: childProcess.spawn, + os: os.type(), +}; + +test('bootstrap to SES lockdown', async t => { + const bootScript = await dist('bootstrap.umd.js'); + const messages = []; + async function handleCommand(message) { + messages.push(decoder.decode(message)); + return new Uint8Array(); + } + const name = 'SES lockdown worker'; + const vat = xsnap({ ...xsnapOptions, handleCommand, name }); + await vat.evaluate(bootScript); + t.deepEqual([], messages); + + const SESinfo = '[typeof harden, typeof Compartment]'; + const toBytes = expr => + `new TextEncoder().encode(JSON.stringify(${expr})).buffer`; + await vat.evaluate(`issueCommand(${toBytes(SESinfo)});`); + await vat.close(); + t.deepEqual(['["function","function"]'], messages); +}); diff --git a/packages/xsnap/src/xsnap.c b/packages/xsnap/src/xsnap.c index fb92cc50178..e778e207bff 100644 --- a/packages/xsnap/src/xsnap.c +++ b/packages/xsnap/src/xsnap.c @@ -322,9 +322,9 @@ int main(int argc, char* argv[]) xsBeginHost(machine); { xsVars(3); - xsVar(1) = xsArrayBuffer(nsbuf + 1, nslen - 1); xsTry { if (command == '?') { + xsVar(1) = xsArrayBuffer(nsbuf + 1, nslen - 1); xsVar(2) = xsCall1(xsGlobal, xsID("handleCommand"), xsVar(1)); if (xsTypeOf(xsVar(2)) != xsUndefinedType) { responseLength = fxGetArrayBufferLength(machine, &xsVar(2)); @@ -332,9 +332,8 @@ int main(int argc, char* argv[]) fxGetArrayBufferData(machine, &xsVar(2), 0, response, responseLength); } } else { - xsVar(0) = xsGet(xsGlobal, xsID("String")); - xsVar(2) = xsCall1(xsVar(0), xsID("fromArrayBuffer"), xsVar(1)); - xsCall1(xsGlobal, xsID("eval"), xsVar(2)); + xsVar(1) = xsStringBuffer(nsbuf + 1, nslen - 1); + xsCall1_noResult(xsGlobal, xsID("eval"), xsVar(1)); } } xsCatch {