퍼블릭 클라우드에서 VM 인스턴스 하나를 빌리는 일은 호스트 커널이나 같은 물리
서버 위에서 도는 다른 테넌트의 VM에는 손댈 수 없다는 전제 위에 서 있습니다.
KVM(Kernel-based Virtual Machine)의 섀도 페이징(shadow paging) 코드가 바로
그 격리를 지키는 핵심 축 중 하나인데, 2026년 7월 이 코드에서 게스트가 호스트
커널 메모리를 직접 건드릴 수 있는 use-after-free 취약점이 공개됐습니다. 연구자가
붙인 이름은 ‘Januscape'(CVE-2026-53359)이고, Intel과 AMD x86 양쪽 모두에서
재현되는 첫 게스트-투-호스트(guest-to-host) 이스케이프로 알려졌습니다. 이 글에서는
Januscape의 기술적 원인, 왜 패치가 하나로는 부족했는지, 영향 범위와 대응 방법을
정리합니다.
Januscape(CVE-2026-53359)란
Januscape는 리눅스 커널 KVM/x86 섀도 MMU(memory management unit)에 있는
use-after-free 취약점입니다. Intel과 AMD가 공유하는 섀도 페이징 코드 경로에
있었고, 약 16년간 발견되지 않은 채로 남아 있었습니다. 보안 연구자 Hyunwoo Kim
(@v4bel)이 구글의 KVM 전용 버그 바운티 프로그램 kvmCTF를 통해 이를 찾아냈고,
게스트-투-호스트 완전 탈출에 최대 25만 달러를 지급하는 프로그램의 취지에 정확히
부합하는 사례가 됐습니다. 공개된 PoC는 호스트를 커널 패닉으로 몰아넣는 수준까지만
시연됐지만, 연구자는 같은 버그를 완전한 호스트 코드 실행으로 확장하는 별도
익스플로잇도 확보했다고 밝혔습니다. 다만 공격자가 게스트 안에서 root 권한을
가지고 있어야 하는데, 퍼블릭 클라우드에서 VM 인스턴스를 할당받으면 기본으로
주어지는 권한이라 진입장벽이 낮은 편입니다.
기술적 원인 — 섀도 페이지의 role 불일치
버그의 핵심은 KVM이 섀도 페이지를 재사용할지 판단하는 로직에 있습니다. 게스트가
페이지 디렉터리 엔트리(PDE)를 수정해 매핑을 바꾸는 상황을 생각해 보면, 원래
2MB 크기의 거대 페이지(huge page)를 direct 섀도 페이지 하나로 매핑하고
있었는데, 게스트가 이를 4KB 단위의 하위 페이지 테이블을 거치는 방식(non-direct)
으로 바꾼다고 가정합니다. 이때 KVM은 게스트 프레임 번호(gfn)만 보고 “이미 있는
섀도 페이지를 재사용하면 되겠다”고 판단합니다. 문제는 프레임 번호는 일치하더라도
role, 즉 direct 여부나 매핑 레벨 같은 해석 방식은 완전히 다르다는 점입니다.
KVM이 이 불일치를 걸러내지 못한 채 낡은 섀도 페이지를 그대로 재사용하면, 이후
정리(cleanup) 루틴이 이미 해제된 메모리에 접근하는 use-after-free로 이어집니다.
왜 패치가 두 개 필요했나 — CVE-2026-46113과의 관계
Januscape를 완전히 막으려면 CVE-2026-53359 패치 하나만으로는 부족하고, 짝을
이루는 CVE-2026-46113 패치까지 함께 적용해야 합니다. CVE-2026-46113은
Januscape보다 먼저 나온 부분적 수정으로, 게스트 프레임 번호(gfn)가 어긋난
섀도 페이지를 재사용하지 못하도록 막는 검사(커밋 0cb2af2ea66a)를 추가했습니다.
그런데 Januscape가 보여준 건 gfn은 정확히 일치하더라도 role이 다른 경우까지는
이 검사가 잡아내지 못한다는 사실이었습니다. 결국 KVM 메인테이너 Paolo Bonzini가
작성한 진짜 수정은 kvm_mmu_get_child_sp() 함수에 한 줄을 추가해, 섀도 페이지를
재사용하기 전에 gfn뿐 아니라 role.word까지 함께 비교하도록 바꾼 것입니다. 두
값이 모두 일치할 때만 재사용하고, role이 어긋나면 기존 엔트리를 무효화(zap)한
뒤 새로 섀도 페이지를 만듭니다. 배포판이 CVE-2026-46113 패치만 먼저 백포트하고
Januscape 패치를 놓친 경우 여전히 취약한 상태로 남을 수 있어, 패치 여부를
확인할 때는 두 CVE 번호를 함께 체크해야 합니다.
영향 범위와 패치 타임라인
수정 사항은 2026년 7월 4일 메인라인 안정 커널에 반영됐습니다 — 7.1.3, 6.18.38,
6.12.95, 6.6.144, 6.1.177, 5.15.211, 5.10.260 이상 버전에서 패치를 확인할
수 있습니다. Rocky Linux 등 주요 배포판도 뒤이어 백포트 패치를 배포하면서,
공지에서 CVE-2026-53359와 CVE-2026-46113 두 CVE를 함께 반영해야 한다는
점을 명시했습니다. 즉시 패치가 어렵다면 신뢰할 수 없는 게스트가 도는 호스트에서는
중첩 가상화(nested virtualization)를 꺼서 공격 경로를 없애는 방법도 있습니다 —
Intel 계열은 kvm_intel.nested=0, AMD 계열은 kvm_amd.nested=0 커널
파라미터로 설정합니다.
Januscape는 Hyunwoo Kim이 약 두 달 사이 내놓은 세 번째 리눅스 커널 익스플로잇
공개이기도 합니다. 2026년 5월에는 Dirty Frag(CVE-2026-43284/CVE-2026-43500)를,
6월에는 KVM/arm64 최초의 공개 게스트-투-호스트 이스케이프인 ITScape
(CVE-2026-46316)를 발표한 데 이어 이번 Januscape로 x86 계열까지 커버한
셈입니다.
주의사항
- 패치를 확인할 때 CVE-2026-53359 하나만 보지 말고 CVE-2026-46113까지 함께 반영됐는지 확인해야 합니다. 두 커밋 중 하나라도 빠지면 여전히 취약합니다.
- 공격에는 게스트 안에서의 root 권한이 필요하지만, 퍼블릭 클라우드 인스턴스는 기본적으로 그 권한을 사용자에게 넘겨주므로 “게스트 root가 필요하니 안전하다”는 가정은 통하지 않습니다.
- 공개된 PoC는 호스트 커널 패닉까지만 시연됐지만, 완전한 코드 실행으로 이어지는 익스플로잇이 이미 연구자 손에 있다고 알려진 만큼 안전 마진을 낮게 잡으면 안 됩니다.
uname -r
apt changelog linux-image-$(uname -r) 2>/dev/null | grep -i '53359\|46113\|Januscape'
rpm -q --changelog kernel 2>/dev/null | grep -i '53359\|46113\|Januscape'
- 위 명령은 각각 Debian/Ubuntu 계열과 RHEL 계열에서 설치된 커널 패키지의 변경 로그에 두 CVE 관련 수정이 모두 포함됐는지 확인하는 용도입니다. 하나라도 결과에 안 잡히면 아직 패치가 반영되지 않았을 가능성이 높으므로 배포판 보안 공지를 다시 확인해야 합니다.
마무리
Januscape는 16년 동안 손대지 않았던 KVM 섀도 페이징 코드에서 나온 버그이면서,
패치 하나로는 막히지 않고 짝을 이루는 CVE까지 함께 적용해야 한다는 점에서 패치
관리의 까다로움을 다시 보여준 사례입니다. Intel과 AMD 양쪽에서 재현되는 첫
게스트-투-호스트 이스케이프라는 점, 그리고 같은 연구자가 두 달 사이 세 건의
KVM 관련 익스플로잇을 연달아 공개했다는 점까지 감안하면, 멀티테넌트 가상화
환경을 운영하는 곳이라면 커널 업데이트와 중첩 가상화 설정을 한 번쯤 점검해 볼
필요가 있습니다.
참고
- 16-Year-Old Linux KVM Flaw Lets Guest VMs Escape to Host on Intel and AMD x86 Systems (The Hacker News)
- Linux Kernel Vulnerability Allows VM Escape on Intel and AMD Systems (SecurityWeek)
- Januscape Exposes the KVM Shadow-Paging Bug That Kept Coming Back (TuxCare)
- Linux KVM Guest-to-Host Escape Hits Both Intel and AMD: Two CVEs Required (Tech Times)