зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1215167 - Forbid unsafe browser CPOWs (disabled by default for now) (r=mrbkap)
This commit is contained in:
Родитель
e3f3d60e8c
Коммит
ac2ca63fc1
|
@ -20,6 +20,7 @@ var Cu = Components.utils;
|
|||
lifetime_test,
|
||||
cancel_test,
|
||||
cancel_test2,
|
||||
unsafe_test,
|
||||
];
|
||||
|
||||
function go() {
|
||||
|
@ -337,3 +338,20 @@ function cancel_test2(finish)
|
|||
if (fin1 && fin2) finish();
|
||||
});
|
||||
}
|
||||
|
||||
function unsafe_test(finish)
|
||||
{
|
||||
if (!is_remote) {
|
||||
// Only run this test when running out-of-process.
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
function f() {}
|
||||
|
||||
sendAsyncMessage("cpows:unsafe", null, {f});
|
||||
addMessageListener("cpows:unsafe_done", msg => {
|
||||
sendRpcMessage("cpows:safe", null, {f});
|
||||
addMessageListener("cpows:safe_done", finish);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -390,6 +390,33 @@
|
|||
msg.target.messageManager.sendAsyncMessage("cpows:cancel_test2_done");
|
||||
}
|
||||
|
||||
function recvUnsafe(msg) {
|
||||
let failed = false;
|
||||
|
||||
const PREF_UNSAFE_FORBIDDEN = "dom.ipc.cpows.forbid-unsafe-from-browser";
|
||||
opener.wrappedJSObject.SpecialPowers.setBoolPref(PREF_UNSAFE_FORBIDDEN, true);
|
||||
try {
|
||||
msg.objects.f();
|
||||
} catch (e if /unsafe CPOW usage forbidden/.test(String(e))) {
|
||||
failed = true;
|
||||
}
|
||||
opener.wrappedJSObject.SpecialPowers.clearUserPref(PREF_UNSAFE_FORBIDDEN);
|
||||
ok(failed, "CPOW should fail when unsafe");
|
||||
msg.target.messageManager.sendAsyncMessage("cpows:unsafe_done");
|
||||
}
|
||||
|
||||
function recvSafe(msg) {
|
||||
const PREF_UNSAFE_FORBIDDEN = "dom.ipc.cpows.forbid-unsafe-from-browser";
|
||||
opener.wrappedJSObject.SpecialPowers.setBoolPref(PREF_UNSAFE_FORBIDDEN, true);
|
||||
try {
|
||||
msg.objects.f();
|
||||
} catch (e if /unsafe CPOW usage forbidden/.test(String(e))) {
|
||||
ok(false, "cpow failed");
|
||||
}
|
||||
opener.wrappedJSObject.SpecialPowers.clearUserPref(PREF_UNSAFE_FORBIDDEN);
|
||||
msg.target.messageManager.sendAsyncMessage("cpows:safe_done");
|
||||
}
|
||||
|
||||
function run_tests(type) {
|
||||
info("Running tests: " + type);
|
||||
var node = document.getElementById('cpowbrowser_' + type);
|
||||
|
@ -429,6 +456,8 @@
|
|||
mm.addMessageListener("cpows:cancel_test", recvCancelTest);
|
||||
mm.addMessageListener("cpows:cancel_sync_message", recvCancelSyncMessage);
|
||||
mm.addMessageListener("cpows:cancel_test2", recvCancelTest2);
|
||||
mm.addMessageListener("cpows:unsafe", recvUnsafe);
|
||||
mm.addMessageListener("cpows:safe", recvSafe);
|
||||
mm.loadFrameScript("chrome://mochitests/content/chrome/dom/base/test/chrome/cpows_child.js", true);
|
||||
}
|
||||
|
||||
|
|
|
@ -1894,28 +1894,6 @@ ContentParent::OnChannelError()
|
|||
PContentParent::OnChannelError();
|
||||
}
|
||||
|
||||
void
|
||||
ContentParent::OnBeginSyncTransaction() {
|
||||
if (XRE_IsParentProcess()) {
|
||||
nsCOMPtr<nsIConsoleService> console(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
|
||||
JSContext *cx = nsContentUtils::GetCurrentJSContext();
|
||||
if (!sDisableUnsafeCPOWWarnings) {
|
||||
if (console && cx) {
|
||||
nsAutoString filename;
|
||||
uint32_t lineno = 0, column = 0;
|
||||
nsJSUtils::GetCallingLocation(cx, filename, &lineno, &column);
|
||||
nsCOMPtr<nsIScriptError> error(do_CreateInstance(NS_SCRIPTERROR_CONTRACTID));
|
||||
error->Init(NS_LITERAL_STRING("unsafe CPOW usage"), filename,
|
||||
EmptyString(), lineno, column,
|
||||
nsIScriptError::warningFlag, "chrome javascript");
|
||||
console->LogMessage(error);
|
||||
} else {
|
||||
NS_WARNING("Unsafe synchronous IPC message");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ContentParent::OnChannelConnected(int32_t pid)
|
||||
{
|
||||
|
|
|
@ -325,8 +325,6 @@ public:
|
|||
|
||||
virtual void OnChannelError() override;
|
||||
|
||||
virtual void OnBeginSyncTransaction() override;
|
||||
|
||||
virtual PCrashReporterParent*
|
||||
AllocPCrashReporterParent(const NativeThreadId& tid,
|
||||
const uint32_t& processType) override;
|
||||
|
|
|
@ -848,9 +848,6 @@ MessageChannel::Send(Message* aMsg, Message* aReply)
|
|||
AssertWorkerThread();
|
||||
mMonitor->AssertNotCurrentThreadOwns();
|
||||
|
||||
if (mCurrentTransaction == 0)
|
||||
mListener->OnBeginSyncTransaction();
|
||||
|
||||
#ifdef OS_WIN
|
||||
SyncStackFrame frame(this, false);
|
||||
NeuteredWindowRegion neuteredRgn(mFlags & REQUIRE_DEFERRED_MESSAGE_PROTECTION);
|
||||
|
|
|
@ -143,6 +143,7 @@ class MessageChannel : HasResultCodes
|
|||
return !mCxxStackFrames.empty();
|
||||
}
|
||||
|
||||
bool IsInTransaction() const { return mCurrentTransaction != 0; }
|
||||
void CancelCurrentTransaction();
|
||||
|
||||
/**
|
||||
|
|
|
@ -88,10 +88,6 @@ class MessageListener
|
|||
virtual void OnExitedCall() {
|
||||
NS_RUNTIMEABORT("default impl shouldn't be invoked");
|
||||
}
|
||||
/* This callback is called when a sync message is sent that begins a new IPC transaction
|
||||
(i.e., when it is not part of an existing sequence of nested messages). */
|
||||
virtual void OnBeginSyncTransaction() {
|
||||
}
|
||||
virtual RacyInterruptPolicy MediateInterruptRace(const Message& parent,
|
||||
const Message& child)
|
||||
{
|
||||
|
|
|
@ -25,6 +25,8 @@ class JavaScriptChild : public JavaScriptBase<PJavaScriptChild>
|
|||
|
||||
void drop(JSObject* obj);
|
||||
|
||||
bool allowMessage(JSContext* cx) override { return true; }
|
||||
|
||||
protected:
|
||||
virtual bool isParent() override { return false; }
|
||||
virtual JSObject* scopeForTargetObjects() override;
|
||||
|
|
|
@ -48,6 +48,54 @@ JavaScriptParent::init()
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
ForbidUnsafeBrowserCPOWs()
|
||||
{
|
||||
static bool result;
|
||||
static bool cached = false;
|
||||
if (!cached) {
|
||||
cached = true;
|
||||
Preferences::AddBoolVarCache(&result, "dom.ipc.cpows.forbid-unsafe-from-browser", false);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
JavaScriptParent::allowMessage(JSContext* cx)
|
||||
{
|
||||
MessageChannel* channel = GetIPCChannel();
|
||||
if (channel->IsInTransaction())
|
||||
return true;
|
||||
|
||||
if (ForbidUnsafeBrowserCPOWs()) {
|
||||
if (JSObject* global = JS::CurrentGlobalOrNull(cx)) {
|
||||
if (!JS::AddonIdOfObject(global)) {
|
||||
JS_ReportError(cx, "unsafe CPOW usage forbidden");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool disableUnsafeCPOWWarnings = PR_GetEnv("DISABLE_UNSAFE_CPOW_WARNINGS");
|
||||
if (!disableUnsafeCPOWWarnings) {
|
||||
nsCOMPtr<nsIConsoleService> console(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
|
||||
if (console && cx) {
|
||||
nsAutoString filename;
|
||||
uint32_t lineno = 0, column = 0;
|
||||
nsJSUtils::GetCallingLocation(cx, filename, &lineno, &column);
|
||||
nsCOMPtr<nsIScriptError> error(do_CreateInstance(NS_SCRIPTERROR_CONTRACTID));
|
||||
error->Init(NS_LITERAL_STRING("unsafe CPOW usage"), filename,
|
||||
EmptyString(), lineno, column,
|
||||
nsIScriptError::warningFlag, "chrome javascript");
|
||||
console->LogMessage(error);
|
||||
} else {
|
||||
NS_WARNING("Unsafe synchronous IPC message");
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
JavaScriptParent::trace(JSTracer* trc)
|
||||
{
|
||||
|
|
|
@ -25,6 +25,8 @@ class JavaScriptParent : public JavaScriptBase<PJavaScriptParent>
|
|||
|
||||
void drop(JSObject* obj);
|
||||
|
||||
bool allowMessage(JSContext* cx) override;
|
||||
|
||||
mozilla::ipc::IProtocol*
|
||||
CloneProtocol(Channel* aChannel, ProtocolCloneContext* aCtx) override;
|
||||
|
||||
|
|
|
@ -150,6 +150,9 @@ const CPOWProxyHandler CPOWProxyHandler::singleton;
|
|||
JS_ReportError(cx, "cannot use a CPOW whose process is gone"); \
|
||||
return false; \
|
||||
} \
|
||||
if (!owner->allowMessage(cx)) { \
|
||||
return false; \
|
||||
} \
|
||||
{ \
|
||||
CPOWTimer timer(cx); \
|
||||
return owner->call args; \
|
||||
|
|
|
@ -74,6 +74,8 @@ class WrapperOwner : public virtual JavaScriptShared
|
|||
|
||||
bool active() { return !inactive_; }
|
||||
|
||||
virtual bool allowMessage(JSContext* cx) = 0;
|
||||
|
||||
void drop(JSObject* obj);
|
||||
void updatePointer(JSObject* obj, const JSObject* old);
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче