Bug 188410 - InputType should not interact with an HTMLInputElement is no longer associated with
Summary: InputType should not interact with an HTMLInputElement is no longer associate...
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: DOM (show other bugs)
Version: WebKit Nightly Build
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Chris Dumez
URL:
Keywords: InRadar
: 186321 (view as bug list)
Depends on:
Blocks:
 
Reported: 2018-08-08 09:36 PDT by Chris Dumez
Modified: 2018-08-21 16:02 PDT (History)
8 users (show)

See Also:


Attachments
Patch (135.24 KB, patch)
2018-08-08 13:01 PDT, Chris Dumez
no flags Details | Formatted Diff | Diff
Patch (2.70 KB, patch)
2018-08-09 15:45 PDT, Chris Dumez
no flags Details | Formatted Diff | Diff
Patch (3.43 KB, patch)
2018-08-09 16:02 PDT, Chris Dumez
no flags Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Chris Dumez 2018-08-08 09:36:06 PDT
InputType does not need to be RefCounted and probably shouldn't be.
Comment 1 Ryosuke Niwa 2018-08-08 12:11:31 PDT
(In reply to Chris Dumez from comment #0)
> InputType does not need to be RefCounted and probably shouldn't be.

There are cases in which InputType needs to outlive the element itself. We can talk about it offline.
Comment 2 Chris Dumez 2018-08-08 12:49:24 PDT
(In reply to Ryosuke Niwa from comment #1)
> (In reply to Chris Dumez from comment #0)
> > InputType does not need to be RefCounted and probably shouldn't be.
> 
> There are cases in which InputType needs to outlive the element itself. We
> can talk about it offline.

InputType was not refcounted until recently so I find it surprising. My patch also does not cause any failures.

Will upload the patch in a bit so we can discuss.
Comment 3 Chris Dumez 2018-08-08 12:50:55 PDT
(In reply to Chris Dumez from comment #2)
> (In reply to Ryosuke Niwa from comment #1)
> > (In reply to Chris Dumez from comment #0)
> > > InputType does not need to be RefCounted and probably shouldn't be.
> > 
> > There are cases in which InputType needs to outlive the element itself. We
> > can talk about it offline.
> 
> InputType was not refcounted until recently so I find it surprising. My
> patch also does not cause any failures.
> 
> Will upload the patch in a bit so we can discuss.

And to be clear I am aware of why it was made refcounted in the first place but have a different proposal to deal with the issue.
Comment 4 Chris Dumez 2018-08-08 13:01:54 PDT
Created attachment 346785 [details]
Patch
Comment 5 EWS Watchlist 2018-08-08 13:04:17 PDT
Attachment 346785 [details] did not pass style-queue:


ERROR: Source/WebCore/ChangeLog:9:  Please consider whether the use of security-sensitive phrasing could help someone exploit WebKit: use-after-free  [changelog/unwantedsecurityterms] [3]
Total errors found: 1 in 31 files


If any of these errors are false positives, please file a bug against check-webkit-style.
Comment 6 Ryosuke Niwa 2018-08-08 19:15:10 PDT
Comment on attachment 346785 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=346785&action=review

r- because of this will re-introduce the bug making InputType RefCounted fixed.

> Source/WebCore/ChangeLog:29
> +        1. Use a EventQueueScope to dealy the firing of events, which we already do in a few places

We can't do this for the particular use-after-free at hand.
We discussed this possibility in length and concluded that it's not viable.
Comment 7 Ryosuke Niwa 2018-08-08 19:15:45 PDT
If you want to re-open this issue, please talk to me in person before doing so. There are some details I can talk about outside the security component.
Comment 8 Ryosuke Niwa 2018-08-08 19:38:56 PDT
The fundamental problem is that EventQueueScope is really broken. I initially introduced it to workaround the most egregious security bugs in editing and a few other places but it probably should never have existed. It was probably one giant mistake.
Comment 9 Chris Dumez 2018-08-08 20:17:13 PDT
(In reply to Ryosuke Niwa from comment #8)
> The fundamental problem is that EventQueueScope is really broken. I
> initially introduced it to workaround the most egregious security bugs in
> editing and a few other places but it probably should never have existed. It
> was probably one giant mistake.

Did you look at the patch? I am NOT using EventQueueScope. I am using weakThis check. I looked at the original radar and made sure my patch addresses that crash.

Also, as explained in my change log the current code is wrong. Even though the lifetime  of the InputType got extended, it is does not get detached from its Element when the element changes input type. Therefore, after you change the input's type, the old InputType can keep messing with an HTMLInputElement it is no longer associated with.

Reopening since this issue (mentioned in my change log) needs to be addressed, one way or another.
Comment 10 Chris Dumez 2018-08-08 20:23:25 PDT
(In reply to Chris Dumez from comment #9)
> (In reply to Ryosuke Niwa from comment #8)
> > The fundamental problem is that EventQueueScope is really broken. I
> > initially introduced it to workaround the most egregious security bugs in
> > editing and a few other places but it probably should never have existed. It
> > was probably one giant mistake.
> 
> Did you look at the patch? I am NOT using EventQueueScope. I am using
> weakThis check. I looked at the original radar and made sure my patch
> addresses that crash.
> 
> Also, as explained in my change log the current code is wrong. Even though
> the lifetime  of the InputType got extended, it is does not get detached
> from its Element when the element changes input type. Therefore, after you
> change the input's type, the old InputType can keep messing with an
> HTMLInputElement it is no longer associated with.
> 
> Reopening since this issue (mentioned in my change log) needs to be
> addressed, one way or another.

Also note that I did discuss my proposal with Brent before implementing this.
Comment 11 Ryosuke Niwa 2018-08-08 20:26:42 PDT
Okay. Then did you run Speedoemter, Dromaeo, & PLT with this change?
Comment 12 Chris Dumez 2018-08-08 20:29:04 PDT
(In reply to Ryosuke Niwa from comment #11)
> Okay. Then did you run Speedoemter, Dromaeo, & PLT with this change?

If people agree with the direction, I would be happy to run those benchmarks. You kinda forced me to upload a patch early to discuss by closing my bug before it even had a patch.
Comment 13 Ryosuke Niwa 2018-08-08 20:32:09 PDT
If the issue we're trying to address is that we're not clearing the element reference in InputType, then that should be clearly stated in the bug title & description.

There is another approach to this problem which is to make InputType store WeakPtr to HTMLInputElement, or clear the pointer when InputType gets disassociated from Element.
Comment 14 Ryosuke Niwa 2018-08-08 20:32:24 PDT
Having said that now that I understand what you're trying to do, I think either approach is fine.
Comment 15 Chris Dumez 2018-08-08 20:37:20 PDT
(In reply to Ryosuke Niwa from comment #13)
> If the issue we're trying to address is that we're not clearing the element
> reference in InputType, then that should be clearly stated in the bug title
> & description.
> 
> There is another approach to this problem which is to make InputType store
> WeakPtr to HTMLInputElement, or clear the pointer when InputType gets
> disassociated from Element.

Actually, Brent already landed a follow-up change to have InputType store a WeakPtr to its HTMLInputElement instead of a C++ reference, in order to address new crashes. While it fixed those crashes, it does not exactly address the issue I mentioned, since an HTMLInputElement can stay alive but be associated to a new InputType (when its type attribute is changed).

However, nulling out the m_element pointer when the HTMLInputElement is no longer associated with the InputType would address the issue I mentioned. I thought about this. The reason I did not go with this approach is that it is not clear when you need to null check m_element or not. Right now, most places do not null check m_element (even though it is weak), they merely assert it is not null.
Comment 16 Ryosuke Niwa 2018-08-08 20:49:41 PDT
There is one drawback with this approach, which is that now every member function of InputType MUST have a local Ref/RefPtr to the element since otherwise "this" object can be deleted if it involves any function which may execute scripts.

And after invoking any function which may execute script, it must check that the input type associated with the retained element didn't change its type (otherwise, we'd have a type confusion bug).
Comment 17 Ryosuke Niwa 2018-08-08 20:57:06 PDT
Comment on attachment 346785 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=346785&action=review

> Source/WebCore/html/CheckboxInputType.cpp:88
> +        element().setIndeterminate(state.indeterminate);
> +        element().setChecked(state.checked);

This code for example should have ScriptDisallowedScope::InMainThread or have a Ref/RefPtr to Element
since setIndeterminate is a non-trivial function which can be modified in the future to dispatch an event.
Comment 18 Ryosuke Niwa 2018-08-08 21:04:30 PDT
My recommendation still is to keep InputType ref-counted and clear the element pointer.

Many WebKit engineers know how to use Ref/RefPtr correctly in most cases. In my experience, whenever we introduced a complicated lifecycle management like one object owning another via unique_ptr, etc... someone eventually comes around and introduce a new security bug.
Comment 19 Chris Dumez 2018-08-09 08:43:10 PDT
(In reply to Chris Dumez from comment #12)
> (In reply to Ryosuke Niwa from comment #11)
> > Okay. Then did you run Speedoemter, Dromaeo, & PLT with this change?
> 
> If people agree with the direction, I would be happy to run those
> benchmarks. You kinda forced me to upload a patch early to discuss by
> closing my bug before it even had a patch.

I triggered A/B analysis tasks for these benchmarks.
Comment 20 Chris Dumez 2018-08-09 08:45:14 PDT
(In reply to Ryosuke Niwa from comment #18)
> My recommendation still is to keep InputType ref-counted and clear the
> element pointer.
> 
> Many WebKit engineers know how to use Ref/RefPtr correctly in most cases. In
> my experience, whenever we introduced a complicated lifecycle management
> like one object owning another via unique_ptr, etc... someone eventually
> comes around and introduce a new security bug.

The whole reason I started this is because of https://bugs.webkit.org/show_bug.cgi?id=186321. How are people supposed to know when to null-check element or not?

As I mentioned on that bug, we could go the direction you suggest but then we'd likely want to null check element everywhere? This could likely have a perf impact though.
Comment 21 Chris Dumez 2018-08-09 08:45:46 PDT
(In reply to Ryosuke Niwa from comment #17)
> Comment on attachment 346785 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=346785&action=review
> 
> > Source/WebCore/html/CheckboxInputType.cpp:88
> > +        element().setIndeterminate(state.indeterminate);
> > +        element().setChecked(state.checked);
> 
> This code for example should have ScriptDisallowedScope::InMainThread or
> have a Ref/RefPtr to Element
> since setIndeterminate is a non-trivial function which can be modified in
> the future to dispatch an event.

Sure we could add ScriptDisallowedScope::InMainThread in more places.
Comment 22 Chris Dumez 2018-08-09 08:48:07 PDT
(In reply to Ryosuke Niwa from comment #16)
> There is one drawback with this approach, which is that now every member
> function of InputType MUST have a local Ref/RefPtr to the element since
> otherwise "this" object can be deleted if it involves any function which may
> execute scripts.

This is inaccurate, you do not need to refcount your element. As a matter of fact you likely should not. If you ref the element and use your local variable then you still have the issue that you may interact with an element that is no longer associated with you.

The way I suggest and use in my patch is to use a weakThis variable and return early if it becomes null as a result of calling script.

> 
> And after invoking any function which may execute script, it must check that
> the input type associated with the retained element didn't change its type
> (otherwise, we'd have a type confusion bug).

Commented above.
Comment 23 Chris Dumez 2018-08-09 15:45:48 PDT
Created attachment 346867 [details]
Patch
Comment 24 Chris Dumez 2018-08-09 16:02:24 PDT
Created attachment 346869 [details]
Patch
Comment 25 WebKit Commit Bot 2018-08-09 16:56:49 PDT
Comment on attachment 346869 [details]
Patch

Clearing flags on attachment: 346869

Committed r234744: <https://trac.webkit.org/changeset/234744>
Comment 26 WebKit Commit Bot 2018-08-09 16:56:51 PDT
All reviewed patches have been landed.  Closing bug.
Comment 27 Radar WebKit Bug Importer 2018-08-09 16:57:18 PDT
<rdar://problem/43117754>
Comment 28 Brent Fulgham 2018-08-21 16:02:10 PDT
*** Bug 186321 has been marked as a duplicate of this bug. ***