← All issues

[11] RenderLayer Re-Entrancy During Reflection Layer Teardown

Severity: Medium | Component: WebCore RenderLayerCompositor | ecde527

child teardown 과정에서 부분적으로 파괴된 RenderLayer에 접근하는 현상이 관측 가능한 영향이며, debug 빌드에서는 CheckedPtr을 통한 assertion 실패로 나타납니다. CheckedPtr 도입 이전 release 빌드에서는 유효하지 않은 메모리에 접근했을 가능성이 있으나, 구체적인 memory corruption primitive는 특정되지 않았습니다. 실제 exploit이 시연된 것이 아니라 fuzzer가 새 assertion을 발생시키면서 노출된 버그이므로, Medium으로 평가합니다.

RenderLayer::removeChild()에서, 제거 대상 child가 reflection layer인 경우 compositor().layerWillBeRemoved() 호출을 건너뛰는 guard가 추가되었습니다.

Source/WebCore/rendering/RenderLayer.cpp

void RenderLayer::removeChild(RenderLayer& oldChild)
{
- if (!renderer().renderTreeBeingDestroyed())
+ if (!renderer().renderTreeBeingDestroyed() && !isReflectionLayer(oldChild))
compositor().layerWillBeRemoved(*this, oldChild);
 
// remove the child

LayoutTests/fast/reflections/reflection-removed-crash-2.html

+<style>
+ rt {
+ translate: 23% 80cap 1svi;
+ -webkit-box-reflect: below;
+ }
+</style>
+ <script>
+ (async () => {
+ let n1 = document.createElement('ruby');
+ document.documentElement.appendChild(n1);
+ n1.appendChild(document.createElement('rt'));
+ let n7 = document.createElement('object');
+ n7.id = 'n4';
+ n1.append(document.createElement('rt'));
+ })();
+ testRunner?.dumpAsText();
+ </script>

render layer tree의 child teardown 과정에서 부분적으로 파괴된 객체에 re-entrant하게 접근하는 패턴.

RenderLayer는 render tree 내 compositing layer를 나타내는 WebKit의 객체로, child layer들과 함께 트리 구조를 형성합니다. reflection layer는 -webkit-box-reflect CSS 속성에 의해 생성되는 특수 child layer로, parent layer의 시각적 내용을 그대로 반사합니다. RenderLayerCompositor::layerWillBeRemoved()는 layer가 제거되려 한다는 사실을 compositor에 통지하며, 이를 통해 composited ancestor에서 repaint가 발생합니다. 여기서 composited ancestor란 자체 compositing backing store를 갖는 가장 가까운 ancestor layer를 의미합니다.

reflection layer를 포함한 RenderLayer가 소멸될 때, reflection child가 먼저 제거됩니다. removeChild()compositor().layerWillBeRemoved(*this, oldChild)를 호출하고, 이 호출은 다시 repaintInCompositedAncestor()로 이어집니다. 이때 reflection layer의 composited ancestor가 현재 소멸 중인 parent layer인 경우, 해당 코드는 부분적으로 파괴된 객체를 대상으로 동작하게 됩니다. 306315@main에서 도입된 CheckedPtr은 pointer가 scope를 벗어날 때 composited ancestor의 유효성을 assertion하는 방식으로 이 문제를 표면화했습니다. 다만 근본적인 버그는 그 이전부터 존재했습니다. 소멸이 진행 중인 layer에 접근하는 코드가 이미 있었던 것입니다.

🔒

Explores the object lifecycle implications and whether the partially-destroyed state could be leveraged beyond a crash

더 확인하려면 구독해 주세요

🔒

Multiple audit patterns identified around render layer teardown re-entrancy, with concrete starting points in the compositor notification infrastructure

더 확인하려면 구독해 주세요