tor-browser

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

test_bug1969341.html (3225B)


      1 <!DOCTYPE html>
      2 <meta charset=utf-8>
      3 <head>
      4  <title>Test for Bug 1969341</title>
      5  <script src="/tests/SimpleTest/SimpleTest.js"></script>
      6  <script type="text/javascript" src="u2futil.js"></script>
      7  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
      8 </head>
      9 <body>
     10 
     11  <h1>Test for Bug 1969341</h1>
     12  <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1969341">Mozilla Bug 1969341</a>
     13 
     14  <script class="testbody" type="text/javascript">
     15    "use strict";
     16 
     17    function arrivingHereIsBad(aResult) {
     18      ok(false, "Bad result! Received a: " + aResult);
     19      return Promise.resolve();
     20    }
     21 
     22    add_task(async () => {
     23      await addVirtualAuthenticator();
     24    });
     25 
     26    add_task(async function test_bug1969341() {
     27      // Bug 1969341 was an assertion crash due to a race condition. To hit the
     28      // assertion you had to rapidly initiate a new WebAuthn transaction
     29      // before the previous transaction state was fully torn down. The reproducer
     30      // attached to bug 1969341 kicked off a WebAuthn transaction in the getter
     31      // for PublicKeyCredential.then, which caused uncontrolled recursion.
     32      // This test case limits the recursion depth. In manual tests, 10 levels
     33      // was sufficient to hit the crash with high probability.
     34      const maxRecursionDepth = 10
     35      let currentRecursionDepth = 0;
     36 
     37      var triggerDone;
     38      var done = new Promise((resolve) => {
     39        triggerDone = resolve;
     40      });
     41 
     42      // Set up a PublicKeyCredential prior to making PublicKeyCredential thenable,
     43      // this lets us control when the recursion starts.
     44      let credential = await navigator.credentials
     45        .create({
     46          publicKey: {
     47            rp: { id: document.domain, name: "none" },
     48            user: { id: crypto.getRandomValues(new Uint8Array(16)), displayName: "A", name: "A" },
     49            challenge: crypto.getRandomValues(new Uint8Array(16)),
     50            pubKeyCredParams: [
     51              { type: "public-key", alg: cose_alg_ECDSA_w_SHA256 },
     52            ],
     53          },
     54        })
     55 
     56      ok(credential instanceof PublicKeyCredential, "expected PublicKeyCredential");
     57 
     58      Object.defineProperty(PublicKeyCredential.prototype, "then", {
     59        async get() {
     60          if (++currentRecursionDepth < maxRecursionDepth) {
     61            await navigator.credentials
     62              .get({
     63                publicKey: {
     64                  challenge: crypto.getRandomValues(new Uint8Array(16)),
     65                  allowCredentials: [
     66                    { type: "public-key", id: credential.rawId },
     67                  ],
     68                },
     69              })
     70          } else {
     71            triggerDone();
     72          }
     73          return undefined;
     74        },
     75      });
     76 
     77      ok(
     78        currentRecursionDepth == 0,
     79        "the 'PublicKeyCredential.then' getter should not have been evaluated"
     80      );
     81 
     82      // This will invoke the PublicKeyCredential.then getter.
     83      await credential;
     84 
     85      // Wait until we've reached maxRecursionDepth.
     86      await done;
     87 
     88      ok(
     89        currentRecursionDepth == maxRecursionDepth,
     90        "the 'PublicKeyCredential.then' getter should been called recursively"
     91      );
     92    });
     93  </script>
     94 </body>
     95 </html>