Skip to content

Commit 0dd8d22

Browse files
Ricardo KollerMarc Zyngier
authored andcommitted
KVM: selftests: aarch64: Relax userfaultfd read vs. write checks
Only Stage1 Page table walks (S1PTW) writing a PTE on an unmapped page should result in a userfaultfd write. However, the userfaultfd tests in page_fault_test wrongly assert that any S1PTW is a PTE write. Fix this by relaxing the read vs. write checks in all userfaultfd handlers. Note that this is also an attempt to focus less on KVM (and userfaultfd) behavior, and more on architectural behavior. Also note that after commit 406504c ("KVM: arm64: Fix S1PTW handling on RO memslots"), the userfaultfd fault (S1PTW with AF on an unmaped PTE page) is actually a read: the translation fault that comes before the permission fault. Signed-off-by: Ricardo Koller <[email protected]> Reviewed-by: Oliver Upton <[email protected]> Signed-off-by: Marc Zyngier <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 6028acb commit 0dd8d22

File tree

1 file changed

+34
-49
lines changed

1 file changed

+34
-49
lines changed

tools/testing/selftests/kvm/aarch64/page_fault_test.c

Lines changed: 34 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ static struct uffd_args {
304304

305305
/* Returns true to continue the test, and false if it should be skipped. */
306306
static int uffd_generic_handler(int uffd_mode, int uffd, struct uffd_msg *msg,
307-
struct uffd_args *args, bool expect_write)
307+
struct uffd_args *args)
308308
{
309309
uint64_t addr = msg->arg.pagefault.address;
310310
uint64_t flags = msg->arg.pagefault.flags;
@@ -313,7 +313,6 @@ static int uffd_generic_handler(int uffd_mode, int uffd, struct uffd_msg *msg,
313313

314314
TEST_ASSERT(uffd_mode == UFFDIO_REGISTER_MODE_MISSING,
315315
"The only expected UFFD mode is MISSING");
316-
ASSERT_EQ(!!(flags & UFFD_PAGEFAULT_FLAG_WRITE), expect_write);
317316
ASSERT_EQ(addr, (uint64_t)args->hva);
318317

319318
pr_debug("uffd fault: addr=%p write=%d\n",
@@ -337,19 +336,14 @@ static int uffd_generic_handler(int uffd_mode, int uffd, struct uffd_msg *msg,
337336
return 0;
338337
}
339338

340-
static int uffd_pt_write_handler(int mode, int uffd, struct uffd_msg *msg)
339+
static int uffd_pt_handler(int mode, int uffd, struct uffd_msg *msg)
341340
{
342-
return uffd_generic_handler(mode, uffd, msg, &pt_args, true);
341+
return uffd_generic_handler(mode, uffd, msg, &pt_args);
343342
}
344343

345-
static int uffd_data_write_handler(int mode, int uffd, struct uffd_msg *msg)
344+
static int uffd_data_handler(int mode, int uffd, struct uffd_msg *msg)
346345
{
347-
return uffd_generic_handler(mode, uffd, msg, &data_args, true);
348-
}
349-
350-
static int uffd_data_read_handler(int mode, int uffd, struct uffd_msg *msg)
351-
{
352-
return uffd_generic_handler(mode, uffd, msg, &data_args, false);
346+
return uffd_generic_handler(mode, uffd, msg, &data_args);
353347
}
354348

355349
static void setup_uffd_args(struct userspace_mem_region *region,
@@ -822,7 +816,7 @@ static void help(char *name)
822816
.mem_mark_cmd = CMD_HOLE_DATA | CMD_HOLE_PT, \
823817
.guest_test_check = { _CHECK(_with_af), _test_check }, \
824818
.uffd_data_handler = _uffd_data_handler, \
825-
.uffd_pt_handler = uffd_pt_write_handler, \
819+
.uffd_pt_handler = uffd_pt_handler, \
826820
.expected_events = { .uffd_faults = _uffd_faults, }, \
827821
}
828822

@@ -878,7 +872,7 @@ static void help(char *name)
878872
.guest_prepare = { _PREPARE(_access) }, \
879873
.guest_test = _access, \
880874
.uffd_data_handler = _uffd_data_handler, \
881-
.uffd_pt_handler = uffd_pt_write_handler, \
875+
.uffd_pt_handler = uffd_pt_handler, \
882876
.mmio_handler = _mmio_handler, \
883877
.expected_events = { .mmio_exits = _mmio_exits, \
884878
.uffd_faults = _uffd_faults }, \
@@ -892,7 +886,7 @@ static void help(char *name)
892886
.mem_mark_cmd = CMD_HOLE_DATA | CMD_HOLE_PT, \
893887
.guest_test = _access, \
894888
.uffd_data_handler = _uffd_data_handler, \
895-
.uffd_pt_handler = uffd_pt_write_handler, \
889+
.uffd_pt_handler = uffd_pt_handler, \
896890
.fail_vcpu_run_handler = fail_vcpu_run_mmio_no_syndrome_handler, \
897891
.expected_events = { .fail_vcpu_runs = 1, \
898892
.uffd_faults = _uffd_faults }, \
@@ -933,29 +927,27 @@ static struct test_desc tests[] = {
933927
* (S1PTW).
934928
*/
935929
TEST_UFFD(guest_read64, with_af, CMD_HOLE_DATA | CMD_HOLE_PT,
936-
uffd_data_read_handler, uffd_pt_write_handler, 2),
937-
/* no_af should also lead to a PT write. */
930+
uffd_data_handler, uffd_pt_handler, 2),
938931
TEST_UFFD(guest_read64, no_af, CMD_HOLE_DATA | CMD_HOLE_PT,
939-
uffd_data_read_handler, uffd_pt_write_handler, 2),
940-
/* Note how that cas invokes the read handler. */
932+
uffd_data_handler, uffd_pt_handler, 2),
941933
TEST_UFFD(guest_cas, with_af, CMD_HOLE_DATA | CMD_HOLE_PT,
942-
uffd_data_read_handler, uffd_pt_write_handler, 2),
934+
uffd_data_handler, uffd_pt_handler, 2),
943935
/*
944936
* Can't test guest_at with_af as it's IMPDEF whether the AF is set.
945937
* The S1PTW fault should still be marked as a write.
946938
*/
947939
TEST_UFFD(guest_at, no_af, CMD_HOLE_DATA | CMD_HOLE_PT,
948-
uffd_data_read_handler, uffd_pt_write_handler, 1),
940+
uffd_no_handler, uffd_pt_handler, 1),
949941
TEST_UFFD(guest_ld_preidx, with_af, CMD_HOLE_DATA | CMD_HOLE_PT,
950-
uffd_data_read_handler, uffd_pt_write_handler, 2),
942+
uffd_data_handler, uffd_pt_handler, 2),
951943
TEST_UFFD(guest_write64, with_af, CMD_HOLE_DATA | CMD_HOLE_PT,
952-
uffd_data_write_handler, uffd_pt_write_handler, 2),
944+
uffd_data_handler, uffd_pt_handler, 2),
953945
TEST_UFFD(guest_dc_zva, with_af, CMD_HOLE_DATA | CMD_HOLE_PT,
954-
uffd_data_write_handler, uffd_pt_write_handler, 2),
946+
uffd_data_handler, uffd_pt_handler, 2),
955947
TEST_UFFD(guest_st_preidx, with_af, CMD_HOLE_DATA | CMD_HOLE_PT,
956-
uffd_data_write_handler, uffd_pt_write_handler, 2),
948+
uffd_data_handler, uffd_pt_handler, 2),
957949
TEST_UFFD(guest_exec, with_af, CMD_HOLE_DATA | CMD_HOLE_PT,
958-
uffd_data_read_handler, uffd_pt_write_handler, 2),
950+
uffd_data_handler, uffd_pt_handler, 2),
959951

960952
/*
961953
* Try accesses when the data and PT memory regions are both
@@ -980,25 +972,25 @@ static struct test_desc tests[] = {
980972
* fault, and nothing in the dirty log. Any S1PTW should result in
981973
* a write in the dirty log and a userfaultfd write.
982974
*/
983-
TEST_UFFD_AND_DIRTY_LOG(guest_read64, with_af, uffd_data_read_handler, 2,
975+
TEST_UFFD_AND_DIRTY_LOG(guest_read64, with_af, uffd_data_handler, 2,
984976
guest_check_no_write_in_dirty_log),
985977
/* no_af should also lead to a PT write. */
986-
TEST_UFFD_AND_DIRTY_LOG(guest_read64, no_af, uffd_data_read_handler, 2,
978+
TEST_UFFD_AND_DIRTY_LOG(guest_read64, no_af, uffd_data_handler, 2,
987979
guest_check_no_write_in_dirty_log),
988-
TEST_UFFD_AND_DIRTY_LOG(guest_ld_preidx, with_af, uffd_data_read_handler,
980+
TEST_UFFD_AND_DIRTY_LOG(guest_ld_preidx, with_af, uffd_data_handler,
989981
2, guest_check_no_write_in_dirty_log),
990-
TEST_UFFD_AND_DIRTY_LOG(guest_at, with_af, 0, 1,
982+
TEST_UFFD_AND_DIRTY_LOG(guest_at, with_af, uffd_no_handler, 1,
991983
guest_check_no_write_in_dirty_log),
992-
TEST_UFFD_AND_DIRTY_LOG(guest_exec, with_af, uffd_data_read_handler, 2,
984+
TEST_UFFD_AND_DIRTY_LOG(guest_exec, with_af, uffd_data_handler, 2,
993985
guest_check_no_write_in_dirty_log),
994-
TEST_UFFD_AND_DIRTY_LOG(guest_write64, with_af, uffd_data_write_handler,
986+
TEST_UFFD_AND_DIRTY_LOG(guest_write64, with_af, uffd_data_handler,
995987
2, guest_check_write_in_dirty_log),
996-
TEST_UFFD_AND_DIRTY_LOG(guest_cas, with_af, uffd_data_read_handler, 2,
988+
TEST_UFFD_AND_DIRTY_LOG(guest_cas, with_af, uffd_data_handler, 2,
997989
guest_check_write_in_dirty_log),
998-
TEST_UFFD_AND_DIRTY_LOG(guest_dc_zva, with_af, uffd_data_write_handler,
990+
TEST_UFFD_AND_DIRTY_LOG(guest_dc_zva, with_af, uffd_data_handler,
999991
2, guest_check_write_in_dirty_log),
1000992
TEST_UFFD_AND_DIRTY_LOG(guest_st_preidx, with_af,
1001-
uffd_data_write_handler, 2,
993+
uffd_data_handler, 2,
1002994
guest_check_write_in_dirty_log),
1003995

1004996
/*
@@ -1051,22 +1043,15 @@ static struct test_desc tests[] = {
10511043
* no userfaultfd write fault. Reads result in userfaultfd getting
10521044
* triggered.
10531045
*/
1054-
TEST_RO_MEMSLOT_AND_UFFD(guest_read64, 0, 0,
1055-
uffd_data_read_handler, 2),
1056-
TEST_RO_MEMSLOT_AND_UFFD(guest_ld_preidx, 0, 0,
1057-
uffd_data_read_handler, 2),
1058-
TEST_RO_MEMSLOT_AND_UFFD(guest_at, 0, 0,
1059-
uffd_no_handler, 1),
1060-
TEST_RO_MEMSLOT_AND_UFFD(guest_exec, 0, 0,
1061-
uffd_data_read_handler, 2),
1046+
TEST_RO_MEMSLOT_AND_UFFD(guest_read64, 0, 0, uffd_data_handler, 2),
1047+
TEST_RO_MEMSLOT_AND_UFFD(guest_ld_preidx, 0, 0, uffd_data_handler, 2),
1048+
TEST_RO_MEMSLOT_AND_UFFD(guest_at, 0, 0, uffd_no_handler, 1),
1049+
TEST_RO_MEMSLOT_AND_UFFD(guest_exec, 0, 0, uffd_data_handler, 2),
10621050
TEST_RO_MEMSLOT_AND_UFFD(guest_write64, mmio_on_test_gpa_handler, 1,
1063-
uffd_data_write_handler, 2),
1064-
TEST_RO_MEMSLOT_NO_SYNDROME_AND_UFFD(guest_cas,
1065-
uffd_data_read_handler, 2),
1066-
TEST_RO_MEMSLOT_NO_SYNDROME_AND_UFFD(guest_dc_zva,
1067-
uffd_no_handler, 1),
1068-
TEST_RO_MEMSLOT_NO_SYNDROME_AND_UFFD(guest_st_preidx,
1069-
uffd_no_handler, 1),
1051+
uffd_data_handler, 2),
1052+
TEST_RO_MEMSLOT_NO_SYNDROME_AND_UFFD(guest_cas, uffd_data_handler, 2),
1053+
TEST_RO_MEMSLOT_NO_SYNDROME_AND_UFFD(guest_dc_zva, uffd_no_handler, 1),
1054+
TEST_RO_MEMSLOT_NO_SYNDROME_AND_UFFD(guest_st_preidx, uffd_no_handler, 1),
10701055

10711056
{ 0 }
10721057
};

0 commit comments

Comments
 (0)