New issue
Advanced search Search tips

Issue 658599 link

Starred by 1 user

Issue metadata

Status: Verified
Owner: ----
Closed: May 2017
Cc:
Components:
EstimatedDays: ----
NextAction: ----
OS: Linux
Pri: 3
Type: Bug-Security



Sign in to add a comment

Heap-use-after-free in blink::HTMLMediaElement::startPlayerLoad

Project Member Reported by ClusterFuzz, Oct 23 2016

Issue description

Detailed report: https://cluster-fuzz.appspot.com/testcase?key=5300755356712960

Fuzzer: inferno_twister
Job Type: linux_asan_content_shell_drt
Platform Id: linux

Crash Type: Heap-use-after-free READ 8
Crash Address: 0x60d00007d310
Crash State:
  blink::HTMLMediaElement::startPlayerLoad
  blink::HTMLMediaElement::loadResource
  blink::HTMLMediaElement::loadSourceFromAttribute
  
Recommended Security Severity: High

Regressed: https://cluster-fuzz.appspot.com/revisions?job=linux_asan_content_shell_drt&range=381067:381276

Minimized Testcase (76.31 Kb): https://cluster-fuzz.appspot.com/download/AMIfv96HTHo61EjU82ed92e1SuH3lNSSRD_Ewmu9YXwmFipQcbJyE5or1UduA8Z6kiBAr9A3HauzBgup9ueIaISoT0YfTJdW-fdn7_pXYY5pclZjdLjLjazYt3EPwuX52tGKCzACUBNPMxyNB2JUJtlhWiltIcPW_usuoSR7MkvwD5rlq6_zQJM?testcase_id=5300755356712960

Issue filed automatically.

See https://dev.chromium.org/Home/chromium-security/bugs/reproducing-clusterfuzz-bugs for more information.
 
Project Member

Comment 1 by sheriffbot@chromium.org, Oct 24 2016

Labels: M-54
Project Member

Comment 2 by sheriffbot@chromium.org, Oct 24 2016

Labels: Pri-1

Comment 3 by ta...@google.com, Oct 25 2016

Components: Blink>HTML
Owner: srirama.m@chromium.org
Status: Assigned (was: Untriaged)

Comment 4 by aarya@google.com, Oct 25 2016

Cc: dalecur...@chromium.org
Components: -Blink>HTML Blink>Media
Owner: xhw...@chromium.org
Project Member

Comment 5 by sheriffbot@chromium.org, Nov 7 2016

xhwang: Uh oh! This issue still open and hasn't been updated in the last 14 days. This is a serious vulnerability, and we want to ensure that there's progress. Could you please leave an update with the current status and any potential blockers?

If you're not the right owner for this issue, could you please remove yourself as soon as possible or help us find the right one?

If the issue is fixed or you can't reproduce it, please close the bug. If you've started working on a fix, please set the status to Started.

Thanks for your time! To disable nags, add the Disable-Nags label.

For more details visit https://www.chromium.org/issue-tracking/autotriage - Your friendly Sheriffbot

Comment 6 by xhw...@chromium.org, Nov 12 2016

Status: Started (was: Assigned)
I'll take a look.

Comment 7 by xhw...@chromium.org, Nov 15 2016

It seems we are still trying to use m_webAudioSourceProvider after it's freed (as part of WMPI dtor):

https://cs.chromium.org/chromium/src/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp?rcl=1479169028&l=4105

Comment 8 by xhw...@chromium.org, Nov 15 2016

Cc: rtoy@chromium.org

Comment 9 by xhw...@chromium.org, Nov 16 2016

Cc: jrumm...@chromium.org foolip@chromium.org
https://codereview.chromium.org/1522463003/ seems to be related. But from code inspection I don't see anything obvious.

I downloaded the binary and can repro when serving the test case through file:///. But it doesn't repro when I serve the test case through http://. Since the issue is "loadResource" related. This actually makes some sense.

I'll look more into this.


I can repro this in a debug build now :)
This can be repro'ed by:
- set SRC url
- internals.setMediaElementNetworkState(audio, 0); // NETWORK_EMPTY
- play()

During play() (playInternal()), since network state is EMPTY, we'll call invokeResourceSelectionAlgorithm() [0].

Then invokeResourceSelectionAlgorithm() will call scheduleNextSourceChild(), which will schedule the loaderTimer and finally trigger this callstack:

    #1 0xbb20e63 in blink::HTMLMediaElement::startPlayerLoad(blink::KURL const&) 
    #2 0xbb1ad15 in blink::HTMLMediaElement::loadResource(blink::WebMediaPlayerSource const&, blink::ContentType const&) 
    #3 0xbb19739 in blink::HTMLMediaElement::loadSourceFromAttribute() 
    #4 0xbb185b3 in blink::HTMLMediaElement::selectMediaResource() 
    #5 0xbb14c2c in blink::HTMLMediaElement::loadInternal()
    #6 0xbb0bb15 in blink::HTMLMediaElement::loadTimerFired(blink::TimerBase*) 

In startPlayerLoad() we'll reset m_webMediaPlayer [1], which is causing the use-after-free.

Clearly, startPlayerLoad() expects m_webMediaPlayer to be null at the beginning of the function [2]. So it seems to me the caller of invokeResourceSelectionAlgorithm() should make sure we have cleared/reset m_webMediaPlayer. This is true for invokeLoadAlgorithm(), but not the case for other callers like playInternal() and pauseInternal().

On the other hand, from the spec, NETWORK_EMPTY means "the element has not yet been initialized. All attributes are in their initial states". So it seems to me when network state is NETWORK_EMPTY, we should be able to dcheck m_webMediaPlayer is null. With that, it seems to me internals.setMediaElementNetworkState(audio, 0) should reset m_webMediaPlayer and other states. Does this make sense?

dalecurtis / foolip: WDYT?


[0] https://cs.chromium.org/chromium/src/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp?rcl=1479284732&l=2286
[1] https://cs.chromium.org/chromium/src/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp?rcl=1479284732&l=1173
[2] https://cs.chromium.org/chromium/src/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp?rcl=1479284732&l=1135
This sounds similar to the "FIXME: remove m_webMediaPlayer check once we figure out how m_webMediaPlayer is going out of sync with readystate" that we have in a few places, but instead for networkState.

Just based on what makes sense, I think that NETWORK_EMPTY should imply !m_webMediaPlayer, but the reverse need not be true, as one goes to NETWORK_NO_SOURCE before actually having a source to load.

As implemented, I'd expect both DCHECK(!m_webMediaPlayer) and DCHECK_EQ(m_networkState, kNetworkEmpty) to hold at the top of HTMLMediaElement::invokeResourceSelectionAlgorithm. If either can be made to fail without the use of internals, that sounds like something to fix.

Note: looking at "invoke the media element's resource selection algorithm" calls in https://html.spec.whatwg.org/multipage/embedded-content.html there is one case where the networkState assert wouldn't hold, but HTMLMediaElement::invokeLoadAlgorithm resets networkState where the spec doesn't, because the resource selection algorithm will change it again as its first step.
Thanks!

By looking at our code (well, from code search), Chromium will never set networkState to NetworkStateEmpty. So it seems to me this issue will not happen in production. I wonder whether this will change the priority and/or the security severity of this issue.

I think it makes a lot sense to reset m_webMediaPlayer when networkState becomes NetworkStateEmpty. This is consistent with the spec, and makes things much easier to reason about.

I'd like to keep this change simple, so that if needed, we can merge it back. Long term, after the FIXME is fixed, hopefully things will be in a much better shape.
I tried to clearMediaPlayer() when we set networkState to NETWORK_EMPTY. But it's causing other issues :(

There are multiple issues here.

# For the spec:

NETWORK_EMPTY (numeric value 0):
The element has not yet been initialized. All attributes are in their initial states.

play(): 
1. If the media element's networkState attribute has the value NETWORK_EMPTY, invoke the media element's resource selection algorithm.
2. If the playback has ended...

The question is, after step 1, why don't we return immediately? If "the element was not initialized and all attibutes are in their initial states", why do we care about "if the playback has ended"?

# For the implementation:

In both playInternal() and pauseInternal(), if networkState is NETWORK_EMPTY, we call invokeResourceSelectionAlgorithm() and continue. This maps the spec text. But then we call updatePlayState(), which is causing trouble.

updatePlayState() has logic like this:

void HTMLMediaElement::updatePlayState() {
  bool isPlaying = webMediaPlayer() && !webMediaPlayer()->paused();
  bool shouldBePlaying = potentiallyPlaying();

  if (shouldBePlaying) {
    if (!isPlaying) {
      webMediaPlayer()->setRate(playbackRate());
      ...
    }
  }

When webMediaPlayer() is null, isPlayering is false. But potentiallyPlaying() doesn't check webMediaPlayer(). So we could end up calling webMediaPlayer()->setRate() when webMediaPlayer() is null...

Does it make sense to check webMediaPlayer() in potentiallyPlaying()?

Personally I feel we need a lot of DCHECKs in HTMLMediaElement to make sure our design assumptions are legit and enforced.
foolip/dalecurtis: Please see the discussion above. Right now I don't have any good idea how to fix this given the complexity involved :)

Since this can only be triggered through "internals", I feel this should not be Security_Impact-Stable.
Also, does it make sense to disallow setting network state to EMPTY through "internals"? This is breaking a lot of assumptions we have in the code.
Cc: mlamouri@chromium.org
#15, in https://html.spec.whatwg.org/multipage/embedded-content.html#dom-media-play there isn't a return after "invoke the media element's resource selection algorithm" because the steps that follow (setting paused to false) will cause the media to eventually play, even though at the time the network request has (at best) just started.

When things blow up in HTMLMediaElement::updatePlayState(), why did potentiallyPlaying() return true? Was pausedToBuffer true? And what was readyState? Maybe  m_readyStateMaximum needs to be reset in some case where m_readyState is set back to 0?
Labels: -M-54 M-56
Labels: -M-56 M-55
foolip: I am really not familiar with the interaction of the states in HTMLMediaElement. Instead of trying to understand more how things work in this file, I feel I should reassign this issue to a better owner of this file. Do you mind taking this bug over? Or who do you think will be the best owner?
Cc: -mlamouri@chromium.org
Owner: mlamouri@chromium.org
Status: Assigned (was: Started)
I volunteer mlamouri@, please reassign if that won't work.
Project Member

Comment 24 by sheriffbot@chromium.org, Dec 7 2016

mlamouri: Uh oh! This issue still open and hasn't been updated in the last 44 days. This is a serious vulnerability, and we want to ensure that there's progress. Could you please leave an update with the current status and any potential blockers?

If you're not the right owner for this issue, could you please remove yourself as soon as possible or help us find the right one?

If the issue is fixed or you can't reproduce it, please close the bug. If you've started working on a fix, please set the status to Started.

Thanks for your time! To disable nags, add the Disable-Nags label.

For more details visit https://www.chromium.org/issue-tracking/autotriage - Your friendly Sheriffbot
Cc: xhw...@chromium.org
Project Member

Comment 26 by sheriffbot@chromium.org, Dec 23 2016

Labels: Deadline-Exceeded
We commit ourselves to a 60 day deadline for fixing for high severity vulnerabilities, and have exceeded it here. If you're unable to look into this soon, could you please find another owner or remove yourself so that this gets back into the security triage queue?

For more details visit https://www.chromium.org/issue-tracking/autotriage - Your friendly Sheriffbot
Project Member

Comment 27 by sheriffbot@chromium.org, Jan 26 2017

Labels: -M-55 M-56
Ping - is there any progress on resolving this issue?
Labels: -Security_Impact-Stable Security_Impact-None
Moving this to "Security_Impact-None" as it can only apply with the use of `internals`.
Cc: mlamouri@chromium.org
Labels: -Pri-1 -M-56 Pri-3
Owner: ----
Status: Available (was: Assigned)
Project Member

Comment 31 by ClusterFuzz, May 12 2017

ClusterFuzz has detected this issue as fixed in range 471033:471049.

Detailed report: https://clusterfuzz.com/testcase?key=5300755356712960

Fuzzer: inferno_twister
Job Type: linux_asan_content_shell_drt
Platform Id: linux

Crash Type: Heap-use-after-free READ 8
Crash Address: 0x60d00007d310
Crash State:
  blink::HTMLMediaElement::startPlayerLoad
  blink::HTMLMediaElement::loadResource
  blink::HTMLMediaElement::loadSourceFromAttribute
  
Sanitizer: address (ASAN)

Recommended Security Severity: High

Regressed: https://clusterfuzz.com/revisions?job=linux_asan_content_shell_drt&range=381067:381276
Fixed: https://clusterfuzz.com/revisions?job=linux_asan_content_shell_drt&range=471033:471049

Reproducer Testcase: https://clusterfuzz.com/download?testcase_id=5300755356712960


See https://dev.chromium.org/Home/chromium-security/bugs/reproducing-clusterfuzz-bugs for more information.

If you suspect that the result above is incorrect, try re-doing that job on the test case report page.
Project Member

Comment 32 by ClusterFuzz, May 12 2017

Labels: ClusterFuzz-Verified
Status: Verified (was: Available)
ClusterFuzz testcase 5300755356712960 is verified as fixed, so closing issue.

If this is incorrect, please add ClusterFuzz-Wrong label and re-open the issue.
Project Member

Comment 33 by sheriffbot@chromium.org, May 12 2017

Labels: -Restrict-View-SecurityTeam Restrict-View-SecurityNotify
Project Member

Comment 34 by sheriffbot@chromium.org, Aug 18 2017

Labels: -Restrict-View-SecurityNotify allpublic
This bug has been closed for more than 14 weeks. Removing security view restrictions.

For more details visit https://www.chromium.org/issue-tracking/autotriage - Your friendly Sheriffbot

Sign in to add a comment