Bug 1506198 - Remove content temp dir r=gcp

Differential Revision: https://phabricator.services.mozilla.com/D220369
This commit is contained in:
Alexandre Lissy 2024-09-11 06:07:42 +00:00
Родитель 61f5cb3849
Коммит 8ffb617205
15 изменённых файлов: 96 добавлений и 425 удалений

Просмотреть файл

@ -1548,13 +1548,6 @@ pref("browser.bookmarks.editDialog.maxRecentFolders", 7);
pref("security.sandbox.content.level", 1);
#endif
#if defined(MOZ_CONTENT_TEMP_DIR)
// ID (a UUID when set by gecko) that is used to form the name of a
// sandbox-writable temporary directory to be used by content processes
// when a temporary writable file is required.
pref("security.sandbox.content.tempDirSuffix", "");
#endif
#ifdef XP_WIN
pref("browser.taskbar.previews.enable", false);
pref("browser.taskbar.previews.max", 20);

Просмотреть файл

@ -1191,6 +1191,7 @@ void ChromeUtils::DefineESModuleGetters(
/* static */
void ChromeUtils::GetLibcConstants(const GlobalObject&,
LibcConstants& aConsts) {
aConsts.mEPERM.Construct(EPERM);
aConsts.mEINTR.Construct(EINTR);
aConsts.mEACCES.Construct(EACCES);
aConsts.mEAGAIN.Construct(EAGAIN);

Просмотреть файл

@ -1123,6 +1123,7 @@ enum JSRFPTarget {
#ifdef XP_UNIX
dictionary LibcConstants {
long EPERM;
long EINTR;
long EACCES;
long EAGAIN;

Просмотреть файл

@ -159,21 +159,24 @@ class BaseProcessLauncher {
std::vector<std::string>&& aExtraOpts)
: mProcessType(aHost->mProcessType),
mLaunchOptions(std::move(aHost->mLaunchOptions)),
mExtraOpts(std::move(aExtraOpts)),
mExtraOpts(std::move(aExtraOpts))
#ifdef XP_WIN
mGroupId(aHost->mGroupId),
,
mGroupId(aHost->mGroupId)
#endif
#if defined(XP_WIN) && defined(MOZ_SANDBOX)
,
mAllowedFilesRead(aHost->mAllowedFilesRead),
mSandboxLevel(aHost->mSandboxLevel),
mSandbox(aHost->mSandbox),
mIsFileContent(aHost->mIsFileContent),
mEnableSandboxLogging(aHost->mEnableSandboxLogging),
mEnableSandboxLogging(aHost->mEnableSandboxLogging)
#endif
#if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
mDisableOSActivityMode(aHost->mDisableOSActivityMode),
,
mDisableOSActivityMode(aHost->mDisableOSActivityMode)
#endif
mTmpDirName(aHost->mTmpDirName) {
{
SprintfLiteral(mPidString, "%" PRIPID, base::GetCurrentProcId());
aHost->mInitialChannelId.ToProvidedString(mInitialChannelIdString);
SprintfLiteral(mChildIDString, "%d", aHost->mChildID);
@ -246,7 +249,6 @@ class BaseProcessLauncher {
// environment variable OS_ACTIVITY_MODE set to "disabled".
bool mDisableOSActivityMode;
#endif
nsCString mTmpDirName;
LaunchResults mResults = LaunchResults();
TimeStamp mStartTimeStamp = TimeStamp::Now();
char mPidString[32];
@ -415,17 +417,7 @@ GeckoChildProcessHost::GeckoChildProcessHost(GeckoProcessType aProcessType,
}
sGeckoChildProcessHosts->insertBack(this);
#if defined(MOZ_SANDBOX) && defined(XP_LINUX)
if (aProcessType == GeckoProcessType_Content) {
# if defined(MOZ_CONTENT_TEMP_DIR)
// The content process needs the content temp dir:
nsCOMPtr<nsIFile> contentTempDir;
nsresult rv = NS_GetSpecialDirectory(NS_APP_CONTENT_PROCESS_TEMP_DIR,
getter_AddRefs(contentTempDir));
if (NS_SUCCEEDED(rv)) {
contentTempDir->GetNativePath(mTmpDirName);
}
# endif
} else if (aProcessType == GeckoProcessType_RDD) {
if (aProcessType == GeckoProcessType_RDD) {
// The RDD process makes limited use of EGL. If Mesa's shader
// cache is enabled and the directory isn't explicitly set, then
// it will try to getpwuid() the user which can cause problems
@ -1190,18 +1182,6 @@ Result<Ok, LaunchError> LinuxProcessLauncher::DoSetup() {
mLaunchOptions->env_map["NO_AT_BRIDGE"] = "1";
}
# ifdef MOZ_SANDBOX
if (!mTmpDirName.IsEmpty()) {
// Point a bunch of things that might want to write from content to our
// shiny new content-process specific tmpdir
mLaunchOptions->env_map[ENVIRONMENT_LITERAL("TMPDIR")] =
ENVIRONMENT_STRING(mTmpDirName.get());
// Partial fix for bug 1380051 (not persistent - should be)
mLaunchOptions->env_map[ENVIRONMENT_LITERAL("MESA_GLSL_CACHE_DIR")] =
ENVIRONMENT_STRING(mTmpDirName.get());
}
# endif // MOZ_SANDBOX
return Ok();
}
#endif // MOZ_WIDGET_GTK

Просмотреть файл

@ -312,8 +312,6 @@ class GeckoChildProcessHost : public SupportsWeakPtr,
// Removes the instance from sGeckoChildProcessHosts
void RemoveFromProcessList();
// Linux-Only. Set this up before we're called from a different thread.
nsCString mTmpDirName;
// Mac and Windows. Set this up before we're called from a different thread.
nsCOMPtr<nsIFile> mProfileDir;

Просмотреть файл

@ -71,17 +71,6 @@ SandboxBroker::SandboxBroker(UniquePtr<const Policy> aPolicy, int aChildPid,
mFileDesc = -1;
aClientFd = -1;
}
#if defined(MOZ_CONTENT_TEMP_DIR)
nsCOMPtr<nsIFile> tmpDir;
nsresult rv = NS_GetSpecialDirectory(NS_APP_CONTENT_PROCESS_TEMP_DIR,
getter_AddRefs(tmpDir));
if (NS_SUCCEEDED(rv)) {
rv = tmpDir->GetNativePath(mContentTempPath);
if (NS_FAILED(rv)) {
mContentTempPath.Truncate();
}
}
#endif
}
UniquePtr<SandboxBroker> SandboxBroker::Create(
@ -572,36 +561,6 @@ size_t SandboxBroker::ConvertRelativePath(char* aPath, size_t aBufSize,
return aPathLen;
}
#if defined(MOZ_CONTENT_TEMP_DIR)
size_t SandboxBroker::RemapTempDirs(char* aPath, size_t aBufSize,
size_t aPathLen) {
nsAutoCString path(aPath);
size_t prefixLen = 0;
if (!mTempPath.IsEmpty() && StringBeginsWith(path, mTempPath)) {
prefixLen = mTempPath.Length();
} else if (StringBeginsWith(path, tempDirPrefix)) {
prefixLen = tempDirPrefix.Length();
}
if (prefixLen) {
const nsDependentCSubstring cutPath =
Substring(path, prefixLen, path.Length() - prefixLen);
// Only now try to get the content process temp dir
if (!mContentTempPath.IsEmpty()) {
nsAutoCString tmpPath;
tmpPath.Assign(mContentTempPath);
tmpPath.Append(cutPath);
base::strlcpy(aPath, tmpPath.get(), aBufSize);
return strlen(aPath);
}
}
return aPathLen;
}
#endif
nsCString SandboxBroker::ReverseSymlinks(const nsACString& aPath) {
// Revert any symlinks we previously resolved.
int32_t cutLength = aPath.Length();
@ -679,38 +638,6 @@ void SandboxBroker::ThreadMain(void) {
// before the main thread loop starts
bool permissive = SandboxInfo::Get().Test(SandboxInfo::kPermissive);
#if defined(MOZ_CONTENT_TEMP_DIR)
// Find the current temporary directory
nsCOMPtr<nsIFile> tmpDir;
nsresult rv =
GetSpecialSystemDirectory(OS_TemporaryDirectory, getter_AddRefs(tmpDir));
if (NS_SUCCEEDED(rv)) {
rv = tmpDir->GetNativePath(mTempPath);
if (NS_SUCCEEDED(rv)) {
// Make sure there's no terminating /
if (mTempPath.Last() == '/') {
mTempPath.Truncate(mTempPath.Length() - 1);
}
}
}
// If we can't find it, we aren't bothered much: we will
// always try /tmp anyway in the substitution code
if (NS_FAILED(rv) || mTempPath.IsEmpty()) {
if (SandboxInfo::Get().Test(SandboxInfo::kVerbose)) {
SANDBOX_LOG("Tempdir: /tmp");
}
} else {
if (SandboxInfo::Get().Test(SandboxInfo::kVerbose)) {
SANDBOX_LOG("Tempdir: %s", mTempPath.get());
}
// If it's /tmp, clear it here so we don't compare against
// it twice. Just let the fallback code do the work.
if (mTempPath.Equals(tempDirPrefix)) {
mTempPath.Truncate();
}
}
#endif
while (true) {
struct iovec ios[2];
// We will receive the path strings in 1 buffer and split them back up.
@ -802,14 +729,6 @@ void SandboxBroker::ThreadMain(void) {
pathLen = ConvertRelativePath(pathBuf, sizeof(pathBuf), pathLen);
perms = mPolicy->Lookup(nsDependentCString(pathBuf, pathLen));
// We don't have permissions on the requested dir.
#if defined(MOZ_CONTENT_TEMP_DIR)
if (!perms) {
// Was it a tempdir that we can remap?
pathLen = RemapTempDirs(pathBuf, sizeof(pathBuf), pathLen);
perms = mPolicy->Lookup(nsDependentCString(pathBuf, pathLen));
}
#endif
if (!perms) {
// Did we arrive from a symlink in a path that is not writable?
// Then try to figure out the original path and see if that is

Просмотреть файл

@ -144,10 +144,6 @@ class SandboxBroker final : private SandboxBrokerCommon,
int mFileDesc;
const int mChildPid;
const UniquePtr<const Policy> mPolicy;
#if defined(MOZ_CONTENT_TEMP_DIR)
nsCString mTempPath;
nsCString mContentTempPath;
#endif
typedef nsTHashMap<nsCStringHashKey, nsCString> PathMap;
PathMap mSymlinkMap;
@ -161,10 +157,6 @@ class SandboxBroker final : private SandboxBrokerCommon,
// Remap relative paths to absolute paths.
size_t ConvertRelativePath(char* aPath, size_t aBufSize, size_t aPathLen);
size_t RealPath(char* aPath, size_t aBufSize, size_t aPathLen);
#if defined(MOZ_CONTENT_TEMP_DIR)
// Remap references to /tmp and friends to the content process tempdir
size_t RemapTempDirs(char* aPath, size_t aBufSize, size_t aPathLen);
#endif
nsCString ReverseSymlinks(const nsACString& aPath);
// Retrieves permissions for the path the original symlink sits in.
int SymlinkPermissions(const char* aPath, const size_t aPathLen);

Просмотреть файл

@ -680,20 +680,6 @@ void SandboxBrokerPolicyFactory::InitContentPolicy() {
AddDynamicPathList(policy, "security.sandbox.content.read_path_whitelist",
rdonly);
#if defined(MOZ_CONTENT_TEMP_DIR)
// Add write permissions on the content process specific temporary dir.
nsCOMPtr<nsIFile> tmpDir;
rv = NS_GetSpecialDirectory(NS_APP_CONTENT_PROCESS_TEMP_DIR,
getter_AddRefs(tmpDir));
if (NS_SUCCEEDED(rv)) {
nsAutoCString tmpPath;
rv = tmpDir->GetNativePath(tmpPath);
if (NS_SUCCEEDED(rv)) {
policy->AddDir(rdwrcr, tmpPath.get());
}
}
#endif
// userContent.css and the extensions dir sit in the profile, which is
// normally blocked.
nsCOMPtr<nsIFile> profileDir;

Просмотреть файл

@ -3,55 +3,84 @@
/* 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 is not permitted");
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 disallowed on
// macOS and Windows but allowed everywhere else. Also test that the content
// process cannot create symlinks on macOS or delete files.
// 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 isOptWin = isWin() && !SpecialPowers.isDebugBuild;
let isDbgWin = isWin() && SpecialPowers.isDebugBuild;
let browser = gBrowser.selectedBrowser;
let path = fileInTempDir().path;
let fileCreated = await SpecialPowers.spawn(browser, [path], createFile);
if (isMac() || isOptWin) {
ok(!fileCreated.ok, "creating a file in temp is not permitted");
if (isDbgWin) {
ok(fileCreated.ok, "creating a file in temp suceeded");
} else {
ok(!!fileCreated.ok, "creating a file in temp is permitted");
}
// now delete the file
let fileDeleted = await SpecialPowers.spawn(browser, [path], deleteFile);
if (isMac() || isOptWin) {
// On macOS we do not allow file deletion - it is not needed by the content
// process itself, and macOS uses a different permission to control access
// so revoking it is easy.
ok(!fileDeleted.ok, "deleting a file in temp is not permitted");
} else {
ok(!!fileDeleted.ok, "deleting a file in temp is permitted");
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"
);
}
// Test that symlink creation is not allowed on macOS.
if (isMac()) {
// 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 is not permitted");
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"
);
}
}

Просмотреть файл

@ -301,8 +301,8 @@ add_task(async function () {
// use open syscall
if (isLinux() || isMac()) {
// open a file for writing in the content temp dir, this should fail on
// macOS and work on Linux. The open handler in the content process closes
// the file for us
// 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(
@ -310,19 +310,11 @@ add_task(async function () {
[{ lib, path, flags }],
callOpen
);
if (isMac()) {
Assert.strictEqual(
fd,
-1,
"opening a file for writing in content temp is not permitted"
);
} else {
Assert.greaterOrEqual(
fd,
0,
"opening a file for writing in content temp is permitted"
);
}
Assert.strictEqual(
fd,
-1,
"opening a file for writing in content temp is not permitted"
);
}
// use fork syscall

Просмотреть файл

@ -48,6 +48,8 @@ function sanityChecks() {
// 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 ContentTask.spawn.
//
// Report the exception's error code in .code as well.
function createFile(path) {
const { FileUtils } = ChromeUtils.importESModule(
"resource://gre/modules/FileUtils.sys.mjs"
@ -76,7 +78,7 @@ function createFile(path) {
ostream.close();
fstream.close();
} catch (e) {
return { ok: false };
return { ok: false, code: e.result };
}
return { ok: true };
@ -86,14 +88,19 @@ function createFile(path) {
// 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 ContentTask.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"
Services.appinfo.OS === "Darwin" ? "libSystem.B.dylib" : "libc.so.6"
);
const symlink = libc.declare(
@ -104,11 +111,14 @@ function createSymlink(path) {
ctypes.char.ptr //linkpath
);
if (symlink("/etc", path)) {
return { ok: false };
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 };
return { ok: false, code: e.result };
}
return { ok: true };
@ -118,6 +128,8 @@ function createSymlink(path) {
// 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 ContentTask.spawn.
//
// Report the exception's error code in .code as well.
function deleteFile(path) {
const { FileUtils } = ChromeUtils.importESModule(
"resource://gre/modules/FileUtils.sys.mjs"
@ -127,7 +139,7 @@ function deleteFile(path) {
const file = new FileUtils.File(path);
file.remove(false);
} catch (e) {
return { ok: false };
return { ok: false, code: e.result };
}
return { ok: true };
@ -137,6 +149,8 @@ function deleteFile(path) {
// 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"
@ -153,7 +167,7 @@ function readDir(path) {
numEntries++;
}
} catch (e) {
return { ok: false, numEntries };
return { ok: false, numEntries, code: e.result };
}
return { ok: true, numEntries };
@ -162,6 +176,8 @@ function readDir(path) {
// 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"
@ -183,7 +199,7 @@ function readFile(path) {
const available = istream.available();
void istream.readBytes(available);
} catch (e) {
return { ok: false };
return { ok: false, code: e.result };
}
return { ok: true };
@ -192,6 +208,8 @@ function readFile(path) {
// 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"
@ -201,7 +219,7 @@ function statPath(path) {
const file = new FileUtils.File(path);
void file.lastModifiedTime;
} catch (e) {
return { ok: false };
return { ok: false, code: e.result };
}
return { ok: true };

Просмотреть файл

@ -3497,9 +3497,6 @@ option(
set_config("MOZ_SANDBOX", True, when="--enable-sandbox")
set_define("MOZ_SANDBOX", True, when="--enable-sandbox")
with only_when(depends(target.kernel)(lambda k: k not in ("Darwin", "WINNT"))):
set_define("MOZ_CONTENT_TEMP_DIR", True, when="--enable-sandbox")
# Searching of system directories for extensions.
# ==============================================================
# Note: this switch is meant to be used for test builds whose behavior should

Просмотреть файл

@ -80,12 +80,6 @@
# include "UIKitDirProvider.h"
#endif
#if defined(MOZ_CONTENT_TEMP_DIR)
# include "mozilla/SandboxSettings.h"
# include "nsID.h"
# include "mozilla/Unused.h"
#endif
#if defined(XP_MACOSX)
# define APP_REGISTRY_NAME "Application Registry"
#elif defined(XP_WIN)
@ -96,16 +90,6 @@
#define PREF_OVERRIDE_DIRNAME "preferences"
#if defined(MOZ_CONTENT_TEMP_DIR)
static already_AddRefed<nsIFile> GetProcessSandboxTempDir(
GeckoProcessType type);
static nsresult DeleteDirIfExists(nsIFile* dir);
static bool IsContentSandboxDisabled();
static const char* GetProcessTempBaseDirKey();
static already_AddRefed<nsIFile> CreateProcessSandboxTempDir(
GeckoProcessType procType);
#endif
nsXREDirProvider* gDirServiceProvider = nullptr;
nsIFile* gDataDirHomeLocal = nullptr;
nsIFile* gDataDirHome = nullptr;
@ -447,17 +431,7 @@ nsXREDirProvider::GetFile(const char* aProperty, bool* aPersistent,
NS_ENSURE_SUCCESS(rv, rv);
bool unused;
rv = dirsvc->GetFile("XCurProcD", &unused, getter_AddRefs(file));
}
#if defined(MOZ_CONTENT_TEMP_DIR)
else if (!strcmp(aProperty, NS_APP_CONTENT_PROCESS_TEMP_DIR)) {
if (!mContentTempDir) {
rv = LoadContentProcessTempDir();
NS_ENSURE_SUCCESS(rv, rv);
}
rv = mContentTempDir->Clone(getter_AddRefs(file));
}
#endif // defined(MOZ_CONTENT_TEMP_DIR)
else if (!strcmp(aProperty, NS_APP_USER_CHROME_DIR)) {
} else if (!strcmp(aProperty, NS_APP_USER_CHROME_DIR)) {
// It isn't clear why this uses GetProfileStartupDir instead of
// GetProfileDir. It could theoretically matter in a non-main
// process where some other directory provider has defined
@ -519,166 +493,6 @@ static void LoadDirIntoArray(nsIFile* dir, const char* const* aAppendList,
}
}
#if defined(MOZ_CONTENT_TEMP_DIR)
static const char* GetProcessTempBaseDirKey() { return NS_OS_TEMP_DIR; }
//
// Sets mContentTempDir so that it refers to the appropriate temp dir.
// If the sandbox is enabled, NS_APP_CONTENT_PROCESS_TEMP_DIR, otherwise
// NS_OS_TEMP_DIR is used.
//
nsresult nsXREDirProvider::LoadContentProcessTempDir() {
// The parent is responsible for creating the sandbox temp dir.
if (XRE_IsParentProcess()) {
mContentProcessSandboxTempDir =
CreateProcessSandboxTempDir(GeckoProcessType_Content);
mContentTempDir = mContentProcessSandboxTempDir;
} else {
mContentTempDir = !IsContentSandboxDisabled()
? GetProcessSandboxTempDir(GeckoProcessType_Content)
: nullptr;
}
if (!mContentTempDir) {
nsresult rv =
NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(mContentTempDir));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
}
return NS_OK;
}
static bool IsContentSandboxDisabled() {
return !mozilla::BrowserTabsRemoteAutostart() ||
(!mozilla::IsContentSandboxEnabled());
}
//
// If a process sandbox temp dir is to be used, returns an nsIFile
// for the directory. Returns null if an error occurs.
//
static already_AddRefed<nsIFile> GetProcessSandboxTempDir(
GeckoProcessType type) {
nsCOMPtr<nsIFile> localFile;
nsresult rv = NS_GetSpecialDirectory(GetProcessTempBaseDirKey(),
getter_AddRefs(localFile));
if (NS_WARN_IF(NS_FAILED(rv))) {
return nullptr;
}
MOZ_ASSERT(type == GeckoProcessType_Content);
const char* prefKey = "security.sandbox.content.tempDirSuffix";
nsAutoString tempDirSuffix;
rv = mozilla::Preferences::GetString(prefKey, tempDirSuffix);
if (NS_WARN_IF(NS_FAILED(rv)) || tempDirSuffix.IsEmpty()) {
return nullptr;
}
rv = localFile->Append(u"Temp-"_ns + tempDirSuffix);
if (NS_WARN_IF(NS_FAILED(rv))) {
return nullptr;
}
return localFile.forget();
}
//
// Create a temporary directory for use from sandboxed processes.
// Only called in the parent. The path is derived from a UUID stored in a
// pref which is available to content processes. Returns null
// if the content sandbox is disabled or if an error occurs.
//
static already_AddRefed<nsIFile> CreateProcessSandboxTempDir(
GeckoProcessType procType) {
if ((procType == GeckoProcessType_Content) && IsContentSandboxDisabled()) {
return nullptr;
}
MOZ_ASSERT(procType == GeckoProcessType_Content);
// Get (and create if blank) temp directory suffix pref.
const char* pref = "security.sandbox.content.tempDirSuffix";
nsresult rv;
nsAutoString tempDirSuffix;
mozilla::Preferences::GetString(pref, tempDirSuffix);
if (tempDirSuffix.IsEmpty()) {
nsID uuid;
rv = nsID::GenerateUUIDInPlace(uuid);
if (NS_WARN_IF(NS_FAILED(rv))) {
return nullptr;
}
char uuidChars[NSID_LENGTH];
uuid.ToProvidedString(uuidChars);
tempDirSuffix.AssignASCII(uuidChars, NSID_LENGTH);
# ifdef XP_UNIX
// Braces in a path are somewhat annoying to deal with
// and pretty alien on Unix
tempDirSuffix.StripChars(u"{}");
# endif
// Save the pref
rv = mozilla::Preferences::SetString(pref, tempDirSuffix);
if (NS_WARN_IF(NS_FAILED(rv))) {
// If we fail to save the pref we don't want to create the temp dir,
// because we won't be able to clean it up later.
return nullptr;
}
nsCOMPtr<nsIPrefService> prefsvc = mozilla::Preferences::GetService();
if (!prefsvc || NS_FAILED((rv = prefsvc->SavePrefFile(nullptr)))) {
// Again, if we fail to save the pref file we might not be able to clean
// up the temp directory, so don't create one. Note that in the case
// the preference values allows an off main thread save, the successful
// return from the call doesn't mean we actually saved the file. See
// bug 1364496 for details.
NS_WARNING("Failed to save pref file, cannot create temp dir.");
return nullptr;
}
}
nsCOMPtr<nsIFile> sandboxTempDir = GetProcessSandboxTempDir(procType);
if (!sandboxTempDir) {
NS_WARNING("Failed to determine sandbox temp dir path.");
return nullptr;
}
// Remove the directory. It may exist due to a previous crash.
if (NS_FAILED(DeleteDirIfExists(sandboxTempDir))) {
NS_WARNING("Failed to reset sandbox temp dir.");
return nullptr;
}
// Create the directory
rv = sandboxTempDir->Create(nsIFile::DIRECTORY_TYPE, 0700);
if (NS_FAILED(rv)) {
NS_WARNING("Failed to create sandbox temp dir.");
return nullptr;
}
return sandboxTempDir.forget();
}
static nsresult DeleteDirIfExists(nsIFile* dir) {
if (dir) {
// Don't return an error if the directory doesn't exist.
nsresult rv = dir->Remove(/* aRecursive */ true);
if (NS_FAILED(rv) && rv != NS_ERROR_FILE_NOT_FOUND) {
return rv;
}
}
return NS_OK;
}
#endif // defined(MOZ_CONTENT_TEMP_DIR)
static const char* const kAppendPrefDir[] = {"defaults", "preferences",
nullptr};
#ifdef MOZ_BACKGROUNDTASKS
@ -855,15 +669,6 @@ nsXREDirProvider::DoStartup() {
mozilla::Telemetry::Accumulate(mozilla::Telemetry::SAFE_MODE_USAGE, mode);
obsSvc->NotifyObservers(nullptr, "profile-initial-state", nullptr);
#if defined(MOZ_CONTENT_TEMP_DIR)
// Makes sure the content temp dir has been loaded if it hasn't been
// already. In the parent this ensures it has been created before we attempt
// to start any content processes.
if (!mContentTempDir) {
mozilla::Unused << NS_WARN_IF(NS_FAILED(LoadContentProcessTempDir()));
}
#endif
}
return NS_OK;
}
@ -895,12 +700,6 @@ void nsXREDirProvider::DoShutdown() {
gDataDirProfileLocal = nullptr;
gDataDirProfile = nullptr;
#if defined(MOZ_CONTENT_TEMP_DIR)
if (XRE_IsParentProcess()) {
mozilla::Unused << DeleteDirIfExists(mContentProcessSandboxTempDir);
}
#endif
}
#ifdef XP_WIN

Просмотреть файл

@ -132,11 +132,6 @@ class nsXREDirProvider final : public nsIDirectoryServiceProvider2,
static nsresult SetUserDataProfileDirectory(nsCOMPtr<nsIFile>& aFile,
bool aLocal);
#if defined(MOZ_CONTENT_TEMP_DIR)
// Load the temp directory for sandboxed content processes
nsresult LoadContentProcessTempDir();
#endif
void Append(nsIFile* aDirectory);
// On OSX, mGREDir points to .app/Contents/Resources
@ -149,10 +144,6 @@ class nsXREDirProvider final : public nsIDirectoryServiceProvider2,
nsCOMPtr<nsIFile> mProfileLocalDir;
bool mAppStarted = false;
bool mPrefsInitialized = false;
#if defined(MOZ_CONTENT_TEMP_DIR)
nsCOMPtr<nsIFile> mContentTempDir;
nsCOMPtr<nsIFile> mContentProcessSandboxTempDir;
#endif
};
#endif

Просмотреть файл

@ -74,29 +74,4 @@
#define NS_APP_PERMISSION_PARENT_DIR "permissionDBPDir"
#if defined(MOZ_CONTENT_TEMP_DIR)
//
// NS_APP_CONTENT_PROCESS_TEMP_DIR refers to a directory that is read and
// write accessible from a sandboxed content process. The key may be used in
// either process, but the directory is intended to be used for short-lived
// files that need to be saved to the filesystem by the content process and
// don't need to survive browser restarts. The directory is reset on startup.
//
// When MOZ_CONTENT_TEMP_DIR is defined and sandboxing is enabled (versus
// manually disabled via prefs), the content process replaces NS_OS_TEMP_DIR
// with NS_APP_CONTENT_PROCESS_TEMP_DIR so that legacy code in content
// attempting to write to NS_OS_TEMP_DIR will write to
// NS_APP_CONTENT_PROCESS_TEMP_DIR instead. When MOZ_SANDBOX is
// defined but sandboxing is disabled, NS_APP_CONTENT_PROCESS_TEMP_DIR
// falls back to NS_OS_TEMP_DIR in both content and chrome processes.
//
// New code should avoid writing to the filesystem from the content process
// and should instead proxy through the parent process whenever possible.
//
// At present, all sandboxed content processes use the same directory for
// NS_APP_CONTENT_PROCESS_TEMP_DIR, but that should not be relied upon.
//
# define NS_APP_CONTENT_PROCESS_TEMP_DIR "ContentTmpD"
#endif // defined(MOZ_SANDBOX)
#endif // nsAppDirectoryServiceDefs_h___