Closed Bug 326501 Opened 19 years ago Closed 18 years ago

Content can implement tree views and trigger memory corruption

Categories

(Core :: XUL, defect)

All
Linux
defect
Not set
critical

Tracking

()

RESOLVED FIXED

People

(Reporter: bzbarsky, Assigned: roc)

References

Details

(Keywords: fixed1.8.1, testcase, verified1.8.0.4, Whiteboard: [sg:critical?] [need testing on 1.7 branch with 1.7 branch tree apis])

Attachments

(4 files)

See bug 325236.  The testcase there exploits a bug in page info, but content can just implement a tree view itself and stick alerts in it, thus leading to dead rendering surfaces.  Jag has a testcase he's going to attach.

On trunk, cairo will make the gfx code in question die, but we're still left with arbitrary JS running (and triggering DOM mutations, reflow, etc) while inside Paint().  That's really not a good idea.

Options I see:

1)  Disallow unprivileged tree views.
2)  Change trees somehow to not call into the view during Paint()

Any other ideas?

This probably affects at least the 1.8 branch; we might be safe on 1.7 with the old tree API; not sure.
Flags: blocking1.9a1?
Flags: blocking1.8.1?
Flags: blocking1.8.0.2?
Whiteboard: [need testing on 1.7 branch with 1.7 branch tree apis]
2) would be ideal. We'd like to support trees for untrusted content.
Agreed.  The problem is I'm not sure how much of the tree arch (and especially performance) is tied to calling getCellText() only in Paint()...

Note also that any getCellText() call can destroy the tree frame.  So doing anything after calling getCellText() is no good, pretty much.
Group: security
The whole tree arch depends on calling tree view methods during Paint().
If you want to avoid it, you will have to cache it somehow, but that would lead to much increased memory footprint IMO.
(In reply to comment #4)
> The whole tree arch depends on calling tree view methods during Paint().
> If you want to avoid it, you will have to cache it somehow, but that would lead
> to much increased memory footprint IMO.

One solution is to disallow unprivileged tree models, and then provide one (or more) tree model implementations that unprivileged content can use.  For example, one that lets you set up # of columns, and then has addrow/deleterow/setvalue operations on it; all the TreeView callbacks would go to the well-behaved model impl, which would have all the data in memory.  I don't think unprivileged content will be doing all that interesting things with native trees anyway..
is this linux only?

don't crash on win32/wine
don't crash on mac osx
(In reply to comment #5)
>One solution is to disallow unprivileged tree models, and then provide one (or
>more) tree model implementations that unprivileged content can use.
Trees default to the DOM model (there are cases where they get the RDF model but that's only useful for sorting). How would they access these other models?
(In reply to comment #5)
> I don't think unprivileged content will be doing all that interesting things
> with native trees anyway..

I don't want to assume this.

However, it seems to me that the best architecture for "asychronous" untrusted tree views (where tree cell data is not fetched during Paint, but Paint triggers loading of cell data with update of the tree when the data arrives, and cell data is cached and prefetched for performance/responsiveness) would be to have a regular synchronous, trusted treeview implementation which delegates to the untrusted one --- keeps the complexity out of the already-nasty tree code. So then, I say we go for requiring treeviews to be trusted.
So perhaps when a view is being set we should just check whether the caller context is system and if it's not wrap the view being set in a trusted one?  If we could check whether the view being set is already trusted that would be nice too; perhaps if it is get the underlying view and rewrap it (I don't think we want to assume anything about the claims of a tree view to being trusted).
So, how is this trusted view supposed to work? At the moment, I'm guessing:
* The frame makes a request
* The view logs that the request was made
* The view queues an event (if there isn't one already queued)
* The view returns the last cached value
* The event fires
* The view queries the script for the actual value(s)
* For each value that has changed, the view requests a repaint
Yeah, that sounds about right to me.
Though the view also needs to have some provisions for dropping data at times, possibly...  otherwise it seems like unbounded memory growth can happen easily.
modifying the testcase

getImageSrc: function(row,col){ return "javascript:alert(this)"; },

gives a strange warning:

JavaScript error: , line 0: uncaught exception: Permission denied to get property Window.alert

don't know in what context the js is tried to execute.
> don't know in what context the js is tried to execute.

The JS context was that of the window involved.  The security context was the one created from the "javascript:" URI (basically, as close to the non-principal as we can get right now).  See http://lxr.mozilla.org/seamonkey/source/dom/src/jsurl/nsJSProtocolHandler.cpp#245
(In reply to comment #11)
> So, how is this trusted view supposed to work? At the moment, I'm guessing:
> * The frame makes a request
> * The view logs that the request was made
> * The view queues an event (if there isn't one already queued)
> * The view returns the last cached value
> * The event fires
> * The view queries the script for the actual value(s)
> * For each value that has changed, the view requests a repaint

Something like that, but that discussion belongs in a different bug. We should make this bug just be about requiring tree views to be trusted.
(In reply to comment #13)
> Though the view also needs to have some provisions for dropping data at times,
> possibly...  otherwise it seems like unbounded memory growth can happen easily.
> 

We might end up with building real content and frames after all :)
The tree widget is quite complex and "nasty" because it implements many things on its own for performance reasons.

The old tree widget was buggy and slow, but it supported almost the same API as other widgets, so it didn't confuse XUL developers as the current widget does.
The outliner/new tree widget is very fast, but it has grown into a monster and doesn't fit the current layout code or plans for other layout changes in future.

There are other things like in-line editing (textbox, menulist), arbitrary content in rows, rows with different height.
These things are hard to implement and would make things even more complex.

Maybe it's time to design tree widget v3 :)

My $0.02
I think it should be possible to design a new high-performance, high-function tree widget with little or no Gecko support. Make the core of it an overflow:hidden box. On scrolling, just shuffle around the content children and/or repopulate them with new data. But that discussion also belongs elsewhere...
(In reply to comment #19)
> I think it should be possible to design a new high-performance, high-function
> tree widget with little or no Gecko support. Make the core of it an
> overflow:hidden box. On scrolling, just shuffle around the content children
> and/or repopulate them with new data. But that discussion also belongs
> elsewhere...
> 

Yeah, that would be great.
I just wanted to express my opinion on that.
(In reply to comment #19)
>I think it should be possible to design a new high-performance, high-function tree
>widget with little or no Gecko support. Make the core of it an overflow:hidden box.
Isn't that what a <listbox> is trying to be?
(In reply to comment #21)
> (In reply to comment #19)
> >I think it should be possible to design a new high-performance, high-function tree
> >widget with little or no Gecko support. Make the core of it an overflow:hidden box.
> Isn't that what a <listbox> is trying to be?
> 

I think listbox is overflow-y:auto

Someone please file a new bug for new tree design.
making the testcase a little more invalid produces this bad sounding assertion:

###!!! ASSERTION: XPConnect is being called on a scope without a 'Components' property!

This is pretty much always bad. It usually means that native code is
making a callback to an interface implemented in JavaScript, but the
document where the JS object was created has already been cleared and the
global properties of that document's window are *gone*. Generally this
indicates a problem that should be addressed in the design and use of the
callback code.
: 'Error', file /opt/firefox-cvs/mozilla/js/src/xpconnect/src/xpcwrappednativescope.cpp, line 589
Break: at file /opt/firefox-cvs/mozilla/js/src/xpconnect/src/xpcwrappednativescope.cpp, line 589
###!!! ASSERTION: XPConnect is being called on a scope without a 'Components' property!
"assert no Components" must be reloaded for the assertion.
Blocks: 327126
Isn't looking like a 1.8.0.2 patch is a reasonable expectation.
Flags: blocking1.8.0.2? → blocking1.8.0.2-
Flags: blocking1.8.0.3?
Any thoughts on how to workaround this bug for 1.8.0.x?  Any takers?
Comment 11 is about it, as far as I can tell.
I thought we were just going to go with comment #10 and disable tree views from untrusted content.
OK.  Is someone willing to cut a patch for that?
I'm working on it. Actually we only need to disable untrusted content setting a non-native tree view.
-> roc
Assignee: Jan.Varga → roc
Attached patch fixSplinter Review
Fairly simple. The psuedointerface approach to marking treeviews as usable by untrusted script isn't ideal, perhaps, but it's good enough as far as I can tell.
Attachment #216077 - Flags: superreview?(bzbarsky)
Attachment #216077 - Flags: review?(bzbarsky)
Note that if we land this, we need to tell XUL developers somehow.
What is this code trying to accomplish? Disable using custom nsITreeViews from remote content?

If so, allowing setting it to anything doesn't serve any purpose for remote content. You seem to be explicitly allowing it to be set to the builder view, which will already be set automatically if needed, and the sql database view (not built by default), which doesn't make any sense since it can't be used from remote content anyway.
OK. Is it okay to assume that we won't add any other tree views that we want to make accessible to remote XUL?
Given the number of bugs we've had filed that used custom tree views, I'm not sure whether disabling custom tree views will break xul-based intranet apps...  I say "not sure" because those testcases may have been reduced from extensions, of course.

Hence the proposal to have a built-in wrapper for these custom views -- it would allow us to make this safe without regressing functionality (hopefully).
That is considerably more work and I hadn't really intended to suggest that approach as a security fix. Getting it right wouldn't be easy, and I suspect that it'd be simpler and more reliable for intranet apps to just get UniveralBrowserWrite.
Comment on attachment 216077 [details] [diff] [review]
fix

OK, fair enough.

>Index: content/base/src/nsContentUtils.cpp

>+  if (nsContentUtils::IsCallerChrome())
>+    return PR_TRUE;

Not sure it's really worth doing this check up front, since for chrome all capabilities are always enabled and figuring that out is pretty fast.  I'd just do the capability checks here.

r+sr=bzbarsky with that.
Attachment #216077 - Flags: superreview?(bzbarsky)
Attachment #216077 - Flags: superreview+
Attachment #216077 - Flags: review?(bzbarsky)
Attachment #216077 - Flags: review+
Flags: blocking1.9a1?
Flags: blocking1.9a1+
Flags: blocking1.8.1?
Flags: blocking1.8.1+
Flags: blocking1.8.0.3?
Flags: blocking1.8.0.3+
Flags: blocking1.7.14?
Flags: blocking-aviary1.0.9?
Whiteboard: [need testing on 1.7 branch with 1.7 branch tree apis] → [sg:critical?] [need testing on 1.7 branch with 1.7 branch tree apis]
checked in.
Status: NEW → RESOLVED
Closed: 18 years ago
Resolution: --- → FIXED
Comment on attachment 216077 [details] [diff] [review]
fix

Need branch approvals for this 1.8.1/1.8.0.3 blocker.
Attachment #216077 - Flags: approval1.8.0.3?
Attachment #216077 - Flags: approval-branch-1.8.1?(bzbarsky)
Attachment #216077 - Flags: approval-branch-1.8.1?(bzbarsky) → approval-branch-1.8.1+
today linux trunk doesn't crash on the testcases and gives error

Error: uncaught exception: [Exception... "Security error"  code: "1000" nsresult: "0x805303e8 (NS_ERROR_DOM_SECURITY_ERR)"  location: "chrome://global/content/bindings/tree.xml Line: 0"]
Comment on attachment 216077 [details] [diff] [review]
fix

approved for 1.8.0 branch, a=dveditz for drivers
Attachment #216077 - Flags: approval1.8.0.3? → approval1.8.0.3+
v.fixed on 1.8.0 branch: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.2) Gecko/20060420 Firefox/1.5.0.2, no crash, but I see the same exception as Georgi:
Error: uncaught exception: [Exception... "Security error"  code: "1000" nsresult: "0x805303e8 (NS_ERROR_DOM_SECURITY_ERR)"  location: "chrome://global/content/bindings/tree.xml Line: 0"]

If there are any other testcases that will test whether or not this will break existing functionality, please let us know.
Group: security
Component: XP Toolkit/Widgets: Trees → XUL
QA Contact: xptoolkit.trees → xptoolkit.widgets
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: