summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrafaelw@chromium.org <rafaelw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-06-01 22:33:23 +0000
committerrafaelw@chromium.org <rafaelw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-06-01 22:33:23 +0000
commit200dcd387d6902556e41e9439ce64f7f219f5809 (patch)
tree4389542472391337f43240c963ff282f696e8676
parentbc2ff51999fe9ef5c041f2df2ffbbdb4c30baec9 (diff)
downloadchromium_src-200dcd387d6902556e41e9439ce64f7f219f5809.zip
chromium_src-200dcd387d6902556e41e9439ce64f7f219f5809.tar.gz
chromium_src-200dcd387d6902556e41e9439ce64f7f219f5809.tar.bz2
Prevent extensions from clobbering JSON implementation that extension calls use
BUG=38857 TEST=none Review URL: http://codereview.chromium.org/2387002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@48667 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/renderer/resources/event_bindings.js36
-rw-r--r--chrome/renderer/resources/extension_process_bindings.js22
-rw-r--r--chrome/renderer/resources/renderer_extension_bindings.js6
-rw-r--r--chrome/test/data/extensions/api_test/messaging/connect/page.js16
-rw-r--r--chrome/test/data/extensions/api_test/messaging/connect/test.html16
5 files changed, 75 insertions, 21 deletions
diff --git a/chrome/renderer/resources/event_bindings.js b/chrome/renderer/resources/event_bindings.js
index aaea01c..4fa1309 100644
--- a/chrome/renderer/resources/event_bindings.js
+++ b/chrome/renderer/resources/event_bindings.js
@@ -9,6 +9,40 @@ var chrome = chrome || {};
native function DetachEvent(eventName);
var chromeHidden = GetChromeHidden();
+
+ // Local implementation of JSON.parse & JSON.stringify that protect us
+ // from being clobbered by an extension.
+ chromeHidden.JSON = new (function() {
+ const $Object = Object;
+ const $Array = Array;
+ const $jsonStringify = JSON.stringify;
+ const $jsonParse = JSON.parse;
+
+ this.stringify = function(thing) {
+ var customizedObjectToJSON = $Object.prototype.toJSON;
+ var customizedArrayToJSON = $Array.prototype.toJSON;
+ if (customizedObjectToJSON !== undefined) {
+ $Object.prototype.toJSON = null;
+ }
+ if (customizedArrayToJSON !== undefined) {
+ $Array.prototype.toJSON = null;
+ }
+ try {
+ return $jsonStringify(thing);
+ } finally {
+ if (customizedObjectToJSON !== undefined) {
+ $Object.prototype.toJSON = customizedObjectToJSON;
+ }
+ if (customizedArrayToJSON !== undefined) {
+ $Array.prototype.toJSON = customizedArrayToJSON;
+ }
+ }
+ };
+
+ this.parse = function(thing) {
+ return $jsonParse(thing);
+ };
+ })();
// Event object. If opt_eventName is provided, this object represents
// the unique instance of that named event, and dispatching an event
@@ -53,7 +87,7 @@ var chrome = chrome || {};
chromeHidden.Event.dispatchJSON = function(name, args) {
if (attachedNamedEvents[name]) {
if (args) {
- args = JSON.parse(args);
+ args = chromeHidden.JSON.parse(args);
}
return attachedNamedEvents[name].dispatch.apply(
attachedNamedEvents[name], args);
diff --git a/chrome/renderer/resources/extension_process_bindings.js b/chrome/renderer/resources/extension_process_bindings.js
index fe393ba..8955daf 100644
--- a/chrome/renderer/resources/extension_process_bindings.js
+++ b/chrome/renderer/resources/extension_process_bindings.js
@@ -92,7 +92,7 @@ var chrome = chrome || {};
if (request.callback) {
// Callbacks currently only support one callback argument.
- var callbackArgs = response ? [JSON.parse(response)] : [];
+ var callbackArgs = response ? [chromeHidden.JSON.parse(response)] : [];
// Validate callback in debug only -- and only when the
// caller has provided a callback. Implementations of api
@@ -177,20 +177,8 @@ var chrome = chrome || {};
if (request.args === undefined)
request.args = null;
- // Some javascript libraries (e.g. prototype.js version <= 1.6) add a toJSON
- // serializer function on Array.prototype that is incompatible with our
- // native JSON library, causing incorrect deserialization in the C++ side of
- // StartRequest. We work around that here by temporarily removing the toJSON
- // function.
- var arrayToJsonTmp;
- if (Array.prototype.toJSON) {
- arrayToJsonTmp = Array.prototype.toJSON;
- Array.prototype.toJSON = null;
- }
- var sargs = JSON.stringify(request.args);
- if (arrayToJsonTmp) {
- Array.prototype.toJSON = arrayToJsonTmp;
- }
+ var sargs = chromeHidden.JSON.stringify(request.args);
+
var requestId = GetNextRequestId();
requests[requestId] = request;
var hasCallback = (request.callback || customCallback) ? true : false;
@@ -334,7 +322,7 @@ var chrome = chrome || {};
// TODO(rafaelw): Handle synchronous functions.
// TOOD(rafaelw): Consider providing some convenient override points
// for api functions that wish to insert themselves into the call.
- var apiDefinitions = JSON.parse(GetExtensionAPIDefinition());
+ var apiDefinitions = chromeHidden.JSON.parse(GetExtensionAPIDefinition());
apiDefinitions.forEach(function(apiDef) {
var module = chrome;
@@ -609,7 +597,7 @@ var chrome = chrome || {};
// Set up the onclick handler if we were passed one in the request.
if (request.args.onclick) {
- var menuItemId = JSON.parse(response);
+ var menuItemId = chromeHidden.JSON.parse(response);
chromeHidden.contextMenuHandlers[menuItemId] = request.args.onclick;
}
};
diff --git a/chrome/renderer/resources/renderer_extension_bindings.js b/chrome/renderer/resources/renderer_extension_bindings.js
index dc53cd7..1f3220c 100644
--- a/chrome/renderer/resources/renderer_extension_bindings.js
+++ b/chrome/renderer/resources/renderer_extension_bindings.js
@@ -75,7 +75,7 @@ var chrome = chrome || {};
var isExternal = sourceExtensionId != chromeHidden.extensionId;
if (tab)
- tab = JSON.parse(tab);
+ tab = chromeHidden.JSON.parse(tab);
var sender = {tab: tab, id: sourceExtensionId};
// Special case for sendRequest/onRequest.
@@ -119,7 +119,7 @@ var chrome = chrome || {};
var port = ports[portId];
if (port) {
if (msg) {
- msg = JSON.parse(msg);
+ msg = chromeHidden.JSON.parse(msg);
}
port.onMessage.dispatch(msg, port);
}
@@ -131,7 +131,7 @@ var chrome = chrome || {};
// JSON.stringify doesn't support a root object which is undefined.
if (msg === undefined)
msg = null;
- PostMessage(this.portId_, JSON.stringify(msg));
+ PostMessage(this.portId_, chromeHidden.JSON.stringify(msg));
};
// Disconnects the port from the other end.
diff --git a/chrome/test/data/extensions/api_test/messaging/connect/page.js b/chrome/test/data/extensions/api_test/messaging/connect/page.js
index b876f7e..9d45f64 100644
--- a/chrome/test/data/extensions/api_test/messaging/connect/page.js
+++ b/chrome/test/data/extensions/api_test/messaging/connect/page.js
@@ -1,3 +1,19 @@
+JSON.parse = function() {
+ return "JSON.parse clobbered by content script.";
+}
+
+JSON.stringify = function() {
+ return "JSON.stringify clobbered by content script.";
+}
+
+Array.prototype.toJSON = function() {
+ return "Array.prototype.toJSON clobbered by content script.";
+}
+
+Object.prototype.toJSON = function() {
+ return "Object.prototype.toJSON clobbered by content script.";
+}
+
// For complex connect tests.
chrome.extension.onConnect.addListener(function(port) {
console.log('connected');
diff --git a/chrome/test/data/extensions/api_test/messaging/connect/test.html b/chrome/test/data/extensions/api_test/messaging/connect/test.html
index 3e24916..4983a75 100644
--- a/chrome/test/data/extensions/api_test/messaging/connect/test.html
+++ b/chrome/test/data/extensions/api_test/messaging/connect/test.html
@@ -1,4 +1,20 @@
<script>
+JSON.parse = function() {
+ return "JSON.parse clobbered by extension.";
+}
+
+JSON.stringify = function() {
+ return "JSON.stringify clobbered by extension.";
+}
+
+Array.prototype.toJSON = function() {
+ return "Array.prototype.toJSON clobbered by extension.";
+}
+
+Object.prototype.toJSON = function() {
+ return "Object.prototype.toJSON clobbered by extension.";
+}
+
// Keep track of the tab that we're running tests in, for simplicity.
var testTab = null;