--- a/extensions/pref/autoconfig/src/nsAutoConfig.cpp
+++ b/extensions/pref/autoconfig/src/nsAutoConfig.cpp
@@ -1,15 +1,17 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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/. */
#include "mozilla/ResultExtensions.h"
#include "nsAutoConfig.h"
+#include "nsJSConfigTriggers.h"
+
#include "nsIURI.h"
#include "nsIHttpChannel.h"
#include "nsIFileStreams.h"
#include "nsThreadUtils.h"
#include "nsAppDirectoryServiceDefs.h"
#include "nsIObserverService.h"
#include "nsLiteralString.h"
#include "nsIPromptService.h"
@@ -24,22 +26,16 @@
#include "mozilla/IntegerPrintfMacros.h"
#include "mozilla/Logging.h"
using mozilla::LogLevel;
mozilla::LazyLogModule MCD("MCD");
-extern nsresult EvaluateAdminConfigScript(const char *js_buffer, size_t length,
- const char *filename,
- bool bGlobalContext,
- bool bCallbacks,
- bool skipFirstLine);
-
// nsISupports Implementation
NS_IMPL_ISUPPORTS(nsAutoConfig, nsIAutoConfig, nsITimerCallback, nsIStreamListener,
nsIObserver, nsIRequestObserver, nsISupportsWeakReference,
nsINamed)
nsAutoConfig::nsAutoConfig()
{
@@ -144,17 +140,17 @@ nsAutoConfig::OnStopRequest(nsIRequest *
MOZ_LOG(MCD, LogLevel::Debug, ("mcd http request failed with status %x\n", httpStatus));
return readOfflineFile();
}
}
// Send the autoconfig.jsc to javascript engine.
rv = EvaluateAdminConfigScript(mBuf.get(), mBuf.Length(),
- nullptr, false,true, false);
+ nullptr, false, true, false);
if (NS_SUCCEEDED(rv)) {
// Write the autoconfig.jsc to failover.jsc (cached copy)
rv = writeFailoverFile();
if (NS_FAILED(rv))
NS_WARNING("Error writing failover.jsc file");
--- a/extensions/pref/autoconfig/src/nsJSConfigTriggers.cpp
+++ b/extensions/pref/autoconfig/src/nsJSConfigTriggers.cpp
@@ -1,45 +1,53 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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/. */
+#include "nsJSConfigTriggers.h"
+
#include "jsapi.h"
#include "nsIXPConnect.h"
#include "nsCOMPtr.h"
#include "nsIServiceManager.h"
#include "nsIComponentManager.h"
#include "nsString.h"
+#include "nsIPrefBranch.h"
#include "nsIPrefService.h"
#include "nspr.h"
#include "mozilla/Attributes.h"
#include "mozilla/Maybe.h"
#include "nsContentUtils.h"
#include "nsIScriptSecurityManager.h"
#include "nsJSPrincipals.h"
#include "nsIScriptError.h"
#include "js/Wrapper.h"
+#include "NullPrincipal.h"
extern mozilla::LazyLogModule MCD;
using mozilla::AutoSafeJSContext;
using mozilla::dom::AutoJSAPI;
//*****************************************************************************
+static JS::PersistentRooted<JSObject *> autoconfigSystemSb;
static JS::PersistentRooted<JSObject *> autoconfigSb;
+static bool sandboxEnabled;
-nsresult CentralizedAdminPrefManagerInit()
+nsresult CentralizedAdminPrefManagerInit(bool aSandboxEnabled)
{
nsresult rv;
// If the sandbox is already created, no need to create it again.
if (autoconfigSb.initialized())
return NS_OK;
+ sandboxEnabled = aSandboxEnabled || !strcmp(NS_STRINGIFY(MOZ_UPDATE_CHANNEL), "release");
+
// Grab XPConnect.
nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID(), &rv);
if (NS_FAILED(rv)) {
return rv;
}
// Grab the system principal.
nsCOMPtr<nsIPrincipal> principal;
@@ -49,34 +57,69 @@ nsresult CentralizedAdminPrefManagerInit
// Create a sandbox.
AutoSafeJSContext cx;
JS::Rooted<JSObject*> sandbox(cx);
rv = xpc->CreateSandbox(cx, principal, sandbox.address());
NS_ENSURE_SUCCESS(rv, rv);
// Unwrap, store and root the sandbox.
NS_ENSURE_STATE(sandbox);
+ autoconfigSystemSb.init(cx, js::UncheckedUnwrap(sandbox));
+
+
+ // Create an unprivileged sandbox.
+ principal = NullPrincipal::CreateWithoutOriginAttributes();
+ rv = xpc->CreateSandbox(cx, principal, sandbox.address());
+ NS_ENSURE_SUCCESS(rv, rv);
+
autoconfigSb.init(cx, js::UncheckedUnwrap(sandbox));
+
+ // Define gSandbox on system sandbox.
+ JSAutoRealm ac(cx, autoconfigSystemSb);
+
+ JS::Rooted<JS::Value> value(cx, JS::ObjectValue(*sandbox));
+
+ if (!JS_WrapValue(cx, &value) ||
+ !JS_DefineProperty(cx, autoconfigSystemSb, "gSandbox", value, JSPROP_ENUMERATE)) {
+ return NS_ERROR_FAILURE;
+ }
+
return NS_OK;
}
nsresult CentralizedAdminPrefManagerFinish()
{
if (autoconfigSb.initialized()) {
AutoSafeJSContext cx;
autoconfigSb.reset();
+ autoconfigSystemSb.reset();
JS_MaybeGC(cx);
}
return NS_OK;
}
nsresult EvaluateAdminConfigScript(const char *js_buffer, size_t length,
- const char *filename, bool bGlobalContext,
- bool bCallbacks, bool skipFirstLine)
+ const char *filename, bool globalContext,
+ bool callbacks, bool skipFirstLine,
+ bool isPrivileged)
+{
+ if (!sandboxEnabled) {
+ isPrivileged = true;
+ }
+ return EvaluateAdminConfigScript(isPrivileged ? autoconfigSystemSb : autoconfigSb,
+ js_buffer, length, filename,
+ globalContext, callbacks, skipFirstLine);
+
+}
+
+nsresult EvaluateAdminConfigScript(JS::HandleObject sandbox,
+ const char *js_buffer, size_t length,
+ const char *filename, bool globalContext,
+ bool callbacks, bool skipFirstLine)
{
nsresult rv = NS_OK;
if (skipFirstLine) {
/* In order to protect the privacy of the JavaScript preferences file
* from loading by the browser, we make the first line unparseable
* by JavaScript. We must skip that line here before executing
* the JavaScript code.
@@ -99,17 +142,17 @@ nsresult EvaluateAdminConfigScript(const
// Grab XPConnect.
nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID(), &rv);
if (NS_FAILED(rv)) {
return rv;
}
AutoJSAPI jsapi;
- if (!jsapi.Init(autoconfigSb)) {
+ if (!jsapi.Init(sandbox)) {
return NS_ERROR_UNEXPECTED;
}
JSContext* cx = jsapi.cx();
nsAutoCString script(js_buffer, length);
JS::RootedValue v(cx);
nsString convertedScript;
@@ -120,19 +163,22 @@ nsresult EvaluateAdminConfigScript(const
nsContentUtils::ReportToConsoleNonLocalized(
NS_LITERAL_STRING("Your AutoConfig file is ASCII. Please convert it to UTF-8."),
nsIScriptError::warningFlag,
NS_LITERAL_CSTRING("autoconfig"),
nullptr);
/* If the length is 0, the conversion failed. Fallback to ASCII */
convertedScript = NS_ConvertASCIItoUTF16(script);
}
- JS::Rooted<JS::Value> value(cx, JS::BooleanValue(isUTF8));
- if (!JS_DefineProperty(cx, autoconfigSb, "gIsUTF8", value, JSPROP_ENUMERATE)) {
- return NS_ERROR_UNEXPECTED;
+ {
+ JSAutoRealm ac(cx, autoconfigSystemSb);
+ JS::Rooted<JS::Value> value(cx, JS::BooleanValue(isUTF8));
+ if (!JS_DefineProperty(cx, autoconfigSystemSb, "gIsUTF8", value, JSPROP_ENUMERATE)) {
+ return NS_ERROR_UNEXPECTED;
+ }
}
rv = xpc->EvalInSandboxObject(convertedScript, filename, cx,
- autoconfigSb, &v);
+ sandbox, &v);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
new file mode 100644
--- /dev/null
+++ b/extensions/pref/autoconfig/src/nsJSConfigTriggers.h
@@ -0,0 +1,21 @@
+#ifndef nsConfigTriggers_h
+#define nsConfigTriggers_h
+
+#include "nscore.h"
+#include "js/TypeDecls.h"
+
+nsresult EvaluateAdminConfigScript(const char *js_buffer, size_t length,
+ const char *filename,
+ bool bGlobalContext,
+ bool bCallbacks,
+ bool skipFirstLine,
+ bool isPrivileged = false);
+
+nsresult EvaluateAdminConfigScript(JS::HandleObject sandbox,
+ const char *js_buffer, size_t length,
+ const char *filename,
+ bool bGlobalContext,
+ bool bCallbacks,
+ bool skipFirstLine);
+
+#endif // nsConfigTriggers_h
--- a/extensions/pref/autoconfig/src/nsReadConfig.cpp
+++ b/extensions/pref/autoconfig/src/nsReadConfig.cpp
@@ -1,14 +1,16 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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/. */
#include "nsReadConfig.h"
+#include "nsJSConfigTriggers.h"
+
#include "nsAppDirectoryServiceDefs.h"
#include "nsIAppStartup.h"
#include "nsDirectoryServiceDefs.h"
#include "nsIAutoConfig.h"
#include "nsIComponentManager.h"
#include "nsIFile.h"
#include "nsIObserverService.h"
#include "nsIPrefBranch.h"
@@ -21,25 +23,19 @@
#include "nsString.h"
#include "nsCRT.h"
#include "nspr.h"
#include "nsXULAppAPI.h"
#include "nsContentUtils.h"
extern mozilla::LazyLogModule MCD;
-extern nsresult EvaluateAdminConfigScript(const char *js_buffer, size_t length,
- const char *filename,
- bool bGlobalContext,
- bool bCallbacks,
- bool skipFirstLine);
-extern nsresult CentralizedAdminPrefManagerInit();
+extern nsresult CentralizedAdminPrefManagerInit(bool aSandboxEnabled);
extern nsresult CentralizedAdminPrefManagerFinish();
-
static nsresult DisplayError(void)
{
nsresult rv;
nsCOMPtr<nsIPromptService> promptService = do_GetService("@mozilla.org/embedcomp/prompt-service;1");
if (!promptService)
return NS_ERROR_FAILURE;
@@ -94,17 +90,18 @@ nsReadConfig::~nsReadConfig()
}
NS_IMETHODIMP nsReadConfig::Observe(nsISupports *aSubject, const char *aTopic, const char16_t *someData)
{
nsresult rv = NS_OK;
if (!nsCRT::strcmp(aTopic, NS_PREFSERVICE_READ_TOPIC_ID)) {
rv = readConfigFile();
- if (NS_FAILED(rv)) {
+ // Don't show error alerts if the sandbox is enabled
+ if (NS_FAILED(rv) && !sandboxEnabled) {
rv = DisplayError();
if (NS_FAILED(rv)) {
nsCOMPtr<nsIAppStartup> appStartup =
do_GetService(NS_APPSTARTUP_CONTRACTID);
if (appStartup)
appStartup->Quit(nsIAppStartup::eAttemptQuit);
}
}
@@ -134,16 +131,20 @@ nsresult nsReadConfig::readConfigFile()
rv = prefService->GetDefaultBranch(nullptr, getter_AddRefs(defaultPrefBranch));
if (NS_FAILED(rv))
return rv;
// This preference is set in the all.js or all-ns.js (depending whether
// running mozilla or netscp6)
+ bool sandboxEnabled = false;
+ rv = defaultPrefBranch->GetBoolPref("general.config.sandbox_enabled",
+ &sandboxEnabled);
+
rv = defaultPrefBranch->GetCharPref("general.config.filename",
lockFileName);
MOZ_LOG(MCD, LogLevel::Debug, ("general.config.filename = %s\n", lockFileName.get()));
if (NS_FAILED(rv))
return rv;
for (size_t index = 0, len = mozilla::ArrayLength(gBlockedConfigs); index < len;
@@ -154,17 +155,17 @@ nsresult nsReadConfig::readConfigFile()
}
}
// This needs to be read only once.
//
if (!mRead) {
// Initiate the new JS Context for Preference management
- rv = CentralizedAdminPrefManagerInit();
+ rv = CentralizedAdminPrefManagerInit(sandboxEnabled);
if (NS_FAILED(rv))
return rv;
// Open and evaluate function calls to set/lock/unlock prefs
rv = openAndEvaluateJSFile("prefcalls.js", 0, false, false);
if (NS_FAILED(rv))
return rv;
@@ -296,15 +297,16 @@ nsresult nsReadConfig::openAndEvaluateJS
if (obscureValue > 0) {
// Unobscure file by subtracting some value from every char.
for (uint32_t i = 0; i < amt; i++)
buf[i] -= obscureValue;
}
rv = EvaluateAdminConfigScript(buf, amt, aFileName,
false, true,
- isEncoded ? true:false);
+ isEncoded,
+ !isBinDir);
}
inStr->Close();
free(buf);
return rv;
}
--- a/extensions/pref/autoconfig/src/prefcalls.js
+++ b/extensions/pref/autoconfig/src/prefcalls.js
@@ -1,14 +1,16 @@
/* global processLDAPValues */
/* -*- tab-width: 4; indent-tabs-mode: nil; js-indent-level: 4 -*-
* 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/. */
+/* globals gSandbox */
+
const nsILDAPURL = Ci.nsILDAPURL;
const LDAPURLContractID = "@mozilla.org/network/ldap-url;1";
const nsILDAPSyncQuery = Ci.nsILDAPSyncQuery;
const LDAPSyncQueryContractID = "@mozilla.org/ldapsyncquery;1";
const nsIPrefService = Ci.nsIPrefService;
const PrefServiceContractID = "@mozilla.org/preferences-service;1";
// ChromeUtils isn't available here, so we can't use Services.*
@@ -204,8 +206,30 @@ function getenv(name) {
var environment = Cc["@mozilla.org/process/environment;1"].
getService(Ci.nsIEnvironment);
return environment.get(name);
} catch (e) {
displayError("getEnvironment", e);
}
return undefined;
}
+
+var APIs = {
+ pref,
+ defaultPref,
+ lockPref,
+ unlockPref,
+ getPref,
+ clearPref,
+ setLDAPVersion,
+ getLDAPAttributes,
+ getLDAPValue,
+ displayError,
+ getenv,
+};
+
+for (let [defineAs, func] of Object.entries(APIs)) {
+ Cu.exportFunction(func, gSandbox, {defineAs});
+}
+
+Object.defineProperty(Cu.waiveXrays(gSandbox), "gIsUTF8", {
+ get: Cu.exportFunction(() => gIsUTF8, gSandbox),
+});
new file mode 100644
--- /dev/null
+++ b/extensions/pref/autoconfig/test/unit/autoconfig-chromecheck.cfg
@@ -0,0 +1,3 @@
+// # don't remove this comment! (the first line is ignored by Mozilla)
+
+lockPref("_test.string.typeofComponents", typeof Components);
--- a/extensions/pref/autoconfig/test/unit/autoconfig.js
+++ b/extensions/pref/autoconfig/test/unit/autoconfig.js
@@ -1,5 +1,6 @@
/* global pref */
+pref("general.config.sandbox_enabled", true);
pref("general.config.filename", "autoconfig.cfg");
pref("general.config.vendor", "autoconfig");
pref("general.config.obscure_value", 0);
--- a/extensions/pref/autoconfig/test/unit/test_autoconfig_nonascii.js
+++ b/extensions/pref/autoconfig/test/unit/test_autoconfig_nonascii.js
@@ -32,16 +32,21 @@ function run_test() {
}, {
filename: "autoconfig-latin1.cfg",
prefs: {
"_test.string.ASCII": "ASCII",
"_test.string.non-ASCII": "日本語",
"_test.string.getPref": "日本語",
"_test.string.gIsUTF8": "false",
}
+ }, {
+ filename: "autoconfig-chromecheck.cfg",
+ prefs: {
+ "_test.string.typeofComponents": "undefined",
+ }
}];
function testAutoConfig(test) {
// Make sure pref values are unset.
for (let prefName in test.prefs) {
Assert.equal(Ci.nsIPrefBranch.PREF_INVALID, Services.prefs.getPrefType(prefName));
}
--- a/extensions/pref/autoconfig/test/unit/xpcshell.ini
+++ b/extensions/pref/autoconfig/test/unit/xpcshell.ini
@@ -1,11 +1,12 @@
[DEFAULT]
head =
skip-if = toolkit == 'android'
support-files =
autoconfig-all.cfg
autoconfig-latin1.cfg
autoconfig-utf8.cfg
+ autoconfig-chromecheck.cfg
autoconfig.js
[test_autoconfig.js]
[test_autoconfig_nonascii.js]