Reptar: Intel CPU의 FSRM/REX 취약점
(lock.cmpxchg8b.com)- 일부 Intel 프로세서에서
rep movs와 중복rex.r접두사가 FSRM 최적화와 맞물리면 CPU가 정상 규칙을 벗어난 “glitch” 상태에 들어갈 수 있음 - 원인은 x86의 느슨한 접두사 디코딩과
movsb처럼 암묵적 피연산자를 쓰는 명령에서 원래 무의미해야 할rex접두사가 특정 최적화 경로를 타는 데 있음 - Google 검증 파이프라인은 2023년 8월 이 조합에서 예측 불가능한 결과를 발견했고, 예기치 않은 분기·무조건 분기 무시·
xsave와call의 명령 포인터 기록 이상을 관찰함 - 여러 코어가 같은 버그를 동시에 트리거하면 machine check exception과 시스템 정지가 발생할 수 있으며, 비권한 게스트 VM 안에서도 재현돼 클라우드 환경에 중요함
- Intel은 영향받는 프로세서용 마이크로코드 업데이트를 공개했으며, 업데이트가 불가능한 경우
IA32_MISC_ENABLE에서 fast strings를 끌 수 있지만 큰 성능 저하가 따름
x86 접두사와 rep movsb
rep movsb는 x86에서 메모리를 옮기는 관용적 방식으로, 소스·목적지·방향·카운트를 설정하면 프로세서가 반복 복사를 처리함- 실제 명령은
movsb이고,rep는 해당 명령을 여러 번 반복하도록 바꾸는 접두사(prefix) 임 - x86 명령 디코딩은 비교적 느슨해서 의미가 없거나 충돌하는 접두사가 붙어도 대개 무시됨
- 컴파일러는 이런 중복 접두사로 단일 명령을 원하는 정렬 경계까지 패딩할 수 있음
rex,vex,evex는 이후 명령의 디코딩 방식을 바꾸는 접두사임
rex 접두사가 문제가 되는 조합
- i386은 범용 레지스터가 8개라 3비트로 레지스터를 지정할 수 있었지만, x86-64는 범용 레지스터가 16개라 추가 비트가 필요함
rex접두사는 다음 명령이 피연산자를 인코딩할 때 빌려 쓸 수 있는 여분의 비트를 제공함- 보통
rex.rxb처럼 표기하며,b,x,r,w비트가 선택적으로 설정됨
- 보통
movsb는 피연산자가 명령에 명시되지 않고 모두 암묵적이므로rex.rxb rep movsb의rex비트는 의미가 없어야 함- 일반적으로 프로세서는 이런
rex접두사를 조용히 무시하지만, fast short repeat move를 지원하는 시스템에서는 이 조합이 취약점으로 이어짐
FSRM과 영향받는 프로세서
- FSRM은 Ice Lake에서 도입된 기능으로, ERMS의 짧은 문자열 처리 한계를 보완함
- ERMS(enhanced repeat move/store)는 버퍼 정렬과 넓은 저장을 마이크로코드에서 처리해 기존
rep movsb코드를 더 빠르게 만들 수 있음- 초기 설정 비용이 커서 매우 짧은 문자열에는 적합하지 않음
- FSRM은 128바이트 이하의 짧은 이동을 더 빠르게 처리하기 위한 기능임
/proc/cpuinfo의flags라인에서fsrm플래그로 지원 여부를 확인할 수 있음- FSRM이 포함된 프로세서 예시는 다음과 같음
- Ice Lake
- Rocket Lake
- Tiger Lake
- Raptor Lake
- Alder Lake
- Sapphire Rapids
- 이 목록은 포괄적이지 않으며, 전체 목록은 Intel advisory INTEL-SA-00950을 확인해야 함
발견과 재현
- Google의 검증 파이프라인은 Oracle Serialization 기법으로 무작위 생성 프로그램의 두 형태를 실행한 뒤 최종 상태가 같은지 비교함
- 관련 설명은 이전 글 Oracle Serialization에 있음
- 2023년 8월, FSRM 최적화된
rep movs에 중복rex.r접두사를 추가했을 때 예측 불가능한 결과가 발생함 - 관찰된 이상 동작은 다음과 같음
- 예기치 않은 위치로 분기
- 무조건 분기 무시
xsave또는call명령에서 명령 포인터(instruction pointer)가 정확히 기록되지 않음- 디버거가 불가능한 상태를 보고함
- 여러 코어가 같은 버그를 트리거하면 프로세서가 machine check exception을 보고하고 정지할 수 있음
- 비권한 게스트 VM 내부에서도 재현 가능해 클라우드 제공자에게 보안상 중요한 문제가 됨
- 재현 도구와 연구 자료는 Google의 security research repository에 공개됨
icebreak도구의 로컬 미러도 icebreak.tar.gz로 제공됨
icebreak는 서로 다른 코어 쌍을 지정해 재현을 시도함- 영향받지 않는 시스템에서는 무한 루프처럼 출력이 없어야 함
- 영향받는 시스템에서는 성공 재현마다
.이 출력됨 - SMT 형제 코어에서는 임의 분기가 관찰될 수 있음
- 같은 패키지의 SMP 형제 코어에서는 machine check가 관찰될 수 있음
- 서로 다른 두 코어를 지정하지 않으면 hammer thread가 필요할 수 있음
가능한 원인과 관찰된 영향
- 현대 시스템의 마이크로코드 동작은 공개되어 있지 않아, 근본 원인은 관찰에 기반한 이론으로만 다룰 수 있음
- CPU는 크게 프론트엔드와 백엔드로 나뉨
- 프론트엔드는 명령을 가져오고 디코딩해 μops를 생성함
- 백엔드는 명령을 비순차 실행하며 ROB(reorder buffer)에 결과를 저장하고 정리함
- 이 버그는 프론트엔드가
movsb명령의 크기를 잘못 계산하게 만들고, 이후 ROB 항목이 잘못된 주소와 연결되는 상태를 유발하는 것으로 보임 - 이 상태에서는 명령 포인터가 잘못 계산되는 혼란 상태가 발생함
- 시스템은 결국 내부적으로 일관된 상태로 회복할 수 있지만, 중간 결과가 잘못될 수 있음
- 여러 SMT 또는 SMP 코어가 동시에 이 상태에 들어가면 충분한 마이크로아키텍처 상태 손상이 발생해 machine check를 강제할 수 있음
- 시스템 상태를 machine check가 날 정도로 손상시킬 수 있고, SMT 형제 코어에 스케줄된 프로세스 실행에서는 스레드 간 간섭이 관찰됨
- 손상을 권한 상승에 충분할 만큼 정밀하게 제어할 수 있는지는 확인되지 않음
대응 방법
- Intel은 영향받는 모든 프로세서용 업데이트된 마이크로코드를 INTEL-SA-00950로 공개함
- 운영체제 또는 BIOS 벤더가 이미 업데이트를 제공할 수 있음
- 업데이트할 수 없는 경우
IA32_MISC_ENABLE모델별 레지스터를 통해 fast strings를 비활성화할 수 있음 - fast strings 비활성화는 큰 성능 저하를 일으키므로 반드시 필요한 경우가 아니면 사용하지 않아야 함
관련 CPU 버그 자료
- Google은 발견한 CPU 버그를 공개하고 있으며, 일부는 보안 영향이 없더라도 읽을 가치가 있음
- 예시 자료
- movlps just doesn’t work:
movlps가 동작하지 않는 사례 - registers can sometimes roll back: 레지스터가 이전 값으로 롤백되는 사례
- movlps just doesn’t work:
댓글과 토론
Hacker News 의견들
-
관련 글: https://cloud.google.com/blog/products/identity-security/goo...
https://news.ycombinator.com/item?id=38268043에서 온 내용인데, 댓글은 여기로 합쳐짐 -
이 글을 읽으니 내 소프트웨어가 돌아가는 하드웨어에 대해 내가 얼마나 모르는지 실감하게 됨
“접두사(prefix)는 기능을 켜거나 꺼서 명령어 동작을 바꿀 수 있게 해준다”는데, 왜 기능을 켜고 끄는 데 “접두사”가 필요한지 궁금함
BIOS에 들어가지 않고 기능을 동적으로 전환하려는 용도인가?- https://wiki.osdev.org/X86-64_Instruction_Encoding#Legacy_Pr...를 읽어보면 됨
REP 접두사가 가장 흔한데, 같은 명령을 가변 횟수만큼 반복하게 해주는 역할임
반복 횟수는 CX 레지스터에서 가져오며, 메모리에서 객체를 옮기는 식의 흔한 루프를 매우 짧게 만들어줌
memcpy 함수는 종종 REP MOVS 한 명령으로 인라인되고, 필요하면 카운트를 CX로 복사하는 명령이 붙음
REX 접두사도 64비트 프로그램이 64비트 값과 주소를 자주 다루기 때문에 꽤 흔함
어떤 접두사도 BIOS 등으로 전역 설정 가능한 것을 토글하지 않고, 모두 다음 명령이 해야 할 일을 지정할 뿐임 - 이 경우 “접두사”는 대체로 명령어 인코딩 공간을 확장하는 역할임
드물게 쓰이는 주소 지정 방식에는 DS가 아닌 다른 세그먼트를 쓰게 하는 “세그먼트 접두사”가 붙고, x86_64의 “REX” 접두사는 레지스터 필드에 비트를 더해 범용 레지스터 16개를 쓸 수 있게 했음
마찬가지로 “LOCK” 접두사는 원래 명세가 부실하긴 했지만 일부 메모리 연산을 시스템 나머지 부분에 대해 원자적으로 만들며, “LOCK CMPXCHG”로 비교 후 설정을 구현하는 식임
다른 CPU 아키텍처도 이런 연산을 표현하지만 보통 기존 명령어 공간 안에 넣어서 모든 명령을 표현하는 데 더 많은 비트가 필요해짐
특히 여기서 문제 된 “REP” 접두사는 예외에 가까운데, 고대부터 남은 마이크로코드 반복 접두사임
그래도 memset/memmove 같은 오늘날에도 성능 민감한 연산을 나타내므로 CPU 업체들이 계속 최적화할 가치가 있고, 이번 버그도 그런 과정에서 생긴 듯함 - 접두사는 프로세서가 실행하는 특정 명령어의 수식자로, 피연산자 크기를 제어하거나 동시성을 위한 잠금을 활성화하는 식으로 쓰임
- x86은 1978년에 사실상 원시적인 레이저 프린터나 비슷한 작업을 돌리려는 목적으로 설계됐음
가장 큰 문제는 명령어 인코딩 공간을 “효율적으로 활용”했다는 점임
나중에 새 명령어, 더 나쁘게는 추가 레지스터가 생기자 새 명령 변형을 어떻게든 끼워 넣어야 했고, 그 방법이 접두사를 덧붙이는 것이었음 - x86은 명령어 집합 구조로서 40년 넘게 덧붙여져 왔고, 가변 길이 명령어를 쓰기 때문에 이런 형태가 됨
명령어 집합을 확장할 때마다 opcode 공간 일부를 파내 새 접두사를 욱여넣었음
Intel이 올해 또 다른 새 방식을 제안한 걸 보면 이런 흐름은 계속될 듯함
- https://wiki.osdev.org/X86-64_Instruction_Encoding#Legacy_Pr...를 읽어보면 됨
-
진단 과정을 보니 qemu가 repz ret를 만났을 때 일이 떠오름: https://repzret.org/p/repzret/
-
HN 규칙상 이런 제목은 금지해야 한다고 봄
링크가 뭔지 전혀 알려주지 않고, URL은 오히려 더 헷갈림
이렇게 의미 없는 제목이라면 게시자가 짧은 설명을 덧붙여야 한다고 생각함- 동의하지 않음
제목에 맥락이 최대한 들어가면 사람들이 링크를 클릭하지 않고, 트윗에 반응하듯 댓글에서 자기 관심사만 다듬는 일이 생기는 걸 이미 봤음
HN은 지적 호기심과 링크 클릭을 유도하는 중간 지점을 택함
모호한 제목이라 링크 클릭을 거부하더라도, 적어도 링크를 클릭한 사람들에게 답하게 되니 인터넷 다른 곳보다 낫다고 봄
모호하고 재치 있는 제목을 정당화할 만큼 보상이 없는 글은 이 글과 달리 첫 페이지에서 내려감
- 동의하지 않음
-
글이 매우 잘 쓰였음
어셈블리 프로그래밍과 Intel 명령어 집합은 물론 마이크로아키텍처도 거의 모르지만, 설명을 따라갈 수 있었고 여기서 무슨 일이 벌어지는지 대략 이해한 느낌임
AMD CPU도 영향을 받는지 아는 사람이 있는지 궁금함 -
문제가 정말 프로세서가 명령어 길이를 헷갈리는 것이라면, 큰 성능 저하 없이 마이크로코드로 고칠 수 있다는 점이 인상적임
내 직감이 완전히 틀릴 수도 있지만, 명령어 길이 계산은 논리 게이트로 직접 합성되는 쪽일 것 같았음
다시 생각해보니 uOP 디코더는 하드웨어적으로 멀쩡하고, 마이크로코드로 최적화된 복사 루틴이 uOP 스트림에 대해 사실이 아닌 것을 추론하려는 상황일 수도 있겠음
예를 들어 “아, 이건 rep mov니까 루프를 위해 uOP 두 개 뒤로 가면 되겠지” 같은 식일 수 있음
Intel CPU 팀이 자세한 내용까지 공개하진 않을 듯함 -
“ERMS”와 “FSRM”을 잘 모르겠고, Google에도 괜찮은 자료가 거의 없어 보임
이것들이 rep movsb를 최적화된 SSE memcpy 구현 대신 최고 성능으로 쓸 수 있음을 알려주는 CPUID 플래그일 뿐인지, 아니면 rep movsb를 더 빠르게 만드는 특별한 인코딩이나 접두사인지 궁금함
후자라면 왜 필요한지, fsrm은 어떻게 활용하는지도 모르겠음- 이 자료를 찾았고 [1], Intel 최적화 매뉴얼 [2]도 링크되어 있음
ERMS는 AVX의 더 저렴한 대체재였고, FSRM은 짧은 블록에 더 나은 버전이었던 듯함
“이후 프로세서의 저가형 버전인 2017년 출시 Kaby Lake Celeron과 Pentium에는 빠른 메모리 복사에 쓸 수 있는 AVX가 없지만 Enhanced REP MOVSB는 있음
그리고 2018년 이후 출시된 Intel 모바일·저전력 아키텍처 일부는 SkyLake 기반이 아니었지만, 이전 세대 마이크로아키텍처보다 REP MOVSB로 CPU 사이클당 약 두 배 많은 바이트를 복사함”
“Ice Lake 마이크로아키텍처의 Fast Short REP MOV(FSRM) 이전 Enhanced REP MOVSB(ERMSB)는 블록 크기가 최소 256바이트일 때만 AVX 복사나 범용 레지스터 복사보다 빨랐음
64바이트 미만 블록에서는 ERMSB 내부 시작 비용이 약 35사이클로 높아서 훨씬 느렸고, FSRM 기능은 128바이트 미만 블록도 빠르게 하려는 목적이었음”
[1] https://stackoverflow.com/a/43837564
[2] http://www.intel.com/content/dam/www/public/us/en/documents/... - FSRM은 기존 코드에 영향을 주는 CPU 최적화의 이름일 뿐임
최적의 명령 선택과 스케줄링은 컴파일 시간에 정적으로 할 수도 있고, 런타임에 여러 라이브러리 함수 중 하나를 고르거나 JIT으로 동적으로 할 수도 있음
런타임에 어떤 명령 스케줄링이 최적인지 감지하려면 실제 CPU를 알아야 함
모든 CPU 모델 표를 둘 수도 있지만, 실행 중인 CPU가 그 최적화를 구현했는지 운영체제에 물어볼 수도 있음
Linux는 CPU가 그 최적화를 구현했다고 보고할 수 있도록 패치가 필요했음
https://www.phoronix.com/news/Intel-5.6-FSRM-Memmove - 플래그는 이 CPU에서는 rep movsb가 빠르므로 SSE/AVX 최적화 구현을 쓸 필요가 없다는 걸 알려줄 뿐임
- 이 자료를 찾았고 [1], Intel 최적화 매뉴얼 [2]도 링크되어 있음
-
Intel 권고문 [1]에 다음과 같이 쓰여 있는 걸 봤음
Intel은 이 문제를 내부적으로 발견한 Intel 직원들에게 감사한다고 했고, 또한 이 문제를 보고한 Google 직원들에게도 감사한다고 했음
[1] https://www.intel.com/content/www/us/en/security-center/advi...- Intel 직원들이 Google보다 얼마나 더 일찍 이 문제를 발견했는지 궁금함
-
영향 설명이 있는 Intel 권고문도 참고할 만함: https://www.intel.com/content/www/us/en/security-center/advi...
“일부 Intel(R) 프로세서에서 프로세서 명령어 시퀀스가 예상치 못한 동작을 유발해, 인증된 사용자가 로컬 접근을 통해 권한 상승, 정보 공개, 서비스 거부를 가능하게 할 수 있음”- 여기서 “일부”는 지난 6년간 만들어진 거의 모든 Intel x86 CPU처럼 보임
-
Paradox Interactive의 Victoria 3 팀 Konrad Magnusson이 이와 mimalloc 관련된 무언가를 찾았음: https://github.com/microsoft/mimalloc/issues/807
완전히 관련 있는지는 모르겠지만 가능성은 있음- 어떻게든 불필요한 접두사를 방출한 게 아니라면 관련 가능성은 낮아 보임