🇰🇷 한글 설명
Linux 커널의 hugetlb 메모리 관리 과정에서 PMD 페이지 테이블의 공유 카운트 계산 오류로 인해 페이지 테이블 누수 및 잘못된 페이지 상태가 발생할 수 있는 취약점입니다. split_huge_pages와 같은 호출자가 folio 참조 횟수를 예기치 않게 증가시켜 페이지 테이블이 정상적으로 해제되지 않는 문제를 야기합니다.
💡 쉬운 설명
컴퓨터의 메모리를 관리하는 장부(페이지 테이블)의 숫자가 실제와 다르게 계산되어, 사용하지 않는 메모리 자원이 시스템에 계속 남아있게 되는 버그입니다. 이로 인해 시스템의 메모리 자원이 낭비되거나 불안정해질 수 있습니다.
🇺🇸 원문 (English)
In the Linux kernel, the following vulnerability has been resolved:
mm: hugetlb: independent PMD page table shared count
The folio refcount may be increased unexpectly through try_get_folio() by
caller such as split_huge_pages. In huge_pmd_unshare(), we use refcount
to check whether a pmd page table is shared. The check is incorrect if
the refcount is increased by the above caller, and this can cause the page
table leaked:
BUG: Bad page state in process sh pfn:109324
page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x66 pfn:0x109324
flags: 0x17ffff800000000(node=0|zone=2|lastcpupid=0xfffff)
page_type: f2(table)
raw: 017ffff800000000 0000000000000000 0000000000000000 0000000000000000
raw: 0000000000000066 0000000000000000 00000000f2000000 0000000000000000
page dumped because: nonzero mapcount
...
CPU: 31 UID: 0 PID: 7515 Comm: sh Kdump: loaded Tainted: G B 6.13.0-rc2master+ #7
Tainted: [B]=BAD_PAGE
Hardware name: QEMU KVM Virtual Machine, BIOS 0.0.0 02/06/2015
Call trace:
show_stack+0x20/0x38 (C)
dump_stack_lvl+0x80/0xf8
dump_stack+0x18/0x28
bad_page+0x8c/0x130
free_page_is_bad_report+0xa4/0xb0
free_unref_page+0x3cc/0x620
__folio_put+0xf4/0x158
split_huge_pages_all+0x1e0/0x3e8
split_huge_pages_write+0x25c/0x2d8
full_proxy_write+0x64/0xd8
vfs_write+0xcc/0x280
ksys_write+0x70/0x110
__arm64_sys_write+0x24/0x38
invoke_syscall+0x50/0x120
el0_svc_common.constprop.0+0xc8/0xf0
do_el0_svc+0x24/0x38
el0_svc+0x34/0x128
el0t_64_sync_handler+0xc8/0xd0
el0t_64_sync+0x190/0x198
The issue may be triggered by damon, offline_page, page_idle, etc, which
will increase the refcount of page table.
1. The page table itself will be discarded after reporting the
"nonzero mapcount".
2. The HugeTLB page mapped by the page table miss freeing since we
treat the page table as shared and a shared page table will not be
unmapped.
Fix it by introducing independent PMD page table shared count. As
described by comment, pt_index/pt_mm/pt_frag_refcount are used for s390
gmap, x86 pgds and powerpc, pt_share_count is used for x86/arm64/riscv
pmds, so we can reuse the field as pt_share_count.
📍 영향받는 시스템
Linux kernel (hugetlb 관련 기능 사용 시, 특히 damon, offline_page, page_idle 등을 사용하는 환경)
⚔️ 공격 벡터
특정 메모리 관리 기능(damon, page_idle 등)을 유도하여 페이지 테이블 참조 횟수를 조작함으로써 메모리 누수를 유발할 수 있음
🛡️ 대응 방법
독립적인 PMD 페이지 테이블 공유 카운트(pt_share_count)를 도입하여 수정된 최신 Linux 커널 버전으로 업데이트
🔧 검증 코드
출력된 커널 버전이 해당 취약점이 수정된 패치 버전 이후인지 확인합니다.