[7] GameControllerGamepad UAF from raw this capture in framework-retained blocks
Severity: Medium | Component: WebCore Gamepad | 101c855
컨트롤러 연결 해제 시 UAF crash가 재현 가능한 수준으로 확인된 점에서 취약점의 존재는 분명합니다. 다만 exploit을 위해서는 물리적 또는 가상 HID 장치에 대한 접근이 필요하며, 웹 콘텐츠만으로는 유발할 수 없습니다. race window도 좁아 UI process context임에도 불구하고 안정적인 exploit은 어렵습니다. 이런 이유로 Medium으로 평가되었습니다.
Objective-C callback block에서 raw this 캡처를 WeakPtr과 null 검사 방식으로 교체했습니다. 또한 객체가 소멸될 때 모든 GameController framework handler를 해제하도록 teardownElements()를 호출하는 destructor가 추가되었습니다.
Source/WebCore/platform/gamepad/cocoa/GameControllerGamepad.mm
void GameControllerGamepad::setupElements()
{
RetainPtr<GCPhysicalInputProfile> profile = m_gcController.get().physicalInputProfile;
+ WeakPtr weakThis { *this };
if ([profile respondsToSelector:@selector(setThumbstickUserIntentHandler:)]) {
[profile setThumbstickUserIntentHandler:^(__kindof GCPhysicalInputProfile*, GCControllerElement*) {
- m_lastUpdateTime = MonotonicTime::now();
- GameControllerGamepadProvider::singleton().gamepadHadInput(*this, true);
+ if (!weakThis)
+ return;
+ weakThis->m_lastUpdateTime = MonotonicTime::now();
+ weakThis->m_lastUpdateTime = MonotonicTime::now();
+ GameControllerGamepadProvider::singleton().gamepadHadInput(*weakThis, true);
}];
}
+GameControllerGamepad::~GameControllerGamepad()
+{
+ teardownElements();
+}
+void GameControllerGamepad::teardownElements()
+{
+ auto profile = RetainPtr { m_gcController.get().physicalInputProfile };
+ if (!profile)
+ return;
+
+ if ([profile respondsToSelector:@selector(setThumbstickUserIntentHandler:)])
+ [profile setThumbstickUserIntentHandler:nil];
+
+ for (GCControllerButtonInput *button in [profile allButtons])
+ button.valueChangedHandler = nil;
+
+ profile.get().dpads[GCInputLeftThumbstick].xAxis.valueChangedHandler = nil;
+ profile.get().dpads[GCInputLeftThumbstick].yAxis.valueChangedHandler = nil;
+ profile.get().dpads[GCInputRightThumbstick].xAxis.valueChangedHandler = nil;
+ profile.get().dpads[GCInputRightThumbstick].yAxis.valueChangedHandler = nil;
+}
Tools/TestWebKitAPI/Tests/mac/HIDGamepads.mm
+TEST(Gamepad, DisconnectDuringInput)
+{
+ // Tests that handler blocks don't crash when invoked after GameControllerGamepad destruction.
+ ...
+ for (int i = 0; i < 100; ++i) {
+ gamepad->setAxisValue(0, (float)i / 100.0);
+ gamepad->setAxisValue(1, (float)(100 - i) / 100.0);
+ gamepad->publishReport();
+ }
+
+ // This destroys VirtualGamepad, which triggers controllerDidDisconnect,
+ // which destroys GameControllerGamepad.
+ gamepad = nullptr;
+
+ // Wait for disconnect message.
+ Util::run(&didReceiveMessage);
+}
Patch Details
패치는 세 가지 변경으로 구성됩니다.
첫째, setupElements()에 WeakPtr weakThis { *this } 캡처가 추가되었습니다. 모든 callback block은 멤버 변수에 접근하기 전에 if (!weakThis) return; 검사를 수행하도록 변경되었습니다.
둘째, 새로운 ~GameControllerGamepad() destructor가 추가되어 teardownElements()를 호출합니다.
셋째, 새로운 teardownElements() 메서드가 추가되었습니다. 이 메서드는 GCPhysicalInputProfile에 등록된 모든 handler block을 nil로 설정하여, 객체 소멸 이후 framework가 callback을 호출하지 못하도록 차단합니다.
이 수정은 belt-and-suspenders 방식을 채택했습니다. WeakPtr null 검사(심층 방어)와 handler 해제(주요 수정)를 함께 적용했습니다. 다만 한 가지 주목할 점이 있습니다. axis handler block은 멤버 접근에 weakThis를 사용하면서도 gamepadHadInput()에는 *weakThis 대신 여전히 *this를 전달하고 있어, 미처 수정되지 않은 부분으로 보입니다. 단, teardownElements()가 소멸 시점에 handler를 초기화하므로 이 문제는 완화됩니다.
Background
Gamepad API는 물리적 게임 컨트롤러를 웹 콘텐츠에 노출하는 기능입니다. Apple 플랫폼에서 WebKit은 GCController, GCPhysicalInputProfile 등 GameController framework를 통해 입력 이벤트를 수신합니다. 입력 handler는 버튼, 축, 썸스틱 등 컨트롤러 요소에 Objective-C block 형태로 등록됩니다. 이 block들은 framework가 retain하며, 하드웨어에서 새로운 입력이 발생할 때 비동기적으로 호출됩니다. 따라서 이 block의 생명주기는 이를 등록한 C++ 객체가 아닌 Objective-C runtime에 의해 관리됩니다.
WeakPtr는 참조 대상이 소멸될 때 자동으로 무효화되는 weak reference로, retain된 callback에서 객체의 유효성을 안전하게 확인할 수 있게 해줍니다. 명시적인 정리 작업이 없으면 framework 객체가 캡처한 Objective-C block은 무기한 유지되며, 캡처된 참조도 함께 살아남게 됩니다.
Analysis
C++ 객체보다 오래 유지되는 framework-retained callback block의 raw this 캡처로 인한 use-after-free.
패치 이전에는 GameControllerGamepad::setupElements()가 raw this 포인터를 캡처하는 Objective-C block callback을 GameController framework에 등록했습니다. 이 block들은 GCController의 input profile이 retain하며, 물리적 컨트롤러에서 입력이 발생할 때마다 비동기적으로 호출될 수 있었습니다.
GameControllerGamepad 객체가 소멸될 때(예: 컨트롤러 연결 해제 시) 이 handler를 해제하는 destructor가 존재하지 않았습니다. 그 결과 GameController framework는 계속해서 block을 보유했습니다. 이 상태에서 대기 중이거나 새로 유입된 입력 이벤트가 callback을 호출하면, 이미 해제된 this 포인터를 역참조하게 되었습니다. 이 과정에서 m_axisValues, m_buttonValues, m_lastUpdateTime에 쓰기가 발생하고, gamepadHadInput()에 dangling reference가 전달되었습니다.
Aaa Aaaa a Aaaa Aaaaaaa Aa Aaaaaa Aaaaaaaaaaaaaaaaaa Aaa Aa Aaa a Aaaaaaaa a Aaaaaaaaa Aa Aaaaa Aaaaaa Aaa Aaaa Aaaaa Aaaaaaaaaaa Aaa Aa Aaa Aaaa Aaaa Aaa Aaa Aaaa Aaaaaa
Aa Aaa Aaaaaaa Aaaaaa Aa Aaaaaaaaa Aaaa Aaa a Aa Aaaaa Aa Aaa a Aaaa Aaaa a Aaaaa Aa Aa Aaaaaaaa Aaa Aaaaaaa Aaaaaaaaaaaaaaaaaaaaaaaa Aaaa Aaaa Aa Aa Aaa Aaa Aa Aaa Aaaaaaaa Aaa Aaaa Aa Aa Aaa Aa Aaaa Aa Aaa Aaaaaa
Aa Aa Aa Aa Aaaaaaaaa Aaaa Aaaaa Aaaaaa Aaaa Aaa Aaaa Aaaa Aaaaa Aaaa Aa Aaaaaaaaa Aaa Aaa Aaaaaaa Aaaaa a Aaaa Aaa a a Aa Aaaaa Aa Aaaaaaaa Aaaaaa Aaa Aaa Aa Aaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaaaaa Aaaaaa Aaa Aaaaaaaaaaa Aaaa Aaaa Aaaa Aaaaaa a Aaa Aa Aaa Aa Aa Aaaa Aaaa
Aaaaaaaaaaaaaa Aaaaaaaaaaaa Aaaaaaa Aaa Aaaaaaaaaa Aaaaaaaa Aa Aaaaa Aa Aaaaaaaaa Aaaaaaaaa Aaaaaaa Aaa Aaaaaaa Aaa Aaaaaaaa Aaa Aa Aaaa Aaaa Aaa Aa Aa Aaa Aaa Aa Aaa Aaaaa Aa Aaaaaaaaaaaaaaa Aa Aaaaaa
a Aaaaaaaaaaaaaa Aaaaaaaaaaaaaa Aaaaaaaaaaaa Aaaa Aaaaaaaa Aaaaaa Aaaaaaa Aaaaaaa Aa Aa Aaa Aaaa Aa Aaa Aa Aa Aaa Aaaa Aaaaaaaa Aaaaaaa Aaaaaaaaaaaa Aaaa Aaaa Aaaaaaaaaa Aaaaaaa
🔒Explores the heap exploitation potential of the dangling-pointer writes and the process-level implications of where this code executes
더 확인하려면 구독해 주세요
Audit directions
a Aaaaaaa Aaaaaaaaaaaaaaa Aaaaaaaaaaaaaa Aaaaaaaaaaaaa Aaaaaaaaa a Aaaaaaaaa Aa Aaa Aaaaaaa Aaaa Aaaaaaaaaaa Aaaaaa Aaaa Aaa Aaa Aaa Aaaaaaaaaaaa Aaaaaaaa Aaaa Aaa Aaaaaa Aaaa Aa Aaaaaa Aaaaa Aaaa Aaaaaaaaaaaaaaaaaaaaaa Aaaaaaaaaaaaa Aa Aaaaaaa Aa Aaa Aa Aaaa Aaaaa Aaa Aaaaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaa a Aa Aaaaaaaaaaa Aaaaaaaaaaaaaaa Aaaaaaaaaaaaaaaa Aaa Aa Aaaaaa
a Aaaaaaa Aa Aaa a Aa Aaaaaaaa Aaaaaa Aaaaaaaa Aaaa Aaaa Aaa Aaaaaa Aaa Aaaa Aaaa Aaaaaaa Aaaaaaa Aa Aaaaaaaaa a Aa Aaaa Aaaaaaaaaaaaaaaaaaaaa Aaaaaa Aa Aaaa Aaaaaaaaaaa Aaaaaa Aaaaaaaaaaaaaaaaaaaaa Aaaaaaaaaaa Aa Aaaaaaaa Aaaa Aaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa a Aaaa Aaa Aaa Aaaaa Aa Aaaaa Aaaaa Aa Aaa Aa Aaaaaaaaaaa Aaaaaaa Aaa Aaa Aaaaaaa
a Aaaaaaa Aaaaaaaa Aaaaaaaaaaa Aaaaa Aaaaaaaaaaa Aa Aa Aaa Aaaaaaaaaaaaaaaaaaaaaaaa Aa Aa Aaa Aaaaaaaaaaa Aaaaaa Aa Aaaaaaaaaaaaaaaaa Aaaaa a Aaa Aaaaaaaa Aaaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaaaaa Aaaaaaaaa Aaaa a Aaaaaaaaaaa Aaa Aaa Aaaaaaa Aaaaaaaaaaaaa Aaaaaaaaaaaaa Aaa Aaaaaaaa Aaa Aaaaaaaaa Aaa Aaaaaaaaaaaa Aaaa Aa Aaaa Aaaaaaa
🔒Multiple audit patterns identified for framework callback lifetime issues across WebKit's platform integration layers, with concrete search targets
더 확인하려면 구독해 주세요