From 6da90a22a8185a737fc2e390f5ea9f04e79544b4 Mon Sep 17 00:00:00 2001 From: "alqahira%ardisson.org" Date: Mon, 28 Feb 2011 05:56:38 +0000 Subject: [PATCH] Bug Block some Mac charsets. Patch by Simon Montagu , backport by Mike Hommey, r=emk, sr=dveditz, a1.9.0.next=dveditz git-svn-id: svn://10.0.0.236/trunk@261973 18797224-902f-48f8-a5cc-f745e15eee43 --- .../uconv/idl/nsICharsetConverterManager.idl | 16 +++++- mozilla/intl/uconv/idl/nsIScriptableUConv.idl | 13 +++++ mozilla/intl/uconv/src/charsetData.properties | 11 ++++ .../uconv/src/nsCharsetConverterManager.cpp | 37 +++++++++++-- .../uconv/src/nsCharsetConverterManager.h | 3 +- mozilla/intl/uconv/src/nsScriptableUConv.cpp | 27 ++++++++-- mozilla/intl/uconv/src/nsScriptableUConv.h | 4 +- .../intl/uconv/tests/unit/test_bug601429.js | 52 +++++++++++++++++++ .../layout/reftests/bugs/603423-1-ref.html | 7 +++ mozilla/layout/reftests/bugs/603423-1.html | 7 +++ mozilla/layout/reftests/bugs/reftest.list | 1 + mozilla/parser/htmlparser/src/nsScanner.cpp | 12 ++++- .../xpfe/components/intl/nsCharsetMenu.cpp | 4 ++ 13 files changed, 182 insertions(+), 12 deletions(-) create mode 100644 mozilla/intl/uconv/tests/unit/test_bug601429.js create mode 100644 mozilla/layout/reftests/bugs/603423-1-ref.html create mode 100644 mozilla/layout/reftests/bugs/603423-1.html diff --git a/mozilla/intl/uconv/idl/nsICharsetConverterManager.idl b/mozilla/intl/uconv/idl/nsICharsetConverterManager.idl index ef0eb900cfc..7164017ceb3 100644 --- a/mozilla/intl/uconv/idl/nsICharsetConverterManager.idl +++ b/mozilla/intl/uconv/idl/nsICharsetConverterManager.idl @@ -113,10 +113,11 @@ interface nsICharsetConverterManager : nsISupports * character encoding may be used for certain purposes, if it is * multi-byte, and the language code for it. See charsetData.properties * for the source of this data. Some known property names: - * notForBrowser - not to be used in the bowser. + * notForBrowser - not to be used in the browser. * notForOutgoing - not to be used for exporting files. * LangGroup - language code for charset, e.g. 'he' and 'zh-CN'. * isMultibyte - is this a multi-byte charset? + * isXSSVulnerable - not to be used in untrusted web content * * @param charset name of the character encoding, e.g. 'iso-8859-15'. * @param prop property desired for the character encoding. @@ -135,3 +136,16 @@ interface nsICharsetConverterManager : nsISupports nsIAtom getCharsetLangGroup(in string charset); nsIAtom getCharsetLangGroupRaw(in string charset); }; + +[scriptable, uuid(36982132-707c-4d77-b27f-958e76e022de)] +interface nsICharsetConverterManager_1_9_BRANCH : nsICharsetConverterManager +{ + /** + * "Internal" versions of getUnicodeDecoder* will return a decoder for any + * charset; the other versions will return NS_ERROR_UCONV_NOCONV if the + * requested charset is vulnerable to XSS attacks and should not be used + * with untrusted input + */ + nsIUnicodeDecoder getUnicodeDecoderInternal(in string charset); + nsIUnicodeDecoder getUnicodeDecoderRawInternal(in string charset); +}; diff --git a/mozilla/intl/uconv/idl/nsIScriptableUConv.idl b/mozilla/intl/uconv/idl/nsIScriptableUConv.idl index af2e3298a0a..beccd19adad 100644 --- a/mozilla/intl/uconv/idl/nsIScriptableUConv.idl +++ b/mozilla/intl/uconv/idl/nsIScriptableUConv.idl @@ -102,3 +102,16 @@ interface nsIScriptableUnicodeConverter : nsISupports */ attribute string charset; }; + +[scriptable, uuid(f7ed6618-5ff5-4f0b-bb83-48ce63eb289b)] +interface nsIScriptableUnicodeConverter_1_9_BRANCH : nsIScriptableUnicodeConverter +{ + /** + * Internal use + * + * When this attribute is set, all charsets may be accessed. + * When it is not set (the default), charsets with the isXSSVulnerable flag + * may not be accessed + */ + attribute boolean isInternal; +}; diff --git a/mozilla/intl/uconv/src/charsetData.properties b/mozilla/intl/uconv/src/charsetData.properties index 853b3fa5aa8..2819f678aaa 100644 --- a/mozilla/intl/uconv/src/charsetData.properties +++ b/mozilla/intl/uconv/src/charsetData.properties @@ -47,6 +47,10 @@ ## charset_name.notForOutgoing = anything - specifies that this charset is ## not to be used for exporting files ('SaveAsCharset' in composer) ## +## charset_name.isXSSVulnerable = anything - specifies that this charset is +## known to be vulnerable to XSS attacks and should not be exposed to web +## content +## ## charset_name.LangGroup = ## ## charset_name.isMultibyte = multi byte charsets @@ -67,6 +71,13 @@ ibm1131.notForBrowser = true x-ibm1046.notForBrowser = true iso-8859-8-e.notForBrowser = true utf-7.notForBrowser = true +x-mac-arabic.notForBrowser = true +x-mac-farsi.notForBrowser = true +x-mac-hebrew.notForBrowser = true + +x-mac-arabic.isXSSVulnerable = true +x-mac-farsi.isXSSVulnerable = true +x-mac-hebrew.isXSSVulnerable = true t.61-8bit.notForOutgoing = true utf-7.notForOutgoing = true diff --git a/mozilla/intl/uconv/src/nsCharsetConverterManager.cpp b/mozilla/intl/uconv/src/nsCharsetConverterManager.cpp index 5b2dc368abd..19c850358d1 100644 --- a/mozilla/intl/uconv/src/nsCharsetConverterManager.cpp +++ b/mozilla/intl/uconv/src/nsCharsetConverterManager.cpp @@ -69,8 +69,9 @@ // Class nsCharsetConverterManager [implementation] -NS_IMPL_THREADSAFE_ISUPPORTS1(nsCharsetConverterManager, - nsICharsetConverterManager) +NS_IMPL_THREADSAFE_ISUPPORTS2(nsCharsetConverterManager, + nsICharsetConverterManager, + nsICharsetConverterManager_1_9_BRANCH) nsCharsetConverterManager::nsCharsetConverterManager() :mDataBundle(NULL), mTitleBundle(NULL) @@ -222,6 +223,20 @@ nsCharsetConverterManager::GetUnicodeEncoderRaw(const char * aDest, return rv; } +NS_IMETHODIMP +nsCharsetConverterManager::GetUnicodeDecoderRaw(const char * aSrc, + nsIUnicodeDecoder ** aResult) +{ + nsresult rv; + + nsAutoString str; + rv = GetCharsetData(aSrc, NS_LITERAL_STRING(".isXSSVulnerable").get(), str); + if (NS_SUCCEEDED(rv)) + return NS_ERROR_UCONV_NOCONV; + + return GetUnicodeDecoderRawInternal(aSrc, aResult); +} + NS_IMETHODIMP nsCharsetConverterManager::GetUnicodeDecoder(const char * aSrc, nsIUnicodeDecoder ** aResult) @@ -237,8 +252,22 @@ nsCharsetConverterManager::GetUnicodeDecoder(const char * aSrc, } NS_IMETHODIMP -nsCharsetConverterManager::GetUnicodeDecoderRaw(const char * aSrc, - nsIUnicodeDecoder ** aResult) +nsCharsetConverterManager::GetUnicodeDecoderInternal(const char * aSrc, + nsIUnicodeDecoder ** aResult) +{ + // resolve the charset first + nsCAutoString charset; + + // fully qualify to possibly avoid vtable call + nsCharsetConverterManager::GetCharsetAlias(aSrc, charset); + + return nsCharsetConverterManager::GetUnicodeDecoderRawInternal(charset.get(), + aResult); +} + +NS_IMETHODIMP +nsCharsetConverterManager::GetUnicodeDecoderRawInternal(const char * aSrc, + nsIUnicodeDecoder ** aResult) { *aResult= nsnull; nsCOMPtr decoder; diff --git a/mozilla/intl/uconv/src/nsCharsetConverterManager.h b/mozilla/intl/uconv/src/nsCharsetConverterManager.h index 21fcd7a2558..0d21405a09f 100644 --- a/mozilla/intl/uconv/src/nsCharsetConverterManager.h +++ b/mozilla/intl/uconv/src/nsCharsetConverterManager.h @@ -46,10 +46,11 @@ #include "nsINativeUConvService.h" #endif -class nsCharsetConverterManager : public nsICharsetConverterManager +class nsCharsetConverterManager : public nsICharsetConverterManager_1_9_BRANCH { NS_DECL_ISUPPORTS NS_DECL_NSICHARSETCONVERTERMANAGER + NS_DECL_NSICHARSETCONVERTERMANAGER_1_9_BRANCH public: diff --git a/mozilla/intl/uconv/src/nsScriptableUConv.cpp b/mozilla/intl/uconv/src/nsScriptableUConv.cpp index 30a0ecb9f80..9e7d51b44c6 100644 --- a/mozilla/intl/uconv/src/nsScriptableUConv.cpp +++ b/mozilla/intl/uconv/src/nsScriptableUConv.cpp @@ -52,9 +52,12 @@ static PRInt32 gInstanceCount = 0; /* Implementation file */ -NS_IMPL_ISUPPORTS1(nsScriptableUnicodeConverter, nsIScriptableUnicodeConverter) +NS_IMPL_ISUPPORTS2(nsScriptableUnicodeConverter, + nsIScriptableUnicodeConverter, + nsIScriptableUnicodeConverter_1_9_BRANCH) nsScriptableUnicodeConverter::nsScriptableUnicodeConverter() +: mIsInternal(PR_FALSE) { PR_AtomicIncrement(&gInstanceCount); } @@ -270,13 +273,27 @@ nsScriptableUnicodeConverter::SetCharset(const char * aCharset) return InitConverter(); } +NS_IMETHODIMP +nsScriptableUnicodeConverter::GetIsInternal(PRBool *aIsInternal) +{ + *aIsInternal = mIsInternal; + return NS_OK; +} + +NS_IMETHODIMP +nsScriptableUnicodeConverter::SetIsInternal(const PRBool aIsInternal) +{ + mIsInternal = aIsInternal; + return NS_OK; +} + nsresult nsScriptableUnicodeConverter::InitConverter() { nsresult rv = NS_OK; mEncoder = NULL ; - nsCOMPtr ccm = do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv); + nsCOMPtr ccm = do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv); if (NS_SUCCEEDED( rv) && (nsnull != ccm)) { // get charset atom due to getting unicode converter @@ -286,7 +303,11 @@ nsScriptableUnicodeConverter::InitConverter() if(NS_SUCCEEDED(rv)) { rv = mEncoder->SetOutputErrorBehavior(nsIUnicodeEncoder::kOnError_Replace, nsnull, (PRUnichar)'?'); if(NS_SUCCEEDED(rv)) { - rv = ccm->GetUnicodeDecoder(mCharset.get(), getter_AddRefs(mDecoder)); + rv = mIsInternal ? + ccm->GetUnicodeDecoderInternal(mCharset.get(), + getter_AddRefs(mDecoder)) : + ccm->GetUnicodeDecoder(mCharset.get(), + getter_AddRefs(mDecoder)); } } } diff --git a/mozilla/intl/uconv/src/nsScriptableUConv.h b/mozilla/intl/uconv/src/nsScriptableUConv.h index 401d7d09e86..ef2bb941704 100644 --- a/mozilla/intl/uconv/src/nsScriptableUConv.h +++ b/mozilla/intl/uconv/src/nsScriptableUConv.h @@ -44,11 +44,12 @@ #include "nsICharsetConverterManager.h" #include "nsIScriptableUConv.h" -class nsScriptableUnicodeConverter : public nsIScriptableUnicodeConverter +class nsScriptableUnicodeConverter : public nsIScriptableUnicodeConverter_1_9_BRANCH { public: NS_DECL_ISUPPORTS NS_DECL_NSISCRIPTABLEUNICODECONVERTER + NS_DECL_NSISCRIPTABLEUNICODECONVERTER_1_9_BRANCH nsScriptableUnicodeConverter(); virtual ~nsScriptableUnicodeConverter(); @@ -59,6 +60,7 @@ protected: nsCAutoString mCharset; nsCOMPtr mEncoder; nsCOMPtr mDecoder; + PRPackedBool mIsInternal; nsresult FinishWithLength(char **_retval, PRInt32* aLength); nsresult ConvertFromUnicodeWithLength(const nsAString& aSrc, diff --git a/mozilla/intl/uconv/tests/unit/test_bug601429.js b/mozilla/intl/uconv/tests/unit/test_bug601429.js new file mode 100644 index 00000000000..0773da36fdb --- /dev/null +++ b/mozilla/intl/uconv/tests/unit/test_bug601429.js @@ -0,0 +1,52 @@ +const Ci = Components.interfaces; +const Cc = Components.classes; +const CC = Components.Constructor; + +// Tests whether characters above 0x7F decode to ASCII characters liable to +// expose XSS vulnerabilities +function run_test() { + var failures = false; + var ccManager = Cc["@mozilla.org/charset-converter-manager;1"] + .getService(Ci.nsICharsetConverterManager); + + var ScriptableUnicodeConverter = + CC("@mozilla.org/intl/scriptableunicodeconverter", + "nsIScriptableUnicodeConverter"); + var decodingConverter = new ScriptableUnicodeConverter(); + + var charsetList = ccManager.getDecoderList(); + var counter = 0; + while (charsetList.hasMore()) { + ++counter; + var charset = charsetList.getNext(); + dump("testing " + counter + " " + charset + "\n"); + + try { + decodingConverter.charset = charset; + } catch(e) { + dump("Warning: couldn't set decoder charset to " + charset + "\n"); + continue; + } + for (var i = 0x80; i < 0x100; ++i) { + var inString = String.fromCharCode(i); + var outString; + try { + outString = decodingConverter.ConvertToUnicode(inString) + + decodingConverter.Finish(); + } catch(e) { + outString = String.fromCharCode(0xFFFD); + } + for (var n = 0; n < outString.length; ++n) { + var outChar = outString.charAt(n); + if (outChar == '<' || outChar == '>' || outChar == '/') { + dump(charset + " has a problem: " + escape(inString) + + " decodes to '" + outString + "'\n"); + failures = true; + } + } + } + } + if (failures) { + do_throw("test failed\n"); + } +} diff --git a/mozilla/layout/reftests/bugs/603423-1-ref.html b/mozilla/layout/reftests/bugs/603423-1-ref.html new file mode 100644 index 00000000000..b63d88d46f5 --- /dev/null +++ b/mozilla/layout/reftests/bugs/603423-1-ref.html @@ -0,0 +1,7 @@ + + + + Testcase for bug 603423 + +

+ diff --git a/mozilla/layout/reftests/bugs/reftest.list b/mozilla/layout/reftests/bugs/reftest.list index e8057edb87c..fb1eae4b15a 100644 --- a/mozilla/layout/reftests/bugs/reftest.list +++ b/mozilla/layout/reftests/bugs/reftest.list @@ -847,3 +847,4 @@ fails-if(MOZ_WIDGET_TOOLKIT=="gtk2") == 424074-1-ref2.xul 424074-1-ref3.xul == 486848-1.xul 486848-1-ref.xul == 487539-1.html about:blank == 488390-1.html 488390-1-ref.html +== 603423-1.html 603423-1-ref.html diff --git a/mozilla/parser/htmlparser/src/nsScanner.cpp b/mozilla/parser/htmlparser/src/nsScanner.cpp index 4a060af508f..e2ffb3fd46f 100644 --- a/mozilla/parser/htmlparser/src/nsScanner.cpp +++ b/mozilla/parser/htmlparser/src/nsScanner.cpp @@ -187,14 +187,22 @@ nsresult nsScanner::SetDocumentCharset(const nsACString& aCharset , PRInt32 aSou nsIUnicodeDecoder * decoder = nsnull; res = nsParser::GetCharsetConverterManager()-> - GetUnicodeDecoderRaw(mCharset.get(), &decoder); + GetUnicodeDecoderRaw(mCharset.get(), &decoder); + if (NS_FAILED(res)) + { + // GetUnicodeDecoderRaw can fail if the charset has the .isXSSVulnerable + // flag. Try to fallback to ISO-8859-1 + mCharset.AssignLiteral("ISO-8859-1"); + mCharsetSource = kCharsetFromWeakDocTypeDefault; + res = nsParser::GetCharsetConverterManager()-> + GetUnicodeDecoderRaw(mCharset.get(), &decoder); + } if(NS_SUCCEEDED(res) && (nsnull != decoder)) { NS_IF_RELEASE(mUnicodeDecoder); mUnicodeDecoder = decoder; } - return res; } diff --git a/mozilla/xpfe/components/intl/nsCharsetMenu.cpp b/mozilla/xpfe/components/intl/nsCharsetMenu.cpp index 4cde09d0ef0..23bcf128af2 100644 --- a/mozilla/xpfe/components/intl/nsCharsetMenu.cpp +++ b/mozilla/xpfe/components/intl/nsCharsetMenu.cpp @@ -1252,6 +1252,10 @@ nsresult nsCharsetMenu::InitMoreSubmenus(nsCStringArray& aDecs) NS_TIMELINE_START_TIMER("nsCharsetMenu::InitMoreSubmenus"); nsresult res = NS_OK; + + // remove charsets "not for browser" + res = RemoveFlaggedCharsets(aDecs, NS_LITERAL_STRING(".notForBrowser")); + if (NS_FAILED(res)) return res; nsCOMPtr container1; nsCOMPtr container2;