← All issues

[6] MediaPlayerPrivateMediaSourceAVFObjC re-entrant KVO during destruction

Severity: Medium | Component: WebCore platform media | 4193d2c

Rated Medium because the diff fixes a UAF-during-teardown of MediaPlayerPrivateMediaSourceAVFObjC via KVO re-entrancy reading the already-destroyed m_logger; attacker influence is limited to driving the teardown shape, and the immediate effect is a renderer crash rather than a controllable read/write.

Revoke all weak pointers at the start of ~MediaPlayerPrivateMediaSourceAVFObjC() to prevent re-entrant callbacks during member destruction. C++ destroys m_logger before m_mediaSourcePrivate (reverse declaration order), and the m_mediaSourcePrivate destructor can trigger synchronous KVO notifications that invoke WeakPtr-guarded callbacks on the partially-destroyed object. Since the CanMakeWeakPtr base class destructor runs after all member destructors, WeakPtr::get() still succeeds, allowing callbacks to access already-destroyed members.

Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.mm

MediaPlayerPrivateMediaSourceAVFObjC::~MediaPlayerPrivateMediaSourceAVFObjC()
{
ALWAYS_LOG(LOGIDENTIFIER);
 
+ // Prevent re-entrant callbacks during member destruction. Without this,
+ // KVO notifications fired during m_mediaSourcePrivate's destruction can
+ // call back into this partially-destroyed object via WeakPtr-guarded
+ // callbacks (such as the error callback calling setNetworkState(),
+ // which accesses the already-destroyed m_logger).
+ weakPtrFactory().revokeAll();
+
cancelPendingSeek();
m_seekTimer.stop();
dispatchToRendererQueue([](auto& renderer) {
renderer.pause();
});
}

A single line is added at the top of the destructor: weakPtrFactory().revokeAll(). This invalidates all outstanding WeakPtrs pointing at this object so any KVO notifications fired later during destruction of members like m_mediaSourcePrivate cannot resolve their WeakPtr back to the now partially-destroyed instance.

Failure to invalidate weak references before destroying members reachable by re-entrant callbacks during teardown.

WeakPtr in WebKit is a non-owning reference backed by a WeakPtrFactory stored on the target via the CanMakeWeakPtr CRTP base; WeakPtr::get() returns null only after the factory has been revoked or destroyed. In C++, members of a derived class are destroyed in reverse declaration order, then base destructors run; the CanMakeWeakPtr destructor that revokes the factory is a base destructor and therefore runs after all derived-class member destructors. KVO (Key-Value Observing) is Cocoa's observer pattern, and AVFoundation objects fire KVO notifications synchronously to registered observers. MediaPlayerPrivateMediaSourceAVFObjC owns m_mediaSourcePrivate (a MediaSourcePrivateAVFObjC) and a Logger reference m_logger. setNetworkState() is the standard MediaPlayer hook used to surface network state changes and in this implementation it logs through m_logger.

The destructor relied on the default CanMakeWeakPtr teardown ordering: the WeakPtrFactory is only revoked when the base destructor runs, which is after all derived-class members have already been destroyed. During member destruction (specifically m_mediaSourcePrivate's destructor), AVFoundation can synchronously fire KVO notifications. Those notifications are wired through WeakPtr-guarded callbacks; because the factory has not yet been revoked, WeakPtr::get() still returns a non-null pointer.

🔒

The ownership and destructor-ordering implications of this bug, and whether the resulting crash can be escalated beyond a renderer DoS, are analyzed in depth.

Subscribe to read more

🔒

Multiple reusable audit patterns identified for finding sibling bugs across WebKit's Cocoa-observer-owning classes, with concrete starting points for variant discovery.

Subscribe to read more