Bug 416534: Clean up cross-site xmlhttprequest security checks. With fixes to tests this time. r/sr=peterv

This commit is contained in:
jonas@sicking.cc 2008-02-26 19:45:29 -08:00
parent 7aff03fc46
commit 28ea51311b
21 changed files with 334 additions and 235 deletions

View File

@ -51,7 +51,7 @@ interface nsIURI;
[ptr] native JSContext(JSContext);
[ptr] native JSPrincipals(JSPrincipals);
[scriptable, uuid(635c413b-47c3-4ee1-87c8-e7919cc65f5a)]
[scriptable, uuid(7292475e-2821-4602-9d00-228476696428)]
interface nsIPrincipal : nsISerializable
{
/**
@ -203,6 +203,29 @@ interface nsIPrincipal : nsISerializable
*/
[noscript] boolean subsumes(in nsIPrincipal other);
/**
* Checks whether this principal is allowed to load the network resource
* located at the given URI under the same-origin policy. This means that
* codebase principals are only allowed to load resources from the same
* domain, the system principal is allowed to load anything, and null
* principals are not allowed to load anything.
*
* If the load is allowed this function does nothing. If the load is not
* allowed the function throws NS_ERROR_DOM_BAD_URI.
*
* NOTE: Other policies might override this, such as the Access-Control
* specification.
* NOTE: The 'domain' attribute has no effect on the behaviour of this
* function.
*
*
* @param uri The URI about to be loaded.
* @param report If true, will report a warning to the console service
* if the load is not allowed.
* @throws NS_ERROR_DOM_BAD_URI if the load is not allowed.
*/
[noscript] void checkMayLoad(in nsIUri uri, in boolean report);
/**
* The subject name for the certificate. This actually identifies the
* subject of the certificate. This may well not be a string that would

View File

@ -395,6 +395,18 @@ public:
JSContext* GetSafeJSContext();
/**
* Utility method for comparing two URIs. For security purposes, two URIs
* are equivalent if their schemes, hosts, and ports (if any) match. This
* method returns true if aSubjectURI and aObjectURI have the same origin,
* false otherwise.
*/
static PRBool SecurityCompareURIs(nsIURI* aSourceURI, nsIURI* aTargetURI);
static nsresult
ReportError(JSContext* cx, const nsAString& messageTag,
nsIURI* aSource, nsIURI* aTarget);
private:
// GetScriptSecurityManager is the only call that can make one
@ -420,10 +432,6 @@ private:
nsIPrincipal*
doGetSubjectPrincipal(nsresult* rv);
static nsresult
ReportError(JSContext* cx, const nsAString& messageTag,
nsIURI* aSource, nsIURI* aTarget);
nsresult
CheckPropertyAccessImpl(PRUint32 aAction,
nsAXPCNativeCallContext* aCallContext,
@ -540,16 +548,9 @@ private:
nsISecurityPref* securityPref);
/**
* Utility method for comparing two URIs. For security purposes, two URIs
* are equivalent if their schemes, hosts, and ports (if any) match. This
* method returns true if aSubjectURI and aObjectURI have the same origin,
* false otherwise.
*/
PRBool SecurityCompareURIs(nsIURI* aSourceURI, nsIURI* aTargetURI);
/* encapsulate the file comparison rules */
PRBool SecurityCompareFileURIs(nsIURI* aSourceURI, nsIURI* aTargetURI);
static PRBool SecurityCompareFileURIs(nsIURI* aSourceURI,
nsIURI* aTargetURI);
#ifdef XPC_IDISPATCH_SUPPORT
// While this header is included outside of caps, this class isn't
@ -590,7 +591,8 @@ private:
PRPackedBool mXPCDefaultGrantAll;
static const char sXPCDefaultGrantAllName[];
#endif
PRInt32 mFileURIOriginPolicy;
static PRInt32 sFileURIOriginPolicy;
static nsIIOService *sIOService;
static nsIXPConnect *sXPConnect;

View File

@ -49,6 +49,8 @@
#include "nsNetUtil.h"
#include "nsIClassInfoImpl.h"
#include "nsNetCID.h"
#include "nsDOMError.h"
#include "nsScriptSecurityManager.h"
static NS_DEFINE_CID(kSimpleURICID, NS_SIMPLEURI_CID);
@ -316,6 +318,17 @@ nsNullPrincipal::Subsumes(nsIPrincipal *aOther, PRBool *aResult)
return NS_OK;
}
NS_IMETHODIMP
nsNullPrincipal::CheckMayLoad(nsIURI* aURI, PRBool aReport)
{
if (aReport) {
nsScriptSecurityManager::ReportError(
nsnull, NS_LITERAL_STRING("CheckSameOriginError"), mURI, aURI);
}
return NS_ERROR_DOM_BAD_URI;
}
NS_IMETHODIMP
nsNullPrincipal::GetSubjectName(nsACString& aName)
{

View File

@ -54,6 +54,7 @@
#include "nsIPrefBranch.h"
#include "nsIPrefService.h"
#include "nsIClassInfoImpl.h"
#include "nsDOMError.h"
#include "nsPrincipal.h"
@ -306,6 +307,21 @@ nsPrincipal::Subsumes(nsIPrincipal *aOther, PRBool *aResult)
return Equals(aOther, aResult);
}
NS_IMETHODIMP
nsPrincipal::CheckMayLoad(nsIURI* aURI, PRBool aReport)
{
if (!nsScriptSecurityManager::SecurityCompareURIs(mCodebase, aURI)) {
if (aReport) {
nsScriptSecurityManager::ReportError(
nsnull, NS_LITERAL_STRING("CheckSameOriginError"), mCodebase, aURI);
}
return NS_ERROR_DOM_BAD_URI;
}
return NS_OK;
}
NS_IMETHODIMP
nsPrincipal::CanEnableCapability(const char *capability, PRInt16 *result)
{

View File

@ -98,6 +98,7 @@ nsIIOService *nsScriptSecurityManager::sIOService = nsnull;
nsIXPConnect *nsScriptSecurityManager::sXPConnect = nsnull;
nsIStringBundle *nsScriptSecurityManager::sStrBundle = nsnull;
JSRuntime *nsScriptSecurityManager::sRuntime = 0;
PRInt32 nsScriptSecurityManager::sFileURIOriginPolicy = FILEURI_SOP_SELF;
// Info we need about the JSClasses used by XPConnects wrapped
// natives, to avoid having to QI to nsIXPConnectWrappedNative all the
@ -277,6 +278,7 @@ nsScriptSecurityManager::GetSafeJSContext()
return cx;
}
/* static */
PRBool
nsScriptSecurityManager::SecurityCompareURIs(nsIURI* aSourceURI,
nsIURI* aTargetURI)
@ -378,7 +380,7 @@ nsScriptSecurityManager::SecurityCompareFileURIs(nsIURI* aSourceURI,
nsIURI* aTargetURI)
{
// in traditional unsafe behavior all files are the same origin
if (mFileURIOriginPolicy == FILEURI_SOP_TRADITIONAL)
if (sFileURIOriginPolicy == FILEURI_SOP_TRADITIONAL)
return PR_TRUE;
@ -387,7 +389,7 @@ nsScriptSecurityManager::SecurityCompareFileURIs(nsIURI* aSourceURI,
PRBool filesAreEqual = PR_FALSE;
if (NS_FAILED( aSourceURI->Equals(aTargetURI, &filesAreEqual) ))
return PR_FALSE;
if (filesAreEqual || mFileURIOriginPolicy == FILEURI_SOP_SELF)
if (filesAreEqual || sFileURIOriginPolicy == FILEURI_SOP_SELF)
return filesAreEqual;
@ -406,7 +408,7 @@ nsScriptSecurityManager::SecurityCompareFileURIs(nsIURI* aSourceURI,
// For policy ANYFILE we're done
if (mFileURIOriginPolicy == FILEURI_SOP_ANYFILE)
if (sFileURIOriginPolicy == FILEURI_SOP_ANYFILE)
return PR_TRUE;
@ -425,7 +427,7 @@ nsScriptSecurityManager::SecurityCompareFileURIs(nsIURI* aSourceURI,
}
// check remaining policies
if (mFileURIOriginPolicy == FILEURI_SOP_SAMEDIR)
if (sFileURIOriginPolicy == FILEURI_SOP_SAMEDIR)
{
// file: URIs in the same directory have the same origin
PRBool sameParent = PR_FALSE;
@ -436,7 +438,7 @@ nsScriptSecurityManager::SecurityCompareFileURIs(nsIURI* aSourceURI,
return sameParent;
}
if (mFileURIOriginPolicy == FILEURI_SOP_SUBDIR)
if (sFileURIOriginPolicy == FILEURI_SOP_SUBDIR)
{
// file: URIs can access files in the same or lower directories
PRBool isChild = PR_FALSE;
@ -3259,11 +3261,10 @@ nsScriptSecurityManager::nsScriptSecurityManager(void)
mIsJavaScriptEnabled(PR_FALSE),
mIsMailJavaScriptEnabled(PR_FALSE),
mIsWritingPrefs(PR_FALSE),
mPolicyPrefsChanged(PR_TRUE),
mPolicyPrefsChanged(PR_TRUE)
#ifdef XPC_IDISPATCH_SUPPORT
mXPCDefaultGrantAll(PR_FALSE),
, mXPCDefaultGrantAll(PR_FALSE)
#endif
mFileURIOriginPolicy(FILEURI_SOP_SELF)
{
NS_ASSERTION(sizeof(long) == sizeof(void*), "long and void* have different lengths on this platform. This may cause a security failure.");
mPrincipals.Init(31);
@ -3877,7 +3878,7 @@ nsScriptSecurityManager::ScriptSecurityPrefChanged()
PRInt32 policy;
rv = mSecurityPref->SecurityGetIntPref(sFileOriginPolicyPrefName, &policy);
mFileURIOriginPolicy = NS_SUCCEEDED(rv) ? policy : FILEURI_SOP_SELF;
sFileURIOriginPolicy = NS_SUCCEEDED(rv) ? policy : FILEURI_SOP_SELF;
#ifdef XPC_IDISPATCH_SUPPORT
rv = mSecurityPref->SecurityGetBoolPref(sXPCDefaultGrantAllName, &temp);

View File

@ -115,6 +115,12 @@ nsSystemPrincipal::Subsumes(nsIPrincipal *other, PRBool *result)
return NS_OK;
}
NS_IMETHODIMP
nsSystemPrincipal::CheckMayLoad(nsIURI* uri, PRBool aReport)
{
return NS_OK;
}
NS_IMETHODIMP
nsSystemPrincipal::GetHashValue(PRUint32 *result)
{

View File

@ -39,6 +39,7 @@
#include "nsISupports.idl"
interface nsIURI;
interface nsIPrincipal;
interface nsIDOMDocument;
interface nsIChannel;
@ -46,10 +47,14 @@ interface nsIChannel;
* *
* **** NOTICE **** *
* *
* nsISyncLoadDOMService defines synchronous methods to download *
* data from the network. Any delays from the server will *
* appear as a hang in the mozilla UI. Therefore, this interface *
* should be avoided as much as possible. *
* *
* This interface is DEPRECATED! *
* You should instead use XMLHttpRequest which now works both from *
* Javascript and C++. *
* *
* Additionally, synchronous network loads are evil. Any delays *
* from the server will appear as a hang in the mozilla UI. *
* Therefore, they should be avoided as much as possible. *
* *
* Don't make me come over there!! *
* *
@ -61,33 +66,34 @@ interface nsIChannel;
* a document.
*/
[scriptable, uuid(2ae03836-0704-45c9-a545-4169548c0669)]
[scriptable, uuid(8095998d-ae1c-4cfa-9b43-0973e5d77eb0)]
interface nsISyncLoadDOMService : nsISupports
{
/**
* Synchronously load the document from the specified channel.
*
* @param aChannel The channel to load the document from.
* @param aLoaderURI URI of loading document. For security checks
* null if no securitychecks should be done
* @param aLoaderPrincipal Principal of loading document. For security
* checks null if no securitychecks should be done
*
* @returns The document loaded from the URI.
*/
nsIDOMDocument loadDocument(in nsIChannel aChannel, in nsIURI aLoaderURI);
nsIDOMDocument loadDocument(in nsIChannel aChannel,
in nsIPrincipal aLoaderPrincipal);
nsIDOMDocument loadDocumentAsXML(in nsIChannel aChannel,
in nsIURI aLoaderURI);
in nsIPrincipal aLoaderPrincipal);
/**
* Synchronously load an XML document from the specified
* channel. The channel must be possible to open synchronously.
*
* @param aChannel The channel to load the document from.
* @param aLoaderURI URI of loading document. For security checks
* null if no securitychecks should be done
* @param aLoaderPrincipal Principal of loading document. For security
* checks null if no securitychecks should be done
*
* @returns The document loaded from the URI.
*/
nsIDOMDocument loadLocalDocument(in nsIChannel aChannel,
in nsIURI aLoaderURI);
in nsIPrincipal aLoaderPrincipal);
};

View File

@ -866,8 +866,7 @@ nsContentSink::ProcessOfflineManifest(nsIContent *aElement)
}
// Documents must list a manifest from the same origin
nsresult rv = nsContentUtils::GetSecurityManager()->
CheckSameOriginURI(manifestURI, mDocumentURI, PR_TRUE);
nsresult rv = mDocument->NodePrincipal()->CheckMayLoad(manifestURI, PR_TRUE);
if (NS_FAILED(rv)) {
return;
}

View File

@ -3834,10 +3834,7 @@ nsContentUtils::CheckSecurityBeforeLoad(nsIURI* aURIToLoad,
return NS_OK;
}
nsCOMPtr<nsIURI> loadingURI;
rv = aLoadingPrincipal->GetURI(getter_AddRefs(loadingURI));
NS_ENSURE_SUCCESS(rv, rv);
return sSecurityManager->CheckSameOriginURI(loadingURI, aURIToLoad, PR_TRUE);
return aLoadingPrincipal->CheckMayLoad(aURIToLoad, PR_TRUE);
}
/* static */

View File

@ -51,18 +51,29 @@
#include "nsParserUtils.h"
#include "nsGkAtoms.h"
#include "nsWhitespaceTokenizer.h"
#include "nsIChannelEventSink.h"
static NS_DEFINE_CID(kCParserCID, NS_PARSER_CID);
NS_IMPL_ISUPPORTS5(nsCrossSiteListenerProxy, nsIStreamListener,
NS_IMPL_ISUPPORTS7(nsCrossSiteListenerProxy, nsIStreamListener,
nsIRequestObserver, nsIContentSink, nsIXMLContentSink,
nsIExpatSink)
nsIExpatSink, nsIChannelEventSink, nsIInterfaceRequestor)
nsCrossSiteListenerProxy::nsCrossSiteListenerProxy(nsIStreamListener* aOuter,
nsIPrincipal* aRequestingPrincipal)
: mOuter(aOuter), mAcceptState(eNotSet), mHasForwardedRequest(PR_FALSE)
nsIPrincipal* aRequestingPrincipal,
nsIChannel* aChannel,
nsresult* aResult)
: mOuterListener(aOuter),
mRequestingPrincipal(aRequestingPrincipal),
mAcceptState(eNotSet),
mHasForwardedRequest(PR_FALSE),
mHasBeenCrossSite(PR_FALSE)
{
aRequestingPrincipal->GetURI(getter_AddRefs(mRequestingURI));
aChannel->GetNotificationCallbacks(getter_AddRefs(mOuterNotificationCallbacks));
aChannel->SetNotificationCallbacks(this);
*aResult = UpdateChannel(aChannel);
}
nsresult
@ -83,13 +94,14 @@ nsCrossSiteListenerProxy::ForwardRequest(PRBool aFromStop)
if (mAcceptState != eAccept) {
mAcceptState = eDeny;
mOuterRequest->Cancel(NS_ERROR_DOM_BAD_URI);
mOuter->OnStartRequest(mOuterRequest, mOuterContext);
mOuterListener->OnStartRequest(mOuterRequest, mOuterContext);
// Only call OnStopRequest here if we were called from OnStopRequest.
// Otherwise the call to Cancel will make us get an OnStopRequest later
// so we'll forward OnStopRequest then.
if (aFromStop) {
mOuter->OnStopRequest(mOuterRequest, mOuterContext, NS_ERROR_DOM_BAD_URI);
mOuterListener->OnStopRequest(mOuterRequest, mOuterContext,
NS_ERROR_DOM_BAD_URI);
}
// Clear this data just in case since it should never be forwarded.
@ -98,7 +110,7 @@ nsCrossSiteListenerProxy::ForwardRequest(PRBool aFromStop)
return NS_ERROR_DOM_BAD_URI;
}
nsresult rv = mOuter->OnStartRequest(mOuterRequest, mOuterContext);
nsresult rv = mOuterListener->OnStartRequest(mOuterRequest, mOuterContext);
NS_ENSURE_SUCCESS(rv, rv);
if (!mStoredData.IsEmpty()) {
@ -106,8 +118,8 @@ nsCrossSiteListenerProxy::ForwardRequest(PRBool aFromStop)
rv = NS_NewCStringInputStream(getter_AddRefs(stream), mStoredData);
NS_ENSURE_SUCCESS(rv, rv);
rv = mOuter->OnDataAvailable(mOuterRequest, mOuterContext, stream, 0,
mStoredData.Length());
rv = mOuterListener->OnDataAvailable(mOuterRequest, mOuterContext, stream,
0, mStoredData.Length());
NS_ENSURE_SUCCESS(rv, rv);
}
@ -137,9 +149,8 @@ nsCrossSiteListenerProxy::OnStartRequest(nsIRequest* aRequest,
}
nsCOMPtr<nsIURI> finalURI;
channel->GetURI(getter_AddRefs(finalURI));
rv = nsContentUtils::GetSecurityManager()->
CheckSameOriginURI(mRequestingURI, finalURI, PR_FALSE);
if (NS_SUCCEEDED(rv)) {
if (!mHasBeenCrossSite) {
mAcceptState = eAccept;
return ForwardRequest(PR_FALSE);
}
@ -247,7 +258,7 @@ nsCrossSiteListenerProxy::OnStopRequest(nsIRequest* aRequest,
nsresult aStatusCode)
{
if (mHasForwardedRequest) {
return mOuter->OnStopRequest(aRequest, aContext, aStatusCode);
return mOuterListener->OnStopRequest(aRequest, aContext, aStatusCode);
}
mAcceptState = eDeny;
@ -281,8 +292,8 @@ nsCrossSiteListenerProxy::OnDataAvailable(nsIRequest* aRequest,
if (mAcceptState != eAccept) {
return NS_ERROR_DOM_BAD_URI;
}
return mOuter->OnDataAvailable(aRequest, aContext, aInputStream, aOffset,
aCount);
return mOuterListener->OnDataAvailable(aRequest, aContext, aInputStream,
aOffset, aCount);
}
NS_ASSERTION(mStoredData.Length() == aOffset,
@ -866,37 +877,88 @@ nsCrossSiteListenerProxy::VerifyAndMatchDomainPattern(const nsACString& aPattern
(!patternHasWild || reqPos >= 1);
}
/* static */
nsresult
nsCrossSiteListenerProxy::AddRequestHeaders(nsIChannel* aChannel,
nsIPrincipal* aRequestingPrincipal)
NS_IMETHODIMP
nsCrossSiteListenerProxy::GetInterface(const nsIID & aIID, void **aResult)
{
// Once bug 386823 is fixed this could just be an assertion.
NS_ENSURE_TRUE(aRequestingPrincipal, NS_ERROR_FAILURE);
if (aIID.Equals(NS_GET_IID(nsIChannelEventSink))) {
*aResult = static_cast<nsIChannelEventSink*>(this);
NS_ADDREF_THIS();
// Work out the requesting URI
return NS_OK;
}
return mOuterNotificationCallbacks ?
mOuterNotificationCallbacks->GetInterface(aIID, aResult) :
NS_ERROR_NO_INTERFACE;
}
NS_IMETHODIMP
nsCrossSiteListenerProxy::OnChannelRedirect(nsIChannel *aOldChannel,
nsIChannel *aNewChannel,
PRUint32 aFlags)
{
nsresult rv;
nsCOMPtr<nsIChannelEventSink> outer =
do_GetInterface(mOuterNotificationCallbacks);
if (outer) {
rv = outer->OnChannelRedirect(aOldChannel, aNewChannel, aFlags);
NS_ENSURE_SUCCESS(rv, rv);
}
return UpdateChannel(aNewChannel);
}
nsresult
nsCrossSiteListenerProxy::UpdateChannel(nsIChannel* aChannel)
{
nsCOMPtr<nsIURI> uri;
nsresult rv = aRequestingPrincipal->GetURI(getter_AddRefs(uri));
nsresult rv = aChannel->GetURI(getter_AddRefs(uri));
NS_ENSURE_SUCCESS(rv, rv);
nsCString scheme, host;
rv = uri->GetScheme(scheme);
// Check that the uri is ok to load
rv = nsContentUtils::GetSecurityManager()->
CheckLoadURIWithPrincipal(mRequestingPrincipal, uri,
nsIScriptSecurityManager::STANDARD);
NS_ENSURE_SUCCESS(rv, rv);
rv = uri->GetAsciiHost(host);
if (!mHasBeenCrossSite &&
NS_SUCCEEDED(mRequestingPrincipal->CheckMayLoad(uri, PR_FALSE))) {
return NS_OK;
}
nsCString userpass;
uri->GetUserPass(userpass);
NS_ENSURE_TRUE(userpass.IsEmpty(), NS_ERROR_DOM_BAD_URI);
// It's a cross site load
mHasBeenCrossSite = PR_TRUE;
// Work out the Referer-Root header
nsCString root, host;
rv = mRequestingURI->GetAsciiHost(host);
NS_ENSURE_SUCCESS(rv, rv);
nsCString root = scheme + NS_LITERAL_CSTRING("://") + host;
// Append the port
PRInt32 port;
uri->GetPort(&port);
if (port != -1) {
PRInt32 defaultPort = NS_GetDefaultPort(scheme.get());
if (port != defaultPort) {
root.Append(":");
root.AppendInt(port);
if (!host.IsEmpty()) {
nsCString scheme;
rv = mRequestingURI->GetScheme(scheme);
NS_ENSURE_SUCCESS(rv, rv);
root = scheme + NS_LITERAL_CSTRING("://") + host;
// If needed, append the port
PRInt32 port;
mRequestingURI->GetPort(&port);
if (port != -1) {
PRInt32 defaultPort = NS_GetDefaultPort(scheme.get());
if (port != defaultPort) {
root.Append(":");
root.AppendInt(port);
}
}
}
else {
root.AssignLiteral("null");
}
// Now add the access-control-origin header
nsCOMPtr<nsIHttpChannel> http = do_QueryInterface(aChannel);

View File

@ -44,6 +44,8 @@
#include "nsIContentSink.h"
#include "nsIXMLContentSink.h"
#include "nsIExpatSink.h"
#include "nsIInterfaceRequestor.h"
#include "nsIChannelEventSink.h"
class nsIURI;
class nsIParser;
@ -51,19 +53,22 @@ class nsIPrincipal;
class nsCrossSiteListenerProxy : public nsIStreamListener,
public nsIXMLContentSink,
public nsIExpatSink
public nsIExpatSink,
public nsIInterfaceRequestor,
public nsIChannelEventSink
{
public:
nsCrossSiteListenerProxy(nsIStreamListener* aOuter,
nsIPrincipal* aRequestingPrincipal);
nsIPrincipal* aRequestingPrincipal,
nsIChannel* aChannel,
nsresult* aResult);
NS_DECL_ISUPPORTS
NS_DECL_NSIREQUESTOBSERVER
NS_DECL_NSISTREAMLISTENER
NS_DECL_NSIEXPATSINK
static nsresult AddRequestHeaders(nsIChannel* aChannel,
nsIPrincipal* aRequestingPrincipal);
NS_DECL_NSIINTERFACEREQUESTOR
NS_DECL_NSICHANNELEVENTSINK
// nsIContentSink
NS_IMETHOD WillTokenize(void) { return NS_OK; }
@ -77,18 +82,21 @@ public:
virtual nsISupports *GetTarget() { return nsnull; }
private:
nsresult UpdateChannel(nsIChannel* aChannel);
nsresult ForwardRequest(PRBool aCallStop);
PRBool MatchPatternList(const char*& aIter, const char* aEnd);
void CheckHeader(const nsCString& aHeader);
PRBool VerifyAndMatchDomainPattern(const nsACString& aDomainPattern);
nsCOMPtr<nsIStreamListener> mOuter;
nsCOMPtr<nsIStreamListener> mOuterListener;
nsCOMPtr<nsIRequest> mOuterRequest;
nsCOMPtr<nsISupports> mOuterContext;
nsCOMPtr<nsIStreamListener> mParserListener;
nsCOMPtr<nsIParser> mParser;
nsCOMPtr<nsIURI> mRequestingURI;
nsCOMPtr<nsIPrincipal> mRequestingPrincipal;
nsCOMPtr<nsIInterfaceRequestor> mOuterNotificationCallbacks;
nsTArray<nsCString> mReqSubdomains;
nsCString mStoredData;
enum {
@ -97,4 +105,5 @@ private:
eNotSet
} mAcceptState;
PRBool mHasForwardedRequest;
PRBool mHasBeenCrossSite;
};

View File

@ -59,6 +59,7 @@
#include "nsAutoPtr.h"
#include "nsLoadListenerProxy.h"
#include "nsStreamUtils.h"
#include "nsCrossSiteListenerProxy.h"
/**
* This class manages loading a single XML document
@ -74,7 +75,7 @@ public:
NS_DECL_ISUPPORTS
nsresult LoadDocument(nsIChannel* aChannel, nsIURI *aLoaderURI,
nsresult LoadDocument(nsIChannel* aChannel, nsIPrincipal *aLoaderPrincipal,
PRBool aChannelIsSync, PRBool aForceToXML,
nsIDOMDocument** aResult);
@ -162,7 +163,7 @@ NS_IMPL_ISUPPORTS4(nsSyncLoader,
nsresult
nsSyncLoader::LoadDocument(nsIChannel* aChannel,
nsIURI *aLoaderURI,
nsIPrincipal *aLoaderPrincipal,
PRBool aChannelIsSync,
PRBool aForceToXML,
nsIDOMDocument **aResult)
@ -171,32 +172,26 @@ nsSyncLoader::LoadDocument(nsIChannel* aChannel,
*aResult = nsnull;
nsresult rv = NS_OK;
nsCOMPtr<nsIURI> loaderUri;
if (aLoaderPrincipal) {
aLoaderPrincipal->GetURI(getter_AddRefs(loaderUri));
}
mChannel = aChannel;
nsCOMPtr<nsIHttpChannel> http = do_QueryInterface(mChannel);
if (http) {
http->SetRequestHeader(NS_LITERAL_CSTRING("Accept"),
NS_LITERAL_CSTRING("text/xml,application/xml,application/xhtml+xml,*/*;q=0.1"),
PR_FALSE);
if (aLoaderURI) {
http->SetReferrer(aLoaderURI);
if (loaderUri) {
http->SetReferrer(loaderUri);
}
}
if (aLoaderURI) {
nsCOMPtr<nsIURI> docURI;
rv = aChannel->GetOriginalURI(getter_AddRefs(docURI));
NS_ENSURE_SUCCESS(rv, rv);
nsIScriptSecurityManager *securityManager =
nsContentUtils::GetSecurityManager();
rv = securityManager->CheckLoadURI(aLoaderURI, docURI,
nsIScriptSecurityManager::STANDARD);
NS_ENSURE_SUCCESS(rv, rv);
rv = securityManager->CheckSameOriginURI(aLoaderURI, docURI, PR_TRUE);
NS_ENSURE_SUCCESS(rv, rv);
}
// Hook us up to listen to redirects and the like.
// Do this before setting up the cross-site proxy since
// that installs its own proxies.
mChannel->SetNotificationCallbacks(this);
// Get the loadgroup of the channel
nsCOMPtr<nsILoadGroup> loadGroup;
@ -223,6 +218,13 @@ nsSyncLoader::LoadDocument(nsIChannel* aChannel,
listener.swap(forceListener);
}
if (aLoaderPrincipal) {
listener = new nsCrossSiteListenerProxy(listener, aLoaderPrincipal,
mChannel, &rv);
NS_ENSURE_TRUE(listener, NS_ERROR_OUT_OF_MEMORY);
NS_ENSURE_SUCCESS(rv, rv);
}
// Register as a load listener on the document
nsCOMPtr<nsPIDOMEventTarget> target = do_QueryInterface(document);
NS_ENSURE_TRUE(target, NS_ERROR_FAILURE);
@ -270,9 +272,6 @@ nsSyncLoader::LoadDocument(nsIChannel* aChannel,
nsresult
nsSyncLoader::PushAsyncStream(nsIStreamListener* aListener)
{
// Hook us up to listen to redirects and the like
mChannel->SetNotificationCallbacks(this);
// Start reading from the channel
nsresult rv = mChannel->AsyncOpen(aListener, nsnull);
@ -367,20 +366,6 @@ nsSyncLoader::OnChannelRedirect(nsIChannel *aOldChannel,
{
NS_PRECONDITION(aNewChannel, "Redirecting to null channel?");
nsCOMPtr<nsIURI> oldURI;
nsresult rv = aOldChannel->GetURI(getter_AddRefs(oldURI)); // The original URI
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIURI> newURI;
rv = aNewChannel->GetURI(getter_AddRefs(newURI)); // The new URI
NS_ENSURE_SUCCESS(rv, rv);
nsIScriptSecurityManager *securityManager =
nsContentUtils::GetSecurityManager();
rv = securityManager->CheckSameOriginURI(oldURI, newURI, PR_TRUE);
NS_ENSURE_SUCCESS(rv, rv);
mChannel = aNewChannel;
return NS_OK;
@ -397,42 +382,49 @@ NS_IMPL_ISUPPORTS1(nsSyncLoadService,
nsISyncLoadDOMService)
static nsresult
LoadFromChannel(nsIChannel* aChannel, nsIURI *aLoaderURI, PRBool aChannelIsSync,
PRBool aForceToXML, nsIDOMDocument** aResult)
LoadFromChannel(nsIChannel* aChannel, nsIPrincipal *aLoaderPrincipal,
PRBool aChannelIsSync, PRBool aForceToXML,
nsIDOMDocument** aResult)
{
nsRefPtr<nsSyncLoader> loader = new nsSyncLoader();
if (!loader) {
return NS_ERROR_OUT_OF_MEMORY;
}
return loader->LoadDocument(aChannel, aLoaderURI, aChannelIsSync,
return loader->LoadDocument(aChannel, aLoaderPrincipal, aChannelIsSync,
aForceToXML, aResult);
}
NS_IMETHODIMP
nsSyncLoadService::LoadDocument(nsIChannel* aChannel, nsIURI* aLoaderURI,
nsSyncLoadService::LoadDocument(nsIChannel* aChannel,
nsIPrincipal* aLoaderPrincipal,
nsIDOMDocument** aResult)
{
return LoadFromChannel(aChannel, aLoaderURI, PR_FALSE, PR_FALSE, aResult);
return LoadFromChannel(aChannel, aLoaderPrincipal, PR_FALSE, PR_FALSE,
aResult);
}
NS_IMETHODIMP
nsSyncLoadService::LoadDocumentAsXML(nsIChannel* aChannel, nsIURI* aLoaderURI,
nsSyncLoadService::LoadDocumentAsXML(nsIChannel* aChannel,
nsIPrincipal* aLoaderPrincipal,
nsIDOMDocument** aResult)
{
return LoadFromChannel(aChannel, aLoaderURI, PR_FALSE, PR_TRUE, aResult);
return LoadFromChannel(aChannel, aLoaderPrincipal, PR_FALSE, PR_TRUE,
aResult);
}
NS_IMETHODIMP
nsSyncLoadService::LoadLocalDocument(nsIChannel* aChannel, nsIURI* aLoaderURI,
nsSyncLoadService::LoadLocalDocument(nsIChannel* aChannel,
nsIPrincipal* aLoaderPrincipal,
nsIDOMDocument** aResult)
{
return LoadFromChannel(aChannel, aLoaderURI, PR_TRUE, PR_TRUE, aResult);
return LoadFromChannel(aChannel, aLoaderPrincipal, PR_TRUE, PR_TRUE,
aResult);
}
/* static */
nsresult
nsSyncLoadService::LoadDocument(nsIURI *aURI, nsIURI *aLoaderURI,
nsSyncLoadService::LoadDocument(nsIURI *aURI, nsIPrincipal *aLoaderPrincipal,
nsILoadGroup *aLoadGroup, PRBool aForceToXML,
nsIDOMDocument** aResult)
{
@ -451,7 +443,8 @@ nsSyncLoadService::LoadDocument(nsIURI *aURI, nsIURI *aLoaderURI,
(NS_SUCCEEDED(aURI->SchemeIs("resource", &isResource)) &&
isResource);
return LoadFromChannel(channel, aLoaderURI, isSync, aForceToXML, aResult);
return LoadFromChannel(channel, aLoaderPrincipal, isSync, aForceToXML,
aResult);
}
/* static */

View File

@ -60,15 +60,15 @@ public:
* Synchronously load the document from the specified URI.
*
* @param aURI URI to load the document from.
* @param aLoaderURI URI of loading document. For security checks and
* referrer header. May be null if no security checks
* should be done.
* @param aLoaderPrincipal Principal of loading document. For security
* checks and referrer header. May be null if no
* security checks should be done.
* @param aLoadGroup The loadgroup to use for loading the document.
* @param aForceToXML Whether to parse the document as XML, regardless of
* content type.
* @param aResult [out] The document loaded from the URI.
*/
static nsresult LoadDocument(nsIURI *aURI, nsIURI *aLoaderURI,
static nsresult LoadDocument(nsIURI *aURI, nsIPrincipal *aLoaderPrincipal,
nsILoadGroup *aLoadGroup, PRBool aForceToXML,
nsIDOMDocument** aResult);

View File

@ -1416,7 +1416,7 @@ nsXMLHttpRequest::CheckChannelForCrossSiteRequest()
// The request is now cross-site, so update flag.
mState |= XML_HTTP_REQUEST_USE_XSITE_AC;
// Remove dangerous headers and set XMLHttpRequest-Security-Check
// Remove dangerous headers
nsCOMPtr<nsIHttpChannel> http = do_QueryInterface(mChannel);
if (http) {
PRUint32 i;
@ -1426,17 +1426,7 @@ nsXMLHttpRequest::CheckChannelForCrossSiteRequest()
mExtraRequestHeaders.Clear();
}
// Cancel if username/password is supplied to avoid brute-force password
// hacking
nsCOMPtr<nsIURI> channelURI;
nsresult rv = mChannel->GetURI(getter_AddRefs(channelURI));
NS_ENSURE_SUCCESS(rv, rv);
nsCString userpass;
channelURI->GetUserPass(userpass);
NS_ENSURE_TRUE(userpass.IsEmpty(), NS_ERROR_DOM_BAD_URI);
return nsCrossSiteListenerProxy::AddRequestHeaders(mChannel, mPrincipal);
return NS_OK;
}
/* noscript void openRequest (in AUTF8String method, in AUTF8String url, in boolean async, in AString user, in AString password); */
@ -1590,8 +1580,6 @@ nsXMLHttpRequest::OpenRequest(const nsACString& method,
nsnull, loadFlags);
NS_ENSURE_SUCCESS(rv, rv);
rv = nsCrossSiteListenerProxy::AddRequestHeaders(mACGetChannel, mPrincipal);
nsCOMPtr<nsIHttpChannel> acHttp = do_QueryInterface(mACGetChannel);
NS_ASSERTION(acHttp, "Failed to QI to nsIHttpChannel!");
@ -2290,8 +2278,10 @@ nsXMLHttpRequest::Send(nsIVariant *aBody)
if (!(mState & XML_HTTP_REQUEST_XSITEENABLED)) {
// Always create a nsCrossSiteListenerProxy here even if it's
// a same-origin request right now, since it could be redirected.
listener = new nsCrossSiteListenerProxy(listener, mPrincipal);
listener = new nsCrossSiteListenerProxy(listener, mPrincipal, mChannel,
&rv);
NS_ENSURE_TRUE(listener, NS_ERROR_OUT_OF_MEMORY);
NS_ENSURE_SUCCESS(rv, rv);
}
// Bypass the network cache in cases where it makes no sense:
@ -2328,8 +2318,10 @@ nsXMLHttpRequest::Send(nsIVariant *aBody)
new nsACProxyListener(mChannel, listener, nsnull, mPrincipal, method);
NS_ENSURE_TRUE(acListener, NS_ERROR_OUT_OF_MEMORY);
listener = new nsCrossSiteListenerProxy(acListener, mPrincipal);
listener = new nsCrossSiteListenerProxy(acListener, mPrincipal,
mACGetChannel, &rv);
NS_ENSURE_TRUE(listener, NS_ERROR_OUT_OF_MEMORY);
NS_ENSURE_SUCCESS(rv, rv);
rv = mACGetChannel->AsyncOpen(listener, nsnull);
}

View File

@ -771,9 +771,6 @@ nsXMLContentSink::ProcessStyleLink(nsIContent* aElement,
nsIScriptSecurityManager::ALLOW_CHROME);
NS_ENSURE_SUCCESS(rv, NS_OK);
rv = secMan->CheckSameOriginURI(mDocumentURI, url, PR_TRUE);
NS_ENSURE_SUCCESS(rv, NS_OK);
// Do content policy check
PRInt16 decision = nsIContentPolicy::ACCEPT;
rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_STYLESHEET,

View File

@ -378,6 +378,9 @@ nsXMLDocument::Load(const nsAString& aUrl, PRBool *aReturn)
// changing the principal of this document.
nsIScriptSecurityManager *secMan = nsContentUtils::GetSecurityManager();
// Enforce same-origin even for chrome loaders to avoid someone accidentally
// using a document that content has a reference to and turn that into a
// chrome document.
if (codebase) {
rv = secMan->CheckSameOriginURI(codebase, uri, PR_FALSE);

View File

@ -100,18 +100,15 @@ txParseDocumentFromURI(const nsAString& aHref, const txXPathNode& aLoader,
nsCOMPtr<nsILoadGroup> loadGroup = loaderDocument->GetDocumentLoadGroup();
nsCOMPtr<nsIURI> loaderUri;
rv = loaderDocument->NodePrincipal()->GetURI(getter_AddRefs(loaderUri));
NS_ENSURE_SUCCESS(rv, rv);
// For the system principal loaderUri will be null here, which is good
// since that means that chrome documents can load any uri.
// Raw pointer, we want the resulting txXPathNode to hold a reference to
// the document.
nsIDOMDocument* theDocument = nsnull;
rv = nsSyncLoadService::LoadDocument(documentURI, loaderUri, loadGroup,
PR_TRUE, &theDocument);
rv = nsSyncLoadService::LoadDocument(documentURI,
loaderDocument->NodePrincipal(),
loadGroup, PR_TRUE, &theDocument);
if (NS_FAILED(rv)) {
aErrMsg.Append(NS_LITERAL_STRING("Document load of ") +

View File

@ -70,6 +70,8 @@
#include "nsAttrName.h"
#include "nsIScriptError.h"
#include "nsIURL.h"
#include "nsCrossSiteListenerProxy.h"
#include "nsDOMError.h"
static NS_DEFINE_CID(kCParserCID, NS_PARSER_CID);
@ -94,7 +96,6 @@ getSpec(nsIChannel* aChannel, nsAString& aSpec)
class txStylesheetSink : public nsIXMLContentSink,
public nsIExpatSink,
public nsIStreamListener,
public nsIChannelEventSink,
public nsIInterfaceRequestor
{
public:
@ -104,7 +105,6 @@ public:
NS_DECL_NSIEXPATSINK
NS_DECL_NSISTREAMLISTENER
NS_DECL_NSIREQUESTOBSERVER
NS_DECL_NSICHANNELEVENTSINK
NS_DECL_NSIINTERFACEREQUESTOR
// nsIContentSink
@ -136,13 +136,12 @@ txStylesheetSink::txStylesheetSink(txStylesheetCompiler* aCompiler,
mListener = do_QueryInterface(aParser);
}
NS_IMPL_ISUPPORTS7(txStylesheetSink,
NS_IMPL_ISUPPORTS6(txStylesheetSink,
nsIXMLContentSink,
nsIContentSink,
nsIExpatSink,
nsIStreamListener,
nsIRequestObserver,
nsIChannelEventSink,
nsIInterfaceRequestor)
NS_IMETHODIMP
@ -374,29 +373,6 @@ txStylesheetSink::OnStopRequest(nsIRequest *aRequest, nsISupports *aContext,
return rv;
}
NS_IMETHODIMP
txStylesheetSink::OnChannelRedirect(nsIChannel *aOldChannel,
nsIChannel *aNewChannel,
PRUint32 aFlags)
{
NS_PRECONDITION(aNewChannel, "Redirect without a channel?");
nsresult rv;
nsCOMPtr<nsIScriptSecurityManager> secMan =
do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIURI> oldURI;
rv = aOldChannel->GetURI(getter_AddRefs(oldURI)); // The original URI
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIURI> newURI;
rv = aNewChannel->GetURI(getter_AddRefs(newURI)); // The new URI
NS_ENSURE_SUCCESS(rv, rv);
return secMan->CheckSameOriginURI(oldURI, newURI, PR_TRUE);
}
NS_IMETHODIMP
txStylesheetSink::GetInterface(const nsIID& aIID, void** aResult)
{
@ -420,7 +396,7 @@ txStylesheetSink::GetInterface(const nsIID& aIID, void** aResult)
return NS_OK;
}
return QueryInterface(aIID, aResult);
return NS_ERROR_NO_INTERFACE;
}
class txCompileObserver : public txACompileObserver
@ -493,13 +469,19 @@ txCompileObserver::loadURI(const nsAString& aUri,
GetCodebasePrincipal(referrerUri, getter_AddRefs(referrerPrincipal));
NS_ENSURE_SUCCESS(rv, rv);
// Do security check.
rv = nsContentUtils::
CheckSecurityBeforeLoad(uri, referrerPrincipal,
nsIScriptSecurityManager::STANDARD, PR_FALSE,
nsIContentPolicy::TYPE_STYLESHEET,
nsnull, NS_LITERAL_CSTRING("application/xml"));
// Content Policy
PRInt16 shouldLoad = nsIContentPolicy::ACCEPT;
rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_STYLESHEET,
uri,
referrerPrincipal,
nsnull,
NS_LITERAL_CSTRING("application/xml"),
nsnull,
&shouldLoad);
NS_ENSURE_SUCCESS(rv, rv);
if (NS_CP_REJECTED(shouldLoad)) {
return NS_ERROR_DOM_BAD_URI;
}
return startLoad(uri, aCompiler, referrerPrincipal);
}
@ -555,6 +537,12 @@ txCompileObserver::startLoad(nsIURI* aUri, txStylesheetCompiler* aCompiler,
parser->SetContentSink(sink);
parser->Parse(aUri);
// Always install in case of redirects
nsCOMPtr<nsIStreamListener> listener =
new nsCrossSiteListenerProxy(sink, aReferrerPrincipal, channel, &rv);
NS_ENSURE_TRUE(listener, NS_ERROR_OUT_OF_MEMORY);
NS_ENSURE_SUCCESS(rv, rv);
return channel->AsyncOpen(sink, parser);
}
@ -566,14 +554,20 @@ TX_LoadSheet(nsIURI* aUri, txMozillaXSLTProcessor* aProcessor,
aUri->GetSpec(spec);
PR_LOG(txLog::xslt, PR_LOG_ALWAYS, ("TX_LoadSheet: %s\n", spec.get()));
// Pass source document as the context
nsresult rv = nsContentUtils::
CheckSecurityBeforeLoad(aUri, aCallerPrincipal,
nsIScriptSecurityManager::STANDARD, PR_FALSE,
nsIContentPolicy::TYPE_STYLESHEET,
aProcessor->GetSourceContentModel(),
NS_LITERAL_CSTRING("application/xml"));
// Content Policy
PRInt16 shouldLoad = nsIContentPolicy::ACCEPT;
nsresult rv =
NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_STYLESHEET,
aUri,
aCallerPrincipal,
aProcessor->GetSourceContentModel(),
NS_LITERAL_CSTRING("application/xml"),
nsnull,
&shouldLoad);
NS_ENSURE_SUCCESS(rv, rv);
if (NS_CP_REJECTED(shouldLoad)) {
return NS_ERROR_DOM_BAD_URI;
}
nsRefPtr<txCompileObserver> observer =
new txCompileObserver(aProcessor, aLoadGroup);
@ -715,18 +709,25 @@ txSyncCompileObserver::loadURI(const nsAString& aUri,
GetCodebasePrincipal(referrerUri, getter_AddRefs(referrerPrincipal));
NS_ENSURE_SUCCESS(rv, rv);
rv = nsContentUtils::
CheckSecurityBeforeLoad(uri, referrerPrincipal,
nsIScriptSecurityManager::STANDARD,
PR_FALSE, nsIContentPolicy::TYPE_STYLESHEET,
nsnull, NS_LITERAL_CSTRING("application/xml"));
// Content Policy
PRInt16 shouldLoad = nsIContentPolicy::ACCEPT;
rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_STYLESHEET,
uri,
referrerPrincipal,
nsnull,
NS_LITERAL_CSTRING("application/xml"),
nsnull,
&shouldLoad);
NS_ENSURE_SUCCESS(rv, rv);
if (NS_CP_REJECTED(shouldLoad)) {
return NS_ERROR_DOM_BAD_URI;
}
// This is probably called by js, a loadGroup for the channel doesn't
// make sense.
nsCOMPtr<nsIDOMDocument> document;
rv = nsSyncLoadService::LoadDocument(uri, referrerUri, nsnull, PR_FALSE,
getter_AddRefs(document));
rv = nsSyncLoadService::LoadDocument(uri, referrerPrincipal, nsnull,
PR_FALSE, getter_AddRefs(document));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIDocument> doc = do_QueryInterface(document);

View File

@ -2605,16 +2605,13 @@ nsXULDocument::LoadOverlayInternal(nsIURI* aURI, PRBool aIsDynamic,
if (aIsDynamic)
mResolutionPhase = nsForwardReference::eStart;
nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
NS_ENSURE_TRUE(secMan, NS_ERROR_NOT_AVAILABLE);
// Chrome documents are allowed to load overlays from anywhere.
// In all other cases, the overlay is only allowed to load if
// the master document and prototype document have the same origin.
if (!IsChromeURI(mDocumentURI)) {
// Make sure we're allowed to load this overlay.
rv = secMan->CheckSameOriginURI(mDocumentURI, aURI, PR_TRUE);
rv = NodePrincipal()->CheckMayLoad(aURI, PR_TRUE);
if (NS_FAILED(rv)) {
*aFailureFromContent = PR_TRUE;
return rv;

View File

@ -23,12 +23,11 @@ var x = new XMLHttpRequest();
x.open("GET", document.location.href);
x.send("");
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
is(x.channel.notificationCallbacks instanceof
Components.interfaces.nsIInterfaceRequestor,
is(x instanceof Components.interfaces.nsIInterfaceRequestor,
true, "Must be interface requestor");
var count = {};
var interfaces = x.channel.notificationCallbacks.
var interfaces = x.
QueryInterface(Components.interfaces.nsIClassInfo).
getInterfaces(count).
map(function(id) {

View File

@ -713,30 +713,16 @@ nsCanvasRenderingContextGLPrivate::DoDrawImageSecurityCheck(nsIURI* aURI, PRBool
}
fprintf (stderr, "DoDrawImageSecuritycheck this 4: %p\n", this);
nsCOMPtr<nsIScriptSecurityManager> ssm =
do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
if (!ssm) {
mCanvasElement->SetWriteOnly();
return;
}
fprintf (stderr, "DoDrawImageSecuritycheck this 5: %p\n", this);
nsCOMPtr<nsINode> elem = do_QueryInterface(mCanvasElement);
if (elem && ssm) {
nsCOMPtr<nsIPrincipal> uriPrincipal;
ssm->GetCodebasePrincipal(aURI, getter_AddRefs(uriPrincipal));
if (uriPrincipal) {
nsresult rv = ssm->CheckSameOriginPrincipal(elem->NodePrincipal(),
uriPrincipal);
if (NS_SUCCEEDED(rv)) {
// Same origin
return;
}
if (elem) {
rv = elem->NodePrincipal()->CheckMayLoad(aURI);
if (NS_SUCCEEDED(rv)) {
// Same origin
return;
}
}
fprintf (stderr, "DoDrawImageSecuritycheck this 6: %p\n", this); fflush(stderr);
fprintf (stderr, "DoDrawImageSecuritycheck this 5: %p\n", this); fflush(stderr);
mCanvasElement->SetWriteOnly();
#endif
}