
일부 구형 Qualcomm 칩셋의 하이퍼바이저 펌웨어에서 발견된 보안 문제
CVE-2022-22063는 일부 구형 퀄컴 칩셋의 하이퍼바이저 펌웨어에서 발견된 보안 문제입니다. 보호되지 않은 하드웨어 구성 요소("부트 리매퍼")를 악용하여 수정된 운영 체제에서 하이퍼바이저에 대한 전체 읽기/쓰기 액세스 권한을 얻을 수 있습니다(권한 상승). 특정 펌웨어 버전(예: 주소 또는 변수)에 대한 지식이 필요하지 않기 때문에 영향을 받는 플랫폼에서 이 문제를 악용하는 것은 간단합니다.
참고: 퀄컴이 고객에게 수정 사항을 제공했지만(업데이트를 출시할 충분한 시간 포함) 영향을 받는 많은 장치가 이미 상당히 오래되어 공급업체로부터 수정 사항을 받지 못할 수 있습니다. 이 문제는 수정되었거나 손상된 운영 체제(다른 보안 문제 사용)에서만 악용될 수 있습니다. 펌웨어에 취약점이 있더라도 운영 체제를 최신 상태로 유지하고 보안을 유지하는 것만으로도 충분할 수 있습니다.
CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H이 문제는 퀄컴의 2022년 12월 보안 게시판에도 게시되었습니다.
이 문제는 영향을 받는 대상에서 실행되는 하드웨어와 소프트웨어의 조합에 따라 달라집니다.
hyp 파티션에 있는 ELF 이미지)를 실행합니다.APCS_BOOT_START_ADDR_NSEC라는 하드웨어 레지스터를 사용하여 구성 가능)가 있습니다.영향을 받는 하드웨어가 있을 가능성이 있는 칩셋(예: MSM8909 및 MSM8953)도 더 있지만, 손상될 수 있는 별도의 하이퍼바이저 펌웨어가 없습니다.
권한 상승: 이미 손상된 운영 체제 커널(예: Linux)이 주어지면, 이 문제는 하이퍼바이저 수준(ARM에서 EL1 -> EL2)으로 권한을 간단하게 상승시킬 수 있습니다. 하이퍼바이저가 관리하는 모든 메모리를 읽거나 쓸 수 있습니다. 이로 인해 하이퍼바이저가 관리하는 서로 다른 보안 도메인 또는 가상 머신(있는 경우, 구성에 따라 다름)의 격리가 깨집니다.
(참조: Qualcomm Snapdragon 플랫폼의 액세스 제어 소개)
시큐어 부트: 생산에 사용되는 대부분의 퀄컴 장치는 펌웨어의 무단 수정을 방지하기 위해 시큐어 부트를 사용합니다. 펌웨어는 부트 체인에 의해 암호화 방식으로 서명되고 확인됩니다. 이 문제를 통해 수정된 운영 체제(공식적으로 지원되는 "부트로더 잠금 해제" 또는 다른 익스플로잇을 통해)에서 로드된 하이퍼바이저 펌웨어를 런타임에 수정하거나 완전히 교체할 수 있습니다.
(참조: Qualcomm Secure Boot and Image Authentication Technical Overview (v1.0) 및 (v2.0))
참고: 이 문제는 원래 Qualcomm Snapdragon 410(MSM8916) 플랫폼에서 발견되었습니다. 다음 설명 중 일부는 MSM8916에 특정될 수 있습니다. 예:
그러나 일반적인 개념은 영향을 받는 모든 플랫폼에 유사하게 적용됩니다.
ARMv8-A 64비트 아키텍처는 4개의 권한 수준("예외 수준", EL)을 정의합니다. 일반적으로 애플리케이션, 운영 체제 커널 및 하이퍼바이저에 사용되는 별도의 수준이 있습니다:
CPU는 예를 들어 들어오는 인터럽트로 인해 예외가 발생하는 동안 수준 간 전환합니다. 하이퍼바이저 호출(hvc)과 같은 특수 명령어를 사용하여 일부 수준 간 전환도 가능합니다.
(참조: AArch64 Exception model)
하이퍼바이저는 별도의 운영 체제 커널을 사용하여 하나 이상의 가상 머신을 호스팅할 수 있습니다. 각 가상 머신은 스테이지 2 변환을 사용하여 자체 메모리 뷰를 제공받을 수 있습니다. 가상 머신의 모든 메모리 액세스는 두 단계의 변환을 거칩니다. 첫 번째 단계는 (가상) 운영 체제에서 관리되고, 두 번째 단계는 하이퍼바이저에서 관리됩니다. 하이퍼바이저 또는 다른 가상 머신에서 사용하는 메모리는 변환 테이블에서 생략하여 숨길 수 있습니다.
(참조: AArch64 virtualization, AArch64 memory management)
퀄컴의 하이퍼바이저 펌웨어는 EL2에서 실행되며 스테이지 2 변환을 사용하여 메인 운영 체제 커널(EL1, 일반적으로 Linux)이 하이퍼바이저 메모리에 액세스하지 못하도록 합니다. 이 설정에서 스테이지 2 변환은 주소 변환 없이 주로 메모리 보호에 사용됩니다. 메인 운영 체제는 메모리 매핑된 입출력(MMIO) 공간에 있는 대부분의 하드웨어 구성 요소(예: SD 컨트롤러 또는 카메라 서브시스템)에 직접 액세스할 수 있습니다. 하이퍼바이저/EL2(hyp) 및 시큐어 모니터/EL3(tz의 일부)에 속하는 메모리에 대한 액세스는 제한됩니다:
_부트 리매퍼_는 가상화와 관련이 없습니다. CPU 코어의 초기 부팅 중에 필요합니다. 이 하드웨어 플랫폼에서 CPU 코어는 항상 주소 0x0에서 실행을 시작합니다. 부트 리매퍼는 CPU 주변에 구축된 추가 하드웨어 구성 요소로, 처음 64 또는 128 KiB(0x00000 - 0x20000)를 구성 가능한 메모리 영역으로 다시 매핑합니다.
기본적으로 부트 리매퍼는 부트 ROM(장치가 시작될 때 실행되는 첫 번째 코드)을 가리킵니다. 나중에 매핑이 변경되어 다른 CPU 코어가 RAM에 로드된 EL3 펌웨어(tz의 일부)에서 즉시 실행을 시작합니다:
CPU가 액세스하는 주소(tz 내)는 두 개의 다른 물리적 주소를 사용하여 액세스할 수 있습니다. RAM의 실제 주소(0x8650xxxx)와 부트 리매퍼를 사용한 다시 매핑된 주소(0x0000xxxx)입니다.
실제로 부트 리매퍼에는 두 개의 별도 인스턴스가 있습니다:
APCS_BOOT_START_ADDR_SEC(= 0x0b010004)를 사용하여 구성할 수 있지만 보안 상태에서만 가능합니다.APCS_BOOT_START_ADDR_NSEC(= 0x0b010008)를 사용하여 구성할 수 있습니다.두 부트 리매퍼 인스턴스 모두 다시 매핑된 영역의 기본 주소와 두 개의 구성 비트(REMAP_EN은 다시 매핑 활성화, BOOT_128KB_EN은 64KiB 대신 처음 128KiB를 다시 매핑)를 포함하는 메모리 레지스터를 사용하여 구성할 수 있습니다.
(참조: Qualcomm Snapdragon 410E Technical Reference Manual rev. D, 85쪽 및 116쪽)
이전 두 섹션의 지식을 사용하면 기본 아이디어는 간단합니다. 부트 리매퍼를 사용하여 하이퍼바이저의 메모리 보호(스테이지 2 변환)를 우회합니다.
부트 리매퍼는 CPU 시작 중에만 작동하지 않습니다. 언제든지 사용할 수 있으며 다시 매핑된 영역에 대한 전체 읽기/쓰기/실행 액세스를 허용합니다. 또한 퀄컴의 하이퍼바이저는 영향을 받는 장치에서 운영 체제가 비보안 인스턴스의 부트 리매퍼를 구성하고 액세스하는 것을 방지하지 않는 것으로 보입니다(스테이지 2 변환을 사용하여 보호되지 않음). 따라서 이 문제는 다음을 통해 쉽게 악용할 수 있습니다:
hyp)을 가리키도록 구성한 다음,다시 매핑된 영역은 블록별로 동적으로 이동하여 부트 리매퍼를 통해 사용 가능한 64/128KiB보다 큰 메모리 영역에 액세스할 수 있습니다. 또한 이를 사용하여 하이퍼바이저 메모리 보호를 완전히 비활성화할 수도 있습니다(개념 증명 참조).
참고: 동일한 익스플로잇은 시큐어 월드 펌웨어(tz)에서는 작동하지 않습니다. 부트 리매퍼를 사용하면 스테이지 2 변환을 우회할 수 있지만 DRAM의 tz 메모리 영역은 부트 리매퍼를 통과한 후 액세스를 차단하는 추가 하드웨어 구성 요소(CPU 외부)에 의해 보호되는 것으로 보입니다:
tz 메모리 영역은 보안 상태에서만 액세스할 수 있을 가능성이 높습니다. 이 익스플로잇은 하이퍼바이저의 메모리 보호만 우회할 수 있으며, 다른 하드웨어 보안 메커니즘은 그대로 유지됩니다.
부트 리매퍼를 사용하면 펌웨어 버전에 대한 지식 없이 런타임에 원래 하이퍼바이저 펌웨어를 완전히 비활성화하고 교체할 수 있습니다. 특히, 수정할 수 있는 변수 및 함수의 메모리 주소를 얻기 위해 리버스 엔지니어링을 사용할 필요가 없습니다. 오픈 소스 Linux 코드의 메모리 예약 또는 내부 저장소의 hyp 파티션에서 사용할 수 있는 하이퍼바이저 펌웨어 바이너리의 ELF 헤더를 읽는 등 하이퍼바이저 펌웨어의 대략적인 메모리 영역을 아는 것만으로 충분합니다.
일반적인 아이디어는 다음과 같습니다:
hvc)을 수행하여 운영 체제에서 하이퍼바이저로 전환합니다(EL1에서 EL2로).이를 구현하는 코드는 길지 않지만 일부 저수준 AArch64 어셈블리와 CPU 캐시와의 신중한 상호 작용이 포함됩니다. 그러나 여전히 주요 질문이 남아 있습니다. 코드를 특정 하이퍼바이저 펌웨어 버전에 종속되지 않도록 하려면 셸 코드를 정확히 어디에 작성해야 할까요?
하이퍼바이저 호출(또는 일반적으로 모든 예외) 중에 CPU 실행은 특수 메모리 주소인 _예외 벡터_로 강제됩니다. 예외 벡터는 현재 또는 낮은 예외 수준에서 발생하는 다양한 유형의 예외를 처리하는 코드를 포함하는 더 큰 _벡터 테이블_의 일부입니다:
각 상자는 32개의 어셈블리 명령어를 위한 공간이 있는 예외 벡터를 나타냅니다. 이 정도 공간으로는 충분하지 않으므로 일반적으로 추가 코드를 위한 더 많은 공간이 있는 다른 곳으로 점프하는 분기 명령어를 포함합니다.
오프셋은 각 예외 수준에 대한 벡터 테이블의 기준 주소를 정의하는 벡터 기준 주소 레지스터(VBAR)를 기준으로 합니다. 하이퍼바이저는 기준 주소를 VBAR_EL2 CPU 레지스터에 씁니다.