mirror of
https://github.com/zen-browser/desktop.git
synced 2026-06-13 15:03:41 +00:00
no-bug: Sync upstream Firefox to version 151.0.4 (gh-14089)
This commit is contained in:
@@ -34,8 +34,8 @@ Zen is a firefox-based browser with the aim of pushing your productivity to a ne
|
||||
|
||||
### Firefox Versions
|
||||
|
||||
- [`Release`](https://zen-browser.app/download) - Is currently built using Firefox version `151.0.3`! 🚀
|
||||
- [`Twilight`](https://zen-browser.app/download?twilight) - Is currently built using Firefox version `RC 151.0.3`!
|
||||
- [`Release`](https://zen-browser.app/download) - Is currently built using Firefox version `151.0.4`! 🚀
|
||||
- [`Twilight`](https://zen-browser.app/download?twilight) - Is currently built using Firefox version `RC 151.0.4`!
|
||||
|
||||
### Contributing
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
5c4d14a559bf26eb4ab3e136d2084310ebe51ac0
|
||||
9a6aa4c359d1fb6ac60decc82402f82d49a17cea
|
||||
@@ -17,16 +17,6 @@ disable = [
|
||||
source = "browser/components/safebrowsing/content/test"
|
||||
is_direct_path = true
|
||||
|
||||
[sandbox]
|
||||
source = "security/sandbox/test"
|
||||
is_direct_path = true
|
||||
disable = [
|
||||
"browser_bug1393259.js",
|
||||
]
|
||||
|
||||
[sandbox.replace-manifest]
|
||||
"../../../" = "../../../../"
|
||||
|
||||
[shell]
|
||||
source = "browser/components/shell/test"
|
||||
is_direct_path = true
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
BROWSER_CHROME_MANIFESTS += [
|
||||
"readermode/browser.toml",
|
||||
"safebrowsing/browser.toml",
|
||||
"sandbox/browser.toml",
|
||||
"shell/browser.toml",
|
||||
"tabMediaIndicator/browser.toml",
|
||||
"tooltiptext/browser.toml",
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
[DEFAULT]
|
||||
skip-if = [
|
||||
"ccov",
|
||||
"os == 'linux' && os_version == '24.04' && arch == 'x86_64' && display == 'x11' && asan", # bug 1784517
|
||||
"os == 'linux' && os_version == '24.04' && arch == 'x86_64' && display == 'x11' && tsan", # bug 1784517
|
||||
]
|
||||
tags = "contentsandbox"
|
||||
support-files = [
|
||||
"browser_content_sandbox_utils.js",
|
||||
"browser_content_sandbox_fs_tests.js",
|
||||
"mac_register_font.py",
|
||||
"../../../../layout/reftests/fonts/fira/FiraSans-Regular.otf"
|
||||
]
|
||||
|
||||
["browser_bug1393259.js"]
|
||||
disabled="Disabled by import_external_tests.py"
|
||||
support-files = ["bug1393259.html"]
|
||||
run-if = [
|
||||
"os == 'mac'", # This is a Mac-specific test
|
||||
]
|
||||
skip-if = [
|
||||
"os == 'mac' && os_version == '14.70' && arch == 'x86_64'", # Bug 1929424
|
||||
]
|
||||
tags = "os_integration"
|
||||
|
||||
["browser_content_sandbox_fs.js"]
|
||||
skip-if = [
|
||||
"os == 'mac' && os_version == '15.30' && arch == 'aarch64'", # Bug 2023967
|
||||
"os == 'win' && os_version == '11.26100' && arch == 'x86' && debug", # bug 1379635
|
||||
"os == 'win' && os_version == '11.26100' && arch == 'x86_64' && debug", # bug 1379635
|
||||
"os == 'win' && os_version == '11.26200' && arch == 'x86' && debug", # bug 1379635
|
||||
"os == 'win' && os_version == '11.26200' && arch == 'x86_64' && debug", # bug 1379635
|
||||
]
|
||||
|
||||
["browser_content_sandbox_syscalls.js"]
|
||||
|
||||
["browser_sandbox_test.js"]
|
||||
skip-if = [
|
||||
"os == 'win' && os_version == '11.26200' && arch == 'x86' && debug", # bug 2028636
|
||||
"os == 'win' && os_version == '11.26200' && arch == 'x86_64' && debug", # bug 2028636
|
||||
]
|
||||
run-if = [
|
||||
"debug",
|
||||
]
|
||||
@@ -1,203 +0,0 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
* This test validates that an OTF font installed in a directory not
|
||||
* accessible to content processes is rendered correctly by checking that
|
||||
* content displayed never uses the OS fallback font "LastResort". When
|
||||
* a content process renders a page with the fallback font, that is an
|
||||
* indication the content process failed to read or load the computed font.
|
||||
* The test uses a version of the Fira Sans font and depends on the font
|
||||
* not being already installed and enabled.
|
||||
*/
|
||||
|
||||
const kPageURL =
|
||||
"http://example.com/browser/security/sandbox/test/bug1393259.html";
|
||||
|
||||
// Parameters for running the python script that registers/unregisters fonts.
|
||||
let kPythonPath = "/usr/bin/python";
|
||||
if (AppConstants.isPlatformAndVersionAtLeast("macosx", 23.0)) {
|
||||
kPythonPath = "/usr/local/bin/python3";
|
||||
}
|
||||
const kFontInstallerPath = "browser/security/sandbox/test/mac_register_font.py";
|
||||
const kUninstallFlag = "-u";
|
||||
const kVerboseFlag = "-v";
|
||||
|
||||
// Where to find the font in the test environment.
|
||||
const kRepoFontPath = "browser/security/sandbox/test/FiraSans-Regular.otf";
|
||||
|
||||
// Font name strings to check for.
|
||||
const kLastResortFontName = "LastResort";
|
||||
const kTestFontName = "Fira Sans";
|
||||
|
||||
// Home-relative path to install a private font. Where a private font is
|
||||
// a font at a location not readable by content processes.
|
||||
const kPrivateFontSubPath = "/FiraSans-Regular.otf";
|
||||
|
||||
add_task(async function () {
|
||||
await new Promise(resolve => waitForFocus(resolve, window));
|
||||
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{
|
||||
gBrowser,
|
||||
url: kPageURL,
|
||||
},
|
||||
async function (aBrowser) {
|
||||
function runProcess(aCmd, aArgs, blocking = true) {
|
||||
let cmdFile = Cc["@mozilla.org/file/local;1"].createInstance(
|
||||
Ci.nsIFile
|
||||
);
|
||||
cmdFile.initWithPath(aCmd);
|
||||
|
||||
let process = Cc["@mozilla.org/process/util;1"].createInstance(
|
||||
Ci.nsIProcess
|
||||
);
|
||||
process.init(cmdFile);
|
||||
process.run(blocking, aArgs, aArgs.length);
|
||||
return process.exitValue;
|
||||
}
|
||||
|
||||
// Register the font at path |fontPath| and wait
|
||||
// for the browser to detect the change.
|
||||
async function registerFont(fontPath) {
|
||||
let fontRegistered = getFontNotificationPromise();
|
||||
let exitCode = runProcess(kPythonPath, [
|
||||
kFontInstallerPath,
|
||||
kVerboseFlag,
|
||||
fontPath,
|
||||
]);
|
||||
Assert.equal(exitCode, 0, "registering font" + fontPath);
|
||||
if (exitCode == 0) {
|
||||
// Wait for the font registration to be detected by the browser.
|
||||
await fontRegistered;
|
||||
}
|
||||
}
|
||||
|
||||
// Unregister the font at path |fontPath|. If |waitForUnreg| is true,
|
||||
// don't wait for the browser to detect the change and don't use
|
||||
// the verbose arg for the unregister command.
|
||||
async function unregisterFont(fontPath, waitForUnreg = true) {
|
||||
let args = [kFontInstallerPath, kUninstallFlag];
|
||||
let fontUnregistered;
|
||||
|
||||
if (waitForUnreg) {
|
||||
args.push(kVerboseFlag);
|
||||
fontUnregistered = getFontNotificationPromise();
|
||||
}
|
||||
|
||||
let exitCode = runProcess(kPythonPath, args.concat(fontPath));
|
||||
if (waitForUnreg) {
|
||||
Assert.equal(exitCode, 0, "unregistering font" + fontPath);
|
||||
if (exitCode == 0) {
|
||||
await fontUnregistered;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Returns a promise that resolves when font info is changed.
|
||||
let getFontNotificationPromise = () =>
|
||||
new Promise(resolve => {
|
||||
const kTopic = "font-info-updated";
|
||||
function observe() {
|
||||
Services.obs.removeObserver(observe, kTopic);
|
||||
resolve();
|
||||
}
|
||||
|
||||
Services.obs.addObserver(observe, kTopic);
|
||||
});
|
||||
|
||||
let homeDir = Services.dirsvc.get("Home", Ci.nsIFile);
|
||||
let privateFontPath = homeDir.path + kPrivateFontSubPath;
|
||||
|
||||
registerCleanupFunction(function () {
|
||||
unregisterFont(privateFontPath, /* waitForUnreg = */ false);
|
||||
runProcess("/bin/rm", [privateFontPath], /* blocking = */ false);
|
||||
});
|
||||
|
||||
// Copy the font file to the private path.
|
||||
runProcess("/bin/cp", [kRepoFontPath, privateFontPath]);
|
||||
|
||||
// Cleanup previous aborted tests.
|
||||
unregisterFont(privateFontPath, /* waitForUnreg = */ false);
|
||||
|
||||
// Get the original width, using the fallback monospaced font
|
||||
let origWidth = await SpecialPowers.spawn(
|
||||
aBrowser,
|
||||
[],
|
||||
async function () {
|
||||
let window = content.window.wrappedJSObject;
|
||||
let contentDiv = window.document.getElementById("content");
|
||||
return contentDiv.offsetWidth;
|
||||
}
|
||||
);
|
||||
|
||||
// Activate the font we want to test at a non-standard path.
|
||||
await registerFont(privateFontPath);
|
||||
|
||||
// Assign the new font to the content.
|
||||
await SpecialPowers.spawn(aBrowser, [], async function () {
|
||||
let window = content.window.wrappedJSObject;
|
||||
let contentDiv = window.document.getElementById("content");
|
||||
contentDiv.style.fontFamily = "'Fira Sans', monospace";
|
||||
});
|
||||
|
||||
// Wait until the width has changed, indicating the content process
|
||||
// has recognized the newly-activated font.
|
||||
while (true) {
|
||||
let width = await SpecialPowers.spawn(aBrowser, [], async function () {
|
||||
let window = content.window.wrappedJSObject;
|
||||
let contentDiv = window.document.getElementById("content");
|
||||
return contentDiv.offsetWidth;
|
||||
});
|
||||
if (width != origWidth) {
|
||||
break;
|
||||
}
|
||||
// If the content wasn't ready yet, wait a little before re-checking.
|
||||
// eslint-disable-next-line mozilla/no-arbitrary-setTimeout
|
||||
await new Promise(c => setTimeout(c, 100));
|
||||
}
|
||||
|
||||
// Get a list of fonts now being used to display the web content.
|
||||
let fontList = await SpecialPowers.spawn(aBrowser, [], async function () {
|
||||
let window = content.window.wrappedJSObject;
|
||||
let range = window.document.createRange();
|
||||
let contentDiv = window.document.getElementById("content");
|
||||
range.selectNode(contentDiv);
|
||||
let fonts = InspectorUtils.getUsedFontFaces(range);
|
||||
|
||||
let fontList = [];
|
||||
for (let i = 0; i < fonts.length; i++) {
|
||||
fontList.push({ name: fonts[i].name });
|
||||
}
|
||||
return fontList;
|
||||
});
|
||||
|
||||
let lastResortFontUsed = false;
|
||||
let testFontUsed = false;
|
||||
|
||||
for (let font of fontList) {
|
||||
// Did we fall back to the "LastResort" font?
|
||||
if (!lastResortFontUsed && font.name.includes(kLastResortFontName)) {
|
||||
lastResortFontUsed = true;
|
||||
continue;
|
||||
}
|
||||
// Did we render using our test font as expected?
|
||||
if (!testFontUsed && font.name.includes(kTestFontName)) {
|
||||
testFontUsed = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
Assert.ok(
|
||||
!lastResortFontUsed,
|
||||
`The ${kLastResortFontName} fallback font was not used`
|
||||
);
|
||||
|
||||
Assert.ok(testFontUsed, `The test font "${kTestFontName}" was used`);
|
||||
|
||||
await unregisterFont(privateFontPath);
|
||||
}
|
||||
);
|
||||
});
|
||||
@@ -1,15 +0,0 @@
|
||||
# Any copyright is dedicated to the Public Domain.
|
||||
# http://creativecommons.org/publicdomain/zero/1.0/
|
||||
[DEFAULT]
|
||||
skip-if = [
|
||||
"ccov",
|
||||
"os == 'linux' && os_version == '24.04' && arch == 'x86_64' && display == 'x11' && asan", # bug 1784517
|
||||
"os == 'linux' && os_version == '24.04' && arch == 'x86_64' && display == 'x11' && tsan", # bug 1784517
|
||||
]
|
||||
tags = "contentsandbox"
|
||||
environment = "XDG_CONFIG_DIRS=:/opt"
|
||||
|
||||
["browser_content_sandbox_bug1717599_XDG-CONFIG-DIRS.js"]
|
||||
run-if = [
|
||||
"os == 'linux'",
|
||||
]
|
||||
@@ -1,13 +0,0 @@
|
||||
[DEFAULT]
|
||||
skip-if = [
|
||||
"ccov",
|
||||
"os == 'linux' && os_version == '24.04' && arch == 'x86_64' && display == 'x11' && asan", # bug 1784517
|
||||
"os == 'linux' && os_version == '24.04' && arch == 'x86_64' && display == 'x11' && tsan", # bug 1784517
|
||||
]
|
||||
tags = "contentsandbox"
|
||||
environment = "XDG_CONFIG_HOME="
|
||||
|
||||
["browser_content_sandbox_bug1717599_XDG-CONFIG-HOME.js"]
|
||||
run-if = [
|
||||
"os == 'linux'",
|
||||
]
|
||||
@@ -1,11 +0,0 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
/* import-globals-from browser_content_sandbox_utils.js */
|
||||
"use strict";
|
||||
|
||||
//
|
||||
// Just test that browser does not die on empty env var
|
||||
//
|
||||
add_task(async function () {
|
||||
ok(true, "Process can run");
|
||||
});
|
||||
@@ -1,11 +0,0 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
/* import-globals-from browser_content_sandbox_utils.js */
|
||||
"use strict";
|
||||
|
||||
//
|
||||
// Just test that browser does not die on empty env var
|
||||
//
|
||||
add_task(async function () {
|
||||
ok(true, "Process can run");
|
||||
});
|
||||
@@ -1,56 +0,0 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
/* import-globals-from browser_content_sandbox_utils.js */
|
||||
"use strict";
|
||||
|
||||
Services.scriptloader.loadSubScript(
|
||||
"chrome://mochitests/content/browser/" +
|
||||
"security/sandbox/test/browser_content_sandbox_utils.js",
|
||||
this
|
||||
);
|
||||
|
||||
Services.scriptloader.loadSubScript(
|
||||
"chrome://mochitests/content/browser/" +
|
||||
"security/sandbox/test/browser_content_sandbox_fs_tests.js",
|
||||
this
|
||||
);
|
||||
|
||||
/*
|
||||
* This test exercises file I/O from web and file content processes using
|
||||
* nsIFile etc. methods to validate that calls that are meant to be blocked by
|
||||
* content sandboxing are blocked.
|
||||
*/
|
||||
|
||||
//
|
||||
// Checks that sandboxing is enabled and at the appropriate level
|
||||
// setting before triggering tests that do the file I/O.
|
||||
//
|
||||
// Tests attempting to write to a file in the home directory from the
|
||||
// content process--expected to fail.
|
||||
//
|
||||
// Tests attempting to write to a file in the content temp directory
|
||||
// from the content process--expected to succeed. Uses "ContentTmpD".
|
||||
//
|
||||
// Tests reading various files and directories from file and web
|
||||
// content processes.
|
||||
//
|
||||
add_task(async function () {
|
||||
sanityChecks();
|
||||
|
||||
// Test creating a file in the home directory from a web content process
|
||||
add_task(createFileInHome); // eslint-disable-line no-undef
|
||||
|
||||
// Test creating a file content temp from a web content process
|
||||
add_task(createTempFile); // eslint-disable-line no-undef
|
||||
|
||||
// Test reading files/dirs from web and file content processes
|
||||
add_task(testFileAccessAllPlatforms); // eslint-disable-line no-undef
|
||||
|
||||
add_task(testFileAccessMacOnly); // eslint-disable-line no-undef
|
||||
|
||||
add_task(testFileAccessLinuxOnly); // eslint-disable-line no-undef
|
||||
|
||||
add_task(testFileAccessWindowsOnly); // eslint-disable-line no-undef
|
||||
|
||||
add_task(cleanupBrowserTabs); // eslint-disable-line no-undef
|
||||
});
|
||||
@@ -1,31 +0,0 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
/* import-globals-from browser_content_sandbox_utils.js */
|
||||
"use strict";
|
||||
|
||||
Services.scriptloader.loadSubScript(
|
||||
"chrome://mochitests/content/browser/" +
|
||||
"security/sandbox/test/browser_content_sandbox_utils.js",
|
||||
this
|
||||
);
|
||||
|
||||
Services.scriptloader.loadSubScript(
|
||||
"chrome://mochitests/content/browser/" +
|
||||
"security/sandbox/test/browser_content_sandbox_fs_tests.js",
|
||||
this
|
||||
);
|
||||
|
||||
add_task(async function () {
|
||||
// Ensure that SNAP is there
|
||||
const snap = Services.env.get("SNAP");
|
||||
Assert.greater(snap.length, 1, "SNAP is defined");
|
||||
|
||||
// If it is there, do actual testing
|
||||
sanityChecks();
|
||||
|
||||
add_task(testFileAccessLinuxOnly); // eslint-disable-line no-undef
|
||||
|
||||
add_task(testFileAccessLinuxSnap); // eslint-disable-line no-undef
|
||||
|
||||
add_task(cleanupBrowserTabs); // eslint-disable-line no-undef
|
||||
});
|
||||
@@ -1,719 +0,0 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
/* import-globals-from browser_content_sandbox_utils.js */
|
||||
"use strict";
|
||||
|
||||
const lazy = {};
|
||||
|
||||
/* getLibcConstants is only present on *nix */
|
||||
ChromeUtils.defineLazyGetter(lazy, "LIBC", () =>
|
||||
ChromeUtils.getLibcConstants()
|
||||
);
|
||||
|
||||
// Test if the content process can create in $HOME, this should fail
|
||||
async function createFileInHome() {
|
||||
let browser = gBrowser.selectedBrowser;
|
||||
let homeFile = fileInHomeDir();
|
||||
let path = homeFile.path;
|
||||
let fileCreated = await SpecialPowers.spawn(browser, [path], createFile);
|
||||
ok(!fileCreated.ok, "creating a file in home dir failed");
|
||||
is(
|
||||
fileCreated.code,
|
||||
Cr.NS_ERROR_FILE_ACCESS_DENIED,
|
||||
"creating a file in home dir failed with access denied"
|
||||
);
|
||||
if (fileCreated.ok) {
|
||||
// content process successfully created the file, now remove it
|
||||
homeFile.remove(false);
|
||||
}
|
||||
}
|
||||
|
||||
// Test if the content process can create a temp file, this is forbidden on all
|
||||
// platforms. Also test that the content process cannot create symlinks on
|
||||
// macOS/Linux or delete files.
|
||||
async function createTempFile() {
|
||||
// On Windows we allow access to the temp dir for DEBUG builds, because of
|
||||
// logging that uses that dir.
|
||||
let isDbgWin = isWin() && SpecialPowers.isDebugBuild;
|
||||
|
||||
let browser = gBrowser.selectedBrowser;
|
||||
let path = fileInTempDir().path;
|
||||
let fileCreated = await SpecialPowers.spawn(browser, [path], createFile);
|
||||
if (isDbgWin) {
|
||||
ok(fileCreated.ok, "creating a file in temp suceeded");
|
||||
} else {
|
||||
ok(!fileCreated.ok, "creating a file in temp failed");
|
||||
is(
|
||||
fileCreated.code,
|
||||
Cr.NS_ERROR_FILE_ACCESS_DENIED,
|
||||
"creating a file in temp failed with access denied"
|
||||
);
|
||||
}
|
||||
|
||||
// now delete the file
|
||||
let fileDeleted = await SpecialPowers.spawn(browser, [path], deleteFile);
|
||||
if (isDbgWin) {
|
||||
ok(fileDeleted.ok, "deleting a file in temp succeeded");
|
||||
} else {
|
||||
ok(!fileDeleted.ok, "deleting a file in temp failed");
|
||||
const expectedError = isLinux()
|
||||
? Cr.NS_ERROR_FILE_ACCESS_DENIED
|
||||
: Cr.NS_ERROR_FILE_NOT_FOUND;
|
||||
is(
|
||||
fileDeleted.code,
|
||||
expectedError,
|
||||
"deleting a file in temp failed with access denied"
|
||||
);
|
||||
}
|
||||
|
||||
// Test that symlink creation is not allowed on macOS/Linux.
|
||||
if (isMac() || isLinux()) {
|
||||
let path = fileInTempDir().path;
|
||||
let symlinkCreated = await SpecialPowers.spawn(
|
||||
browser,
|
||||
[path],
|
||||
createSymlink
|
||||
);
|
||||
ok(!symlinkCreated.ok, "created a symlink in temp failed");
|
||||
const expectedError = isLinux() ? lazy.LIBC.EACCES : lazy.LIBC.EPERM;
|
||||
is(
|
||||
symlinkCreated.code,
|
||||
expectedError,
|
||||
"created a symlink in temp failed with access denied"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Test reading files and dirs from web and file content processes.
|
||||
async function testFileAccessAllPlatforms() {
|
||||
let webBrowser = GetWebBrowser();
|
||||
let fileContentProcessEnabled = isFileContentProcessEnabled();
|
||||
let fileBrowser = GetFileBrowser();
|
||||
|
||||
// Directories/files to test accessing from content processes.
|
||||
// For directories, we test whether a directory listing is allowed
|
||||
// or blocked. For files, we test if we can read from the file.
|
||||
// Each entry in the array represents a test file or directory
|
||||
// that will be read from either a web or file process.
|
||||
let tests = [];
|
||||
|
||||
let profileDir = GetProfileDir();
|
||||
tests.push({
|
||||
desc: "profile dir", // description
|
||||
ok: false, // expected to succeed?
|
||||
browser: webBrowser, // browser to run test in
|
||||
file: profileDir, // nsIFile object
|
||||
minLevel: minProfileReadSandboxLevel(), // min level to enable test
|
||||
func: readDir,
|
||||
});
|
||||
if (fileContentProcessEnabled) {
|
||||
tests.push({
|
||||
desc: "profile dir",
|
||||
ok: true,
|
||||
browser: fileBrowser,
|
||||
file: profileDir,
|
||||
minLevel: 0,
|
||||
func: readDir,
|
||||
});
|
||||
}
|
||||
|
||||
let homeDir = GetHomeDir();
|
||||
tests.push({
|
||||
desc: "home dir",
|
||||
ok: false,
|
||||
browser: webBrowser,
|
||||
file: homeDir,
|
||||
minLevel: minHomeReadSandboxLevel(),
|
||||
func: readDir,
|
||||
});
|
||||
if (fileContentProcessEnabled) {
|
||||
tests.push({
|
||||
desc: "home dir",
|
||||
ok: true,
|
||||
browser: fileBrowser,
|
||||
file: homeDir,
|
||||
minLevel: 0,
|
||||
func: readDir,
|
||||
});
|
||||
}
|
||||
|
||||
let extensionsDir = GetProfileEntry("extensions");
|
||||
if (extensionsDir.exists() && extensionsDir.isDirectory()) {
|
||||
tests.push({
|
||||
desc: "extensions dir",
|
||||
ok: true,
|
||||
browser: webBrowser,
|
||||
file: extensionsDir,
|
||||
minLevel: 0,
|
||||
func: readDir,
|
||||
});
|
||||
} else {
|
||||
ok(false, `${extensionsDir.path} is a valid dir`);
|
||||
}
|
||||
|
||||
let chromeDir = GetProfileEntry("chrome");
|
||||
if (chromeDir.exists() && chromeDir.isDirectory()) {
|
||||
tests.push({
|
||||
desc: "chrome dir",
|
||||
ok: true,
|
||||
browser: webBrowser,
|
||||
file: chromeDir,
|
||||
minLevel: 0,
|
||||
func: readDir,
|
||||
});
|
||||
} else {
|
||||
ok(false, `${chromeDir.path} is valid dir`);
|
||||
}
|
||||
|
||||
let cookiesFile = GetProfileEntry("cookies.sqlite");
|
||||
if (cookiesFile.exists() && !cookiesFile.isDirectory()) {
|
||||
tests.push({
|
||||
desc: "cookies file",
|
||||
ok: false,
|
||||
browser: webBrowser,
|
||||
file: cookiesFile,
|
||||
minLevel: minProfileReadSandboxLevel(),
|
||||
func: readFile,
|
||||
});
|
||||
if (fileContentProcessEnabled) {
|
||||
tests.push({
|
||||
desc: "cookies file",
|
||||
ok: true,
|
||||
browser: fileBrowser,
|
||||
file: cookiesFile,
|
||||
minLevel: 0,
|
||||
func: readFile,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
ok(false, `${cookiesFile.path} is a valid file`);
|
||||
}
|
||||
|
||||
if (isMac() || isLinux()) {
|
||||
let varDir = GetDir("/var");
|
||||
|
||||
if (isMac()) {
|
||||
// Mac sandbox rules use /private/var because /var is a symlink
|
||||
// to /private/var on OS X. Make sure that hasn't changed.
|
||||
varDir.normalize();
|
||||
Assert.strictEqual(
|
||||
varDir.path,
|
||||
"/private/var",
|
||||
"/var resolves to /private/var"
|
||||
);
|
||||
}
|
||||
|
||||
tests.push({
|
||||
desc: "/var",
|
||||
ok: false,
|
||||
browser: webBrowser,
|
||||
file: varDir,
|
||||
minLevel: minHomeReadSandboxLevel(),
|
||||
func: readDir,
|
||||
});
|
||||
if (fileContentProcessEnabled) {
|
||||
tests.push({
|
||||
desc: "/var",
|
||||
ok: true,
|
||||
browser: fileBrowser,
|
||||
file: varDir,
|
||||
minLevel: 0,
|
||||
func: readDir,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
await runTestsList(tests);
|
||||
}
|
||||
|
||||
async function testFileAccessMacOnly() {
|
||||
if (!isMac()) {
|
||||
return;
|
||||
}
|
||||
|
||||
let webBrowser = GetWebBrowser();
|
||||
let fileContentProcessEnabled = isFileContentProcessEnabled();
|
||||
let fileBrowser = GetFileBrowser();
|
||||
let level = GetSandboxLevel();
|
||||
|
||||
let tests = [];
|
||||
|
||||
// If ~/Library/Caches/TemporaryItems exists, when level <= 2 we
|
||||
// make sure it's readable. For level 3, we make sure it isn't.
|
||||
let homeTempDir = GetHomeDir();
|
||||
homeTempDir.appendRelativePath("Library/Caches/TemporaryItems");
|
||||
if (homeTempDir.exists()) {
|
||||
let shouldBeReadable, minLevel;
|
||||
if (level >= minHomeReadSandboxLevel()) {
|
||||
shouldBeReadable = false;
|
||||
minLevel = minHomeReadSandboxLevel();
|
||||
} else {
|
||||
shouldBeReadable = true;
|
||||
minLevel = 0;
|
||||
}
|
||||
tests.push({
|
||||
desc: "home library cache temp dir",
|
||||
ok: shouldBeReadable,
|
||||
browser: webBrowser,
|
||||
file: homeTempDir,
|
||||
minLevel,
|
||||
func: readDir,
|
||||
});
|
||||
}
|
||||
|
||||
// Test if we can read from $TMPDIR because we expect it
|
||||
// to be within /private/var. Reading from it should be
|
||||
// prevented in a 'web' process.
|
||||
let macTempDir = GetDirFromEnvVariable("TMPDIR");
|
||||
|
||||
macTempDir.normalize();
|
||||
Assert.ok(
|
||||
macTempDir.path.startsWith("/private/var"),
|
||||
"$TMPDIR is in /private/var"
|
||||
);
|
||||
|
||||
tests.push({
|
||||
desc: `$TMPDIR (${macTempDir.path})`,
|
||||
ok: false,
|
||||
browser: webBrowser,
|
||||
file: macTempDir,
|
||||
minLevel: minHomeReadSandboxLevel(),
|
||||
func: readDir,
|
||||
});
|
||||
if (fileContentProcessEnabled) {
|
||||
tests.push({
|
||||
desc: `$TMPDIR (${macTempDir.path})`,
|
||||
ok: true,
|
||||
browser: fileBrowser,
|
||||
file: macTempDir,
|
||||
minLevel: 0,
|
||||
func: readDir,
|
||||
});
|
||||
}
|
||||
|
||||
// The font registry directory is in the Darwin user cache dir which is
|
||||
// accessible with the getconf(1) library call using DARWIN_USER_CACHE_DIR.
|
||||
// For this test, assume the cache dir is located at $TMPDIR/../C and use
|
||||
// the $TMPDIR to derive the path to the registry.
|
||||
let fontRegistryDir = macTempDir.parent.clone();
|
||||
fontRegistryDir.appendRelativePath("C/com.apple.FontRegistry");
|
||||
if (fontRegistryDir.exists()) {
|
||||
tests.push({
|
||||
desc: `FontRegistry (${fontRegistryDir.path})`,
|
||||
ok: true,
|
||||
browser: webBrowser,
|
||||
file: fontRegistryDir,
|
||||
minLevel: minHomeReadSandboxLevel(),
|
||||
func: readDir,
|
||||
});
|
||||
// Check that we can read the file named `font` which typically
|
||||
// exists in the the font registry directory.
|
||||
let fontFile = fontRegistryDir.clone();
|
||||
fontFile.appendRelativePath("font");
|
||||
if (fontFile.exists()) {
|
||||
tests.push({
|
||||
desc: `FontRegistry file (${fontFile.path})`,
|
||||
ok: true,
|
||||
browser: webBrowser,
|
||||
file: fontFile,
|
||||
minLevel: minHomeReadSandboxLevel(),
|
||||
func: readFile,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Test that we cannot read from /Volumes at level 3
|
||||
let volumes = GetDir("/Volumes");
|
||||
tests.push({
|
||||
desc: "/Volumes",
|
||||
ok: false,
|
||||
browser: webBrowser,
|
||||
file: volumes,
|
||||
minLevel: minHomeReadSandboxLevel(),
|
||||
func: readDir,
|
||||
});
|
||||
|
||||
// Test that we cannot read from /Users at level 3
|
||||
let users = GetDir("/Users");
|
||||
tests.push({
|
||||
desc: "/Users",
|
||||
ok: false,
|
||||
browser: webBrowser,
|
||||
file: users,
|
||||
minLevel: minHomeReadSandboxLevel(),
|
||||
func: readDir,
|
||||
});
|
||||
|
||||
// Test that we can stat /Users at level 3
|
||||
tests.push({
|
||||
desc: "/Users",
|
||||
ok: true,
|
||||
browser: webBrowser,
|
||||
file: users,
|
||||
minLevel: minHomeReadSandboxLevel(),
|
||||
func: statPath,
|
||||
});
|
||||
|
||||
// Test that we can stat /Library at level 3, but can't get a
|
||||
// directory listing of /Library. This test uses "/Library"
|
||||
// because it's a path that is expected to always be present.
|
||||
let libraryDir = GetDir("/Library");
|
||||
tests.push({
|
||||
desc: "/Library",
|
||||
ok: true,
|
||||
browser: webBrowser,
|
||||
file: libraryDir,
|
||||
minLevel: minHomeReadSandboxLevel(),
|
||||
func: statPath,
|
||||
});
|
||||
tests.push({
|
||||
desc: "/Library",
|
||||
ok: false,
|
||||
browser: webBrowser,
|
||||
file: libraryDir,
|
||||
minLevel: minHomeReadSandboxLevel(),
|
||||
func: readDir,
|
||||
});
|
||||
|
||||
// Similarly, test that we can stat /private, but not /private/etc.
|
||||
let privateDir = GetDir("/private");
|
||||
tests.push({
|
||||
desc: "/private",
|
||||
ok: true,
|
||||
browser: webBrowser,
|
||||
file: privateDir,
|
||||
minLevel: minHomeReadSandboxLevel(),
|
||||
func: statPath,
|
||||
});
|
||||
|
||||
await runTestsList(tests);
|
||||
}
|
||||
|
||||
async function testFileAccessLinuxOnly() {
|
||||
if (!isLinux()) {
|
||||
return;
|
||||
}
|
||||
|
||||
let webBrowser = GetWebBrowser();
|
||||
let fileContentProcessEnabled = isFileContentProcessEnabled();
|
||||
let fileBrowser = GetFileBrowser();
|
||||
|
||||
let tests = [];
|
||||
|
||||
// Test /proc/self/fd, because that can be used to unfreeze
|
||||
// frozen shared memory.
|
||||
let selfFdDir = GetDir("/proc/self/fd");
|
||||
tests.push({
|
||||
desc: "/proc/self/fd",
|
||||
ok: false,
|
||||
browser: webBrowser,
|
||||
file: selfFdDir,
|
||||
minLevel: isContentFileIOSandboxed(),
|
||||
func: readDir,
|
||||
});
|
||||
|
||||
let cacheFontConfigDir = GetHomeSubdir(".cache/fontconfig/");
|
||||
tests.push({
|
||||
desc: `$HOME/.cache/fontconfig/ (${cacheFontConfigDir.path})`,
|
||||
ok: true,
|
||||
browser: webBrowser,
|
||||
file: cacheFontConfigDir,
|
||||
minLevel: minHomeReadSandboxLevel(),
|
||||
func: readDir,
|
||||
});
|
||||
|
||||
// allows to handle both $HOME/.config/ or $XDG_CONFIG_HOME
|
||||
let configDir = GetHomeSubdir(".config");
|
||||
|
||||
const xdgConfigHome = Services.env.get("XDG_CONFIG_HOME");
|
||||
if (xdgConfigHome) {
|
||||
configDir = GetDir(xdgConfigHome);
|
||||
configDir.normalize();
|
||||
}
|
||||
|
||||
tests.push({
|
||||
desc: `$XDG_CONFIG_HOME (${configDir.path})`,
|
||||
ok: true, // access should not be granted outside of XDG support
|
||||
browser: webBrowser,
|
||||
file: configDir,
|
||||
minLevel: minHomeReadSandboxLevel(),
|
||||
func: readDir,
|
||||
});
|
||||
|
||||
tests.push({
|
||||
desc: `XDG_CONFIG_HOME=${configDir.path} dir should have rdonly`,
|
||||
ok: true, // should be allowed only if XDG support is there
|
||||
browser: webBrowser,
|
||||
file: configDir,
|
||||
minLevel: minHomeReadSandboxLevel(),
|
||||
func: readDir,
|
||||
});
|
||||
|
||||
if (fileContentProcessEnabled) {
|
||||
tests.push({
|
||||
desc: `${configDir.path} dir`,
|
||||
ok: true, // should be allowed only if XDG support is there
|
||||
browser: fileBrowser,
|
||||
file: configDir,
|
||||
minLevel: 0,
|
||||
func: readDir,
|
||||
});
|
||||
}
|
||||
|
||||
if (isXdgEnabled() && xdgConfigHome) {
|
||||
const homeConfigDir = GetHomeSubdir(".config");
|
||||
tests.push({
|
||||
desc: `XDG_CONFIG_HOME=${homeConfigDir.path} dir should deny $HOME/.config`,
|
||||
ok: false,
|
||||
browser: webBrowser,
|
||||
file: homeConfigDir,
|
||||
minLevel: minHomeReadSandboxLevel(),
|
||||
func: readDir,
|
||||
});
|
||||
if (fileContentProcessEnabled) {
|
||||
tests.push({
|
||||
desc: `${homeConfigDir.path} dir`,
|
||||
ok: true,
|
||||
browser: fileBrowser,
|
||||
file: homeConfigDir,
|
||||
minLevel: 0,
|
||||
func: readDir,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// WWhen XDG_CONFIG_HOME is not set, verify we do not allow $HOME/.configlol
|
||||
// (i.e., check allow the dir and not the prefix)
|
||||
//
|
||||
// Checking $HOME/.config is already done above.
|
||||
const homeConfigPrefix = GetHomeSubdir(".configlol");
|
||||
tests.push({
|
||||
desc: `No XDG_CONFIG_HOME we dont allow ${homeConfigPrefix.path} access`,
|
||||
ok: false,
|
||||
browser: webBrowser,
|
||||
file: homeConfigPrefix,
|
||||
minLevel: minHomeReadSandboxLevel(),
|
||||
func: readDir,
|
||||
});
|
||||
if (fileContentProcessEnabled) {
|
||||
tests.push({
|
||||
desc: `No XDG_CONFIG_HOME we dont allow ${homeConfigPrefix.path} access`,
|
||||
ok: false,
|
||||
browser: fileBrowser,
|
||||
file: homeConfigPrefix,
|
||||
minLevel: 0,
|
||||
func: readDir,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Create a file under $HOME/.config/ or $XDG_CONFIG_HOME and ensure we can
|
||||
// read it
|
||||
let fileUnderConfig = GetSubdirFile(configDir);
|
||||
await IOUtils.writeUTF8(fileUnderConfig.path, "TEST FILE DUMMY DATA");
|
||||
ok(
|
||||
await IOUtils.exists(fileUnderConfig.path),
|
||||
`File ${fileUnderConfig.path} was properly created`
|
||||
);
|
||||
|
||||
tests.push({
|
||||
desc: `${configDir.path}/xxx is readable (${fileUnderConfig.path})`,
|
||||
ok: true,
|
||||
browser: webBrowser,
|
||||
file: fileUnderConfig,
|
||||
minLevel: minHomeReadSandboxLevel(),
|
||||
func: readFile,
|
||||
cleanup: aPath => IOUtils.remove(aPath),
|
||||
});
|
||||
|
||||
let configFile = GetSubdirFile(configDir);
|
||||
tests.push({
|
||||
desc: `${configDir.path} file write`,
|
||||
ok: false,
|
||||
browser: webBrowser,
|
||||
file: configFile,
|
||||
minLevel: minHomeReadSandboxLevel(),
|
||||
func: createFile,
|
||||
});
|
||||
if (fileContentProcessEnabled) {
|
||||
tests.push({
|
||||
desc: `${configDir.path} file write`,
|
||||
ok: false,
|
||||
browser: fileBrowser,
|
||||
file: configFile,
|
||||
minLevel: 0,
|
||||
func: createFile,
|
||||
});
|
||||
}
|
||||
|
||||
// Create a $HOME/.config/mozilla/ or $XDG_CONFIG_HOME/mozilla/ if none
|
||||
// exists and assert content process cannot access it
|
||||
let configMozilla = GetSubdir(configDir, "mozilla");
|
||||
const emptyFileName = ".test_run_browser_sandbox.tmp";
|
||||
let emptyFile = configMozilla.clone();
|
||||
emptyFile.appendRelativePath(emptyFileName);
|
||||
|
||||
let populateFakeConfigMozilla = async aPath => {
|
||||
// called with configMozilla
|
||||
await IOUtils.makeDirectory(aPath, { permissions: 0o700 });
|
||||
await IOUtils.writeUTF8(emptyFile.path, "");
|
||||
ok(
|
||||
await IOUtils.exists(emptyFile.path),
|
||||
`Temp file ${emptyFile.path} was created`
|
||||
);
|
||||
};
|
||||
|
||||
let unpopulateFakeConfigMozilla = async aPath => {
|
||||
// called with emptyFile
|
||||
await IOUtils.remove(aPath);
|
||||
ok(!(await IOUtils.exists(aPath)), `Temp file ${aPath} was removed`);
|
||||
const parentDir = PathUtils.parent(aPath);
|
||||
try {
|
||||
await IOUtils.remove(parentDir, { recursive: false });
|
||||
} catch (ex) {
|
||||
if (
|
||||
!DOMException.isInstance(ex) ||
|
||||
ex.name !== "OperationError" ||
|
||||
/Could not remove the non-empty directory/.test(ex.message)
|
||||
) {
|
||||
// If we get here it means the directory was not empty and since we assert
|
||||
// earlier we removed the temp file we created it means we should not
|
||||
// worrying about removing this directory ...
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
await populateFakeConfigMozilla(configMozilla.path);
|
||||
|
||||
tests.push({
|
||||
desc: `stat ${configDir.path}/mozilla (${configMozilla.path})`,
|
||||
ok: false,
|
||||
browser: webBrowser,
|
||||
file: configMozilla,
|
||||
minLevel: minHomeReadSandboxLevel(),
|
||||
func: statPath,
|
||||
});
|
||||
|
||||
tests.push({
|
||||
desc: `read ${configDir.path}/mozilla (${configMozilla.path})`,
|
||||
ok: false,
|
||||
browser: webBrowser,
|
||||
file: configMozilla,
|
||||
minLevel: minHomeReadSandboxLevel(),
|
||||
func: readDir,
|
||||
});
|
||||
|
||||
tests.push({
|
||||
desc: `stat ${configDir.path}/mozilla/${emptyFileName} (${emptyFile.path})`,
|
||||
ok: false,
|
||||
browser: webBrowser,
|
||||
file: emptyFile,
|
||||
minLevel: minHomeReadSandboxLevel(),
|
||||
func: statPath,
|
||||
});
|
||||
|
||||
tests.push({
|
||||
desc: `read ${configDir.path}/mozilla/${emptyFileName} (${emptyFile.path})`,
|
||||
ok: false,
|
||||
browser: webBrowser,
|
||||
file: emptyFile,
|
||||
minLevel: minHomeReadSandboxLevel(),
|
||||
func: readFile,
|
||||
cleanup: unpopulateFakeConfigMozilla,
|
||||
});
|
||||
|
||||
// Only needed to perform cleanup
|
||||
if (isXdgEnabled()) {
|
||||
tests.push({
|
||||
desc: `$XDG_CONFIG_HOME (${configDir.path}) cleanup`,
|
||||
ok: true,
|
||||
browser: webBrowser,
|
||||
file: configDir,
|
||||
minLevel: minHomeReadSandboxLevel(),
|
||||
func: readDir,
|
||||
});
|
||||
}
|
||||
|
||||
await runTestsList(tests);
|
||||
}
|
||||
|
||||
async function testFileAccessLinuxSnap() {
|
||||
let webBrowser = GetWebBrowser();
|
||||
|
||||
let tests = [];
|
||||
|
||||
// Assert that if we run with SNAP= env, then we allow access to it in the
|
||||
// content process
|
||||
let snap = Services.env.get("SNAP");
|
||||
let snapExpectedResult = false;
|
||||
if (snap.length > 1) {
|
||||
snapExpectedResult = true;
|
||||
} else {
|
||||
snap = "/tmp/.snap_firefox_current/";
|
||||
}
|
||||
|
||||
let snapDir = GetDir(snap);
|
||||
snapDir.normalize();
|
||||
|
||||
let snapFile = GetSubdirFile(snapDir);
|
||||
await createFile(snapFile.path);
|
||||
ok(await IOUtils.exists(snapFile.path), `SNAP ${snapFile.path} was created`);
|
||||
info(`SNAP (file) ${snapFile.path} was created`);
|
||||
|
||||
tests.push({
|
||||
desc: `$SNAP (${snapDir.path} => ${snapFile.path})`,
|
||||
ok: snapExpectedResult,
|
||||
browser: webBrowser,
|
||||
file: snapFile,
|
||||
minLevel: minHomeReadSandboxLevel(),
|
||||
func: readFile,
|
||||
});
|
||||
|
||||
await runTestsList(tests);
|
||||
}
|
||||
|
||||
async function testFileAccessWindowsOnly() {
|
||||
if (!isWin()) {
|
||||
return;
|
||||
}
|
||||
|
||||
let webBrowser = GetWebBrowser();
|
||||
|
||||
let tests = [];
|
||||
|
||||
let extDir = GetPerUserExtensionDir();
|
||||
// We used to unconditionally create this directory from Firefox, but that
|
||||
// was dropped in bug 2001887. The value of this directory is questionable;
|
||||
// the test was added in Firefox 56 (bug 1403744) to cover legacy add-ons,
|
||||
// but legacy add-on support was discontinued in Firefox 57, and we stopped
|
||||
// sideloading add-ons from this directory on all builds except ESR in
|
||||
// Firefox 74 (bug 1602840).
|
||||
await IOUtils.makeDirectory(extDir.path);
|
||||
tests.push({
|
||||
desc: "per-user extensions dir",
|
||||
ok: true,
|
||||
browser: webBrowser,
|
||||
file: extDir,
|
||||
minLevel: minHomeReadSandboxLevel(),
|
||||
func: readDir,
|
||||
});
|
||||
|
||||
await runTestsList(tests);
|
||||
}
|
||||
|
||||
function cleanupBrowserTabs() {
|
||||
let fileBrowser = GetFileBrowser();
|
||||
if (fileBrowser.selectedTab) {
|
||||
gBrowser.removeTab(fileBrowser.selectedTab);
|
||||
}
|
||||
|
||||
let webBrowser = GetWebBrowser();
|
||||
if (webBrowser.selectedTab) {
|
||||
gBrowser.removeTab(webBrowser.selectedTab);
|
||||
}
|
||||
|
||||
let tab1 = gBrowser.tabs[1];
|
||||
if (tab1) {
|
||||
gBrowser.removeTab(tab1);
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
/* import-globals-from browser_content_sandbox_utils.js */
|
||||
"use strict";
|
||||
|
||||
Services.scriptloader.loadSubScript(
|
||||
"chrome://mochitests/content/browser/" +
|
||||
"security/sandbox/test/browser_content_sandbox_utils.js",
|
||||
this
|
||||
);
|
||||
|
||||
Services.scriptloader.loadSubScript(
|
||||
"chrome://mochitests/content/browser/" +
|
||||
"security/sandbox/test/browser_content_sandbox_fs_tests.js",
|
||||
this
|
||||
);
|
||||
|
||||
SimpleTest.requestCompleteLog();
|
||||
|
||||
add_setup(async function setup() {
|
||||
const xdgConfigHome = Services.env.exists("XDG_CONFIG_HOME");
|
||||
Assert.equal(xdgConfigHome, false, `XDG_CONFIG_HOME is not set`);
|
||||
|
||||
const mozLegacyHome = Services.env.exists("MOZ_LEGACY_HOME");
|
||||
Assert.equal(mozLegacyHome, false, "MOZ_LEGACY_HOME is not set");
|
||||
|
||||
// If it is there, do actual testing
|
||||
sanityChecks();
|
||||
});
|
||||
|
||||
add_task(async function () {
|
||||
// Make sure we dont break others.
|
||||
add_task(testFileAccessAllPlatforms); // eslint-disable-line no-undef
|
||||
|
||||
// The linux only tests are the ones that can behave differently based on
|
||||
// existence of XDG_CONFIG_HOME
|
||||
add_task(testFileAccessLinuxOnly); // eslint-disable-line no-undef
|
||||
|
||||
add_task(cleanupBrowserTabs); // eslint-disable-line no-undef
|
||||
});
|
||||
@@ -1,42 +0,0 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
/* import-globals-from browser_content_sandbox_utils.js */
|
||||
"use strict";
|
||||
|
||||
Services.scriptloader.loadSubScript(
|
||||
"chrome://mochitests/content/browser/" +
|
||||
"security/sandbox/test/browser_content_sandbox_utils.js",
|
||||
this
|
||||
);
|
||||
|
||||
Services.scriptloader.loadSubScript(
|
||||
"chrome://mochitests/content/browser/" +
|
||||
"security/sandbox/test/browser_content_sandbox_fs_tests.js",
|
||||
this
|
||||
);
|
||||
|
||||
SimpleTest.requestCompleteLog();
|
||||
|
||||
add_setup(async function setup() {
|
||||
const xdgConfigHome = Services.env.exists("XDG_CONFIG_HOME");
|
||||
Assert.equal(xdgConfigHome, true, "XDG_CONFIG_HOME is defined");
|
||||
|
||||
if (isXdgEnabled()) {
|
||||
const mozLegacyHome = Services.env.get("MOZ_LEGACY_HOME");
|
||||
Assert.equal(mozLegacyHome, 1, "MOZ_LEGACY_HOME is set to 1");
|
||||
}
|
||||
|
||||
// If it is there, do actual testing
|
||||
sanityChecks();
|
||||
});
|
||||
|
||||
add_task(async function () {
|
||||
// Make sure we dont break others.
|
||||
add_task(testFileAccessAllPlatforms); // eslint-disable-line no-undef
|
||||
|
||||
// The linux only tests are the ones that can behave differently based on
|
||||
// existence of XDG_CONFIG_HOME
|
||||
add_task(testFileAccessLinuxOnly); // eslint-disable-line no-undef
|
||||
|
||||
add_task(cleanupBrowserTabs); // eslint-disable-line no-undef
|
||||
});
|
||||
@@ -1,45 +0,0 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
/* import-globals-from browser_content_sandbox_utils.js */
|
||||
"use strict";
|
||||
|
||||
Services.scriptloader.loadSubScript(
|
||||
"chrome://mochitests/content/browser/" +
|
||||
"security/sandbox/test/browser_content_sandbox_utils.js",
|
||||
this
|
||||
);
|
||||
|
||||
Services.scriptloader.loadSubScript(
|
||||
"chrome://mochitests/content/browser/" +
|
||||
"security/sandbox/test/browser_content_sandbox_fs_tests.js",
|
||||
this
|
||||
);
|
||||
|
||||
SimpleTest.requestCompleteLog();
|
||||
|
||||
add_setup(async function setup() {
|
||||
// Ensure that XDG_CONFIG_HOME is there
|
||||
const xdgConfigHome = Services.env.get("XDG_CONFIG_HOME");
|
||||
Assert.greater(xdgConfigHome.length, 1, "XDG_CONFIG_HOME is defined");
|
||||
|
||||
// Verify the profile directory is inside XDG_CONFIG_HOME
|
||||
const profileDir = Services.dirsvc.get("ProfD", Ci.nsIFile);
|
||||
Assert.ok(
|
||||
profileDir.path.startsWith(xdgConfigHome),
|
||||
`Profile directory (${profileDir.path}) should be inside XDG_CONFIG_HOME (${xdgConfigHome})`
|
||||
);
|
||||
|
||||
// If it is there, do actual testing
|
||||
sanityChecks();
|
||||
});
|
||||
|
||||
add_task(async function () {
|
||||
// Make sure we dont break others.
|
||||
add_task(testFileAccessAllPlatforms); // eslint-disable-line no-undef
|
||||
|
||||
// The linux only tests are the ones that can behave differently based on
|
||||
// existence of XDG_CONFIG_HOME
|
||||
add_task(testFileAccessLinuxOnly); // eslint-disable-line no-undef
|
||||
|
||||
add_task(cleanupBrowserTabs); // eslint-disable-line no-undef
|
||||
});
|
||||
@@ -1,405 +0,0 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
/* import-globals-from browser_content_sandbox_utils.js */
|
||||
"use strict";
|
||||
|
||||
Services.scriptloader.loadSubScript(
|
||||
"chrome://mochitests/content/browser/" +
|
||||
"security/sandbox/test/browser_content_sandbox_utils.js",
|
||||
this
|
||||
);
|
||||
|
||||
const lazy = {};
|
||||
|
||||
/* getLibcConstants is only present on *nix */
|
||||
ChromeUtils.defineLazyGetter(lazy, "LIBC", () =>
|
||||
ChromeUtils.getLibcConstants()
|
||||
);
|
||||
|
||||
/*
|
||||
* This test is for executing system calls in content processes to validate
|
||||
* that calls that are meant to be blocked by content sandboxing are blocked.
|
||||
* We use the term system calls loosely so that any OS API call such as
|
||||
* fopen could be included.
|
||||
*/
|
||||
|
||||
// Calls the native execv library function. Include imports so this can be
|
||||
// safely serialized and run remotely by SpecialPowers.spawn.
|
||||
function callExec(args) {
|
||||
const { ctypes } = ChromeUtils.importESModule(
|
||||
"resource://gre/modules/ctypes.sys.mjs"
|
||||
);
|
||||
let { lib, cmd } = args;
|
||||
let libc = ctypes.open(lib);
|
||||
let exec = libc.declare(
|
||||
"execv",
|
||||
ctypes.default_abi,
|
||||
ctypes.int,
|
||||
ctypes.char.ptr
|
||||
);
|
||||
let rv = exec(cmd);
|
||||
libc.close();
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Calls the native fork syscall.
|
||||
function callFork(args) {
|
||||
const { ctypes } = ChromeUtils.importESModule(
|
||||
"resource://gre/modules/ctypes.sys.mjs"
|
||||
);
|
||||
let { lib } = args;
|
||||
let libc = ctypes.open(lib);
|
||||
let fork = libc.declare("fork", ctypes.default_abi, ctypes.int);
|
||||
let rv = fork();
|
||||
libc.close();
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Calls the native sysctl syscall.
|
||||
function callSysctl(args) {
|
||||
const { ctypes } = ChromeUtils.importESModule(
|
||||
"resource://gre/modules/ctypes.sys.mjs"
|
||||
);
|
||||
let { lib, name } = args;
|
||||
let libc = ctypes.open(lib);
|
||||
let sysctlbyname = libc.declare(
|
||||
"sysctlbyname",
|
||||
ctypes.default_abi,
|
||||
ctypes.int,
|
||||
ctypes.char.ptr,
|
||||
ctypes.voidptr_t,
|
||||
ctypes.size_t.ptr,
|
||||
ctypes.voidptr_t,
|
||||
ctypes.size_t.ptr
|
||||
);
|
||||
let rv = sysctlbyname(name, null, null, null, null);
|
||||
libc.close();
|
||||
return rv;
|
||||
}
|
||||
|
||||
function callPrctl(args) {
|
||||
const { ctypes } = ChromeUtils.importESModule(
|
||||
"resource://gre/modules/ctypes.sys.mjs"
|
||||
);
|
||||
let { lib, option } = args;
|
||||
let libc = ctypes.open(lib);
|
||||
let prctl = libc.declare(
|
||||
"prctl",
|
||||
ctypes.default_abi,
|
||||
ctypes.int,
|
||||
ctypes.int, // option
|
||||
ctypes.unsigned_long, // arg2
|
||||
ctypes.unsigned_long, // arg3
|
||||
ctypes.unsigned_long, // arg4
|
||||
ctypes.unsigned_long // arg5
|
||||
);
|
||||
let rv = prctl(option, 0, 0, 0, 0);
|
||||
if (rv == -1) {
|
||||
rv = ctypes.errno;
|
||||
}
|
||||
libc.close();
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Calls the native open/close syscalls.
|
||||
function callOpen(args) {
|
||||
const { ctypes } = ChromeUtils.importESModule(
|
||||
"resource://gre/modules/ctypes.sys.mjs"
|
||||
);
|
||||
let { lib, path, flags } = args;
|
||||
let libc = ctypes.open(lib);
|
||||
let open = libc.declare(
|
||||
"open",
|
||||
ctypes.default_abi,
|
||||
ctypes.int,
|
||||
ctypes.char.ptr,
|
||||
ctypes.int
|
||||
);
|
||||
let close = libc.declare("close", ctypes.default_abi, ctypes.int, ctypes.int);
|
||||
let fd = open(path, flags);
|
||||
close(fd);
|
||||
libc.close();
|
||||
return fd;
|
||||
}
|
||||
|
||||
// Verify faccessat2
|
||||
function callFaccessat2(args) {
|
||||
const { ctypes } = ChromeUtils.importESModule(
|
||||
"resource://gre/modules/ctypes.sys.mjs"
|
||||
);
|
||||
let { lib, dirfd, path, mode, flag } = args;
|
||||
let libc = ctypes.open(lib);
|
||||
let faccessat = libc.declare(
|
||||
"faccessat",
|
||||
ctypes.default_abi,
|
||||
ctypes.int,
|
||||
ctypes.int, // dirfd
|
||||
ctypes.char.ptr, // path
|
||||
ctypes.int, // mode
|
||||
ctypes.int // flag
|
||||
);
|
||||
let rv = faccessat(dirfd, path, mode, flag);
|
||||
if (rv == -1) {
|
||||
rv = ctypes.errno;
|
||||
}
|
||||
libc.close();
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Returns the name of the native library needed for native syscalls
|
||||
function getOSLib() {
|
||||
switch (Services.appinfo.OS) {
|
||||
case "WINNT":
|
||||
return "kernel32.dll";
|
||||
case "Darwin":
|
||||
return "libc.dylib";
|
||||
case "Linux":
|
||||
return "libc.so.6";
|
||||
default:
|
||||
Assert.ok(false, "Unknown OS");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Reading a header might be weird, but the alternatives to read a stable
|
||||
// version number we can easily check against are not much more fun
|
||||
async function getKernelVersion() {
|
||||
let header = await IOUtils.readUTF8("/usr/include/linux/version.h");
|
||||
let hr = header.split("\n");
|
||||
for (let line in hr) {
|
||||
let hrs = hr[line].split(" ");
|
||||
if (hrs[0] === "#define" && hrs[1] === "LINUX_VERSION_CODE") {
|
||||
return Number(hrs[2]);
|
||||
}
|
||||
}
|
||||
throw Error("No LINUX_VERSION_CODE");
|
||||
}
|
||||
|
||||
// This is how it is done in /usr/include/linux/version.h
|
||||
function computeKernelVersion(major, minor, dot) {
|
||||
return (major << 16) + (minor << 8) + dot;
|
||||
}
|
||||
|
||||
function getGlibcVersion() {
|
||||
const { ctypes } = ChromeUtils.importESModule(
|
||||
"resource://gre/modules/ctypes.sys.mjs"
|
||||
);
|
||||
let libc = ctypes.open(getOSLib());
|
||||
let gnu_get_libc_version = libc.declare(
|
||||
"gnu_get_libc_version",
|
||||
ctypes.default_abi,
|
||||
ctypes.char.ptr
|
||||
);
|
||||
let rv = gnu_get_libc_version().readString();
|
||||
libc.close();
|
||||
let ar = rv.split(".");
|
||||
// return a number made of MAJORMINOR
|
||||
return Number(ar[0] + ar[1]);
|
||||
}
|
||||
|
||||
// Returns a harmless command to execute with execv
|
||||
function getOSExecCmd() {
|
||||
Assert.ok(!isWin());
|
||||
return "/bin/cat";
|
||||
}
|
||||
|
||||
// Returns true if the current content sandbox level, passed in
|
||||
// the |level| argument, supports syscall sandboxing.
|
||||
function areContentSyscallsSandboxed(level) {
|
||||
let syscallsSandboxMinLevel = 0;
|
||||
|
||||
// Set syscallsSandboxMinLevel to the lowest level that has
|
||||
// syscall sandboxing enabled. For now, this varies across
|
||||
// Windows, Mac, Linux, other.
|
||||
switch (Services.appinfo.OS) {
|
||||
case "WINNT":
|
||||
syscallsSandboxMinLevel = 1;
|
||||
break;
|
||||
case "Darwin":
|
||||
syscallsSandboxMinLevel = 1;
|
||||
break;
|
||||
case "Linux":
|
||||
syscallsSandboxMinLevel = 1;
|
||||
break;
|
||||
default:
|
||||
Assert.ok(false, "Unknown OS");
|
||||
}
|
||||
|
||||
return level >= syscallsSandboxMinLevel;
|
||||
}
|
||||
|
||||
//
|
||||
// Drive tests for a single content process.
|
||||
//
|
||||
// Tests executing OS API calls in the content process. Limited to Mac
|
||||
// and Linux calls for now.
|
||||
//
|
||||
add_task(async function () {
|
||||
// This test is only relevant in e10s
|
||||
if (!gMultiProcessBrowser) {
|
||||
ok(false, "e10s is enabled");
|
||||
info("e10s is not enabled, exiting");
|
||||
return;
|
||||
}
|
||||
|
||||
let level = 0;
|
||||
let prefExists = true;
|
||||
|
||||
// Read the security.sandbox.content.level pref.
|
||||
// If the pref isn't set and we're running on Linux on !isNightly(),
|
||||
// exit without failing. The Linux content sandbox is only enabled
|
||||
// on Nightly at this time.
|
||||
// eslint-disable-next-line mozilla/use-default-preference-values
|
||||
try {
|
||||
level = Services.prefs.getIntPref("security.sandbox.content.level");
|
||||
} catch (e) {
|
||||
prefExists = false;
|
||||
}
|
||||
|
||||
ok(prefExists, "pref security.sandbox.content.level exists");
|
||||
if (!prefExists) {
|
||||
return;
|
||||
}
|
||||
|
||||
info(`security.sandbox.content.level=${level}`);
|
||||
Assert.greater(level, 0, "content sandbox is enabled.");
|
||||
|
||||
let areSyscallsSandboxed = areContentSyscallsSandboxed(level);
|
||||
|
||||
// Content sandbox enabled, but level doesn't include syscall sandboxing.
|
||||
ok(areSyscallsSandboxed, "content syscall sandboxing is enabled.");
|
||||
if (!areSyscallsSandboxed) {
|
||||
info("content sandbox level too low for syscall tests, exiting\n");
|
||||
return;
|
||||
}
|
||||
|
||||
let browser = gBrowser.selectedBrowser;
|
||||
let lib = getOSLib();
|
||||
|
||||
// use execv syscall
|
||||
// (causes content process to be killed on Linux)
|
||||
if (isMac()) {
|
||||
// exec something harmless, this should fail
|
||||
let cmd = getOSExecCmd();
|
||||
let rv = await SpecialPowers.spawn(browser, [{ lib, cmd }], callExec);
|
||||
Assert.equal(rv, -1, `exec(${cmd}) is not permitted`);
|
||||
}
|
||||
|
||||
// use open syscall
|
||||
if (isLinux() || isMac()) {
|
||||
// open a file for writing in $HOME, this should fail
|
||||
let path = fileInHomeDir().path;
|
||||
let flags = lazy.LIBC.O_CREAT | lazy.LIBC.O_WRONLY;
|
||||
let fd = await SpecialPowers.spawn(
|
||||
browser,
|
||||
[{ lib, path, flags }],
|
||||
callOpen
|
||||
);
|
||||
Assert.less(fd, 0, "opening a file for writing in home is not permitted");
|
||||
}
|
||||
|
||||
// use open syscall
|
||||
if (isLinux() || isMac()) {
|
||||
// open a file for writing in the content temp dir, this should fail on
|
||||
// macOS and Linux. The open handler in the content process closes the file
|
||||
// for us
|
||||
let path = fileInTempDir().path;
|
||||
let flags = lazy.LIBC.O_CREAT | lazy.LIBC.O_WRONLY;
|
||||
let fd = await SpecialPowers.spawn(
|
||||
browser,
|
||||
[{ lib, path, flags }],
|
||||
callOpen
|
||||
);
|
||||
Assert.strictEqual(
|
||||
fd,
|
||||
-1,
|
||||
"opening a file for writing in content temp is not permitted"
|
||||
);
|
||||
}
|
||||
|
||||
// use fork syscall
|
||||
if (isLinux() || isMac()) {
|
||||
let rv = await SpecialPowers.spawn(browser, [{ lib }], callFork);
|
||||
Assert.equal(rv, -1, "calling fork is not permitted");
|
||||
}
|
||||
|
||||
// On macOS before 10.10 the |sysctl-name| predicate didn't exist for
|
||||
// filtering |sysctl| access. Check the Darwin version before running the
|
||||
// tests (Darwin 14.0.0 is macOS 10.10). This branch can be removed when we
|
||||
// remove support for macOS 10.9.
|
||||
if (isMac() && Services.sysinfo.getProperty("version") >= "14.0.0") {
|
||||
let rv = await SpecialPowers.spawn(
|
||||
browser,
|
||||
[{ lib, name: "kern.boottime" }],
|
||||
callSysctl
|
||||
);
|
||||
Assert.equal(rv, -1, "calling sysctl('kern.boottime') is not permitted");
|
||||
|
||||
rv = await SpecialPowers.spawn(
|
||||
browser,
|
||||
[{ lib, name: "net.inet.ip.ttl" }],
|
||||
callSysctl
|
||||
);
|
||||
Assert.equal(rv, -1, "calling sysctl('net.inet.ip.ttl') is not permitted");
|
||||
|
||||
rv = await SpecialPowers.spawn(
|
||||
browser,
|
||||
[{ lib, name: "hw.ncpu" }],
|
||||
callSysctl
|
||||
);
|
||||
Assert.equal(rv, 0, "calling sysctl('hw.ncpu') is permitted");
|
||||
}
|
||||
|
||||
if (isLinux()) {
|
||||
// These constants are not portable.
|
||||
|
||||
// verify we block PR_CAPBSET_READ with EINVAL
|
||||
let option = lazy.LIBC.PR_CAPBSET_READ;
|
||||
let rv = await SpecialPowers.spawn(browser, [{ lib, option }], callPrctl);
|
||||
Assert.strictEqual(
|
||||
rv,
|
||||
lazy.LIBC.EINVAL,
|
||||
"prctl(PR_CAPBSET_READ) is blocked"
|
||||
);
|
||||
|
||||
const kernelVersion = await getKernelVersion();
|
||||
const glibcVersion = getGlibcVersion();
|
||||
// faccessat2 is only used with kernel 5.8+ by glibc 2.33+
|
||||
if (glibcVersion >= 233 && kernelVersion >= computeKernelVersion(5, 8, 0)) {
|
||||
info("Linux v5.8+, glibc 2.33+, checking faccessat2");
|
||||
const dirfd = 0;
|
||||
const path = "/";
|
||||
const mode = 0;
|
||||
// the value 0x01 is just one we know should get rejected
|
||||
let rv = await SpecialPowers.spawn(
|
||||
browser,
|
||||
[{ lib, dirfd, path, mode, flag: 0x01 }],
|
||||
callFaccessat2
|
||||
);
|
||||
Assert.strictEqual(
|
||||
rv,
|
||||
lazy.LIBC.ENOSYS,
|
||||
"faccessat2 (flag=0x01) was blocked with ENOSYS"
|
||||
);
|
||||
|
||||
rv = await SpecialPowers.spawn(
|
||||
browser,
|
||||
[{ lib, dirfd, path, mode, flag: lazy.LIBC.AT_EACCESS }],
|
||||
callFaccessat2
|
||||
);
|
||||
Assert.strictEqual(
|
||||
rv,
|
||||
lazy.LIBC.EACCES,
|
||||
"faccessat2 (flag=0x200) was allowed, errno=EACCES"
|
||||
);
|
||||
} else {
|
||||
info(
|
||||
"Unsupported kernel (" +
|
||||
kernelVersion +
|
||||
" )/glibc (" +
|
||||
glibcVersion +
|
||||
"), skipping faccessat2"
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -1,502 +0,0 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
const uuidGenerator = Services.uuid;
|
||||
|
||||
/*
|
||||
* Utility functions for the browser content sandbox tests.
|
||||
*/
|
||||
|
||||
function sanityChecks() {
|
||||
// This test is only relevant in e10s
|
||||
if (!gMultiProcessBrowser) {
|
||||
ok(false, "e10s is enabled");
|
||||
info("e10s is not enabled, exiting");
|
||||
return;
|
||||
}
|
||||
|
||||
let level = 0;
|
||||
let prefExists = true;
|
||||
|
||||
// Read the security.sandbox.content.level pref.
|
||||
// eslint-disable-next-line mozilla/use-default-preference-values
|
||||
try {
|
||||
level = Services.prefs.getIntPref("security.sandbox.content.level");
|
||||
} catch (e) {
|
||||
prefExists = false;
|
||||
}
|
||||
|
||||
ok(prefExists, "pref security.sandbox.content.level exists");
|
||||
if (!prefExists) {
|
||||
return;
|
||||
}
|
||||
|
||||
info(`security.sandbox.content.level=${level}`);
|
||||
Assert.greater(level, 0, "content sandbox is enabled.");
|
||||
|
||||
let isFileIOSandboxed = isContentFileIOSandboxed(level);
|
||||
|
||||
// Content sandbox enabled, but level doesn't include file I/O sandboxing.
|
||||
ok(isFileIOSandboxed, "content file I/O sandboxing is enabled.");
|
||||
if (!isFileIOSandboxed) {
|
||||
info("content sandbox level too low for file I/O tests, exiting\n");
|
||||
}
|
||||
}
|
||||
|
||||
function isXdgEnabled() {
|
||||
try {
|
||||
return Services.prefs.getBoolPref("widget.support-xdg-config");
|
||||
} catch (ex) {
|
||||
// if the pref is not there it means we dont have XDG support
|
||||
if (ex.name === "NS_ERROR_UNEXPECTED") {
|
||||
return false;
|
||||
}
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
// Creates file at |path| and returns a promise that resolves with an object
|
||||
// with .ok boolean to indicate true if the file was successfully created,
|
||||
// otherwise false. Include imports so this can be safely serialized and run
|
||||
// remotely by SpecialPowers.spawn.
|
||||
//
|
||||
// Report the exception's error code in .code as well.
|
||||
function createFile(path) {
|
||||
const { FileUtils } = ChromeUtils.importESModule(
|
||||
"resource://gre/modules/FileUtils.sys.mjs"
|
||||
);
|
||||
|
||||
try {
|
||||
const fstream = Cc[
|
||||
"@mozilla.org/network/file-output-stream;1"
|
||||
].createInstance(Ci.nsIFileOutputStream);
|
||||
|
||||
fstream.init(
|
||||
new FileUtils.File(path),
|
||||
-1, // readonly mode
|
||||
-1, // default permissions
|
||||
0
|
||||
); // behaviour flags
|
||||
|
||||
const ostream = Cc["@mozilla.org/binaryoutputstream;1"].createInstance(
|
||||
Ci.nsIBinaryOutputStream
|
||||
);
|
||||
ostream.setOutputStream(fstream);
|
||||
|
||||
const data = "TEST FILE DUMMY DATA";
|
||||
ostream.writeBytes(data, data.length);
|
||||
|
||||
ostream.close();
|
||||
fstream.close();
|
||||
} catch (e) {
|
||||
return { ok: false, code: e.result };
|
||||
}
|
||||
|
||||
return { ok: true };
|
||||
}
|
||||
|
||||
// Creates a symlink at |path| and returns a promise that resolves with an
|
||||
// object with .ok boolean to indicate true if the symlink was successfully
|
||||
// created, otherwise false. Include imports so this can be safely serialized
|
||||
// and run remotely by SpecialPowers.spawn.
|
||||
//
|
||||
// Report the exception's error code in .code as well.
|
||||
// Report errno in .code if syscall returns -1.
|
||||
function createSymlink(path) {
|
||||
const { ctypes } = ChromeUtils.importESModule(
|
||||
"resource://gre/modules/ctypes.sys.mjs"
|
||||
);
|
||||
|
||||
try {
|
||||
// Trying to open "libc.so" on linux will fail with invalid elf header error
|
||||
// because it would be a linker script. Using libc.so.6 avoids that.
|
||||
const libc = ctypes.open(
|
||||
Services.appinfo.OS === "Darwin" ? "libSystem.B.dylib" : "libc.so.6"
|
||||
);
|
||||
|
||||
const symlink = libc.declare(
|
||||
"symlink",
|
||||
ctypes.default_abi,
|
||||
ctypes.int, // return value
|
||||
ctypes.char.ptr, // target
|
||||
ctypes.char.ptr //linkpath
|
||||
);
|
||||
|
||||
ctypes.errno = 0;
|
||||
const rv = symlink("/etc", path);
|
||||
const _errno = ctypes.errno;
|
||||
if (rv < 0) {
|
||||
return { ok: false, code: _errno };
|
||||
}
|
||||
} catch (e) {
|
||||
return { ok: false, code: e.result };
|
||||
}
|
||||
|
||||
return { ok: true };
|
||||
}
|
||||
|
||||
// Deletes file at |path| and returns a promise that resolves with an object
|
||||
// with .ok boolean to indicate true if the file was successfully deleted,
|
||||
// otherwise false. Include imports so this can be safely serialized and run
|
||||
// remotely by SpecialPowers.spawn.
|
||||
//
|
||||
// Report the exception's error code in .code as well.
|
||||
function deleteFile(path) {
|
||||
const { FileUtils } = ChromeUtils.importESModule(
|
||||
"resource://gre/modules/FileUtils.sys.mjs"
|
||||
);
|
||||
|
||||
try {
|
||||
const file = new FileUtils.File(path);
|
||||
file.remove(false);
|
||||
} catch (e) {
|
||||
return { ok: false, code: e.result };
|
||||
}
|
||||
|
||||
return { ok: true };
|
||||
}
|
||||
|
||||
// Reads the directory at |path| and returns a promise that resolves when
|
||||
// iteration over the directory finishes or encounters an error. The promise
|
||||
// resolves with an object where .ok indicates success or failure and
|
||||
// .numEntries is the number of directory entries found.
|
||||
//
|
||||
// Report the exception's error code in .code as well.
|
||||
function readDir(path) {
|
||||
const { FileUtils } = ChromeUtils.importESModule(
|
||||
"resource://gre/modules/FileUtils.sys.mjs"
|
||||
);
|
||||
|
||||
let numEntries = 0;
|
||||
|
||||
try {
|
||||
const file = new FileUtils.File(path);
|
||||
const enumerator = file.directoryEntries;
|
||||
|
||||
while (enumerator.hasMoreElements()) {
|
||||
void enumerator.nextFile;
|
||||
numEntries++;
|
||||
}
|
||||
} catch (e) {
|
||||
return { ok: false, numEntries, code: e.result };
|
||||
}
|
||||
|
||||
return { ok: true, numEntries };
|
||||
}
|
||||
|
||||
// Reads the file at |path| and returns a promise that resolves when
|
||||
// reading is completed. Returned object has boolean .ok to indicate
|
||||
// success or failure.
|
||||
//
|
||||
// Report the exception's error code in .code as well.
|
||||
function readFile(path) {
|
||||
const { FileUtils } = ChromeUtils.importESModule(
|
||||
"resource://gre/modules/FileUtils.sys.mjs"
|
||||
);
|
||||
|
||||
try {
|
||||
const file = new FileUtils.File(path);
|
||||
|
||||
const fstream = Cc[
|
||||
"@mozilla.org/network/file-input-stream;1"
|
||||
].createInstance(Ci.nsIFileInputStream);
|
||||
fstream.init(file, -1, -1, 0);
|
||||
|
||||
const istream = Cc["@mozilla.org/binaryinputstream;1"].createInstance(
|
||||
Ci.nsIBinaryInputStream
|
||||
);
|
||||
istream.setInputStream(fstream);
|
||||
|
||||
const available = istream.available();
|
||||
void istream.readBytes(available);
|
||||
} catch (e) {
|
||||
return { ok: false, code: e.result };
|
||||
}
|
||||
|
||||
return { ok: true };
|
||||
}
|
||||
|
||||
// Does a stat of |path| and returns a promise that resolves if the
|
||||
// stat is successful. Returned object has boolean .ok to indicate
|
||||
// success or failure.
|
||||
//
|
||||
// Report the exception's error code in .code as well.
|
||||
function statPath(path) {
|
||||
const { FileUtils } = ChromeUtils.importESModule(
|
||||
"resource://gre/modules/FileUtils.sys.mjs"
|
||||
);
|
||||
|
||||
try {
|
||||
const file = new FileUtils.File(path);
|
||||
void file.lastModifiedTime;
|
||||
} catch (e) {
|
||||
return { ok: false, code: e.result };
|
||||
}
|
||||
|
||||
return { ok: true };
|
||||
}
|
||||
|
||||
// Returns true if the current content sandbox level, passed in
|
||||
// the |level| argument, supports filesystem sandboxing.
|
||||
function isContentFileIOSandboxed(level) {
|
||||
let fileIOSandboxMinLevel = 0;
|
||||
|
||||
// Set fileIOSandboxMinLevel to the lowest level that has
|
||||
// content filesystem sandboxing enabled. For now, this
|
||||
// varies across Windows, Mac, Linux, other.
|
||||
switch (Services.appinfo.OS) {
|
||||
case "WINNT":
|
||||
fileIOSandboxMinLevel = 1;
|
||||
break;
|
||||
case "Darwin":
|
||||
fileIOSandboxMinLevel = 1;
|
||||
break;
|
||||
case "Linux":
|
||||
fileIOSandboxMinLevel = 2;
|
||||
break;
|
||||
default:
|
||||
Assert.ok(false, "Unknown OS");
|
||||
}
|
||||
|
||||
return level >= fileIOSandboxMinLevel;
|
||||
}
|
||||
|
||||
// Returns the lowest sandbox level where blanket reading of the profile
|
||||
// directory from the content process should be blocked by the sandbox.
|
||||
function minProfileReadSandboxLevel() {
|
||||
switch (Services.appinfo.OS) {
|
||||
case "WINNT":
|
||||
return 3;
|
||||
case "Darwin":
|
||||
return 2;
|
||||
case "Linux":
|
||||
return 3;
|
||||
default:
|
||||
Assert.ok(false, "Unknown OS");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the lowest sandbox level where blanket reading of the home
|
||||
// directory from the content process should be blocked by the sandbox.
|
||||
function minHomeReadSandboxLevel() {
|
||||
switch (Services.appinfo.OS) {
|
||||
case "WINNT":
|
||||
return 3;
|
||||
case "Darwin":
|
||||
return 3;
|
||||
case "Linux":
|
||||
return 3;
|
||||
default:
|
||||
Assert.ok(false, "Unknown OS");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
function isMac() {
|
||||
return Services.appinfo.OS == "Darwin";
|
||||
}
|
||||
function isWin() {
|
||||
return Services.appinfo.OS == "WINNT";
|
||||
}
|
||||
function isLinux() {
|
||||
return Services.appinfo.OS == "Linux";
|
||||
}
|
||||
|
||||
function isNightly() {
|
||||
let version = SpecialPowers.Services.appinfo.version;
|
||||
return version.endsWith("a1");
|
||||
}
|
||||
|
||||
function uuid() {
|
||||
return uuidGenerator.generateUUID().toString();
|
||||
}
|
||||
|
||||
// Returns a file object for a new file in the home dir ($HOME/<UUID>).
|
||||
function fileInHomeDir() {
|
||||
// get home directory, make sure it exists
|
||||
let homeDir = Services.dirsvc.get("Home", Ci.nsIFile);
|
||||
Assert.ok(homeDir.exists(), "Home dir exists");
|
||||
Assert.ok(homeDir.isDirectory(), "Home dir is a directory");
|
||||
|
||||
// build a file object for a new file named $HOME/<UUID>
|
||||
let homeFile = homeDir.clone();
|
||||
homeFile.appendRelativePath(uuid());
|
||||
Assert.ok(!homeFile.exists(), homeFile.path + " does not exist");
|
||||
return homeFile;
|
||||
}
|
||||
|
||||
// Returns a file object for a new file in the content temp dir (.../<UUID>).
|
||||
function fileInTempDir() {
|
||||
let contentTempKey = "TmpD";
|
||||
|
||||
// get the content temp dir, make sure it exists
|
||||
let ctmp = Services.dirsvc.get(contentTempKey, Ci.nsIFile);
|
||||
Assert.ok(ctmp.exists(), "Temp dir exists");
|
||||
Assert.ok(ctmp.isDirectory(), "Temp dir is a directory");
|
||||
|
||||
// build a file object for a new file in content temp
|
||||
let tempFile = ctmp.clone();
|
||||
tempFile.appendRelativePath(uuid());
|
||||
Assert.ok(!tempFile.exists(), tempFile.path + " does not exist");
|
||||
return tempFile;
|
||||
}
|
||||
|
||||
function GetProfileDir() {
|
||||
// get profile directory
|
||||
let profileDir = Services.dirsvc.get("ProfD", Ci.nsIFile);
|
||||
return profileDir;
|
||||
}
|
||||
|
||||
function GetHomeDir() {
|
||||
// get home directory
|
||||
let homeDir = Services.dirsvc.get("Home", Ci.nsIFile);
|
||||
return homeDir;
|
||||
}
|
||||
|
||||
function GetHomeSubdir(subdir) {
|
||||
return GetSubdir(GetHomeDir(), subdir);
|
||||
}
|
||||
|
||||
function GetHomeSubdirFile(subdir) {
|
||||
return GetSubdirFile(GetHomeSubdir(subdir));
|
||||
}
|
||||
|
||||
function GetSubdir(dir, subdir) {
|
||||
let newSubdir = dir.clone();
|
||||
newSubdir.appendRelativePath(subdir);
|
||||
return newSubdir;
|
||||
}
|
||||
|
||||
function GetSubdirFile(dir) {
|
||||
let newFile = dir.clone();
|
||||
newFile.appendRelativePath(uuid());
|
||||
return newFile;
|
||||
}
|
||||
|
||||
function GetPerUserExtensionDir() {
|
||||
return Services.dirsvc.get("XREUSysExt", Ci.nsIFile);
|
||||
}
|
||||
|
||||
// Returns a file object for the file or directory named |name| in the
|
||||
// profile directory.
|
||||
function GetProfileEntry(name) {
|
||||
let entry = GetProfileDir();
|
||||
entry.append(name);
|
||||
return entry;
|
||||
}
|
||||
|
||||
function GetDir(path) {
|
||||
info(`GetDir(${path})`);
|
||||
let dir = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
|
||||
dir.initWithPath(path);
|
||||
Assert.ok(dir.isDirectory(), `${path} is a directory`);
|
||||
return dir;
|
||||
}
|
||||
|
||||
function GetDirFromEnvVariable(varName) {
|
||||
return GetDir(Services.env.get(varName));
|
||||
}
|
||||
|
||||
function GetFile(path) {
|
||||
let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
|
||||
file.initWithPath(path);
|
||||
return file;
|
||||
}
|
||||
|
||||
function GetBrowserType(type) {
|
||||
let browserType = undefined;
|
||||
|
||||
if (!GetBrowserType[type]) {
|
||||
if (type === "web") {
|
||||
GetBrowserType[type] = gBrowser.selectedBrowser;
|
||||
} else {
|
||||
// open a tab in a `type` content process
|
||||
gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser, "about:blank", {
|
||||
preferredRemoteType: type,
|
||||
allowInheritPrincipal: true,
|
||||
});
|
||||
// get the browser for the `type` process tab
|
||||
GetBrowserType[type] = gBrowser.getBrowserForTab(gBrowser.selectedTab);
|
||||
}
|
||||
}
|
||||
|
||||
browserType = GetBrowserType[type];
|
||||
Assert.strictEqual(
|
||||
browserType.remoteType,
|
||||
type,
|
||||
`GetBrowserType(${type}) returns a ${type} process`
|
||||
);
|
||||
return browserType;
|
||||
}
|
||||
|
||||
function GetWebBrowser() {
|
||||
return GetBrowserType("web");
|
||||
}
|
||||
|
||||
function isFileContentProcessEnabled() {
|
||||
// Ensure that the file content process is enabled.
|
||||
let fileContentProcessEnabled = Services.prefs.getBoolPref(
|
||||
"browser.tabs.remote.separateFileUriProcess"
|
||||
);
|
||||
ok(fileContentProcessEnabled, "separate file content process is enabled");
|
||||
return fileContentProcessEnabled;
|
||||
}
|
||||
|
||||
function GetFileBrowser() {
|
||||
if (!isFileContentProcessEnabled()) {
|
||||
return undefined;
|
||||
}
|
||||
return GetBrowserType("file");
|
||||
}
|
||||
|
||||
function GetSandboxLevel() {
|
||||
// Current level
|
||||
return Services.prefs.getIntPref("security.sandbox.content.level");
|
||||
}
|
||||
|
||||
async function runTestsList(tests) {
|
||||
let level = GetSandboxLevel();
|
||||
|
||||
// remove tests not enabled by the current sandbox level
|
||||
tests = tests.filter(test => test.minLevel <= level);
|
||||
|
||||
for (let test of tests) {
|
||||
let okString = test.ok ? "allowed" : "blocked";
|
||||
let processType = test.browser.remoteType;
|
||||
|
||||
// ensure the file/dir exists before we ask a content process to stat
|
||||
// it so we know a failure is not due to a nonexistent file/dir
|
||||
if (test.func === statPath) {
|
||||
ok(test.file.exists(), `${test.file.path} exists`);
|
||||
}
|
||||
|
||||
let result = await SpecialPowers.spawn(
|
||||
test.browser,
|
||||
[test.file.path],
|
||||
test.func
|
||||
);
|
||||
|
||||
Assert.equal(
|
||||
result.ok,
|
||||
test.ok,
|
||||
`reading ${test.desc} from a ${processType} process ` +
|
||||
`is ${okString} (${test.file.path})`
|
||||
);
|
||||
|
||||
// if the directory is not expected to be readable,
|
||||
// ensure the listing has zero entries
|
||||
if (test.func === readDir && !test.ok) {
|
||||
Assert.equal(
|
||||
result.numEntries,
|
||||
0,
|
||||
`directory list is empty (${test.file.path})`
|
||||
);
|
||||
}
|
||||
|
||||
if (test.cleanup != undefined) {
|
||||
await test.cleanup(test.file.path);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
[DEFAULT]
|
||||
skip-if = [
|
||||
"ccov",
|
||||
"os == 'linux' && os_version == '24.04' && arch == 'x86_64' && display == 'x11' && asan", # bug 1784517 for sandbox, bug 1885381 for profiler
|
||||
"os == 'linux' && os_version == '24.04' && arch == 'x86_64' && display == 'x11' && tsan", # bug 1784517 for sandbox, bug 1885381 for profiler
|
||||
]
|
||||
tags = "contentsandbox"
|
||||
|
||||
# This is here to make sure we will not have prelaunched processes, which will
|
||||
# mess with sandbox profiling interaction: we will miss launch-related markers
|
||||
# and this makes the test intermittently fail on TV jobs
|
||||
prefs = [
|
||||
"dom.ipc.processPrelaunch.fission.number=0"
|
||||
]
|
||||
|
||||
environment = "MOZ_SANDBOX_LOGGING_FOR_TESTS=1"
|
||||
|
||||
["browser_sandbox_profiler.js"]
|
||||
run-if = [
|
||||
"os == 'linux'",
|
||||
]
|
||||
@@ -1,153 +0,0 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
const { ProfilerTestUtils } = ChromeUtils.importESModule(
|
||||
"resource://testing-common/ProfilerTestUtils.sys.mjs"
|
||||
);
|
||||
|
||||
async function addTab() {
|
||||
const tab = BrowserTestUtils.addTab(gBrowser, "https://example.com/browser", {
|
||||
forceNewProcess: true,
|
||||
});
|
||||
const browser = gBrowser.getBrowserForTab(tab);
|
||||
await BrowserTestUtils.browserLoaded(browser);
|
||||
return tab;
|
||||
}
|
||||
|
||||
const sandboxSettingsEnabled = {
|
||||
entries: 8 * 1024 * 1024, // 8M entries = 64MB
|
||||
interval: 1, // ms
|
||||
features: ["stackwalk", "sandbox"],
|
||||
threads: ["SandboxProfilerEmitter"],
|
||||
};
|
||||
|
||||
const sandboxSettingsDisabled = {
|
||||
entries: 8 * 1024 * 1024, // 8M entries = 64MB
|
||||
interval: 1, // ms
|
||||
features: ["stackwalk"],
|
||||
threads: ["SandboxProfilerEmitter"],
|
||||
};
|
||||
|
||||
const kNewProcesses = 2;
|
||||
|
||||
async function waitForMaybeSandboxProfilerData(
|
||||
threadName,
|
||||
name1,
|
||||
withStacks,
|
||||
enabled
|
||||
) {
|
||||
let tabs = [];
|
||||
for (let i = 0; i < kNewProcesses; ++i) {
|
||||
tabs.push(await addTab());
|
||||
}
|
||||
|
||||
let profile;
|
||||
let intercepted = undefined;
|
||||
try {
|
||||
await TestUtils.waitForCondition(
|
||||
async () => {
|
||||
profile = await Services.profiler.getProfileDataAsync();
|
||||
intercepted = profile.processes
|
||||
.flatMap(ps => {
|
||||
let sandboxThreads = ps.threads.filter(
|
||||
th => th.name === threadName
|
||||
);
|
||||
return sandboxThreads.flatMap(th => {
|
||||
let markersData = th.markers.data;
|
||||
return markersData.flatMap(d => {
|
||||
let [, , , , , o] = d;
|
||||
return o;
|
||||
});
|
||||
});
|
||||
})
|
||||
.filter(x => "name1" in x && name1.includes(x.name1) >= 0);
|
||||
return !!intercepted.length;
|
||||
},
|
||||
`Wait for some samples from ${threadName}`,
|
||||
/* interval*/ 100,
|
||||
/* maxTries */ 25
|
||||
);
|
||||
Assert.greater(
|
||||
intercepted.length,
|
||||
0,
|
||||
`Should have collected some data from ${threadName}`
|
||||
);
|
||||
} catch (ex) {
|
||||
if (!enabled && ex.includes(`Wait for some samples from ${threadName}`)) {
|
||||
Assert.equal(
|
||||
intercepted.length,
|
||||
0,
|
||||
`Should have NOT collected data from ${threadName}`
|
||||
);
|
||||
} else {
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
if (withStacks) {
|
||||
let stacks = profile.processes.flatMap(ps => {
|
||||
let sandboxThreads = ps.threads.filter(th => th.name === threadName);
|
||||
return sandboxThreads.flatMap(th => {
|
||||
let stackTableData = th.stackTable.data;
|
||||
return stackTableData.flatMap(d => {
|
||||
return [d];
|
||||
});
|
||||
});
|
||||
});
|
||||
if (enabled) {
|
||||
Assert.greater(stacks.length, 0, "Should have some stack as well");
|
||||
} else {
|
||||
Assert.equal(stacks.length, 0, "Should have NO stack as well");
|
||||
}
|
||||
}
|
||||
|
||||
for (let tab of tabs) {
|
||||
await BrowserTestUtils.removeTab(tab);
|
||||
}
|
||||
}
|
||||
|
||||
add_task(async () => {
|
||||
await ProfilerTestUtils.startProfiler(sandboxSettingsEnabled);
|
||||
await waitForMaybeSandboxProfilerData(
|
||||
"SandboxProfilerEmitterSyscalls",
|
||||
["id", "init"],
|
||||
/* withStacks */ true,
|
||||
/* enabled */ true
|
||||
);
|
||||
await Services.profiler.StopProfiler();
|
||||
});
|
||||
|
||||
add_task(async () => {
|
||||
await ProfilerTestUtils.startProfiler(sandboxSettingsEnabled);
|
||||
await waitForMaybeSandboxProfilerData(
|
||||
"SandboxProfilerEmitterLogs",
|
||||
["log"],
|
||||
/* withStacks */ false,
|
||||
/* enabled */ true
|
||||
);
|
||||
await Services.profiler.StopProfiler();
|
||||
});
|
||||
|
||||
add_task(async () => {
|
||||
await ProfilerTestUtils.startProfiler(sandboxSettingsDisabled);
|
||||
await waitForMaybeSandboxProfilerData(
|
||||
"SandboxProfilerEmitterSyscalls",
|
||||
["id", "init"],
|
||||
/* withStacks */ true,
|
||||
/* enabled */ false
|
||||
);
|
||||
await Services.profiler.StopProfiler();
|
||||
});
|
||||
|
||||
add_task(async () => {
|
||||
await ProfilerTestUtils.startProfiler(sandboxSettingsEnabled);
|
||||
await waitForMaybeSandboxProfilerData(
|
||||
"SandboxProfilerEmitterLogs",
|
||||
["log"],
|
||||
/* withStacks */ false,
|
||||
/* enabled */ false
|
||||
);
|
||||
await Services.profiler.StopProfiler();
|
||||
});
|
||||
@@ -1,78 +0,0 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
// Types of processes to test, taken from GeckoProcessTypes.h
|
||||
// GPU process might not run depending on the platform, so we need it to be
|
||||
// the last one of the list to allow the remainingTests logic below to work
|
||||
// as expected.
|
||||
//
|
||||
// For UtilityProcess, allow constructing a string made of the process type
|
||||
// and the sandbox variant we want to test, e.g.,
|
||||
// utility:0 for GENERIC_UTILITY
|
||||
// utility:1 for AppleMedia/WMF on macOS/Windows
|
||||
var processTypes = ["tab", "socket", "rdd", "gmplugin", "utility:0", "gpu"];
|
||||
|
||||
const platform = SpecialPowers.Services.appinfo.OS;
|
||||
if (platform === "WINNT" || platform === "Darwin") {
|
||||
processTypes.push("utility:1");
|
||||
}
|
||||
|
||||
// A callback called after each test-result.
|
||||
let sandboxTestResult = (subject, topic, data) => {
|
||||
let { testid, passed, message } = JSON.parse(data);
|
||||
ok(
|
||||
passed,
|
||||
"Test " + testid + (passed ? " passed: " : " failed: ") + message
|
||||
);
|
||||
};
|
||||
Services.obs.addObserver(sandboxTestResult, "sandbox-test-result");
|
||||
|
||||
var remainingTests = processTypes.length;
|
||||
|
||||
// A callback that is notified when a child process is done running tests.
|
||||
let sandboxTestDone = () => {
|
||||
remainingTests = remainingTests - 1;
|
||||
if (remainingTests == 0) {
|
||||
// Clean up test file
|
||||
if (homeTestFile.exists()) {
|
||||
ok(homeTestFile.isFile(), "homeTestFile should be a file");
|
||||
if (homeTestFile.isFile()) {
|
||||
homeTestFile.remove(false);
|
||||
}
|
||||
}
|
||||
|
||||
Services.obs.removeObserver(sandboxTestResult, "sandbox-test-result");
|
||||
Services.obs.removeObserver(sandboxTestDone, "sandbox-test-done");
|
||||
|
||||
// Notify SandboxTest component that it should terminate the connection
|
||||
// with the child processes.
|
||||
comp.finishTests();
|
||||
// Notify mochitest that all process tests are complete.
|
||||
finish();
|
||||
}
|
||||
};
|
||||
Services.obs.addObserver(sandboxTestDone, "sandbox-test-done");
|
||||
|
||||
var comp = Cc["@mozilla.org/sandbox/sandbox-test;1"].getService(
|
||||
Ci.mozISandboxTest
|
||||
);
|
||||
|
||||
let homeTestFile;
|
||||
try {
|
||||
homeTestFile = Services.dirsvc.get("Home", Ci.nsIFile);
|
||||
homeTestFile.append(".mozilla_gpu_sandbox_read_test");
|
||||
if (!homeTestFile.exists()) {
|
||||
homeTestFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0o600);
|
||||
}
|
||||
} catch (e) {
|
||||
ok(false, "Failed to create home test file: " + e);
|
||||
}
|
||||
|
||||
comp.startTests(processTypes);
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
# Any copyright is dedicated to the Public Domain.
|
||||
# http://creativecommons.org/publicdomain/zero/1.0/
|
||||
[DEFAULT]
|
||||
skip-if = [
|
||||
"ccov",
|
||||
"os == 'linux' && os_version == '24.04' && arch == 'x86_64' && display == 'x11' && asan", # bug 1784517
|
||||
"os == 'linux' && os_version == '24.04' && arch == 'x86_64' && display == 'x11' && tsan", # bug 1784517
|
||||
]
|
||||
tags = "contentsandbox"
|
||||
support-files = [
|
||||
"browser_content_sandbox_utils.js",
|
||||
"browser_content_sandbox_fs_tests.js",
|
||||
]
|
||||
test-directories = "/tmp/.snap_firefox_current_real/"
|
||||
environment = "SNAP=/tmp/.snap_firefox_current_real/"
|
||||
|
||||
["browser_content_sandbox_fs_snap.js"]
|
||||
run-if = [
|
||||
"os == 'linux'",
|
||||
]
|
||||
@@ -1,26 +0,0 @@
|
||||
# Any copyright is dedicated to the Public Domain.
|
||||
# http://creativecommons.org/publicdomain/zero/1.0/
|
||||
[DEFAULT]
|
||||
skip-if = [
|
||||
"ccov",
|
||||
"os == 'linux' && os_version == '24.04' && arch == 'x86_64' && display == 'x11' && asan", # bug 1784517
|
||||
"os == 'linux' && os_version == '24.04' && arch == 'x86_64' && display == 'x11' && tsan", # bug 1784517
|
||||
]
|
||||
tags = "contentsandbox"
|
||||
support-files = [
|
||||
"browser_content_sandbox_utils.js",
|
||||
"browser_content_sandbox_fs_tests.js",
|
||||
]
|
||||
test-directories = [
|
||||
"/tmp/.xdg_default_test",
|
||||
"/tmp/.xdg_default_test/.config/mozilla/firefox/xdg_default_profile",
|
||||
]
|
||||
environment = [
|
||||
"HOME=/tmp/.xdg_default_test",
|
||||
]
|
||||
profile-path = "/tmp/.xdg_default_test/.config/mozilla/firefox/xdg_default_profile"
|
||||
|
||||
["browser_content_sandbox_fs_xdg_default.js"]
|
||||
run-if = [
|
||||
"os == 'linux'"
|
||||
]
|
||||
@@ -1,29 +0,0 @@
|
||||
# Any copyright is dedicated to the Public Domain.
|
||||
# http://creativecommons.org/publicdomain/zero/1.0/
|
||||
[DEFAULT]
|
||||
skip-if = [
|
||||
"ccov",
|
||||
"os == 'linux' && os_version == '24.04' && arch == 'x86_64' && display == 'x11' && asan", # bug 1784517
|
||||
"os == 'linux' && os_version == '24.04' && arch == 'x86_64' && display == 'x11' && tsan", # bug 1784517
|
||||
]
|
||||
tags = "contentsandbox"
|
||||
support-files = [
|
||||
"browser_content_sandbox_utils.js",
|
||||
"browser_content_sandbox_fs_tests.js",
|
||||
]
|
||||
test-directories = [
|
||||
"/tmp/.xdg_mozLegacyHome_test/.config",
|
||||
"/tmp/.xdg_config_home_test",
|
||||
"/tmp/.xdg_mozLegacyHome_test/.mozilla/firefox/xdg_mozLegacyHome_profile",
|
||||
]
|
||||
environment = [
|
||||
"XDG_CONFIG_HOME=/tmp/.xdg_config_home_test",
|
||||
"HOME=/tmp/.xdg_mozLegacyHome_test",
|
||||
"MOZ_LEGACY_HOME=1",
|
||||
]
|
||||
profile-path = "/tmp/.xdg_mozLegacyHome_test/.mozilla/firefox/xdg_mozLegacyHome_profile"
|
||||
|
||||
["browser_content_sandbox_fs_xdg_mozLegacyHome.js"]
|
||||
run-if = [
|
||||
"os == 'linux'"
|
||||
]
|
||||
@@ -1,27 +0,0 @@
|
||||
# Any copyright is dedicated to the Public Domain.
|
||||
# http://creativecommons.org/publicdomain/zero/1.0/
|
||||
[DEFAULT]
|
||||
skip-if = [
|
||||
"ccov",
|
||||
"os == 'linux' && os_version == '24.04' && arch == 'x86_64' && display == 'x11' && asan", # bug 1784517
|
||||
"os == 'linux' && os_version == '24.04' && arch == 'x86_64' && display == 'x11' && tsan", # bug 1784517
|
||||
]
|
||||
tags = "contentsandbox"
|
||||
support-files = [
|
||||
"browser_content_sandbox_utils.js",
|
||||
"browser_content_sandbox_fs_tests.js",
|
||||
]
|
||||
test-directories = [
|
||||
"/tmp/.xdg_config_home_test",
|
||||
"/tmp/.xdg_config_home_test/mozilla/firefox/xdg_config_home_profile",
|
||||
]
|
||||
environment = [
|
||||
"XDG_CONFIG_HOME=/tmp/.xdg_config_home_test",
|
||||
"MOZ_LEGACY_HOME=0",
|
||||
]
|
||||
profile-path = "/tmp/.xdg_config_home_test/mozilla/firefox/xdg_config_home_profile"
|
||||
|
||||
["browser_content_sandbox_fs_xdg_xdgConfigHome.js"]
|
||||
run-if = [
|
||||
"os == 'linux'",
|
||||
]
|
||||
@@ -1,19 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
</head>
|
||||
<style>
|
||||
#content { display: inline-block; }
|
||||
.monospace_fallback { font: 3em monospace; }
|
||||
</style>
|
||||
<body>
|
||||
|
||||
<div id="content" class="monospace_fallback">
|
||||
abcdefghijklmnopqrstuvwxyz<br>
|
||||
<b>abcdefghijklmnopqrstuvwxyz</b><br>
|
||||
<i>abcdefghijklmnopqrstuvwxyz</i>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,85 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"""
|
||||
mac_register_font.py
|
||||
|
||||
Mac-specific utility command to register a font file with the OS.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
|
||||
import Cocoa
|
||||
import CoreText
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument(
|
||||
"-v",
|
||||
"--verbose",
|
||||
action="store_true",
|
||||
help="print verbose registration failures",
|
||||
default=False,
|
||||
)
|
||||
parser.add_argument(
|
||||
"file", nargs="*", help="font file to register or unregister", default=[]
|
||||
)
|
||||
parser.add_argument(
|
||||
"-u",
|
||||
"--unregister",
|
||||
action="store_true",
|
||||
help="unregister the provided fonts",
|
||||
default=False,
|
||||
)
|
||||
parser.add_argument(
|
||||
"-p",
|
||||
"--persist-user",
|
||||
action="store_true",
|
||||
help="permanently register the font",
|
||||
default=False,
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.persist_user:
|
||||
scope = CoreText.kCTFontManagerScopeUser
|
||||
scopeDesc = "user"
|
||||
else:
|
||||
scope = CoreText.kCTFontManagerScopeSession
|
||||
scopeDesc = "session"
|
||||
|
||||
failureCount = 0
|
||||
for fontPath in args.file:
|
||||
fontURL = Cocoa.NSURL.fileURLWithPath_(fontPath)
|
||||
(result, error) = register_or_unregister_font(fontURL, args.unregister, scope)
|
||||
if result:
|
||||
print(
|
||||
"%sregistered font %s with %s scope"
|
||||
% (("un" if args.unregister else ""), fontPath, scopeDesc)
|
||||
)
|
||||
else:
|
||||
print(
|
||||
"Failed to %sregister font %s with %s scope"
|
||||
% (("un" if args.unregister else ""), fontPath, scopeDesc)
|
||||
)
|
||||
if args.verbose:
|
||||
print(error)
|
||||
failureCount += 1
|
||||
|
||||
sys.exit(failureCount)
|
||||
|
||||
|
||||
def register_or_unregister_font(fontURL, unregister, scope):
|
||||
return (
|
||||
CoreText.CTFontManagerUnregisterFontsForURL(fontURL, scope, None)
|
||||
if unregister
|
||||
else CoreText.CTFontManagerRegisterFontsForURL(fontURL, scope, None)
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
10
surfer.json
10
surfer.json
@@ -5,8 +5,8 @@
|
||||
"binaryName": "zen",
|
||||
"version": {
|
||||
"product": "firefox",
|
||||
"version": "151.0.3",
|
||||
"candidate": "151.0.3",
|
||||
"version": "151.0.4",
|
||||
"candidate": "151.0.4",
|
||||
"candidateBuild": 1
|
||||
},
|
||||
"buildOptions": {
|
||||
@@ -20,7 +20,7 @@
|
||||
"brandShortName": "Zen",
|
||||
"brandFullName": "Zen Browser",
|
||||
"release": {
|
||||
"displayVersion": "1.20.2b",
|
||||
"displayVersion": "1.21b",
|
||||
"github": {
|
||||
"repo": "zen-browser/desktop"
|
||||
},
|
||||
@@ -40,7 +40,7 @@
|
||||
"brandShortName": "Twilight",
|
||||
"brandFullName": "Zen Twilight",
|
||||
"release": {
|
||||
"displayVersion": "1.21t",
|
||||
"displayVersion": "1.22t",
|
||||
"github": {
|
||||
"repo": "zen-browser/desktop"
|
||||
}
|
||||
@@ -54,4 +54,4 @@
|
||||
"licenseType": "MPL-2.0"
|
||||
},
|
||||
"updateHostname": "updates.zen-browser.app"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user