tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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();