From: Sean Christopherson <seanjc@google.com>
To: Ackerley Tng <ackerleytng@google.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>,
Christian Borntraeger <borntraeger@linux.ibm.com>,
Janosch Frank <frankja@linux.ibm.com>,
Claudio Imbrenda <imbrenda@linux.ibm.com>,
kvm@vger.kernel.org, linux-kernel@vger.kernel.org,
David Hildenbrand <david@redhat.com>,
Fuad Tabba <tabba@google.com>
Subject: Re: [PATCH 6/6] KVM: selftests: Verify that faulting in private guest_memfd memory fails
Date: Mon, 29 Sep 2025 11:10:46 -0700 [thread overview]
Message-ID: <aNrLpkrbnwVSaQGX@google.com> (raw)
In-Reply-To: <diqzldlx1fyk.fsf@google.com>
On Mon, Sep 29, 2025, Ackerley Tng wrote:
> Sean Christopherson <seanjc@google.com> writes:
>
> > Add a guest_memfd testcase to verify that faulting in private memory gets
> > a SIGBUS. For now, test only the case where memory is private by default
> > since KVM doesn't yet support in-place conversion.
> >
> > Cc: Ackerley Tng <ackerleytng@google.com>
> > Signed-off-by: Sean Christopherson <seanjc@google.com>
> > ---
> > .../testing/selftests/kvm/guest_memfd_test.c | 62 ++++++++++++++-----
> > 1 file changed, 46 insertions(+), 16 deletions(-)
> >
> > diff --git a/tools/testing/selftests/kvm/guest_memfd_test.c b/tools/testing/selftests/kvm/guest_memfd_test.c
> > index 5dd40b77dc07..b5a631aca933 100644
> > --- a/tools/testing/selftests/kvm/guest_memfd_test.c
> > +++ b/tools/testing/selftests/kvm/guest_memfd_test.c
> > @@ -40,17 +40,26 @@ static void test_file_read_write(int fd, size_t total_size)
> > "pwrite on a guest_mem fd should fail");
> > }
> >
>
> I feel that the tests should be grouped by concepts being tested
>
> + test_cow_not_supported()
> + mmap() should fail
> + test_mmap_supported()
> + kvm_mmap()
> + regular, successful accesses to offsets within the size of the fd
> + kvm_munmap()
> + test_fault_overflow()
> + kvm_mmap()
> + a helper (perhaps "assert_fault_sigbus(char *mem)"?) that purely
> tries to access beyond the size of the fd and catches SIGBUS
> + regular, successful accesses to offsets within the size of the fd
> + kvm_munmap()
> + test_fault_private()
> + kvm_mmap()
> + a helper (perhaps "assert_fault_sigbus(char *mem)"?) that purely
> tries to access within the size of the fd and catches SIGBUS
> + kvm_munmap()
>
> I think some code duplication in tests is okay if it makes the test flow
> more obvious.
Yeah, depends on what is being duplicated, and how much.
> > -static void test_mmap_supported(int fd, size_t total_size)
> > +static void *test_mmap_common(int fd, size_t size)
> > {
> > - const char val = 0xaa;
> > - char *mem;
> > - size_t i;
> > - int ret;
> > + void *mem;
> >
> > - mem = mmap(NULL, total_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
> > + mem = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
> > TEST_ASSERT(mem == MAP_FAILED, "Copy-on-write not allowed by guest_memfd.");
> >
>
> When grouped this way, test_mmap_common() tests that MAP_PRIVATE or COW
> is not allowed twice, once in test_mmap_supported() and once in
> test_fault_sigbus(). Is that intentional?
Hmm, no? I suspect I just lost track of what was being tested.
> > - mem = kvm_mmap(total_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd);
> > + mem = kvm_mmap(size, PROT_READ | PROT_WRITE, MAP_SHARED, fd);
> > +
> > + return mem;
>
> I feel that returning (and using) the userspace address from a test
> (test_mmap_common()) is a little hard to follow.
Agreed. Should be easy enough to eliminate this helper.
> > -static void test_fault_overflow(int fd, size_t total_size)
> > +static void *test_fault_sigbus(int fd, size_t size)
> > {
> > struct sigaction sa_old, sa_new = {
> > .sa_handler = fault_sigbus_handler,
> > };
> > - size_t map_size = total_size * 4;
> > - const char val = 0xaa;
> > - char *mem;
> > - size_t i;
> > + void *mem;
> >
> > - mem = kvm_mmap(map_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd);
> > + mem = test_mmap_common(fd, size);
> >
> > sigaction(SIGBUS, &sa_new, &sa_old);
> > if (sigsetjmp(jmpbuf, 1) == 0) {
> > - memset(mem, 0xaa, map_size);
> > + memset(mem, 0xaa, size);
> > TEST_ASSERT(false, "memset() should have triggered SIGBUS.");
> > }
> > sigaction(SIGBUS, &sa_old, NULL);
> >
> > + return mem;
>
> I think returning the userspace address from a test is a little hard to
> follow. This one feels even more unexpected because a valid address is
> being returned (and used) from a test that has sigbus in its name.
Yeah, and it's fugly all around. If we pass in the "accessible" size, then we
can reduce the amount of copy+paste, eliminate the weird return and split mmap()
versus munmap(), and get bonus coverage that reads SIGBUS as well.
How's this look?
static void test_fault_sigbus(int fd, size_t accessible_size, size_t mmap_size)
{
struct sigaction sa_old, sa_new = {
.sa_handler = fault_sigbus_handler,
};
const uint8_t val = 0xaa;
uint8_t *mem;
size_t i;
mem = kvm_mmap(mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd);
sigaction(SIGBUS, &sa_new, &sa_old);
if (sigsetjmp(jmpbuf, 1) == 0) {
memset(mem, val, mmap_size);
TEST_FAIL("memset() should have triggered SIGBUS");
}
if (sigsetjmp(jmpbuf, 1) == 0) {
(void)READ_ONCE(mem[accessible_size]);
TEST_FAIL("load at first unaccessible byte should have triggered SIGBUS");
}
sigaction(SIGBUS, &sa_old, NULL);
for (i = 0; i < accessible_size; i++)
TEST_ASSERT_EQ(READ_ONCE(mem[i]), val);
kvm_munmap(mem, mmap_size);
}
static void test_fault_overflow(int fd, size_t total_size)
{
test_fault_sigbus(fd, total_size, total_size * 4);
}
static void test_fault_private(int fd, size_t total_size)
{
test_fault_sigbus(fd, 0, total_size);
}
> > +static void test_fault_private(int fd, size_t total_size)
> > +{
> > + void *mem = test_fault_sigbus(fd, total_size);
> > +
> > + kvm_munmap(mem, total_size);
> > +}
> > +
>
> Testing that faults fail when GUEST_MEMFD_FLAG_DEFAULT_SHARED is not set
> is a good idea. Perhaps it could be even clearer if further split up:
>
> + test_mmap_supported()
> + kvm_mmap()
> + kvm_munmap()
> + test_mmap_supported_fault_supported()
> + kvm_mmap()
> + successful accesses to offsets within the size of the fd
> + kvm_munmap()
> + test_mmap_supported_fault_sigbus()
> + kvm_mmap()
> + expect SIGBUS from accesses to offsets within the size of the fd
> + kvm_munmap()
>
> > static void test_mmap_not_supported(int fd, size_t total_size)
> > {
> > char *mem;
> > @@ -274,9 +299,12 @@ static void __test_guest_memfd(struct kvm_vm *vm, uint64_t flags)
> >
> > gmem_test(file_read_write, vm, flags);
> >
> > - if (flags & GUEST_MEMFD_FLAG_MMAP) {
> > + if (flags & GUEST_MEMFD_FLAG_MMAP &&
> > + flags & GUEST_MEMFD_FLAG_DEFAULT_SHARED) {
> > gmem_test(mmap_supported, vm, flags);
> > gmem_test(fault_overflow, vm, flags);
> > + } else if (flags & GUEST_MEMFD_FLAG_MMAP) {
> > + gmem_test(fault_private, vm, flags);
>
> test_fault_private() makes me think the test is testing for private
> faults, but there's nothing private about this fault,
It's a user fault on private memory, not sure how else to describe that :-)
The CoCo shared vs. private and MAP_{SHARED,PRIVATE} collision is unfortunate,
but I think we should prioritize standardizing on CoCo shared vs. private since
that is what KVM will care about 99.9% of the time, i.e. in literally everything
except kvm_gmem_mmap().
> and the fault doesn't even come from the guest.
Sure, but I don't see what that has to do with anything, e.g. fault_overflow()
isn't a fault from the guest either.
> > } else {
> > gmem_test(mmap_not_supported, vm, flags);
> > }
>
> If split up as described above, this could be
>
> if (flags & GUEST_MEMFD_FLAG_MMAP &&
> flags & GUEST_MEMFD_FLAG_DEFAULT_SHARED) {
> gmem_test(mmap_supported_fault_supported, vm, flags);
> gmem_test(fault_overflow, vm, flags);
> } else if (flags & GUEST_MEMFD_FLAG_MMAP) {
> gmem_test(mmap_supported_fault_sigbus, vm, flags);
I find these unintuitive, e.g. is this one "mmap() supported, test fault sigbus",
or is it "mmap(), test supported fault sigbus". I also don't like that some of
the test names describe the _result_ (SIBGUS), where as others describe _what_
is being tested.
In general, I don't like test names that describe the result, because IMO what
is being tested is far more interesting. E.g. from a test coverage persective,
I don't care if attempting to fault in (CoCO) private memory gets SIGBUS versus
SIGSEGV, but I most definitely care that we have test coverage for the "what".
Looking at everything, I think the only that doesn't fit well is the CoW
scenario. What if we extract that to its own helper? That would eliminate the
ugly test_mmap_common(),
So my vote would be to keep things largely the same:
if (flags & GUEST_MEMFD_FLAG_MMAP &&
flags & GUEST_MEMFD_FLAG_DEFAULT_SHARED) {
gmem_test(mmap_supported, vm, flags);
gmem_test(mmap_cow, vm, flags);
gmem_test(fault_overflow, vm, flags);
gmem_test(mbind, vm, flags);
gmem_test(numa_allocation, vm, flags);
} else if (flags & GUEST_MEMFD_FLAG_MMAP) {
gmem_test(fault_private, vm, flags);
} else {
gmem_test(mmap_not_supported, vm, flags);
}
next prev parent reply other threads:[~2025-09-29 18:10 UTC|newest]
Thread overview: 55+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-09-26 16:31 [PATCH 0/6] KVM: Avoid a lurking guest_memfd ABI mess Sean Christopherson
2025-09-26 16:31 ` [PATCH 1/6] KVM: guest_memfd: Add DEFAULT_SHARED flag, reject user page faults if not set Sean Christopherson
2025-09-29 8:38 ` David Hildenbrand
2025-09-29 8:57 ` Fuad Tabba
2025-09-29 9:01 ` David Hildenbrand
2025-09-29 9:04 ` Fuad Tabba
2025-09-29 9:43 ` Ackerley Tng
2025-09-29 10:15 ` Patrick Roy
2025-09-29 10:22 ` David Hildenbrand
2025-09-29 10:51 ` Ackerley Tng
2025-09-29 16:55 ` Sean Christopherson
2025-09-30 0:15 ` Sean Christopherson
2025-09-30 8:36 ` Ackerley Tng
2025-10-01 14:22 ` Vishal Annapurve
2025-10-01 16:15 ` Sean Christopherson
2025-10-01 16:31 ` Vishal Annapurve
2025-10-01 17:16 ` Sean Christopherson
2025-10-01 22:13 ` Vishal Annapurve
2025-10-02 0:04 ` Sean Christopherson
2025-10-02 15:41 ` Vishal Annapurve
2025-10-03 0:12 ` Sean Christopherson
2025-10-03 4:10 ` Vishal Annapurve
2025-10-03 16:13 ` Sean Christopherson
2025-10-03 20:30 ` Vishal Annapurve
2025-09-29 16:54 ` Sean Christopherson
2025-09-26 16:31 ` [PATCH 2/6] KVM: selftests: Stash the host page size in a global in the guest_memfd test Sean Christopherson
2025-09-29 9:12 ` Fuad Tabba
2025-09-29 9:17 ` David Hildenbrand
2025-09-29 10:56 ` Ackerley Tng
2025-09-29 16:58 ` Sean Christopherson
2025-09-30 6:52 ` Ackerley Tng
2025-09-26 16:31 ` [PATCH 3/6] KVM: selftests: Create a new guest_memfd for each testcase Sean Christopherson
2025-09-29 9:18 ` David Hildenbrand
2025-09-29 9:24 ` Fuad Tabba
2025-09-29 11:02 ` Ackerley Tng
2025-09-26 16:31 ` [PATCH 4/6] KVM: selftests: Add test coverage for guest_memfd without GUEST_MEMFD_FLAG_MMAP Sean Christopherson
2025-09-29 9:21 ` David Hildenbrand
2025-09-29 9:24 ` Fuad Tabba
2025-09-26 16:31 ` [PATCH 5/6] KVM: selftests: Add wrappers for mmap() and munmap() to assert success Sean Christopherson
2025-09-29 9:24 ` Fuad Tabba
2025-09-29 9:28 ` David Hildenbrand
2025-09-29 11:08 ` Ackerley Tng
2025-09-29 17:32 ` Sean Christopherson
2025-09-30 7:09 ` Ackerley Tng
2025-09-30 14:24 ` Sean Christopherson
2025-10-01 10:18 ` Ackerley Tng
2025-09-26 16:31 ` [PATCH 6/6] KVM: selftests: Verify that faulting in private guest_memfd memory fails Sean Christopherson
2025-09-29 9:24 ` Fuad Tabba
2025-09-29 9:28 ` David Hildenbrand
2025-09-29 14:38 ` Ackerley Tng
2025-09-29 18:10 ` Sean Christopherson [this message]
2025-09-29 18:35 ` Sean Christopherson
2025-09-30 7:53 ` Ackerley Tng
2025-09-30 14:58 ` Sean Christopherson
2025-10-01 10:26 ` Ackerley Tng
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=aNrLpkrbnwVSaQGX@google.com \
--to=seanjc@google.com \
--cc=ackerleytng@google.com \
--cc=borntraeger@linux.ibm.com \
--cc=david@redhat.com \
--cc=frankja@linux.ibm.com \
--cc=imbrenda@linux.ibm.com \
--cc=kvm@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=pbonzini@redhat.com \
--cc=tabba@google.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.