From: Sean Christopherson <seanjc@google.com>
To: Paolo Bonzini <pbonzini@redhat.com>,
kvm@vger.kernel.org, linux-kernel@vger.kernel.org,
Alexander Potapenko <glider@google.com>
Subject: Re: [PATCH 0/2] KVM: Fix a guest_memfd memslot UAF
Date: Tue, 2 Dec 2025 07:27:10 -0800 [thread overview]
Message-ID: <aS8FTggpT_7cY3cr@google.com> (raw)
In-Reply-To: <20251202020334.1171351-1-seanjc@google.com>
[-- Attachment #1: Type: text/plain, Size: 904 bytes --]
On Mon, Dec 01, 2025, Sean Christopherson wrote:
> Fix a UAF due to leaving a dangling guest_memfd memslot binding by
> disallowing clearing KVM_MEM_GUEST_MEMFD on a memslot. The intent was
> that guest_memfd memslots would be immutable (could only be deleted),
> but somewhat ironically we missed the case where KVM_MEM_GUEST_MEMFD
> itself is the only flag that's toggled.
>
> This is an ABI change, but I can't imagine anyone was relying on
> disappearing a guest_memfd memslot.
>
> Patch 2 hardens against the UAF, and prepares for allowing FLAGS_ONLY
> changes on guest_memfd memslots. Sooner or later, we're going to allow
> dirty logging on guest_memfd, so I think it makes sense to guard against
> that so that whoever adds dirty logging support doesn't forget to unbind
> on a FLAGS_ONLY change.
>
> I'll respond with the syzkaller reproducer (it's comically simple).
And almost forgot...
[-- Attachment #2: reproducer.c --]
[-- Type: text/x-csrc, Size: 5755 bytes --]
// autogenerated by syzkaller (https://github.com/google/syzkaller)
#define _GNU_SOURCE
#include <endian.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>
uint64_t r[3] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff};
int main(void)
{
syscall(__NR_mmap, /*addr=*/0x1ffffffff000ul, /*len=*/0x1000ul, /*prot=*/0ul,
/*flags=MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE*/ 0x32ul,
/*fd=*/(intptr_t)-1, /*offset=*/0ul);
syscall(__NR_mmap, /*addr=*/0x200000000000ul, /*len=*/0x1000000ul,
/*prot=PROT_WRITE|PROT_READ|PROT_EXEC*/ 7ul,
/*flags=MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE*/ 0x32ul,
/*fd=*/(intptr_t)-1, /*offset=*/0ul);
syscall(__NR_mmap, /*addr=*/0x200001000000ul, /*len=*/0x1000ul, /*prot=*/0ul,
/*flags=MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE*/ 0x32ul,
/*fd=*/(intptr_t)-1, /*offset=*/0ul);
const char* reason;
(void)reason;
intptr_t res = 0;
if (write(1, "executing program\n", sizeof("executing program\n") - 1)) {
}
// openat$kvm arguments: [
// fd: const = 0xffffffffffffff9c (8 bytes)
// file: ptr[in, buffer] {
// buffer: {2f 64 65 76 2f 6b 76 6d 00} (length 0x9)
// }
// flags: open_flags = 0x0 (4 bytes)
// mode: const = 0x0 (2 bytes)
// ]
// returns fd_kvm
memcpy((void*)0x200000000000, "/dev/kvm\000", 9);
res = syscall(__NR_openat, /*fd=*/0xffffffffffffff9cul,
/*file=*/0x200000000000ul, /*flags=*/0, /*mode=*/0);
if (res != -1)
r[0] = res;
// ioctl$KVM_CREATE_VM arguments: [
// fd: fd_kvm (resource)
// cmd: const = 0xae01 (4 bytes)
// type: intptr = 0x0 (8 bytes)
// ]
// returns fd_kvmvm
res = syscall(__NR_ioctl, /*fd=*/r[0], /*cmd=*/0xae01, /*type=*/0ul);
if (res != -1)
r[1] = res;
// ioctl$KVM_CREATE_GUEST_MEMFD arguments: [
// fd: fd_kvmvm (resource)
// cmd: const = 0xc040aed4 (4 bytes)
// arg: ptr[in, kvm_create_guest_memfd] {
// kvm_create_guest_memfd {
// size: int64 = 0x200001fe0000 (8 bytes)
// flags: int64 = 0x0 (8 bytes)
// reserved: buffer: {00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
// 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
// 00 00 00 00 00 00 00 00 00} (length 0x30)
// }
// }
// ]
// returns fd_kvm_guest_memfd
*(uint64_t*)0x2000000001c0 = 0x200001fe0000;
*(uint64_t*)0x2000000001c8 = 0;
memset((void*)0x2000000001d0, 0, 48);
res = syscall(__NR_ioctl, /*fd=*/r[1], /*cmd=*/0xc040aed4,
/*arg=*/0x2000000001c0ul);
if (res != -1)
r[2] = res;
// ioctl$KVM_SET_USER_MEMORY_REGION2 arguments: [
// fd: fd_kvmvm (resource)
// cmd: const = 0x40a0ae49 (4 bytes)
// arg: ptr[in, kvm_userspace_memory_region2] {
// kvm_userspace_memory_region2 {
// slot: kvm_mem_slots = 0x4 (4 bytes)
// flags: kvm_mem_region_flags = 0x4 (4 bytes)
// paddr: kvm_guest_addrs = 0x80a0000 (8 bytes)
// size: len = 0x2000 (8 bytes)
// addr: VMA[0x2000]
// guest_memfd_offset: int64 = 0x4000 (8 bytes)
// guest_memfd: fd_kvm_guest_memfd (resource)
// pad1: const = 0x0 (4 bytes)
// pad2: buffer: {00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
// 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
// 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
// 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
// 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
// 00 00} (length 0x70)
// }
// }
// ]
*(uint32_t*)0x200000000180 = 4;
*(uint32_t*)0x200000000184 = 4;
*(uint64_t*)0x200000000188 = 0x80a0000;
*(uint64_t*)0x200000000190 = 0x2000;
*(uint64_t*)0x200000000198 = 0x200000ffc000;
*(uint64_t*)0x2000000001a0 = 0x4000;
*(uint32_t*)0x2000000001a8 = r[2];
*(uint32_t*)0x2000000001ac = 0;
memset((void*)0x2000000001b0, 0, 112);
syscall(__NR_ioctl, /*fd=*/r[1], /*cmd=*/0x40a0ae49,
/*arg=*/0x200000000180ul);
// ioctl$KVM_SET_USER_MEMORY_REGION2 arguments: [
// fd: fd_kvmvm (resource)
// cmd: const = 0x40a0ae49 (4 bytes)
// arg: ptr[in, kvm_userspace_memory_region2] {
// kvm_userspace_memory_region2 {
// slot: kvm_mem_slots = 0x4 (4 bytes)
// flags: kvm_mem_region_flags = 0x1 (4 bytes)
// paddr: kvm_guest_addrs = 0xffff1000 (8 bytes)
// size: len = 0x2000 (8 bytes)
// addr: VMA[0x2000]
// guest_memfd_offset: int64 = 0x8 (8 bytes)
// guest_memfd: fd_kvm_guest_memfd (resource)
// pad1: const = 0x0 (4 bytes)
// pad2: buffer: {00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
// 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
// 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
// 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
// 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
// 00 00} (length 0x70)
// }
// }
// ]
*(uint32_t*)0x200000000240 = 4;
*(uint32_t*)0x200000000244 = 1;
*(uint64_t*)0x200000000248 = 0xffff1000;
*(uint64_t*)0x200000000250 = 0x2000;
*(uint64_t*)0x200000000258 = 0x200000ffc000;
*(uint64_t*)0x200000000260 = 8;
*(uint32_t*)0x200000000268 = r[2];
*(uint32_t*)0x20000000026c = 0;
memset((void*)0x200000000270, 0, 112);
syscall(__NR_ioctl, /*fd=*/r[1], /*cmd=*/0x40a0ae49,
/*arg=*/0x200000000240ul);
return 0;
}
next prev parent reply other threads:[~2025-12-02 15:27 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-12-02 2:03 [PATCH 0/2] KVM: Fix a guest_memfd memslot UAF Sean Christopherson
2025-12-02 2:03 ` [PATCH 1/2] KVM: Disallow toggling KVM_MEM_GUEST_MEMFD on an existing memslot Sean Christopherson
2025-12-02 2:03 ` [PATCH 2/2] KVM: Harden and prepare for modifying existing guest_memfd memslots Sean Christopherson
2025-12-02 15:27 ` Sean Christopherson [this message]
2025-12-05 16:59 ` [PATCH 0/2] KVM: Fix a guest_memfd memslot UAF Sean Christopherson
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=aS8FTggpT_7cY3cr@google.com \
--to=seanjc@google.com \
--cc=glider@google.com \
--cc=kvm@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=pbonzini@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.