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>