[CVE-2023-20593] AMD VECTOR REGISTER FILE ZENBLEED 취약점

https://www.amd.com/en/resources/product-security/bulletin/amd-sb-7008.html

 

Cross-Process Information Leak

 

www.amd.com

 

AMD에서 Cross-Process Information Leak가 올라왔습니다. Side Channel 취약점이므로 한번 작성해보고 싶었습니다.

구글 보안팀에서 취약점 리서처로 근무하시는 Tavis Ormandy님이 찾은 취약점으로 위험도는 Medium으로 분류되었습니다.

 

Zen2 CPU가 레지스터의 0에 기록하지 못 하는 버그로 YMM 레지스터에 저장되어 사용자 데이터에 접근이 가능한 버그입니다.

이미 2세대 에픽 프로세서에는 보안 패치를 제공한 상태입니다.

 

작동원리

x86-64 CPU는 128bit의 XMM 레지스터는 메모리를 어드레싱하지 않고 계산할 수 있습니다.

이는 256bit의 YMM 레지스터, 512bit의 ZMM 레지스터로 확장될 수 있습니다. (XMM은 ZMM의 하위 128bit입니다)

 

이런 큰 레지스터들은 stcmp, memcpy, strlen과 같은 C 표준 라이브러리 함수들에서도 사용됩니다.

예를들어 glibc의 AVX2 optimized strlen 같은 경우 아래와 같은 명령어 작업을 가집니다.

(gdb) x/20i __strlen_avx2
...
   <__strlen_avx2+9>:   vpxor  xmm0,xmm0,xmm0
...
   <__strlen_avx2+29>:  vpcmpeqb ymm1,ymm0,YMMWORD PTR [rdi]
   <__strlen_avx2+33>:  vpmovmskb eax,ymm1
...
   <__strlen_avx2+41>:  tzcnt  eax,eax
   <__strlen_avx2+45>:  vzeroupper
   <__strlen_avx2+48>:  ret

이를 분석해보겠습니다.

 

1. ymm0을 0으로 초기화하는데 단순히 xmm0을 xor합니다.

 

    > vpxor xmm0, xmm0, xmm0
      vpcmpeqb ymm1, ymm0, [rdi]
      vpmovmskb eax, ymm1
      tzcnt eax, eax
      vzeroupper

 

 

2. RDI 레지스터에는 문자열에 대한 포인터가 있다고 할 때, vpcmpeqb은 ymm0의 어떤 바이트가 문자열과 일치하는지 비교하고 그 값을 ymm1에 저장합니다. 이미 ymm0은 all zero byte이기에 nul 바이트만 매치됩니다.

 

      vpxor xmm0, xmm0, xmm0
    > vpcmpeqb ymm1, ymm0, [rdi]
      vpmovmskb eax, ymm1
      tzcnt eax, eax
      vzeroupper

 

 

3. vpmovmskb로 범용 레지스터의 결과를 추출할 수 있습니다.

nul 바이트는 1비트가 될 거고 다른 값은 0의 값이 될 겁니다.

 

      vpxor xmm0, xmm0, xmm0
      vpcmpeqb ymm1, ymm0, [rdi]
    > vpmovmskb eax, ymm1
      tzcnt eax, eax
      vzeroupper

 

 

4. trailing zero bits로 first zero를 찾습니다.

tzcnt(Trailing Zero Count)에 대한 일반적인 연산입니다.

      vpxor xmm0, xmm0, xmm0
      vpcmpeqb ymm1, ymm0, [rdi]
      vpmovmskb eax, ymm1
    > tzcnt eax, eax
      vzeroupper

4번의 명령어로 first nul byte의 위치를 찾았습니다. 이런 동작을 통해 strlen과 같은 함수들이 우리 시스템에서 작동되는 만큼 시스템 곳곳에서 벡터 레지스터로 끊임없이 유입되고 있음을 유추할 수 있습니다.

 

Zeroing Register

      vpxor xmm0, xmm0, xmm0
      vpcmpeqb ymm1, ymm0, [rdi]
      vpmovmskb eax, ymm1
      tzcnt eax, eax
    > vzeroupper

vzeroupper 벡터 레지스터는 벡터 레지스트의 상위비트를 0으로 만듭니다.

 

XMM 레지스터와 YMM을 섞으면 XMM 레지스터는 확장(promotion)됩니다.

정상적으로 연산을 하지만 superscalar 프로세서에서는 어떤 연산이 병렬화 될 수 있는지 알 수 있도록 종속성을 추적해야 하는데

이 확장은 상위 비트에 종속성을 해, 프로세서가 필요하지 않은 값을 연산하게 되는 지연을 갖습니다.

 

Vector Register File

프로세서에는 각 레지스터가 single physical location이 없다. 이를 Register File, Register Allocation Table 이라합니다.

레지스터 포인터로 생각하면 malloc 및 free로 힙을 관리하는 것과 같습니다.

RAT는 레지스터 파일의 공간이 어떤 레지스터에 할당되었느지 추적하지만 XMM 레지스터를 0으로 설정하면 프로세서는 어디에도 비트를 저장하지 않습니다. flag를 YMM 레지스터 상위 부분과 하위 부분에 독립적으로 적용하므로 vzeroupper는 z-bit를 설정하고 레지스터 파일에 할당된 리소스를 해제합니다.

왼쪽은 레지스터 할당 테이블, 오른쪽은 physical register file

 

Speculation

프로세서는 추측성실행(speculative execution)을 사용하기에 연산을 뒤로 미뤄야 하는 경우가 있는데

프로세서가 vzeroupper를 추측성 실행을 했지만 해당 실행이 분기 예측이였다면 연산을 다시 되돌려야 합니다.

이때 z-bit를 해제하면 use-after-free 취약점이 될 수 있다.

vzeroupper의 잘못된 예측실행으로 스케쥴링 일부가 복구될 수 있습니다.

 

이 취약점은 XMM 레지스터 병합 최적화를 트리거하고 레지스터 이름 변경과 잘못된  vzeroupper을 트리거 하면 생겨난다.

strlen, memcpy, strcmp와 같은 기본 작업이 벡터 레지스터를 사용하는만큼 시스템 어디에서나 일어날 수 있는 취약점입니다.

레지스터 파일이 같은 물리적인 코어에서 공유되기 때문에 작동합니다. (예를들어 하이퍼쓰레딩이 동일한 레지스터 파일을 공유하는등) 

 

Exploitation

    vcvtsi2s{s,d}   xmm, xmm, r64
    vmovdqa         ymm, ymm
    jcc             overzero
    vzeroupper
overzero:
    nop

vcvtsi2s는 병합 최적화를 트리거하는데 사용된다. 그 다음 레지스터 이름을 트리거 해야하고 vmovdqa가 작동한다. 조건분기(conditional branch)를 사용했지만 CPU가 사용하지 않는 경로를 예측하면 vzeroupper가 잘못 예측되고 버그가 발생한다.

 

SLS로 인해 조건분기는 전혀 필요하지 않으니 vzeroupper가 분기 예측되도록 경로를 짠 것이다.

https://grsecurity.net/amd_branch_mispredictor_part_2_where_no_cpu_has_gone_before

 

 

 

Optimization

 

실험 결과 의도적으로 잘못 에측하는건 코드 최적화가 힘듭니다.

코어당 30kb/s 데이터를 누출할 수 있는 방법을 찾았고 이 속도는 사용자가 로그인할 때 암호 키와 암호를 모니터링 할 수 있을 만큼 빠릅니다.

 

 

 

 

 

 

 

해당 버그는 퍼징으로 발견되었으며, AMD에는 23년 5월 15일에 보고 되었고 이미 보안패치가 끝났습니다.

https://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git/commit/?id=0bc3126c9cfa0b8c761483215c25382f831a7c6f

 

 

취약점 대상

 

해당 취약점은 아래 zen2 CPU에 영향을 끼칩니다.

  • AMD Ryzen 3000 Series Processors 
  • AMD Ryzen PRO 3000 Series Processors 
  • AMD Ryzen Threadripper 3000 Series Processors 
  • AMD Ryzen 4000 Series Processors with Radeon Graphics 
  • AMD Ryzen PRO 4000 Series Processors 
  • AMD Ryzen 5000 Series Processors with Radeon Graphics
  • AMD Ryzen 7020 Series Processors with Radeon Graphics 
  • AMD EPYC “Rome” Processors

 

 


zenbleed poc는 깃헙에서 확인

https://github.com/google/security-research/tree/master/pocs/cpus/zenbleed

Exploit Code는 여기서 다운로드

https://lock.cmpxchg8b.com/files/zenbleed-v5.tar.gz

 

 

ref.

https://lock.cmpxchg8b.com/zenbleed.html#fnref1

https://www.xda-developers.com/zenbleed/

https://rmagur1203.tistory.com/17