diff options
Diffstat (limited to 'js/xpconnect/tests/unit/test_xray_SavedFrame.js')
-rw-r--r-- | js/xpconnect/tests/unit/test_xray_SavedFrame.js | 104 |
1 files changed, 104 insertions, 0 deletions
diff --git a/js/xpconnect/tests/unit/test_xray_SavedFrame.js b/js/xpconnect/tests/unit/test_xray_SavedFrame.js new file mode 100644 index 0000000000..85c91a2aa1 --- /dev/null +++ b/js/xpconnect/tests/unit/test_xray_SavedFrame.js @@ -0,0 +1,104 @@ +// Bug 1117242: Test calling SavedFrame getters from globals that don't subsume +// that frame's principals. + +const {addDebuggerToGlobal} = ChromeUtils.importESModule("resource://gre/modules/jsdebugger.sys.mjs"); +addDebuggerToGlobal(globalThis); + +const lowP = Services.scriptSecurityManager.createNullPrincipal({}); +const midP = [lowP, "http://other.com"]; +const highP = Cc["@mozilla.org/systemprincipal;1"].createInstance(Ci.nsIPrincipal); + +const low = new Cu.Sandbox(lowP); +const mid = new Cu.Sandbox(midP); +const high = new Cu.Sandbox(highP); + +function run_test() { + // Test that the priveleged view of a SavedFrame from a subsumed compartment + // is the same view that the subsumed compartment gets. Create the following + // chain of function calls (with some intermediate system-principaled frames + // due to implementation): + // + // low.lowF -> mid.midF -> high.highF -> high.saveStack + // + // Where high.saveStack gets monkey patched to create stacks in each of our + // sandboxes. + + Cu.evalInSandbox("function highF() { return saveStack(); }", high); + + mid.highF = () => high.highF(); + Cu.evalInSandbox("function midF() { return highF(); }", mid); + + low.midF = () => mid.midF(); + Cu.evalInSandbox("function lowF() { return midF(); }", low); + + const expected = [ + { + sandbox: low, + frames: ["lowF"], + }, + { + sandbox: mid, + frames: ["midF", "lowF"], + }, + { + sandbox: high, + frames: ["getSavedFrameInstanceFromSandbox", + "saveStack", + "highF", + "run_test/mid.highF", + "midF", + "run_test/low.midF", + "lowF", + "run_test", + "_execute_test", + null], + } + ]; + + for (let { sandbox, frames } of expected) { + high.saveStack = function saveStack() { + return getSavedFrameInstanceFromSandbox(sandbox); + }; + + const xrayStack = low.lowF(); + equal(xrayStack.functionDisplayName, "getSavedFrameInstanceFromSandbox", + "Xrays should always be able to see everything."); + + let waived = Cu.waiveXrays(xrayStack); + do { + ok(frames.length, + "There should still be more expected frames while we have actual frames."); + equal(waived.functionDisplayName, frames.shift(), + "The waived wrapper should give us the stack's compartment's view."); + waived = waived.parent; + } while (waived); + } +} + +// Get a SavedFrame instance from inside the given sandbox. +// +// We can't use Cu.getJSTestingFunctions().saveStack() because Cu isn't +// available to sandboxes that don't have the system principal. The easiest way +// to get the SavedFrame is to use the Debugger API to track allocation sites +// and then do an allocation. +function getSavedFrameInstanceFromSandbox(sandbox) { + const dbg = new Debugger(sandbox); + + dbg.memory.trackingAllocationSites = true; + Cu.evalInSandbox("new Object", sandbox); + const allocs = dbg.memory.drainAllocationsLog(); + dbg.memory.trackingAllocationSites = false; + + ok(allocs[0], "We should observe the allocation"); + const { frame } = allocs[0]; + + if (sandbox !== high) { + ok(Cu.isXrayWrapper(frame), "`frame` should be an xray..."); + equal(Object.prototype.toString.call(Cu.waiveXrays(frame)), + "[object SavedFrame]", + "...and that xray should wrap a SavedFrame"); + } + + return frame; +} + |