Bug 1380690 - Part 2 - Whitelist repo and object dirs using paths from the Info.plist files. r=Alex_Gaynor, r=spohl
On Mac developer builds, read the repo path and object dir path from the
Info.plist files in the application bundle instead of the
MOZ_DEVELOPER_REPO_DIR and MOZ_DEVELOPER_OBJ_DIR environment variables.
MozReview-Commit-ID: 8UtjkNPGUM1
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -1458,33 +1458,16 @@ GetDirectoryPath(const char *aPath) {
nsAutoCString directoryPath;
if (NS_FAILED(directoryFile->GetNativePath(directoryPath))) {
MOZ_CRASH("Failed to get path for an nsIFile");
}
return directoryPath;
}
#endif // DEBUG
-static nsresult
-NormalizePath(const char* aPath, nsCString& aOutPath)
-{
- nsresult rv;
-
- nsCOMPtr<nsIFile> file;
- rv = NS_NewLocalFile(NS_ConvertUTF8toUTF16(aPath), true, getter_AddRefs(file));
- NS_ENSURE_SUCCESS(rv, rv);
-
- rv = file->Normalize();
- NS_ENSURE_SUCCESS(rv, rv);
-
- rv = file->GetNativePath(aOutPath);
- NS_ENSURE_SUCCESS(rv, rv);
- return NS_OK;
-}
-
static bool
StartMacOSContentSandbox()
{
int sandboxLevel = GetEffectiveContentSandboxLevel();
if (sandboxLevel < 1) {
return false;
}
@@ -1519,25 +1502,16 @@ StartMacOSContentSandbox()
profileDir->Normalize();
rv = profileDir->GetNativePath(profileDirPath);
if (NS_FAILED(rv) || profileDirPath.IsEmpty()) {
MOZ_CRASH("Failed to get profile path");
}
}
bool isFileProcess = cc->GetRemoteType().EqualsLiteral(FILE_REMOTE_TYPE);
- char *developer_repo_dir = nullptr;
- char *developer_obj_dir = nullptr;
- if (mozilla::IsDevelopmentBuild()) {
- // If this is a developer build the resources in the .app are symlinks to
- // outside of the .app. Therefore in non-release builds we allow reads from
- // the whole repository. MOZ_DEVELOPER_REPO_DIR is set by mach run.
- developer_repo_dir = PR_GetEnv("MOZ_DEVELOPER_REPO_DIR");
- developer_obj_dir = PR_GetEnv("MOZ_DEVELOPER_OBJ_DIR");
- }
MacSandboxInfo info;
info.type = MacSandboxType_Content;
info.level = sandboxLevel;
info.hasFilePrivileges = isFileProcess;
info.shouldLog = Preferences::GetBool("security.sandbox.logging.enabled") ||
PR_GetEnv("MOZ_SANDBOX_LOGGING");
info.appPath.assign(appPath.get());
@@ -1554,31 +1528,34 @@ StartMacOSContentSandbox()
info.testingReadPath1.assign(testingReadPath1.get());
}
nsAdoptingCString testingReadPath2 =
Preferences::GetCString("security.sandbox.content.mac.testing_read_path2");
if (!testingReadPath2.IsEmpty()) {
info.testingReadPath2.assign(testingReadPath2.get());
}
- if (developer_repo_dir) {
+ if (mozilla::IsDevelopmentBuild()) {
+ nsCOMPtr<nsIFile> repoDir;
+ rv = mozilla::GetRepoDir(getter_AddRefs(repoDir));
+ if (NS_FAILED(rv)) {
+ MOZ_CRASH("Failed to get path to repo dir");
+ }
nsCString repoDirPath;
- rv = NormalizePath(developer_repo_dir, repoDirPath);
- if (NS_FAILED(rv)) {
- MOZ_CRASH("Failed to normalize repo path");
- }
+ Unused << repoDir->GetNativePath(repoDirPath);
info.testingReadPath3.assign(repoDirPath.get());
- }
-
- if (developer_obj_dir) {
+
+ nsCOMPtr<nsIFile> objDir;
+ rv = mozilla::GetObjDir(getter_AddRefs(objDir));
+ if (NS_FAILED(rv)) {
+ MOZ_CRASH("Failed to get path to build object dir");
+ }
+
nsCString objDirPath;
- rv = NormalizePath(developer_obj_dir, objDirPath);
- if (NS_FAILED(rv)) {
- MOZ_CRASH("Failed to normalize obj dir path");
- }
+ Unused << objDir->GetNativePath(objDirPath);
info.testingReadPath4.assign(objDirPath.get());
}
if (profileDir) {
info.hasSandboxedProfile = true;
info.profileDir.assign(profileDirPath.get());
} else {
info.hasSandboxedProfile = false;
--- a/netwerk/protocol/res/ExtensionProtocolHandler.cpp
+++ b/netwerk/protocol/res/ExtensionProtocolHandler.cpp
@@ -510,27 +510,21 @@ ExtensionProtocolHandler::SubstituteChan
Result<Ok, nsresult>
ExtensionProtocolHandler::DevRepoContains(nsIFile* aRequestedFile,
bool *aResult)
{
MOZ_ASSERT(!IsNeckoChild());
MOZ_ASSERT(aResult);
*aResult = false;
- // On the first invocation, set mDevRepo if this is a
- // development build with MOZ_DEVELOPER_REPO_DIR set.
+ // On the first invocation, set mDevRepo if this is a development build
if (!mAlreadyCheckedDevRepo) {
mAlreadyCheckedDevRepo = true;
if (mozilla::IsDevelopmentBuild()) {
- char *developer_repo_dir = PR_GetEnv("MOZ_DEVELOPER_REPO_DIR");
- if (developer_repo_dir) {
- NS_TRY(NS_NewLocalFile(NS_ConvertUTF8toUTF16(developer_repo_dir),
- false, getter_AddRefs(mDevRepo)));
- NS_TRY(mDevRepo->Normalize());
- }
+ NS_TRY(mozilla::GetRepoDir(getter_AddRefs(mDevRepo)));
}
}
if (mDevRepo) {
// This is a development build
NS_TRY(mDevRepo->Contains(aRequestedFile, aResult));
}
--- a/security/sandbox/common/SandboxSettings.cpp
+++ b/security/sandbox/common/SandboxSettings.cpp
@@ -5,25 +5,158 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozISandboxSettings.h"
#include "mozilla/Omnijar.h"
#include "mozilla/ModuleUtils.h"
#include "mozilla/Preferences.h"
+#include "nsDirectoryServiceDefs.h"
+
+#if defined(XP_MACOSX)
+#include <CoreServices/CoreServices.h>
+// Info.plist key associated with the developer repo path
+#define MAC_DEV_REPO_KEY "MozillaDeveloperRepoPath"
+// Info.plist key associated with the developer repo object directory
+#define MAC_DEV_OBJ_KEY "MozillaDeveloperObjPath"
+#else
+#include "prenv.h"
+#endif /* XP_MACOSX */
+
namespace mozilla {
bool IsDevelopmentBuild()
{
nsCOMPtr<nsIFile> path = mozilla::Omnijar::GetPath(mozilla::Omnijar::GRE);
// If the path doesn't exist, we're a dev build.
return path == nullptr;
}
+#if defined(XP_MACOSX)
+/*
+ * Helper function to read a string value for a given key from the .app's
+ * Info.plist.
+ */
+static nsresult
+GetStringValueFromBundlePlist(const nsAString& aKey, nsAutoCString& aValue)
+{
+ CFBundleRef mainBundle = CFBundleGetMainBundle();
+
+ // Read this app's bundle Info.plist as a dictionary
+ CFDictionaryRef bundleInfoDict = CFBundleGetInfoDictionary(mainBundle);
+ if (bundleInfoDict == NULL) {
+ return NS_ERROR_FAILURE;
+ }
+
+ nsAutoCString keyAutoCString = NS_ConvertUTF16toUTF8(aKey);
+ CFStringRef key = CFStringCreateWithCString(kCFAllocatorDefault,
+ keyAutoCString.get(),
+ kCFStringEncodingUTF8);
+
+ CFStringRef value = (CFStringRef)CFDictionaryGetValue(bundleInfoDict, key);
+ const char* valueCString = CFStringGetCStringPtr(value,
+ kCFStringEncodingUTF8);
+ aValue.Assign(valueCString);
+ CFRelease(key);
+
+ return NS_OK;
+}
+
+/*
+ * Helper function for reading a path string from the .app's Info.plist
+ * and returning a directory object for that path with symlinks resolved.
+ */
+static nsresult
+GetDirFromBundlePlist(const nsAString& aKey, nsIFile **aDir)
+{
+ nsresult rv;
+
+ nsAutoCString dirPath;
+ rv = GetStringValueFromBundlePlist(aKey, dirPath);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr<nsIFile> dir;
+ rv = NS_NewLocalFile(NS_ConvertUTF8toUTF16(dirPath),
+ false,
+ getter_AddRefs(dir));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = dir->Normalize();
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ bool isDirectory = false;
+ rv = dir->IsDirectory(&isDirectory);
+ NS_ENSURE_SUCCESS(rv, rv);
+ if (!isDirectory) {
+ return NS_ERROR_FILE_NOT_DIRECTORY;
+ }
+
+ dir.swap(*aDir);
+ return NS_OK;
+}
+
+#else /* !XP_MACOSX */
+
+/*
+ * Helper function for getting a directory object for a given env variable
+ */
+static nsresult
+GetDirFromEnv(const char* aEnvVar, nsIFile **aDir)
+{
+ nsresult rv;
+
+ nsCOMPtr<nsIFile> dir;
+ const char *dir_path = PR_GetEnv(aEnvVar);
+ if (!dir_path) {
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ rv = NS_NewLocalFile(NS_ConvertUTF8toUTF16(dir_path),
+ false,
+ getter_AddRefs(dir));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = dir->Normalize();
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ bool isDirectory = false;
+ rv = dir->IsDirectory(&isDirectory);
+ NS_ENSURE_SUCCESS(rv, rv);
+ if (!isDirectory) {
+ return NS_ERROR_FILE_NOT_DIRECTORY;
+ }
+
+ dir.swap(*aDir);
+ return NS_OK;
+}
+#endif /* XP_MACOSX */
+
+nsresult
+GetRepoDir(nsIFile **aRepoDir)
+{
+ MOZ_ASSERT(IsDevelopmentBuild());
+#if defined(XP_MACOSX)
+ return GetDirFromBundlePlist(NS_LITERAL_STRING(MAC_DEV_REPO_KEY), aRepoDir);
+#else
+ return GetDirFromEnv("MOZ_DEVELOPER_REPO_DIR", aRepoDir);
+#endif /* XP_MACOSX */
+}
+
+nsresult
+GetObjDir(nsIFile **aObjDir)
+{
+ MOZ_ASSERT(IsDevelopmentBuild());
+#if defined(XP_MACOSX)
+ return GetDirFromBundlePlist(NS_LITERAL_STRING(MAC_DEV_OBJ_KEY), aObjDir);
+#else
+ return GetDirFromEnv("MOZ_DEVELOPER_OBJ_DIR", aObjDir);
+#endif /* XP_MACOSX */
+}
+
int GetEffectiveContentSandboxLevel() {
int level = Preferences::GetInt("security.sandbox.content.level");
// On Windows and macOS, enforce a minimum content sandbox level of 1 (except on
// Nightly, where it can be set to 0).
#if !defined(NIGHTLY_BUILD) && (defined(XP_WIN) || defined(XP_MACOSX))
if (level < 1) {
level = 1;
}
--- a/security/sandbox/common/SandboxSettings.h
+++ b/security/sandbox/common/SandboxSettings.h
@@ -14,10 +14,15 @@ namespace mozilla {
int GetEffectiveContentSandboxLevel();
// Returns whether or not the currently running build is a development build -
// where development build means "the files in the .app are symlinks to the src
// directory". This check is implemented by looking for omni.ja in
// .app/Contents/Resources/.
bool IsDevelopmentBuild();
+// Return the repo directory and the repo object directory respectively. These
+// should only be used on developer builds to determine the path to the repo
+// or object directory.
+nsresult GetRepoDir(nsIFile **aRepoDir);
+nsresult GetObjDir(nsIFile **aObjDir);
}
#endif // mozilla_SandboxPolicies_h