зеркало из 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 "nsXPCOMPrivate.h"
|
||||
|
||||
#if defined(MOZ_CONTENT_SANDBOX)
|
||||
#if defined(MOZ_CONTENT_SANDBOX) && defined(XP_MACOSX)
|
||||
#include "nsAppDirectoryServiceDefs.h"
|
||||
#endif
|
||||
|
||||
|
@ -48,7 +48,6 @@
|
|||
#if defined(MOZ_SANDBOX)
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/sandboxing/sandboxLogging.h"
|
||||
#include "nsDirectoryServiceUtils.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
@ -112,34 +111,6 @@ GeckoChildProcessHost::GeckoChildProcessHost(GeckoProcessType aProcessType,
|
|||
#endif
|
||||
{
|
||||
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()
|
||||
|
@ -323,78 +294,6 @@ GeckoChildProcessHost::GetUniqueID()
|
|||
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
|
||||
GeckoChildProcessHost::PrepareLaunch()
|
||||
{
|
||||
|
@ -415,11 +314,6 @@ GeckoChildProcessHost::PrepareLaunch()
|
|||
mSandboxLevel = Preferences::GetInt("security.sandbox.content.level");
|
||||
mEnableSandboxLogging =
|
||||
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
|
||||
|
||||
|
|
|
@ -1462,6 +1462,7 @@ XRE_XPCShellMain(int argc, char** argv, char** envp,
|
|||
// Required for sandboxed child processes.
|
||||
if (aShellData->sandboxBrokerServices) {
|
||||
SandboxBroker::Initialize(aShellData->sandboxBrokerServices);
|
||||
SandboxBroker::CacheRulesDirectories();
|
||||
} else {
|
||||
NS_WARNING("Failed to initialize broker services, sandboxed "
|
||||
"processes will fail to start.");
|
||||
|
|
|
@ -8,8 +8,17 @@
|
|||
|
||||
#include "base/win/windows_version.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
#include "mozilla/Logging.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/security_level.h"
|
||||
|
||||
|
@ -18,6 +27,11 @@ namespace mozilla
|
|||
|
||||
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");
|
||||
|
||||
#define LOG_E(...) MOZ_LOG(sSandboxBrokerLog, LogLevel::Error, (__VA_ARGS__))
|
||||
|
@ -30,6 +44,50 @@ SandboxBroker::Initialize(sandbox::BrokerServices* 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()
|
||||
{
|
||||
if (sBrokerService) {
|
||||
|
@ -133,7 +191,35 @@ SandboxBroker::LaunchApp(const wchar_t *aPath,
|
|||
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)
|
||||
|
||||
void
|
||||
SandboxBroker::SetSecurityLevelForContentProcess(int32_t aSandboxLevel,
|
||||
base::ChildPrivileges aPrivs)
|
||||
|
@ -159,7 +245,12 @@ SandboxBroker::SetSecurityLevelForContentProcess(int32_t aSandboxLevel,
|
|||
accessTokenLevel = sandbox::USER_LIMITED;
|
||||
initialIntegrityLevel = 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;
|
||||
accessTokenLevel = sandbox::USER_INTERACTIVE;
|
||||
initialIntegrityLevel = sandbox::INTEGRITY_LEVEL_LOW;
|
||||
|
@ -204,7 +295,7 @@ SandboxBroker::SetSecurityLevelForContentProcess(int32_t aSandboxLevel,
|
|||
MOZ_RELEASE_ASSERT(sandbox::SBOX_ALL_OK == result,
|
||||
"SetDelayedIntegrityLevel should never fail, what happened?");
|
||||
|
||||
if (aSandboxLevel > 2) {
|
||||
if (aSandboxLevel > 3) {
|
||||
result = mPolicy->SetAlternateDesktop(true);
|
||||
MOZ_RELEASE_ASSERT(sandbox::SBOX_ALL_OK == result,
|
||||
"Failed to create alternate desktop for sandbox.");
|
||||
|
@ -229,6 +320,13 @@ SandboxBroker::SetSecurityLevelForContentProcess(int32_t aSandboxLevel,
|
|||
MOZ_RELEASE_ASSERT(sandbox::SBOX_ALL_OK == result,
|
||||
"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
|
||||
// files, so add a rule to allow read access to everything when required.
|
||||
if (aSandboxLevel == 1 ||
|
||||
|
@ -238,6 +336,18 @@ SandboxBroker::SetSecurityLevelForContentProcess(int32_t aSandboxLevel,
|
|||
L"*");
|
||||
MOZ_RELEASE_ASSERT(sandbox::SBOX_ALL_OK == result,
|
||||
"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
|
||||
|
|
|
@ -26,6 +26,12 @@ public:
|
|||
|
||||
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,
|
||||
const wchar_t *aArguments,
|
||||
const bool aEnableLogging,
|
||||
|
|
|
@ -4441,6 +4441,10 @@ XREMain::XRE_mainRun()
|
|||
// We intentionally leak the string here since it is required by PR_SetEnv.
|
||||
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
|
||||
|
||||
SaveStateForAppInitiatedRestart();
|
||||
|
|
Загрузка…
Ссылка в новой задаче