🇰🇷 한글 설명
Linux 커널의 KVM 구성 요소에서 guest_memfd 파일에 memslot을 바인딩할 때 오프셋과 크기를 부호 있는 정수(signed)로 처리하여 발생하는 취약점입니다. 매우 큰 오프셋과 크기를 더할 경우 합계가 음수로 변하여 파일 크기 검사를 우회할 수 있으며, 이로 인해 잘못된 메모리 바인딩이 허용될 수 있습니다.
💡 쉬운 설명
메모리 주소를 계산할 때 숫자를 처리하는 방식의 오류로 인해, 시스템이 허용 범위를 벗어난 잘못된 메모리 위치를 정상적인 것으로 착각하게 만드는 문제입니다. 공격자가 이를 이용하면 시스템의 메모리 경계를 넘어서는 조작을 시도할 수 있습니다.
🇺🇸 원문 (English)
In the Linux kernel, the following vulnerability has been resolved:
KVM: guest_memfd: Treat memslot binding offset+size as unsigned values
When binding a memslot to a guest_memfd file, treat the offset and size as
unsigned values to fix a bug where the sum of the two can result in a false
negative when checking for overflow against the size of the file. Passing
unsigned values also avoids relying on somewhat obscure checks in other
flows for safety, and tracks the offset and size as they are intended to be
tracked, as unsigned values.
On 64-bit kernels, the number of pages a memslot contains and thus the size
(and offset) of its guest_memfd binding are unsigned 64-bit values. Taking
the offset+size as an loff_t instead of a uoff_t inadvertently converts
the unsigned value to a signed value if the offset and/or size is massive.
Locally storing the offset and size as signed values is benign in and of
itself (though even that is *extremely* difficult to discern), but
operating on their sum is not.
For the offset, KVM explicitly checks against a negative value, which might
seem like a bug as KVM could incorrectly reject a legitimate binding, but
that's not actually the case as KVM_CREATE_GUEST_MEMFD takes a signed value
for its size, i.e. a would-be-negative offset is also greater than the
maximum possible size of any guest_memfd file.
Regarding the size, while KVM lacks an explicit check for a negative value,
i.e. seemingly has a flawed overflow check, KVM restricts the number of
pages in a single memslot to the largest positive signed 32-bit value:
if (id < KVM_USER_MEM_SLOTS &&
(mem->memory_size >> PAGE_SHIFT) > KVM_MEM_MAX_NR_PAGES)
return -EINVAL;
and so that maximum "size" will ever be is 0x7fffffff000.
The sum of the two is, however, problematic. While the size is restricted
by KVM's memslot logic, the offset is not, i.e. the offset is completely
unchecked until the "offset + size > i_size_read(inode)" check. If the
offset is the (nearly) largest possible _positive_ value, then adding size
to the offset can result in a signed, negative 64-bit value. When compared
against the size of the file (guaranteed to be positive), the negative sum
is always smaller, and KVM incorrectly allows the absurd offset.
Opportunistically add missing includes in kvm_mm.h (instead of relying on
its parents).
📍 영향받는 시스템
Linux Kernel (KVM guest_memfd 관련 기능이 포함된 버전)
⚔️ 공격 벡터
로컬 공격자가 매우 큰 오프셋 값을 가진 memslot 바인딩을 시도하여 메모리 경계 검사를 우회함
🛡️ 대응 방법
오프셋과 크기를 부호 없는 정수(unsigned)로 처리하도록 수정된 최신 Linux 커널로 업데이트
🔧 검증 코드
출력된 커널 버전이 해당 취약점이 패치된 최신 보안 업데이트 버전인지 확인하십시오.