test_xray_SavedFrame.js (3391B)
1 // Bug 1117242: Test calling SavedFrame getters from globals that don't subsume 2 // that frame's principals. 3 4 const {addDebuggerToGlobal} = ChromeUtils.importESModule("resource://gre/modules/jsdebugger.sys.mjs"); 5 addDebuggerToGlobal(globalThis); 6 7 const lowP = Services.scriptSecurityManager.createNullPrincipal({}); 8 const midP = [lowP, "http://other.com"]; 9 const highP = Cc["@mozilla.org/systemprincipal;1"].createInstance(Ci.nsIPrincipal); 10 11 const low = new Cu.Sandbox(lowP); 12 const mid = new Cu.Sandbox(midP); 13 const high = new Cu.Sandbox(highP); 14 15 function run_test() { 16 // Test that the priveleged view of a SavedFrame from a subsumed compartment 17 // is the same view that the subsumed compartment gets. Create the following 18 // chain of function calls (with some intermediate system-principaled frames 19 // due to implementation): 20 // 21 // low.lowF -> mid.midF -> high.highF -> high.saveStack 22 // 23 // Where high.saveStack gets monkey patched to create stacks in each of our 24 // sandboxes. 25 26 Cu.evalInSandbox("function highF() { return saveStack(); }", high); 27 28 mid.highF = () => high.highF(); 29 Cu.evalInSandbox("function midF() { return highF(); }", mid); 30 31 low.midF = () => mid.midF(); 32 Cu.evalInSandbox("function lowF() { return midF(); }", low); 33 34 const expected = [ 35 { 36 sandbox: low, 37 frames: ["lowF"], 38 }, 39 { 40 sandbox: mid, 41 frames: ["midF", "lowF"], 42 }, 43 { 44 sandbox: high, 45 frames: ["getSavedFrameInstanceFromSandbox", 46 "saveStack", 47 "highF", 48 "run_test/mid.highF", 49 "midF", 50 "run_test/low.midF", 51 "lowF", 52 "run_test", 53 "_execute_test", 54 null], 55 } 56 ]; 57 58 for (let { sandbox, frames } of expected) { 59 high.saveStack = function saveStack() { 60 return getSavedFrameInstanceFromSandbox(sandbox); 61 }; 62 63 const xrayStack = low.lowF(); 64 equal(xrayStack.functionDisplayName, "getSavedFrameInstanceFromSandbox", 65 "Xrays should always be able to see everything."); 66 67 let waived = Cu.waiveXrays(xrayStack); 68 do { 69 ok(frames.length, 70 "There should still be more expected frames while we have actual frames."); 71 equal(waived.functionDisplayName, frames.shift(), 72 "The waived wrapper should give us the stack's compartment's view."); 73 waived = waived.parent; 74 } while (waived); 75 } 76 } 77 78 // Get a SavedFrame instance from inside the given sandbox. 79 // 80 // We can't use Cu.getJSTestingFunctions().saveStack() because Cu isn't 81 // available to sandboxes that don't have the system principal. The easiest way 82 // to get the SavedFrame is to use the Debugger API to track allocation sites 83 // and then do an allocation. 84 function getSavedFrameInstanceFromSandbox(sandbox) { 85 const dbg = new Debugger(sandbox); 86 87 dbg.memory.trackingAllocationSites = true; 88 Cu.evalInSandbox("new Object", sandbox); 89 const allocs = dbg.memory.drainAllocationsLog(); 90 dbg.memory.trackingAllocationSites = false; 91 92 ok(allocs[0], "We should observe the allocation"); 93 const { frame } = allocs[0]; 94 95 if (sandbox !== high) { 96 ok(Cu.isXrayWrapper(frame), "`frame` should be an xray..."); 97 equal(Object.prototype.toString.call(Cu.waiveXrays(frame)), 98 "[object SavedFrame]", 99 "...and that xray should wrap a SavedFrame"); 100 } 101 102 return frame; 103 }