🇰🇷 한글 설명
Linux 커널의 AMD IOMMU 호스트 페이지 테이블 구현에서 페이지 테이블 레벨을 증가시키는 동안 발생할 수 있는 레이스 컨디션 취약점입니다. unmap 경로에서 잠금 없이 페이지 테이블 정보를 읽을 때, 업데이트 중인 잘못된 레벨 값을 참조하여 unmap 작업이 실패할 수 있습니다.
💡 쉬운 설명
컴퓨터의 메모리 관리 방식이 변경되는 찰나에 다른 작업이 잘못된 정보를 읽어 메모리 해제 작업이 실패하는 문제입니다. 이로 인해 시스템 오류나 경고 메시지가 발생할 수 있습니다.
🇺🇸 원문 (English)
In the Linux kernel, the following vulnerability has been resolved:
iommu/amd/pgtbl: Fix possible race while increase page table level
The AMD IOMMU host page table implementation supports dynamic page table levels
(up to 6 levels), starting with a 3-level configuration that expands based on
IOVA address. The kernel maintains a root pointer and current page table level
to enable proper page table walks in alloc_pte()/fetch_pte() operations.
The IOMMU IOVA allocator initially starts with 32-bit address and onces its
exhuasted it switches to 64-bit address (max address is determined based
on IOMMU and device DMA capability). To support larger IOVA, AMD IOMMU
driver increases page table level.
But in unmap path (iommu_v1_unmap_pages()), fetch_pte() reads
pgtable->[root/mode] without lock. So its possible that in exteme corner case,
when increase_address_space() is updating pgtable->[root/mode], fetch_pte()
reads wrong page table level (pgtable->mode). It does compare the value with
level encoded in page table and returns NULL. This will result is
iommu_unmap ops to fail and upper layer may retry/log WARN_ON.
CPU 0 CPU 1
------ ------
map pages unmap pages
alloc_pte() -> increase_address_space() iommu_v1_unmap_pages() -> fetch_pte()
pgtable->root = pte (new root value)
READ pgtable->[mode/root]
Reads new root, old mode
Updates mode (pgtable->mode += 1)
Since Page table level updates are infrequent and already synchronized with a
spinlock, implement seqcount to enable lock-free read operations on the read path.
📍 영향받는 시스템
AMD IOMMU를 사용하는 Linux 커널 (페이지 테이블 레벨이 동적으로 변경되는 환경)
⚔️ 공격 벡터
특정 메모리 주소 공간 확장과 해제가 동시에 일어나는 극단적인 타이밍을 이용한 레이스 컨디션 유도
🛡️ 대응 방법
Linux 커널을 최신 보안 패치가 적용된 버전으로 업데이트하여 seqcount 기반의 동기화 메커니즘을 적용해야 합니다.
🔧 검증 코드
출력된 커널 버전이 해당 취약점이 해결된 패치 버전 이후인지 확인합니다.