[하루한줄] CVE-2021-26863: race condition을 통한 win32k 커널 UAF 취약점

URL

Issue 2139: Windows Kernel win32k UAF of the PDEVOBJ object via a race condition in NtGdiGetDeviceCapsAll

Target

  • win32k kernel

Explain

Google Project Zero팀이 Windows Kernel에서 발생하는 race condition을 통한 UAF 취약점의 세부 보고서를 공개했습니다.

취약점이 존재하는 NtGdiGetDeviceCapsAll 함수는 GDI에서 내부적으로 사용하는 system call입니다.

...
BOOL NtGdiGetDeviceCapsAll(HDC hdc, DEVCAPS *devcaps) {
	BOOL bRet = TRUE;
	PDEVOBJ *pdevobj;

	if (PsGetWin32KFilterSet() == 5 && hdc == 0xFFFFFFFFDCDE5000) {
		pdevobj = gpDispInfo->pdevobj;
	// DCOBJ scope
	} else {
		DCOBJ dc(hdc); //[1]

		if (!dc.valid) {
			EngSetLastError(ERROR_INVALID_HANDLE);
			DCOBJ::~DCOBJ(dc);
			return FALSE;
		}

		pdevobj = dc.pdevobj;
		DCOBJ::~DCOBJ(dc);
	}
	// DCOBJ scope

__try {
	ProbeForWrite(devcaps, sizeof(DEVCAPS), 1);
	vGetDeviceCaps(pdevobj, devcaps);  //[2]
	}except(EXCEPTION_EXECUTE_HANDLER) {
		bRet = FALSE;
	}

	return bRet;
}
...

해당 함수는 Device Context(DC) 핸들을 얻어 장치 정보를 DEVCAPS 구조체에 저장하는 기능을 수행합니다.

DCOBJ 객체인 dcelse 문 내부에서 선언해 해당 객체의 scope가 else문으로 한정됩니다. 또한 객체가 syscall 전체에서 활성화된 상태를 유지할 수 있는 메커니즘이 존재하지 않아 else 코드를 벗어나면 DCOBJ::~DCOBJ(dc) 소멸자가 자동으로 호출되어 dc에 대한 참조가 삭제됩니다. 결과적으로 dc를 참조하는 pdevobj 객체가 race condition의 영향을 받습니다.

위 취약점을 악용해 [1]에서 DCOBJ생성자에 의해 참조된 이후 다른 스레드가 [2]에서 vGetDeviceCaps() 호출 전 또는 도중 Device Context를 닫는 경우 해제된 메모리에 액세스 할 수 있습니다.