nsJSConfigTriggers.cpp (5362B)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 #include "nsJSConfigTriggers.h" 7 8 #include "jsapi.h" 9 #include "nsIXPConnect.h" 10 #include "nsCOMPtr.h" 11 #include "nsString.h" 12 #include "nspr.h" 13 #include "mozilla/Attributes.h" 14 #include "mozilla/NullPrincipal.h" 15 #include "mozilla/dom/ScriptSettings.h" 16 #include "mozilla/dom/ChromeUtilsBinding.h" 17 #include "nsContentUtils.h" 18 #include "nsJSPrincipals.h" 19 #include "nsIScriptError.h" 20 #include "js/PropertyAndElement.h" // JS_DefineProperty 21 #include "js/Wrapper.h" 22 #include "mozilla/Utf8.h" 23 24 extern mozilla::LazyLogModule MCD; 25 using mozilla::AutoSafeJSContext; 26 using mozilla::IsUtf8; 27 using mozilla::NullPrincipal; 28 using mozilla::dom::AutoJSAPI; 29 30 //***************************************************************************** 31 32 MOZ_RUNINIT static JS::PersistentRooted<JSObject*> autoconfigSystemSb; 33 MOZ_RUNINIT static JS::PersistentRooted<JSObject*> autoconfigSb; 34 bool sandboxEnabled; 35 36 nsresult CentralizedAdminPrefManagerInit(bool aSandboxEnabled) { 37 // If the sandbox is already created, no need to create it again. 38 if (autoconfigSb.initialized()) return NS_OK; 39 40 sandboxEnabled = aSandboxEnabled; 41 42 // Grab XPConnect. 43 nsCOMPtr<nsIXPConnect> xpc = nsIXPConnect::XPConnect(); 44 45 // Grab the system principal. 46 nsCOMPtr<nsIPrincipal> principal; 47 nsContentUtils::GetSecurityManager()->GetSystemPrincipal( 48 getter_AddRefs(principal)); 49 50 // Create a sandbox. 51 AutoSafeJSContext cx; 52 JS::Rooted<JSObject*> sandbox(cx); 53 nsresult rv = xpc->CreateSandbox(cx, principal, sandbox.address()); 54 NS_ENSURE_SUCCESS(rv, rv); 55 56 // Unwrap, store and root the sandbox. 57 NS_ENSURE_STATE(sandbox); 58 autoconfigSystemSb.init(cx, js::UncheckedUnwrap(sandbox)); 59 60 // Create an unprivileged sandbox. 61 principal = NullPrincipal::CreateWithoutOriginAttributes(); 62 rv = xpc->CreateSandbox(cx, principal, sandbox.address()); 63 NS_ENSURE_SUCCESS(rv, rv); 64 65 autoconfigSb.init(cx, js::UncheckedUnwrap(sandbox)); 66 67 // Define gSandbox on system sandbox. 68 JSAutoRealm ar(cx, autoconfigSystemSb); 69 70 JS::Rooted<JS::Value> value(cx, JS::ObjectValue(*sandbox)); 71 72 if (!JS_WrapValue(cx, &value) || 73 !JS_DefineProperty(cx, autoconfigSystemSb, "gSandbox", value, 74 JSPROP_ENUMERATE)) { 75 return NS_ERROR_FAILURE; 76 } 77 78 // Define ChromeUtils for ChromeUtils.import. 79 if (!mozilla::dom::ChromeUtils_Binding::CreateAndDefineOnGlobal(cx)) { 80 return NS_ERROR_FAILURE; 81 } 82 83 return NS_OK; 84 } 85 86 nsresult CentralizedAdminPrefManagerFinish() { 87 if (autoconfigSb.initialized()) { 88 AutoSafeJSContext cx; 89 autoconfigSb.reset(); 90 autoconfigSystemSb.reset(); 91 JS_MaybeGC(cx); 92 } 93 return NS_OK; 94 } 95 96 nsresult EvaluateAdminConfigScript(const char* js_buffer, size_t length, 97 const char* filename, bool globalContext, 98 bool callbacks, bool skipFirstLine, 99 bool isPrivileged) { 100 if (!sandboxEnabled) { 101 isPrivileged = true; 102 } 103 return EvaluateAdminConfigScript( 104 isPrivileged ? autoconfigSystemSb : autoconfigSb, js_buffer, length, 105 filename, globalContext, callbacks, skipFirstLine); 106 } 107 108 nsresult EvaluateAdminConfigScript(JS::Handle<JSObject*> sandbox, 109 const char* js_buffer, size_t length, 110 const char* filename, bool globalContext, 111 bool callbacks, bool skipFirstLine) { 112 if (skipFirstLine) { 113 /* In order to protect the privacy of the JavaScript preferences file 114 * from loading by the browser, we make the first line unparseable 115 * by JavaScript. We must skip that line here before executing 116 * the JavaScript code. 117 */ 118 unsigned int i = 0; 119 while (i < length) { 120 char c = js_buffer[i++]; 121 if (c == '\r') { 122 if (js_buffer[i] == '\n') i++; 123 break; 124 } 125 if (c == '\n') break; 126 } 127 128 length -= i; 129 js_buffer += i; 130 } 131 132 // Grab XPConnect. 133 nsCOMPtr<nsIXPConnect> xpc = nsIXPConnect::XPConnect(); 134 135 AutoJSAPI jsapi; 136 if (!jsapi.Init(sandbox)) { 137 return NS_ERROR_UNEXPECTED; 138 } 139 JSContext* cx = jsapi.cx(); 140 141 nsAutoCString script(js_buffer, length); 142 JS::Rooted<JS::Value> v(cx); 143 144 nsString convertedScript; 145 bool isUTF8 = IsUtf8(script); 146 if (isUTF8) { 147 CopyUTF8toUTF16(script, convertedScript); 148 } else { 149 nsContentUtils::ReportToConsoleNonLocalized( 150 nsLiteralString( 151 u"Your AutoConfig file is ASCII. Please convert it to UTF-8."), 152 nsIScriptError::warningFlag, "autoconfig"_ns, nullptr); 153 /* If the length is 0, the conversion failed. Fallback to ASCII */ 154 convertedScript = NS_ConvertASCIItoUTF16(script); 155 } 156 { 157 JSAutoRealm ar(cx, autoconfigSystemSb); 158 JS::Rooted<JS::Value> value(cx, JS::BooleanValue(isUTF8)); 159 if (!JS_DefineProperty(cx, autoconfigSystemSb, "gIsUTF8", value, 160 JSPROP_ENUMERATE)) { 161 return NS_ERROR_UNEXPECTED; 162 } 163 } 164 nsresult rv = 165 xpc->EvalInSandboxObject(convertedScript, filename, cx, sandbox, &v); 166 NS_ENSURE_SUCCESS(rv, rv); 167 168 return NS_OK; 169 }