[하루한줄] CVE-2021-29628 : PlayStation5 SMAP Bypass
URL
Target
PlayStation5, FreeBSD 12
Explain
SMAP(Supervisor-Mode Access Prevention)은 커널에서 유저랜드 메모리에 접근하지 못하게 하여 취약점 익스플로잇을 어렵게 하는 커널 레벨 보호기법입니다.
PlayStation 5(이하 PS5)는 FreeBSD 12 기반으로 개발된 운영체제인 Orbis 2.0을 사용합니다. CVE-2021-29628은 FreeBSD 12에서 발견됐었던 취약점이지만, PS5에서 이 취약점에 대해 패치를 하지 않아 PS5에서 SMAP를 bypass할 수 있었습니다.
PS5에서 SMAP가 활성화되어 있는 상태(Rflags
의 Alignment Check Flag
, %RFLAGS.AC
가 세팅되지 않은 상태)에서 커널에서 유저 페이지에 접근하면 page fault가 발생합니다. 반면에 %RFLAGS.AC
가 세팅되지 않은 상태에서는 커널에서 정상적으로 유저 페이지에 접근이 가능합니다. 하지만 FreeBSD 커널에서는 copyin()
과 copyout()
함수들을 통해 %RFLAGS.AC
를 잠시 세팅해서 유저 페이지에 접근합니다.
.macro COPYIN smap erms
/* ... */
movq $copy_fault,PCB_ONFAULT(%r11)
/* ... */
stac // set %RFLAGS.AC, to allow access to user pages
do_the_copyin
clac // clear %RFLAGS.AC, to forbid access to user pages
/* ... */
copy_fault:
movq $0,PCB_ONFAULT(%r11)
movl $EFAULT,%eax
POP_FRAME_POINTER
ret
copyin()
함수가 실행되면 fault handler인 copy_fault()
함수를 handler로 등록한 후 %RFLAGS.AC
를 세팅해 복사 작업을 진행합니다. 그리고 복사 작업이 끝나면 다시 %RFLAGS.AC
를 클리어합니다. 이 때, 복사 과정에서 fault가 발생하면 trap()
함수가 실행됩니다.
void
trap(struct trapframe *frame)
{
/* ... */
if (curpcb->pcb_onfault != NULL) {
frame->tf_rip = (long)curpcb->pcb_onfault;
return;
}
/* ... */
}
trap()
함수에서는 curpcb->pcb_onfault
에 값이 들어가 있으면 이 안에 값을 fram→tf_rip
에 넣고 바로 return 하는데, 이 때 %RFLAGS.AC
를 클리어하지 않아 SMAP이 비활성화인 상태로 핸들링을 마무리합니다. 따라서 이를 통해 SMAP를 bypass하여 이 이후의 syscall들을 SMAP이 비활성화된 상태에서 실행할 수 있습니다.
본 글은 CC BY-SA 4.0 라이선스로 배포됩니다. 공유 또는 변경 시 반드시 출처를 남겨주시기 바랍니다.