async-principals.js (6797B)
1 // Test cases when a SavedFrame or one of its ancestors have a principal that is 2 // not subsumed by the caller's principal, when async parents are present. 3 4 function checkVisibleStack(stackFrame, expectedFrames) { 5 // We check toString separately from properties like asyncCause to check that 6 // it walks the physical SavedFrame chain consistently with the properties. 7 var stringFrames = stackFrame.toString().split("\n"); 8 9 while (expectedFrames.length) { 10 let expectedFrame = expectedFrames.shift(); 11 let stringFrame = stringFrames.shift(); 12 13 // Check the frame properties. 14 assertEq(stackFrame.functionDisplayName, expectedFrame.name); 15 assertEq(stackFrame.asyncCause, expectedFrame.asyncCause); 16 17 // Check the stringified version. 18 let expectedStart = 19 (expectedFrame.asyncCause ? expectedFrame.asyncCause + "*" : "") + 20 expectedFrame.name; 21 assertEq(stringFrame.replace(/@.*$/, ""), expectedStart); 22 23 // If the next frame has an asyncCause, it should be an asyncParent. 24 if (expectedFrames.length && expectedFrames[0].asyncCause) { 25 assertEq(stackFrame.parent, null); 26 stackFrame = stackFrame.asyncParent; 27 } else { 28 assertEq(stackFrame.asyncParent, null); 29 stackFrame = stackFrame.parent; 30 } 31 } 32 } 33 34 var low = newGlobal({ principal: 0 }); 35 var high = newGlobal({ principal: 0xfffff }); 36 37 // Test with synchronous cross-compartment calls. 38 // 39 // With arrows representing child-to-parent links, and fat arrows representing 40 // child-to-async-parent links, create a SavedFrame stack like this: 41 // 42 // low.e -> high.d => high.c => high.b -> low.a 43 // 44 // This stack captured in function `e` would be seen in its complete version if 45 // accessed by `high`'s compartment, while in `low`'s compartment it would look 46 // like this: 47 // 48 // low.e => low.a 49 // 50 // The asyncCause seen on `low.a` above should not leak information about the 51 // real asyncCause on `high.c` and `high.d`. 52 // 53 // The stack captured in function `d` would be seen in its complete version if 54 // accessed by `high`'s compartment, while in `low`'s compartment it would look 55 // like this: 56 // 57 // low.a 58 59 // We'll move these functions into the right globals below before invoking them. 60 function a() { 61 b(); 62 } 63 function b() { 64 callFunctionWithAsyncStack(c, saveStack(), "BtoC"); 65 } 66 function c() { 67 callFunctionWithAsyncStack(d, saveStack(), "CtoD"); 68 } 69 function d() { 70 let stackD = saveStack(); 71 72 print("high.checkVisibleStack(stackD)"); 73 checkVisibleStack(stackD, [ 74 { name: "d", asyncCause: null }, 75 { name: "c", asyncCause: "CtoD" }, 76 { name: "b", asyncCause: "BtoC" }, 77 { name: "a", asyncCause: null }, 78 ]); 79 80 let stackE = e(saveStack(0, low)); 81 82 print("high.checkVisibleStack(stackE)"); 83 checkVisibleStack(stackE, [ 84 { name: "e", asyncCause: null }, 85 { name: "d", asyncCause: null }, 86 { name: "c", asyncCause: "CtoD" }, 87 { name: "b", asyncCause: "BtoC" }, 88 { name: "a", asyncCause: null }, 89 ]); 90 } 91 function e(stackD) { 92 print("low.checkVisibleStack(stackD)"); 93 checkVisibleStack(stackD, [ 94 { name: "a", asyncCause: "Async" }, 95 ]); 96 97 let stackE = saveStack(); 98 99 print("low.checkVisibleStack(stackE)"); 100 checkVisibleStack(stackE, [ 101 { name: "e", asyncCause: null }, 102 { name: "a", asyncCause: "Async" }, 103 ]); 104 105 return saveStack(0, high); 106 } 107 108 // Test with asynchronous cross-compartment calls and shared frames. 109 // 110 // With arrows representing child-to-parent links, and fat arrows representing 111 // child-to-async-parent links, create a SavedFrame stack like this: 112 // 113 // low.x => high.v => low.u 114 // low.y -> high.v => low.u 115 // low.z => high.w -> low.u 116 // 117 // This stack captured in functions `x`, `y`, and `z` would be seen in its 118 // complete version if accessed by `high`'s compartment, while in `low`'s 119 // compartment it would look like this: 120 // 121 // low.x => low.u 122 // low.y => low.u 123 // low.z => low.u 124 // 125 // The stack captured in function `v` would be seen in its complete version if 126 // accessed by `high`'s compartment, while in `low`'s compartment it would look 127 // like this: 128 // 129 // low.u 130 131 // We'll move these functions into the right globals below before invoking them. 132 function u() { 133 callFunctionWithAsyncStack(v, saveStack(), "UtoV"); 134 w(); 135 } 136 function v() { 137 let stackV = saveStack(); 138 print("high.checkVisibleStack(stackV)"); 139 checkVisibleStack(stackV, [ 140 { name: "v", asyncCause: null }, 141 { name: "u", asyncCause: "UtoV" }, 142 ]); 143 144 let stack = saveStack(0, low); 145 function xToCall() { return x(stack);}; 146 147 let stackX = callFunctionWithAsyncStack(xToCall, saveStack(), "VtoX"); 148 149 print("high.checkVisibleStack(stackX)"); 150 checkVisibleStack(stackX, [ 151 { name: "x", asyncCause: null }, 152 { name: "xToCall", asyncCause: null }, 153 { name: "v", asyncCause: "VtoX" }, 154 { name: "u", asyncCause: "UtoV" }, 155 ]); 156 157 let stackY = y(); 158 159 print("high.checkVisibleStack(stackY)"); 160 checkVisibleStack(stackY, [ 161 { name: "y", asyncCause: null }, 162 { name: "v", asyncCause: null }, 163 { name: "u", asyncCause: "UtoV" }, 164 ]); 165 } 166 function w() { 167 let stackZ = callFunctionWithAsyncStack(z, saveStack(), "WtoZ"); 168 169 print("high.checkVisibleStack(stackZ)"); 170 checkVisibleStack(stackZ, [ 171 { name: "z", asyncCause: null }, 172 { name: "w", asyncCause: "WtoZ" }, 173 { name: "u", asyncCause: null }, 174 ]); 175 } 176 function x(stackV) { 177 print("low.checkVisibleStack(stackV)"); 178 checkVisibleStack(stackV, [ 179 { name: "u", asyncCause: "UtoV" }, 180 ]); 181 182 let stackX = saveStack(); 183 184 print("low.checkVisibleStack(stackX)"); 185 checkVisibleStack(stackX, [ 186 { name: "x", asyncCause: null }, 187 { name: "u", asyncCause: "UtoV" }, 188 ]); 189 190 return saveStack(0, high); 191 } 192 193 function y() { 194 let stackY = saveStack(); 195 196 print("low.checkVisibleStack(stackY)"); 197 checkVisibleStack(stackY, [ 198 { name: "y", asyncCause: null }, 199 { name: "u", asyncCause: "UtoV" }, 200 ]); 201 202 return saveStack(0, high); 203 } 204 function z() { 205 let stackZ = saveStack(); 206 207 print("low.checkVisibleStack(stackZ)"); 208 checkVisibleStack(stackZ, [ 209 { name: "z", asyncCause: null }, 210 { name: "u", asyncCause: "Async" }, 211 ]); 212 213 return saveStack(0, high); 214 } 215 216 // Split the functions in their respective globals. 217 low .eval(a.toString()); 218 high.eval(b.toString()); 219 high.eval(c.toString()); 220 high.eval(d.toString()); 221 low .eval(e.toString()); 222 223 low .b = high.b; 224 high.e = low .e; 225 226 low .eval(u.toString()); 227 high.eval(v.toString()); 228 high.eval(w.toString()); 229 low .eval(x.toString()); 230 low .eval(y.toString()); 231 low .eval(z.toString()); 232 233 low .v = high.v; 234 low .w = high.w; 235 high.x = low .x; 236 high.y = low .y; 237 high.z = low .z; 238 239 low .high = high; 240 high.low = low; 241 242 low .eval(checkVisibleStack.toString()); 243 high.eval(checkVisibleStack.toString()); 244 245 // Execute the tests. 246 low.a(); 247 low.u();