Closed Bug 319847 Opened 19 years ago Closed 19 years ago

CVE-2006-0296 XULDocument.persist() allows an attacker to inject bogus RDF data into localstore.rdf

Categories

(Core :: Security, defect, P2)

x86
Windows XP
defect

Tracking

()

VERIFIED FIXED
mozilla1.9alpha1

People

(Reporter: moz_bug_r_a4, Assigned: mrbkap)

References

Details

(Keywords: fixed1.7.13, verified1.8.0.1, verified1.8.1, Whiteboard: [sg:critical])

Attachments

(3 files, 2 obsolete files)

XULDocument.persist() function doesn't verify whether the second argument is
a valid attribute name.  Thus, an attacker can inject bogus RDF data into
localstore.rdf in order to run arbitrary code.

Steps to Reproduce:
1. Load testcase, and click "Click me!" button.
2. Shutdown the browser.
3. (See the content of localstore.rdf.)
4. Start the browser.

An alert dialog that shows Components.stack will appear.


This affects:
Firefox 1.0.7, 1.5 and trunk
Mozilla 1.7.12
I can reproduce on 1.0.7 but not in 1.5. Will play more tomorrow, I can't think of any changes that would "fix" this in 1.5.
Depends on: CVE-2008-5505
Flags: blocking1.8.0.1+
Flags: blocking1.7.13+
Flags: blocking-aviary1.0.8+
Whiteboard: [sg:critical]
I think Axel worked on this in the RDF serializer layer.
When any of the following condition is satisfied, you can't reproduce on 1.5
and trunk.

1) localstore.rdf contains many data.

In this case, JS console shows many "junk after document element" error and one
"[nsIRDFService.GetDataSource]" error on startup.

Error: junk after document element
Source File: file:///C:/Profiles/Firefox/fx-1.5/localstore.rdf
Line: 11, Column: 1
Source Code:
<RDF:RDF a="#"^

Error: uncaught exception: [Exception... "Component returned failure code: 
0x8000ffff (NS_ERROR_UNEXPECTED) [nsIRDFService.GetDataSource]"  nsresult: 
"0x8000ffff (NS_ERROR_UNEXPECTED)"  location: "JS frame :: 
chrome://browser/content/search.xml :: initialize :: line 94"  data: no]


2) xmlns:NS1 already exists.

(due to the RDF serializer issue: Bug 307558 comment 17)

I will attach new testcase that could deal with 2).
Attached file testcase 3 (obsolete) —
This could deal with the RDF serializer issue.
Would it be possible and feasable for nsXULDocument::Persist to escape its input here?
The escaping should be performed by the serializer, not by the client code.
Attached file testcase 4
This should work even when localstore.rdf contains many data.
I need to pick out bsmedberg or axel on IRC to explain to me exactly how the second argument to persist ends up being a _namespace_ in the serialized RDF document, and we need to make sure bugs are filed on the fact that the RDF content sink will gladly accept a malformed XML file as input, but this patch fixes the exploit by making sure that the argument to persist is not able to take over the rest of the file by escaping it (do I need to actually do that string copy?).
Assignee: dveditz → mrbkap
Status: NEW → ASSIGNED
Attachment #205810 - Flags: review?
Attachment #205810 - Flags: review? → review?(benjamin)
Comment on attachment 205810 [details] [diff] [review]
Fix the serializer, v1

doh! /me wonders why we didn't do this before...

I'd like Pike to look at this, but I don't know what his travel situation is; let's get this landed on trunk and get him to ex-post-facto review this before putting it on branch.
Attachment #205810 - Flags: review?(benjamin) → review+
Comment on attachment 205810 [details] [diff] [review]
Fix the serializer, v1

Looks good to me.
Attachment #205810 - Flags: review+
Fix checked into trunk.
Status: ASSIGNED → RESOLVED
Closed: 19 years ago
Priority: -- → P2
Resolution: --- → FIXED
Target Milestone: --- → mozilla1.9alpha
It's still exploitable.

http://lxr.mozilla.org/mozilla/source/rdf/base/src/nsRDFXMLSerializer.cpp#228
228 nsresult
229 nsRDFXMLSerializer::RegisterQName(nsIRDFResource* aResource)
230 {
231     nsCAutoString uri, qname;
232     aResource->GetValueUTF8(uri);
233 
234     nsNameSpaceMap::const_iterator iter = mNameSpaces.GetNameSpaceOf(uri);
235     if (iter != mNameSpaces.last()) {
236         NS_ENSURE_TRUE(iter->mPrefix, NS_ERROR_UNEXPECTED);
237         iter->mPrefix->ToUTF8String(qname);
238         qname.Append(':');
239         qname += StringTail(uri, uri.Length() - iter->mURI.Length());
240         return mQNames.Put(aResource, qname) ? NS_OK : NS_ERROR_FAILURE;
241     }

When the second argument to persist is a string beginning with an existing
namespace URI, the substring following the namespace URI part ends up being
treated as the local part of the qualified name.  Thus, an attacker can still
inject any string without being escaped.

Is it possible to do nsContentUtils::CheckQName for |aAttr| at 
nsXULDocument::Persist?
Status: RESOLVED → REOPENED
Resolution: FIXED → ---
Attached file testcase 5
injects bogus RDF data into the local part of the qualified name.
Damnit, I was looking at the QName stuff when I found the namespace problem, but managed to get myself turned around by all of the Gets and Sets.
Status: REOPENED → ASSIGNED
bsmedberg and I talked about this on IRC, and we concluded that the easiest way to deal with the case of a malformed QName is to simply stop its setting in the XUL document. I'll open another bug on making the serializer itself deal with malformed URIs and QNames.

This patch is slightly ugly because I had to copy the logic to find the QName from the RDF serializer. We might want to consider putting a function to do that on the RDF service to avoid this sort of code duplication. It also would have been nice to have a RFindCharInReadable in nsReadableUtils (I'll look into adding one).
Attachment #206041 - Flags: superreview?(jst)
Attachment #206041 - Flags: review?
Comment on attachment 206041 [details] [diff] [review]
Protect the serializer from itself

+    // XXX Why does this use RFindChar for the hash mark?

Is that question answered by "RDF vocabularies favor http://someurl/for/vocab#item for resources, with QName being vocab:item"?
(In reply to comment #18)
> Is that question answered by "RDF vocabularies favor
> http://someurl/for/vocab#item for resources, with QName being vocab:item"?

Not quite. Given http://someurl/for/vocab#item#foo, we'll currently use a namespace of "http://someurl/for/vocab#item#" and a name of "foo", whereas most of the times I've seen URL parsers do this, they've treated the _first_ hash as the end of the URL (and beginning of the resource name). I'm actually tempted to also throw an error (in nsXULDocument::Persist) if there is more than one # mark.
I don't really have the relevant specs at my finger tip, but both the URL and
the XML QName specs are involved here. Is foo:bar#item a valid QName? A pound in
a namespace is surely OK, so I'd have no problem with keeping it this way.

I won't look that up in the specs today, though.
No that isn't a valid qname, but I'm not sure if my example is a valid URL either (I'm not even sure which spec covers URLs).
Actually, persist is completely broken with any namespaced attribute (or rather,
working ones are just coincidence), so nsXULDocument::Persist should bail on 
anything that is not an NCName, http://www.w3.org/TR/xml-names11/#NT-NCName.

The right fix for namespaces and persist is to store the localname and the
namespace separatly, no way around it. Just try to part "urn:x-foo:bar" "item"
after making one string out of it.
Attached patch Enforce the 2nd argument (obsolete) — Splinter Review
The second argument to persist should be a QName, so we should verify that. We might as well let a namespace specifier get in (it can't hurt if content can say NC:foo, right?). This patch stops all testcases here cold.
Attachment #206041 - Attachment is obsolete: true
Attachment #206125 - Flags: superreview?(jst)
Attachment #206125 - Flags: review?(axel)
Attachment #206041 - Flags: superreview?(jst)
Attachment #206041 - Flags: review?
Attachment #206125 - Flags: review?(benjamin)
Comment on attachment 206125 [details] [diff] [review]
Enforce the 2nd argument

QNames are not supported. They just don't work.

See
http://lxr.mozilla.org/seamonkey/source/content/xul/document/src/nsXULDocument.cpp#1147
http://lxr.mozilla.org/seamonkey/source/content/xul/document/src/nsXULDocument.cpp#2310

It may be sensible to throw a NS_ERROR_NOT_IMPLEMENTED in the case of a non-NCName QName, though, instead of an INVALID_ARG
Attachment #206125 - Flags: review?(axel) → review-
Attachment #206125 - Attachment is obsolete: true
Attachment #206132 - Flags: superreview?(jst)
Attachment #206132 - Flags: review?(axel)
Attachment #206125 - Flags: superreview?(jst)
Attachment #206125 - Flags: review?(benjamin)
Attachment #206132 - Flags: review?(benjamin)
Comment on attachment 206132 [details] [diff] [review]
No namespace qualifiers

sr=jst
Attachment #206132 - Flags: superreview?(jst) → superreview+
Comment on attachment 206132 [details] [diff] [review]
No namespace qualifiers

Our namespace handling in xul:persist is so screwed up :-(
Attachment #206132 - Flags: review?(benjamin) → review+
I've checked the last fix into the trunk. Hopefully this plugs nsXULDocument::Persist for good.
Status: ASSIGNED → RESOLVED
Closed: 19 years ago19 years ago
Resolution: --- → FIXED
Attachment #206132 - Flags: review?(axel) → review+
Comment on attachment 206132 [details] [diff] [review]
No namespace qualifiers

a=schrep for Drivers.  This bug should have landed before the freeze since it was nominated as a blocker.
Attachment #206132 - Flags: approval1.8.0.1+
I checked attachment 206132 [details] [diff] [review] into the branches.
I am trying to verify this on the branch, and I followed the initial STR and and ran testcase 1 - I did not get the alert dialog - is this enough to verify? 
You should get an error in your javascript console, as well.
reproduced testcase 5 with vanilla firefox 1.5 but not with 1.8.0.1, 1.8.1 1.9a1 on winxp from 20060112 where it generated:
Error: uncaught exception: [Exception... "Component returned failure code: 0x80070057 (NS_ERROR_ILLEGAL_VALUE) [nsIDOMXULDocument.persist]"  nsresult: "0x80070057 (NS_ERROR_ILLEGAL_VALUE)"  location: "JS frame :: https://bugzilla.mozilla.org/attachment.cgi?id=205981&action=view :: a :: line 19"  data: no]
Status: RESOLVED → VERIFIED
Flags: testcase?
Flags: testcase? → testcase+
Summary: XULDocument.persist() allows an attacker to inject bogus RDF data into localstore.rdf → CVE-2006-0296 XULDocument.persist() allows an attacker to inject bogus RDF data into localstore.rdf
For reference, the trunk patch mostly applied to 1.0.x; there was also a build error because nsContentUtils::GetParserService() did not exist in 1.0.x -- the line needed to be changed to reference nsContentUtils::GetParserServiceWeakRef().
Checked into aviary101/moz17 branches
Attachment #210095 - Flags: approval1.7.13+
Attachment #210095 - Flags: approval-aviary1.0.8+
v.fixed on 1.0.8 Aviary with Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.12) Gecko/20060209 Firefox/1.0.7 with the various testcases in this bug.
Group: security
Flags: in-testsuite+ → in-testsuite?
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: