From 26a029d407be480d791972afb5975cf62c9360a6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 02:47:55 +0200 Subject: Adding upstream version 124.0.1. Signed-off-by: Daniel Baumann --- .../tests/unit/test_promise_job_across_sandbox.js | 221 +++++++++++++++++++++ 1 file changed, 221 insertions(+) create mode 100644 dom/promise/tests/unit/test_promise_job_across_sandbox.js (limited to 'dom/promise/tests/unit/test_promise_job_across_sandbox.js') diff --git a/dom/promise/tests/unit/test_promise_job_across_sandbox.js b/dom/promise/tests/unit/test_promise_job_across_sandbox.js new file mode 100644 index 0000000000..ff1d1575e3 --- /dev/null +++ b/dom/promise/tests/unit/test_promise_job_across_sandbox.js @@ -0,0 +1,221 @@ +function createSandbox() { + const uri = Services.io.newURI("https://example.com"); + const principal = Services.scriptSecurityManager.createContentPrincipal( + uri, + {} + ); + return new Cu.Sandbox(principal, {}); +} + +add_task(async function testReactionJob() { + const sandbox = createSandbox(); + + sandbox.eval(` +var testPromise = Promise.resolve(10); +`); + + // Calling `Promise.prototype.then` from sandbox performs GetFunctionRealm + // on wrapped `resolve` in sandbox realm, and it fails to unwrap the security + // wrapper. The reaction job should be created with sandbox realm. + const p = new Promise(resolve => { + sandbox.resolve = resolve; + + sandbox.eval(` +testPromise.then(resolve); +`); + }); + + const result = await p; + + equal(result, 10); +}); + +add_task(async function testReactionJobNuked() { + const sandbox = createSandbox(); + + sandbox.eval(` +var testPromise = Promise.resolve(10); +`); + + // Calling `Promise.prototype.then` from sandbox performs GetFunctionRealm + // on wrapped `resolve` in sandbox realm, and it fails to unwrap the security + // wrapper. The reaction job should be created with sandbox realm. + const p1 = new Promise(resolve => { + sandbox.resolve = resolve; + + sandbox.eval(` +testPromise.then(resolve); +`); + + // Given the reaction job is created with the sandbox realm, nuking the + // sandbox prevents the job gets executed. + Cu.nukeSandbox(sandbox); + }); + + const p2 = Promise.resolve(11); + + // Given the p1 doesn't get resolved, p2 should win. + const result = await Promise.race([p1, p2]); + + equal(result, 11); +}); + +add_task(async function testReactionJobWithXray() { + const sandbox = createSandbox(); + + sandbox.eval(` +var testPromise = Promise.resolve(10); +`); + + // Calling `Promise.prototype.then` from privileged realm via Xray uses + // privileged `Promise.prototype.then` function, and GetFunctionRealm + // performed there successfully gets top-level realm. The reaction job + // should be created with top-level realm. + const result = await new Promise(resolve => { + sandbox.testPromise.then(resolve); + + // Given the reaction job is created with the top-level realm, nuking the + // sandbox doesn't affect the reaction job. + Cu.nukeSandbox(sandbox); + }); + + equal(result, 10); +}); + +add_task(async function testBoundReactionJob() { + const sandbox = createSandbox(); + + sandbox.eval(` +var resolve = undefined; +var callbackPromise = new Promise(r => { resolve = r; }); +var callback = function (v) { resolve(v + 1); }; +`); + + // Create a bound function where its realm is privileged realm, and + // its target is from sandbox realm. + sandbox.bound_callback = Function.prototype.bind.call( + sandbox.callback, + sandbox + ); + + // Calling `Promise.prototype.then` from sandbox performs GetFunctionRealm + // and it fails. The reaction job should be created with sandbox realm. + sandbox.eval(` +Promise.resolve(10).then(bound_callback); +`); + + const result = await sandbox.callbackPromise; + equal(result, 11); +}); + +add_task(async function testThenableJob() { + const sandbox = createSandbox(); + + const p = new Promise(resolve => { + // Create a bound function where its realm is privileged realm, and + // its target is from sandbox realm. + sandbox.then = function (onFulfilled, onRejected) { + resolve(10); + }; + }); + + // Creating a promise thenable job in the following `Promise.resolve` performs + // GetFunctionRealm on the bound thenable.then and fails. The reaction job + // should be created with sandbox realm. + sandbox.eval(` +var thenable = { + then: then, +}; + +Promise.resolve(thenable); +`); + + const result = await p; + equal(result, 10); +}); + +add_task(async function testThenableJobNuked() { + const sandbox = createSandbox(); + + let called = false; + sandbox.then = function (onFulfilled, onRejected) { + called = true; + }; + + // Creating a promise thenable job in the following `Promise.resolve` performs + // GetFunctionRealm on the bound thenable.then and fails. The reaction job + // should be created with sandbox realm. + sandbox.eval(` +var thenable = { + then: then, +}; + +Promise.resolve(thenable); +`); + + Cu.nukeSandbox(sandbox); + + // Drain the job queue, to make sure we hit dead object error inside the + // thenable job. + await Promise.resolve(10); + + equal( + Services.console.getMessageArray().find(x => { + return x.toString().includes("can't access dead object"); + }) !== undefined, + true + ); + equal(called, false); +}); + +add_task(async function testThenableJobAccessError() { + const sandbox = createSandbox(); + + let accessed = false; + sandbox.thenable = { + get then() { + accessed = true; + }, + }; + + // The following operation silently fails when accessing `then` property. + sandbox.eval(` +var x = typeof thenable.then; + +Promise.resolve(thenable); +`); + + equal(accessed, false); +}); + +add_task(async function testBoundThenableJob() { + const sandbox = createSandbox(); + + sandbox.eval(` +var resolve = undefined; +var callbackPromise = new Promise(r => { resolve = r; }); +var callback = function (v) { resolve(v + 1); }; + +var then = function(onFulfilled, onRejected) { + onFulfilled(10); +}; +`); + + // Create a bound function where its realm is privileged realm, and + // its target is from sandbox realm. + sandbox.bound_then = Function.prototype.bind.call(sandbox.then, sandbox); + + // Creating a promise thenable job in the following `Promise.resolve` performs + // GetFunctionRealm on the bound thenable.then and fails. The reaction job + // should be created with sandbox realm. + sandbox.eval(` +var thenable = { + then: bound_then, +}; + +Promise.resolve(thenable).then(callback); +`); + + const result = await sandbox.callbackPromise; + equal(result, 11); +}); -- cgit v1.2.3