Source code
Revision control
Copy as Markdown
Other Tools
Test Info:
/* Any copyright is dedicated to the Public Domain.
*/
"use strict";
// Observers of permission removals may re-enter the permission manager and
// reallocate or free the storage the removal was operating on. These tests
// ensure the removal paths don't touch that storage after notifying.
const PERM_TYPE = "test-reentrant-perm";
const PERM_TYPE_B = "test-reentrant-perm-b";
const BROWSER_ID = 91001;
const FILLER_COUNT = 200;
function makePrincipal(uri) {
return Services.scriptSecurityManager.createContentPrincipal(
Services.io.newURI(uri),
{}
);
}
function fillerPrincipal(i) {
}
// Runs `callback`, once, from within the "deleted" notification for `PERM_TYPE`.
function reenterOnDeletion(topic, callback) {
let reentry = { fired: false };
reentry.promise = new Promise(resolve => {
let observer = {
observe(subject, aTopic, data) {
if (data != "deleted") {
return;
}
let perm = subject.QueryInterface(Ci.nsIPermission);
if (
perm.type != PERM_TYPE ||
(topic == "browser-perm-changed" && perm.browserId != BROWSER_ID)
) {
return;
}
Services.obs.removeObserver(observer, topic);
callback();
reentry.fired = true;
resolve();
},
};
Services.obs.addObserver(observer, topic);
});
return reentry;
}
function addFillerBrowserPermissions() {
let pm = Services.perms;
for (let i = 1; i <= FILLER_COUNT; i++) {
pm.addFromPrincipalForBrowser(
PRINCIPAL,
PERM_TYPE,
pm.ALLOW_ACTION,
BROWSER_ID + i,
0
);
}
}
function assertAndClearFillerBrowserPermissions() {
let pm = Services.perms;
let present = 0;
for (let i = 1; i <= FILLER_COUNT; i++) {
if (
pm.testForBrowser(PRINCIPAL, PERM_TYPE, BROWSER_ID + i) == pm.ALLOW_ACTION
) {
present++;
}
pm.removeAllForBrowser(BROWSER_ID + i);
}
Assert.equal(
present,
FILLER_COUNT,
"Permissions added by the observer should be present"
);
}
add_task(async function test_remove_reentrant_table_growth() {
let pm = Services.perms;
pm.addFromPrincipal(PRINCIPAL, PERM_TYPE, pm.ALLOW_ACTION);
let reentry = reenterOnDeletion("perm-changed", () => {
for (let i = 0; i < FILLER_COUNT; i++) {
pm.addFromPrincipal(fillerPrincipal(i), PERM_TYPE_B, pm.ALLOW_ACTION);
}
});
pm.removeFromPrincipal(PRINCIPAL, PERM_TYPE);
Assert.ok(reentry.fired, "Observer should have run during the removal");
Assert.equal(
pm.testPermissionFromPrincipal(PRINCIPAL, PERM_TYPE),
pm.UNKNOWN_ACTION,
"Removed permission should be gone"
);
Assert.equal(
pm.getAllByTypes([PERM_TYPE_B]).length,
FILLER_COUNT,
"Permissions added by the observer should be present"
);
pm.removeAll();
});
add_task(async function test_remove_reentrant_remove_all() {
let pm = Services.perms;
pm.addFromPrincipal(PRINCIPAL, PERM_TYPE, pm.ALLOW_ACTION);
pm.addFromPrincipal(PRINCIPAL, PERM_TYPE_B, pm.ALLOW_ACTION);
let reentry = reenterOnDeletion("perm-changed", () => pm.removeAll());
pm.removeFromPrincipal(PRINCIPAL, PERM_TYPE);
Assert.ok(reentry.fired, "Observer should have run during the removal");
Assert.equal(
pm.testPermissionFromPrincipal(PRINCIPAL, PERM_TYPE),
pm.UNKNOWN_ACTION,
"Removed permission should be gone"
);
Assert.equal(
pm.testPermissionFromPrincipal(PRINCIPAL, PERM_TYPE_B),
pm.UNKNOWN_ACTION,
"Permission cleared by the observer should be gone"
);
});
add_task(async function test_remove_browser_reentrant_table_growth() {
let pm = Services.perms;
pm.addFromPrincipalForBrowser(
PRINCIPAL,
PERM_TYPE,
pm.ALLOW_ACTION,
BROWSER_ID,
0
);
let reentry = reenterOnDeletion(
"browser-perm-changed",
addFillerBrowserPermissions
);
pm.removeFromPrincipalForBrowser(PRINCIPAL, PERM_TYPE, BROWSER_ID);
Assert.ok(reentry.fired, "Observer should have run during the removal");
Assert.equal(
pm.testForBrowser(PRINCIPAL, PERM_TYPE, BROWSER_ID),
pm.UNKNOWN_ACTION,
"Removed permission should be gone"
);
assertAndClearFillerBrowserPermissions();
});
add_task(async function test_remove_browser_reentrant_clear() {
let pm = Services.perms;
pm.addFromPrincipalForBrowser(
PRINCIPAL,
PERM_TYPE,
pm.ALLOW_ACTION,
BROWSER_ID,
0
);
pm.addFromPrincipalForBrowser(
PRINCIPAL,
PERM_TYPE_B,
pm.ALLOW_ACTION,
BROWSER_ID,
0
);
let reentry = reenterOnDeletion("browser-perm-changed", () =>
pm.removeAllForBrowser(BROWSER_ID)
);
pm.removeFromPrincipalForBrowser(PRINCIPAL, PERM_TYPE, BROWSER_ID);
Assert.ok(reentry.fired, "Observer should have run during the removal");
Assert.equal(
pm.testForBrowser(PRINCIPAL, PERM_TYPE, BROWSER_ID),
pm.UNKNOWN_ACTION,
"Removed permission should be gone"
);
Assert.equal(
pm.testForBrowser(PRINCIPAL, PERM_TYPE_B, BROWSER_ID),
pm.UNKNOWN_ACTION,
"Permission cleared by the observer should be gone"
);
});
add_task(async function test_browser_expiry_reentrant_table_growth() {
let pm = Services.perms;
let reentry = reenterOnDeletion(
"browser-perm-changed",
addFillerBrowserPermissions
);
pm.addFromPrincipalForBrowser(
PRINCIPAL,
PERM_TYPE,
pm.ALLOW_ACTION,
BROWSER_ID,
100
);
await reentry.promise;
Assert.equal(
pm.testForBrowser(PRINCIPAL, PERM_TYPE, BROWSER_ID),
pm.UNKNOWN_ACTION,
"Expired permission should be gone"
);
assertAndClearFillerBrowserPermissions();
});
add_task(async function test_browser_expiry_reentrant_clear() {
let pm = Services.perms;
let reentry = reenterOnDeletion("browser-perm-changed", () =>
pm.removeAllForBrowser(BROWSER_ID)
);
pm.addFromPrincipalForBrowser(
PRINCIPAL,
PERM_TYPE_B,
pm.ALLOW_ACTION,
BROWSER_ID,
0
);
pm.addFromPrincipalForBrowser(
PRINCIPAL,
PERM_TYPE,
pm.ALLOW_ACTION,
BROWSER_ID,
100
);
await reentry.promise;
Assert.equal(
pm.testForBrowser(PRINCIPAL, PERM_TYPE, BROWSER_ID),
pm.UNKNOWN_ACTION,
"Expired permission should be gone"
);
Assert.equal(
pm.testForBrowser(PRINCIPAL, PERM_TYPE_B, BROWSER_ID),
pm.UNKNOWN_ACTION,
"Permission cleared by the observer should be gone"
);
});