зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1339105 Part 1: Implement Windows Level 3 content process sandbox policy. r=jimm
MozReview-Commit-ID: L8wcVhdLvFe
This commit is contained in:
Родитель
e75f6bd810
Коммит
f24abd4ac3
|
@ -23,7 +23,7 @@
|
||||||
#include "prenv.h"
|
#include "prenv.h"
|
||||||
#include "nsXPCOMPrivate.h"
|
#include "nsXPCOMPrivate.h"
|
||||||
|
|
||||||
#if defined(MOZ_CONTENT_SANDBOX)
|
#if defined(MOZ_CONTENT_SANDBOX) && defined(XP_MACOSX)
|
||||||
#include "nsAppDirectoryServiceDefs.h"
|
#include "nsAppDirectoryServiceDefs.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -48,7 +48,6 @@
|
||||||
#if defined(MOZ_SANDBOX)
|
#if defined(MOZ_SANDBOX)
|
||||||
#include "mozilla/Preferences.h"
|
#include "mozilla/Preferences.h"
|
||||||
#include "mozilla/sandboxing/sandboxLogging.h"
|
#include "mozilla/sandboxing/sandboxLogging.h"
|
||||||
#include "nsDirectoryServiceUtils.h"
|
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -112,34 +111,6 @@ GeckoChildProcessHost::GeckoChildProcessHost(GeckoProcessType aProcessType,
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
MOZ_COUNT_CTOR(GeckoChildProcessHost);
|
MOZ_COUNT_CTOR(GeckoChildProcessHost);
|
||||||
|
|
||||||
#if defined(OS_WIN) && defined(MOZ_CONTENT_SANDBOX)
|
|
||||||
// Add $PROFILE/chrome to the white list because it may located on network
|
|
||||||
// drive.
|
|
||||||
if (mProcessType == GeckoProcessType_Content) {
|
|
||||||
nsCOMPtr<nsIProperties> directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID));
|
|
||||||
NS_ASSERTION(directoryService, "Expected XPCOM to be available");
|
|
||||||
if (directoryService) {
|
|
||||||
// Full path to the profile dir
|
|
||||||
nsCOMPtr<nsIFile> profileDir;
|
|
||||||
nsresult rv = directoryService->Get(NS_APP_USER_PROFILE_50_DIR,
|
|
||||||
NS_GET_IID(nsIFile),
|
|
||||||
getter_AddRefs(profileDir));
|
|
||||||
if (NS_SUCCEEDED(rv)) {
|
|
||||||
profileDir->Append(NS_LITERAL_STRING("chrome"));
|
|
||||||
profileDir->Append(NS_LITERAL_STRING("*"));
|
|
||||||
nsAutoCString path;
|
|
||||||
MOZ_ALWAYS_SUCCEEDS(profileDir->GetNativePath(path));
|
|
||||||
std::wstring wpath = UTF8ToWide(path.get());
|
|
||||||
// If the patch starts with "\\\\", it is a UNC path.
|
|
||||||
if (wpath.find(L"\\\\") == 0) {
|
|
||||||
wpath.insert(1, L"??\\UNC");
|
|
||||||
}
|
|
||||||
mAllowedFilesRead.push_back(wpath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GeckoChildProcessHost::~GeckoChildProcessHost()
|
GeckoChildProcessHost::~GeckoChildProcessHost()
|
||||||
|
@ -323,78 +294,6 @@ GeckoChildProcessHost::GetUniqueID()
|
||||||
return sNextUniqueID++;
|
return sNextUniqueID++;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(XP_WIN) && defined(MOZ_SANDBOX)
|
|
||||||
|
|
||||||
// This is pretty much a duplicate of the function in PluginProcessParent.
|
|
||||||
// Simply copying for now due to uplift. I will address this duplication and for
|
|
||||||
// example the similar code in the Constructor in bug 1339105.
|
|
||||||
static void
|
|
||||||
AddSandboxAllowedFile(std::vector<std::wstring>& aAllowedFiles,
|
|
||||||
nsIProperties* aDirSvc, const char* aDirKey,
|
|
||||||
const nsAString& aSuffix = EmptyString())
|
|
||||||
{
|
|
||||||
nsCOMPtr<nsIFile> ruleDir;
|
|
||||||
nsresult rv =
|
|
||||||
aDirSvc->Get(aDirKey, NS_GET_IID(nsIFile), getter_AddRefs(ruleDir));
|
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsAutoString rulePath;
|
|
||||||
rv = ruleDir->GetPath(rulePath);
|
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert network share path to format for sandbox policy.
|
|
||||||
if (Substring(rulePath, 0, 2).Equals(L"\\\\")) {
|
|
||||||
rulePath.InsertLiteral(u"??\\UNC", 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!aSuffix.IsEmpty()) {
|
|
||||||
rulePath.Append(aSuffix);
|
|
||||||
}
|
|
||||||
|
|
||||||
aAllowedFiles.push_back(std::wstring(rulePath.get()));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
AddContentSandboxAllowedFiles(int32_t aSandboxLevel,
|
|
||||||
std::vector<std::wstring>& aAllowedFilesRead,
|
|
||||||
std::vector<std::wstring>& aAllowedFilesReadWrite)
|
|
||||||
{
|
|
||||||
if (aSandboxLevel < 1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult rv;
|
|
||||||
nsCOMPtr<nsIProperties> dirSvc =
|
|
||||||
do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv);
|
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add rule to allow read / write access to content temp dir. If for some
|
|
||||||
// reason the addition of the content temp failed, this will give write access
|
|
||||||
// to the normal TEMP dir. However such failures should be pretty rare and
|
|
||||||
// without this printing will not currently work.
|
|
||||||
AddSandboxAllowedFile(aAllowedFilesReadWrite, dirSvc,
|
|
||||||
NS_APP_CONTENT_PROCESS_TEMP_DIR,
|
|
||||||
NS_LITERAL_STRING("\\*"));
|
|
||||||
|
|
||||||
if (aSandboxLevel < 2) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add rule to allow read access to installation directory. At less than
|
|
||||||
// level 2 we already add a global read rule.
|
|
||||||
AddSandboxAllowedFile(aAllowedFilesRead, dirSvc, NS_GRE_DIR,
|
|
||||||
NS_LITERAL_STRING("\\*"));
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void
|
void
|
||||||
GeckoChildProcessHost::PrepareLaunch()
|
GeckoChildProcessHost::PrepareLaunch()
|
||||||
{
|
{
|
||||||
|
@ -415,11 +314,6 @@ GeckoChildProcessHost::PrepareLaunch()
|
||||||
mSandboxLevel = Preferences::GetInt("security.sandbox.content.level");
|
mSandboxLevel = Preferences::GetInt("security.sandbox.content.level");
|
||||||
mEnableSandboxLogging =
|
mEnableSandboxLogging =
|
||||||
Preferences::GetBool("security.sandbox.logging.enabled");
|
Preferences::GetBool("security.sandbox.logging.enabled");
|
||||||
|
|
||||||
// This calls the directory service, which can also cause issues if called
|
|
||||||
// off main thread.
|
|
||||||
AddContentSandboxAllowedFiles(mSandboxLevel, mAllowedFilesRead,
|
|
||||||
mAllowedFilesReadWrite);
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -1462,6 +1462,7 @@ XRE_XPCShellMain(int argc, char** argv, char** envp,
|
||||||
// Required for sandboxed child processes.
|
// Required for sandboxed child processes.
|
||||||
if (aShellData->sandboxBrokerServices) {
|
if (aShellData->sandboxBrokerServices) {
|
||||||
SandboxBroker::Initialize(aShellData->sandboxBrokerServices);
|
SandboxBroker::Initialize(aShellData->sandboxBrokerServices);
|
||||||
|
SandboxBroker::CacheRulesDirectories();
|
||||||
} else {
|
} else {
|
||||||
NS_WARNING("Failed to initialize broker services, sandboxed "
|
NS_WARNING("Failed to initialize broker services, sandboxed "
|
||||||
"processes will fail to start.");
|
"processes will fail to start.");
|
||||||
|
|
|
@ -8,8 +8,17 @@
|
||||||
|
|
||||||
#include "base/win/windows_version.h"
|
#include "base/win/windows_version.h"
|
||||||
#include "mozilla/Assertions.h"
|
#include "mozilla/Assertions.h"
|
||||||
|
#include "mozilla/ClearOnShutdown.h"
|
||||||
#include "mozilla/Logging.h"
|
#include "mozilla/Logging.h"
|
||||||
#include "mozilla/NSPRLogModulesParser.h"
|
#include "mozilla/NSPRLogModulesParser.h"
|
||||||
|
#include "mozilla/UniquePtr.h"
|
||||||
|
#include "nsAppDirectoryServiceDefs.h"
|
||||||
|
#include "nsCOMPtr.h"
|
||||||
|
#include "nsDirectoryServiceDefs.h"
|
||||||
|
#include "nsIFile.h"
|
||||||
|
#include "nsIProperties.h"
|
||||||
|
#include "nsServiceManagerUtils.h"
|
||||||
|
#include "nsString.h"
|
||||||
#include "sandbox/win/src/sandbox.h"
|
#include "sandbox/win/src/sandbox.h"
|
||||||
#include "sandbox/win/src/security_level.h"
|
#include "sandbox/win/src/security_level.h"
|
||||||
|
|
||||||
|
@ -18,6 +27,11 @@ namespace mozilla
|
||||||
|
|
||||||
sandbox::BrokerServices *SandboxBroker::sBrokerService = nullptr;
|
sandbox::BrokerServices *SandboxBroker::sBrokerService = nullptr;
|
||||||
|
|
||||||
|
// Cached special directories used for adding policy rules.
|
||||||
|
static UniquePtr<nsString> sBinDir;
|
||||||
|
static UniquePtr<nsString> sProfileDir;
|
||||||
|
static UniquePtr<nsString> sContentTempDir;
|
||||||
|
|
||||||
static LazyLogModule sSandboxBrokerLog("SandboxBroker");
|
static LazyLogModule sSandboxBrokerLog("SandboxBroker");
|
||||||
|
|
||||||
#define LOG_E(...) MOZ_LOG(sSandboxBrokerLog, LogLevel::Error, (__VA_ARGS__))
|
#define LOG_E(...) MOZ_LOG(sSandboxBrokerLog, LogLevel::Error, (__VA_ARGS__))
|
||||||
|
@ -30,6 +44,50 @@ SandboxBroker::Initialize(sandbox::BrokerServices* aBrokerServices)
|
||||||
sBrokerService = aBrokerServices;
|
sBrokerService = aBrokerServices;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
CacheDirAndAutoClear(nsIProperties* aDirSvc, const char* aDirKey,
|
||||||
|
UniquePtr<nsString>* cacheVar)
|
||||||
|
{
|
||||||
|
nsCOMPtr<nsIFile> dirToCache;
|
||||||
|
nsresult rv =
|
||||||
|
aDirSvc->Get(aDirKey, NS_GET_IID(nsIFile), getter_AddRefs(dirToCache));
|
||||||
|
if (NS_FAILED(rv)) {
|
||||||
|
// This can only be an NS_WARNING, because it can fail for xpcshell tests.
|
||||||
|
NS_WARNING("Failed to get directory to cache.");
|
||||||
|
LOG_E("Failed to get directory to cache, key: %s.", aDirKey);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
*cacheVar = MakeUnique<nsString>();
|
||||||
|
ClearOnShutdown(cacheVar);
|
||||||
|
MOZ_ALWAYS_SUCCEEDS(dirToCache->GetPath(**cacheVar));
|
||||||
|
|
||||||
|
// Convert network share path to format for sandbox policy.
|
||||||
|
if (Substring(**cacheVar, 0, 2).Equals(L"\\\\")) {
|
||||||
|
(*cacheVar)->InsertLiteral(u"??\\UNC", 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* static */
|
||||||
|
void
|
||||||
|
SandboxBroker::CacheRulesDirectories()
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
|
nsresult rv;
|
||||||
|
nsCOMPtr<nsIProperties> dirSvc =
|
||||||
|
do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv);
|
||||||
|
if (NS_FAILED(rv)) {
|
||||||
|
MOZ_ASSERT(false, "Failed to get directory service, cannot cache directories for rules.");
|
||||||
|
LOG_E("Failed to get directory service, cannot cache directories for rules.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CacheDirAndAutoClear(dirSvc, NS_GRE_DIR, &sBinDir);
|
||||||
|
CacheDirAndAutoClear(dirSvc, NS_APP_USER_PROFILE_50_DIR, &sProfileDir);
|
||||||
|
CacheDirAndAutoClear(dirSvc, NS_APP_CONTENT_PROCESS_TEMP_DIR, &sContentTempDir);
|
||||||
|
}
|
||||||
|
|
||||||
SandboxBroker::SandboxBroker()
|
SandboxBroker::SandboxBroker()
|
||||||
{
|
{
|
||||||
if (sBrokerService) {
|
if (sBrokerService) {
|
||||||
|
@ -133,7 +191,35 @@ SandboxBroker::LaunchApp(const wchar_t *aPath,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
AddCachedDirRule(sandbox::TargetPolicy* aPolicy,
|
||||||
|
sandbox::TargetPolicy::Semantics aAccess,
|
||||||
|
const UniquePtr<nsString>& aBaseDir,
|
||||||
|
const nsAString& aRelativePath)
|
||||||
|
{
|
||||||
|
if (!aBaseDir) {
|
||||||
|
// This can only be an NS_WARNING, because it can null for xpcshell tests.
|
||||||
|
NS_WARNING("Tried to add rule with null base dir.");
|
||||||
|
LOG_E("Tried to add rule with null base dir. Relative path: %S, Access: %d",
|
||||||
|
aRelativePath, aAccess);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsAutoString rulePath(*aBaseDir);
|
||||||
|
rulePath.Append(aRelativePath);
|
||||||
|
|
||||||
|
sandbox::ResultCode result =
|
||||||
|
aPolicy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES, aAccess,
|
||||||
|
rulePath.get());
|
||||||
|
if (sandbox::SBOX_ALL_OK != result) {
|
||||||
|
NS_ERROR("Failed to add file policy rule.");
|
||||||
|
LOG_E("Failed (ResultCode %d) to add %d access to: %S",
|
||||||
|
result, aAccess, rulePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(MOZ_CONTENT_SANDBOX)
|
#if defined(MOZ_CONTENT_SANDBOX)
|
||||||
|
|
||||||
void
|
void
|
||||||
SandboxBroker::SetSecurityLevelForContentProcess(int32_t aSandboxLevel,
|
SandboxBroker::SetSecurityLevelForContentProcess(int32_t aSandboxLevel,
|
||||||
base::ChildPrivileges aPrivs)
|
base::ChildPrivileges aPrivs)
|
||||||
|
@ -159,7 +245,12 @@ SandboxBroker::SetSecurityLevelForContentProcess(int32_t aSandboxLevel,
|
||||||
accessTokenLevel = sandbox::USER_LIMITED;
|
accessTokenLevel = sandbox::USER_LIMITED;
|
||||||
initialIntegrityLevel = sandbox::INTEGRITY_LEVEL_LOW;
|
initialIntegrityLevel = sandbox::INTEGRITY_LEVEL_LOW;
|
||||||
delayedIntegrityLevel = sandbox::INTEGRITY_LEVEL_LOW;
|
delayedIntegrityLevel = sandbox::INTEGRITY_LEVEL_LOW;
|
||||||
} else if (aSandboxLevel >= 2) {
|
} else if (aSandboxLevel >= 3) {
|
||||||
|
jobLevel = sandbox::JOB_RESTRICTED;
|
||||||
|
accessTokenLevel = sandbox::USER_LIMITED;
|
||||||
|
initialIntegrityLevel = sandbox::INTEGRITY_LEVEL_LOW;
|
||||||
|
delayedIntegrityLevel = sandbox::INTEGRITY_LEVEL_LOW;
|
||||||
|
} else if (aSandboxLevel == 2) {
|
||||||
jobLevel = sandbox::JOB_INTERACTIVE;
|
jobLevel = sandbox::JOB_INTERACTIVE;
|
||||||
accessTokenLevel = sandbox::USER_INTERACTIVE;
|
accessTokenLevel = sandbox::USER_INTERACTIVE;
|
||||||
initialIntegrityLevel = sandbox::INTEGRITY_LEVEL_LOW;
|
initialIntegrityLevel = sandbox::INTEGRITY_LEVEL_LOW;
|
||||||
|
@ -204,7 +295,7 @@ SandboxBroker::SetSecurityLevelForContentProcess(int32_t aSandboxLevel,
|
||||||
MOZ_RELEASE_ASSERT(sandbox::SBOX_ALL_OK == result,
|
MOZ_RELEASE_ASSERT(sandbox::SBOX_ALL_OK == result,
|
||||||
"SetDelayedIntegrityLevel should never fail, what happened?");
|
"SetDelayedIntegrityLevel should never fail, what happened?");
|
||||||
|
|
||||||
if (aSandboxLevel > 2) {
|
if (aSandboxLevel > 3) {
|
||||||
result = mPolicy->SetAlternateDesktop(true);
|
result = mPolicy->SetAlternateDesktop(true);
|
||||||
MOZ_RELEASE_ASSERT(sandbox::SBOX_ALL_OK == result,
|
MOZ_RELEASE_ASSERT(sandbox::SBOX_ALL_OK == result,
|
||||||
"Failed to create alternate desktop for sandbox.");
|
"Failed to create alternate desktop for sandbox.");
|
||||||
|
@ -229,6 +320,13 @@ SandboxBroker::SetSecurityLevelForContentProcess(int32_t aSandboxLevel,
|
||||||
MOZ_RELEASE_ASSERT(sandbox::SBOX_ALL_OK == result,
|
MOZ_RELEASE_ASSERT(sandbox::SBOX_ALL_OK == result,
|
||||||
"Invalid flags for SetDelayedProcessMitigations.");
|
"Invalid flags for SetDelayedProcessMitigations.");
|
||||||
|
|
||||||
|
// Add rule to allow read / write access to content temp dir. If for some
|
||||||
|
// reason the addition of the content temp failed, this will give write access
|
||||||
|
// to the normal TEMP dir. However such failures should be pretty rare and
|
||||||
|
// without this printing will not currently work.
|
||||||
|
AddCachedDirRule(mPolicy, sandbox::TargetPolicy::FILES_ALLOW_ANY,
|
||||||
|
sContentTempDir, NS_LITERAL_STRING("\\*"));
|
||||||
|
|
||||||
// We still have edge cases where the child at low integrity can't read some
|
// We still have edge cases where the child at low integrity can't read some
|
||||||
// files, so add a rule to allow read access to everything when required.
|
// files, so add a rule to allow read access to everything when required.
|
||||||
if (aSandboxLevel == 1 ||
|
if (aSandboxLevel == 1 ||
|
||||||
|
@ -238,6 +336,18 @@ SandboxBroker::SetSecurityLevelForContentProcess(int32_t aSandboxLevel,
|
||||||
L"*");
|
L"*");
|
||||||
MOZ_RELEASE_ASSERT(sandbox::SBOX_ALL_OK == result,
|
MOZ_RELEASE_ASSERT(sandbox::SBOX_ALL_OK == result,
|
||||||
"With these static arguments AddRule should never fail, what happened?");
|
"With these static arguments AddRule should never fail, what happened?");
|
||||||
|
} else {
|
||||||
|
// Add rule to allow read access to installation directory.
|
||||||
|
AddCachedDirRule(mPolicy, sandbox::TargetPolicy::FILES_ALLOW_READONLY,
|
||||||
|
sBinDir, NS_LITERAL_STRING("\\*"));
|
||||||
|
|
||||||
|
// Add rule to allow read access chrome directory within profile.
|
||||||
|
AddCachedDirRule(mPolicy, sandbox::TargetPolicy::FILES_ALLOW_READONLY,
|
||||||
|
sProfileDir, NS_LITERAL_STRING("\\chrome\\*"));
|
||||||
|
|
||||||
|
// Add rule to allow read access extensions directory within profile.
|
||||||
|
AddCachedDirRule(mPolicy, sandbox::TargetPolicy::FILES_ALLOW_READONLY,
|
||||||
|
sProfileDir, NS_LITERAL_STRING("\\extensions\\*"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the policy for the client side of a pipe. It is just a file
|
// Add the policy for the client side of a pipe. It is just a file
|
||||||
|
|
|
@ -26,6 +26,12 @@ public:
|
||||||
|
|
||||||
static void Initialize(sandbox::BrokerServices* aBrokerServices);
|
static void Initialize(sandbox::BrokerServices* aBrokerServices);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cache directory paths for use in policy rules. Must be called on main
|
||||||
|
* thread.
|
||||||
|
*/
|
||||||
|
static void CacheRulesDirectories();
|
||||||
|
|
||||||
bool LaunchApp(const wchar_t *aPath,
|
bool LaunchApp(const wchar_t *aPath,
|
||||||
const wchar_t *aArguments,
|
const wchar_t *aArguments,
|
||||||
const bool aEnableLogging,
|
const bool aEnableLogging,
|
||||||
|
|
|
@ -4441,6 +4441,10 @@ XREMain::XRE_mainRun()
|
||||||
// We intentionally leak the string here since it is required by PR_SetEnv.
|
// We intentionally leak the string here since it is required by PR_SetEnv.
|
||||||
PR_SetEnv(saved.release());
|
PR_SetEnv(saved.release());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Call SandboxBroker to cache directories needed for policy rules, this must
|
||||||
|
// be called after mDirProvider.DoStartup as it needs the profile dir.
|
||||||
|
SandboxBroker::CacheRulesDirectories();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
SaveStateForAppInitiatedRestart();
|
SaveStateForAppInitiatedRestart();
|
||||||
|
|
Загрузка…
Ссылка в новой задаче