Bug 441359: Check script and css loads against the classifier. r+sr=jonas

This commit is contained in:
Dave Camp 2009-01-13 23:13:48 -08:00
Родитель 2cfdc4867d
Коммит 1e04293c7f
14 изменённых файлов: 287 добавлений и 13 удалений

Просмотреть файл

@ -149,3 +149,8 @@ https://sectest1.example.org:443 privileged
https://sub.sectest2.example.org:443 privileged
https://sectest2.example.org:443
https://sub.sectest1.example.org:443
#
# Used while testing the url-classifier
#
http://malware.com:80

Просмотреть файл

@ -1753,7 +1753,7 @@ nsObjectLoadingContent::CheckClassifier(nsIChannel *aChannel)
do_CreateInstance(NS_CHANNELCLASSIFIER_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = classifier->Start(aChannel);
rv = classifier->Start(aChannel, PR_FALSE);
if (rv == NS_ERROR_FACTORY_NOT_REGISTERED) {
// no URI classifier, ignore this
return NS_OK;

Просмотреть файл

@ -68,6 +68,8 @@
#include "nsContentErrors.h"
#include "nsIParser.h"
#include "nsThreadUtils.h"
#include "nsIChannelClassifier.h"
#include "nsDocShellCID.h"
//////////////////////////////////////////////////////////////
// Per-request data structure
@ -266,7 +268,21 @@ nsScriptLoader::StartLoad(nsScriptLoadRequest *aRequest, const nsAString &aType)
rv = NS_NewStreamLoader(getter_AddRefs(loader), this);
NS_ENSURE_SUCCESS(rv, rv);
return channel->AsyncOpen(loader, aRequest);
rv = channel->AsyncOpen(loader, aRequest);
NS_ENSURE_SUCCESS(rv, rv);
// Check the load against the URI classifier
nsCOMPtr<nsIChannelClassifier> classifier =
do_CreateInstance(NS_CHANNELCLASSIFIER_CONTRACTID);
if (classifier) {
rv = classifier->Start(channel, PR_TRUE);
if (NS_FAILED(rv)) {
channel->Cancel(rv);
return rv;
}
}
return NS_OK;
}
PRBool

Просмотреть файл

@ -7797,7 +7797,7 @@ nsDocShell::CheckClassifier(nsIChannel *aChannel)
nsRefPtr<nsClassifierCallback> classifier = new nsClassifierCallback();
if (!classifier) return NS_ERROR_OUT_OF_MEMORY;
nsresult rv = classifier->Start(aChannel);
nsresult rv = classifier->Start(aChannel, PR_FALSE);
if (rv == NS_ERROR_FACTORY_NOT_REGISTERED ||
rv == NS_ERROR_NOT_AVAILABLE) {
// no URI classifier => ignored cases
@ -9683,10 +9683,12 @@ nsDocShell::IsOKToLoadURI(nsIURI* aURI)
// nsClassifierCallback
//*****************************************************************************
NS_IMPL_ISUPPORTS3(nsClassifierCallback,
NS_IMPL_ISUPPORTS5(nsClassifierCallback,
nsIChannelClassifier,
nsIURIClassifierCallback,
nsIRunnable)
nsIRunnable,
nsIChannelEventSink,
nsIInterfaceRequestor)
NS_IMETHODIMP
nsClassifierCallback::Run()
@ -9711,7 +9713,7 @@ nsClassifierCallback::Run()
// Don't bother to run the classifier on a cached load that was
// previously classified.
if (HasBeenClassified()) {
if (HasBeenClassified(channel)) {
return NS_OK;
}
@ -9803,10 +9805,10 @@ nsClassifierCallback::MarkEntryClassified(nsresult status)
}
PRBool
nsClassifierCallback::HasBeenClassified()
nsClassifierCallback::HasBeenClassified(nsIChannel *aChannel)
{
nsCOMPtr<nsICachingChannel> cachingChannel =
do_QueryInterface(mSuspendedChannel);
do_QueryInterface(aChannel);
if (!cachingChannel) {
return PR_FALSE;
}
@ -9862,15 +9864,26 @@ nsClassifierCallback::OnClassifyComplete(nsresult aErrorCode)
}
NS_IMETHODIMP
nsClassifierCallback::Start(nsIChannel *aChannel)
nsClassifierCallback::Start(nsIChannel *aChannel, PRBool aInstallListener)
{
mChannel = aChannel;
if (aInstallListener) {
nsresult rv = aChannel->GetNotificationCallbacks
(getter_AddRefs(mNotificationCallbacks));
NS_ENSURE_SUCCESS(rv, rv);
rv = aChannel->SetNotificationCallbacks
(static_cast<nsIInterfaceRequestor*>(this));
NS_ENSURE_SUCCESS(rv, rv);
}
return Run();
}
NS_IMETHODIMP
nsClassifierCallback::OnRedirect(nsIChannel *aOldChannel,
nsIChannel *aNewChannel)
nsIChannel *aNewChannel)
{
mChannel = aNewChannel;
@ -9900,3 +9913,36 @@ nsClassifierCallback::Cancel()
return NS_OK;
}
NS_IMETHODIMP
nsClassifierCallback::OnChannelRedirect(nsIChannel *aOldChannel,
nsIChannel *aNewChannel,
PRUint32 aFlags)
{
nsresult rv = OnRedirect(aOldChannel, aNewChannel);
NS_ENSURE_SUCCESS(rv, rv);
if (mNotificationCallbacks) {
nsCOMPtr<nsIChannelEventSink> sink =
do_GetInterface(mNotificationCallbacks);
if (sink) {
return sink->OnChannelRedirect(aOldChannel, aNewChannel, aFlags);
}
}
return NS_OK;
}
NS_IMETHODIMP
nsClassifierCallback::GetInterface(const nsIID &aIID, void **aResult)
{
if (aIID.Equals(NS_GET_IID(nsIChannelEventSink))) {
NS_ADDREF_THIS();
*aResult = static_cast<nsIChannelEventSink *>(this);
return NS_OK;
} else if (mNotificationCallbacks) {
return mNotificationCallbacks->GetInterface(aIID, aResult);
} else {
return NS_ERROR_NO_INTERFACE;
}
}

Просмотреть файл

@ -148,6 +148,8 @@ protected:
class nsClassifierCallback : public nsIChannelClassifier
, public nsIURIClassifierCallback
, public nsIRunnable
, public nsIChannelEventSink
, public nsIInterfaceRequestor
{
public:
nsClassifierCallback() {}
@ -157,13 +159,16 @@ public:
NS_DECL_NSICHANNELCLASSIFIER
NS_DECL_NSIURICLASSIFIERCALLBACK
NS_DECL_NSIRUNNABLE
NS_DECL_NSICHANNELEVENTSINK
NS_DECL_NSIINTERFACEREQUESTOR
private:
nsCOMPtr<nsIChannel> mChannel;
nsCOMPtr<nsIChannel> mSuspendedChannel;
nsCOMPtr<nsIInterfaceRequestor> mNotificationCallbacks;
void MarkEntryClassified(nsresult status);
PRBool HasBeenClassified();
PRBool HasBeenClassified(nsIChannel *aChannel);
};
//*****************************************************************************

Просмотреть файл

@ -46,7 +46,7 @@ interface nsIChannel;
* URI classifier service, and cancels the channel before OnStartRequest
* if it is found on a blacklist.
*/
[scriptable, uuid(d17f8f74-d403-4dea-b124-3ace5dbe44dc)]
[scriptable, uuid(1481c5b5-9f6e-4995-8fe3-2aad5c06440d)]
interface nsIChannelClassifier : nsISupports
{
/**
@ -59,10 +59,18 @@ interface nsIChannelClassifier : nsISupports
* If there is no URI classifier service, NS_ERROR_FACTORY_NOT_REGISTERED
* will be returned.
*
* This method must be called immediately after AsyncOpen() has been called
* on the channel.
*
* @param aChannel
* The channel to suspend.
* @param aInstallListener
* If true, the classifier will install notification
* callbacks to listen for redirects. The classifier will
* pass all notifications on to the channel's existing
* notification callbacks.
*/
void start(in nsIChannel aChannel);
void start(in nsIChannel aChannel, in boolean aInstallListener);
/**
* Notify the classifier that the channel was redirected. The new channel

Просмотреть файл

@ -79,6 +79,8 @@
#include "nsICSSImportRule.h"
#include "nsThreadUtils.h"
#include "nsGkAtoms.h"
#include "nsDocShellCID.h"
#include "nsIChannelClassifier.h"
#ifdef MOZ_XUL
#include "nsXULPrototypeCache.h"
@ -1461,6 +1463,19 @@ CSSLoaderImpl::LoadSheet(SheetLoadData* aLoadData, StyleSheetState aSheetState)
return rv;
}
// Check the load against the URI classifier
nsCOMPtr<nsIChannelClassifier> classifier =
do_CreateInstance(NS_CHANNELCLASSIFIER_CONTRACTID);
if (classifier) {
rv = classifier->Start(channel, PR_TRUE);
if (NS_FAILED(rv)) {
LOG_ERROR((" Failed to classify URI"));
SheetComplete(aLoadData, rv);
channel->Cancel(rv);
return rv;
}
}
if (!mLoadingDatas.Put(&key, aLoadData)) {
LOG_ERROR((" Failed to put data in loading table"));
aLoadData->mIsCancelled = PR_TRUE;

Просмотреть файл

@ -55,6 +55,10 @@ REQUIRES = \
necko \
$(NULL)
# mochitest tests
DIRS += mochitest \
$(NULL)
# xpcshell tests
XPCSHELL_TESTS=unit

Просмотреть файл

@ -0,0 +1,57 @@
#
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
# # The Original Code is mozilla.org code.
#
# The Initial Developer of the Original Code is
# Mozilla Corporation.
# Portions created by the Initial Developer are Copyright (C) 2008
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
#
# Alternatively, the contents of this file may be used under the terms of
# either of the GNU General Public License Version 2 or later (the "GPL"),
# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
DEPTH = ../../../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
relativesrcdir = toolkit/components/url-classifier/tests/mochitest
MODULE = test_url-classifier
include $(DEPTH)/config/autoconf.mk
include $(topsrcdir)/config/rules.mk
_TEST_FILES = \
test_classifier.html \
classifierFrame.html \
evil.js \
evil.css \
import.css \
$(NULL)
libs:: $(_TEST_FILES)
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)

Просмотреть файл

@ -0,0 +1,34 @@
<html> <head>
<title></title>
</head>
<script type="text/javascript">
var scriptItem = "untouched";
function checkLoads() {
// Make sure the javascript did not load.
window.parent.is(scriptItem, "untouched", "Should not load bad javascript");
// Make sure the css did not load.
var elt = document.getElementById("styleCheck");
var style = document.defaultView.getComputedStyle(elt, "");
window.parent.isnot(style.visibility, "hidden", "Should not load bad css");
window.parent.SimpleTest.finish();
}
</script>
<!-- Try loading from a malware javascript URI -->
<script type="text/javascript" src="http://malware.com/tests/toolkit/components/url-classifier/tests/mochitest/evil.js"></script>
<!-- Try loading from a malware css URI
<link rel="stylesheet" type="text/css" href="http://malware.com/tests/toolkit/components/url-classifier/tests/mochitest/evil.css"></link>
<!-- Try loading a marked-as-malware css through an @import from a clean URI -->
<link rel="stylesheet" type="text/css" href="import.css"></link>
<body onload="checkLoads()">
The following should not be hidden:
<div id="styleCheck">STYLE TEST</div>
</body> </html>

Просмотреть файл

@ -0,0 +1 @@
#styleCheck { visibility: hidden; }

Просмотреть файл

@ -0,0 +1 @@
scriptItem = "loaded malware javascript!";

1
toolkit/components/url-classifier/tests/mochitest/import.css поставляемый Normal file
Просмотреть файл

@ -0,0 +1 @@
@import url("http://malware.com/tests/docshell/test/classifierBad.css");

Просмотреть файл

@ -0,0 +1,81 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test the URI Classifier</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var Cc = Components.classes;
var Ci = Components.interfaces;
// Add some URLs to the malware database.
var testData = "malware.com/"
var testUpdate =
"n:1000\ni:test-malware-simple\nad:1\n" +
"a:524:32:" + testData.length + "\n" +
testData;
var dbService = Cc["@mozilla.org/url-classifier/dbservice;1"]
.getService(Ci.nsIUrlClassifierDBService);
var numTries = 10;
function doUpdate(update) {
var listener = {
QueryInterface: function(iid)
{
if (iid.equals(Ci.nsISupports) ||
iid.equals(Ci.nsIUrlClassifierUpdateObserver))
return this;
throw Cr.NS_ERROR_NO_INTERFACE;
},
updateUrlRequested: function(url) { },
streamFinished: function(status) { },
updateError: function(errorCode) {
ok(false, "Couldn't update classifier.");
SimpleTest.finish();
},
updateSuccess: function(requestedTimeout) {
document.getElementById("testFrame").src = "classifierFrame.html";
}
};
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
try {
dbService.beginUpdate(listener,
"test-malware-simple", "");
dbService.beginStream("", "");
dbService.updateStream(update);
dbService.finishStream();
dbService.finishUpdate();
} catch(ex) {
// The DB service might already be updating. Try again after a 5 seconds...
if (--numTries != 0) {
setTimeout(function() { doUpdate(update) }, 5000);
return;
}
throw ex;
}
}
doUpdate(testUpdate);
SimpleTest.waitForExplicitFinish();
</script>
</pre>
<iframe id="testFrame" onload=""></iframe>
</body>
</html>