Mark Brown <broonie@xxxxxxxxxx> writes: > + /* Same thing via process_vm_readv() */ > + local_iov.iov_base = &rval; > + local_iov.iov_len = sizeof(rval); > + remote_iov.iov_base = (void *)gcspr; > + remote_iov.iov_len = sizeof(rval); > + ret = process_vm_writev(child, &local_iov, 1, &remote_iov, 1, 0); > + if (ret == -1) > + ksft_print_msg("process_vm_readv() failed: %s (%d)\n", > + strerror(errno), errno); The comment and the error message say "process_vm_readv()", but the function actually called is process_vm_writev(). Is this intended? Also, process_vm_writev() is failing when I run on my Arm FVP: # # RUN global.ptrace_read_write ... # # Child: 1150 # # Child GCSPR 0xffffa210ffd8, flags 1, locked 0 # # process_vm_readv() failed: Bad address (14) # # libc-gcs.c:271:ptrace_read_write:Expected ret (-1) == sizeof(rval) (8) # # libc-gcs.c:272:ptrace_read_write:Expected val (281473401005692) == rval (281473402849248) # # libc-gcs.c:293:ptrace_read_write:Expected val (281473401005692) == ptrace(PTRACE_PEEKDATA, child, (void *)gcspr, NULL) (0) # # ptrace_read_write: Test failed at step #1 # # FAIL global.ptrace_read_write # not ok 4 global.ptrace_read_write If I swap process_vm_readv() and process_vm_writev(), then the read succeeds but the write fails: # RUN global.ptrace_read_write ... # Child: 1996 # Child GCSPR 0xffffa7fcffd8, flags 1, locked 0 # process_vm_writev() failed: Bad address (14) # libc-gcs.c:291:ptrace_read_write:Expected ret (-1) == sizeof(rval) (8) # libc-gcs.c:293:ptrace_read_write:Expected val (281473500358268) == ptrace(PTRACE_PEEKDATA, child, (void *)gcspr, NULL) (0) # ptrace_read_write: Test failed at step #1 # FAIL global.ptrace_read_write not ok 4 global.ptrace_read_write > +/* Put it all together, we can safely switch to and from the stack */ > +TEST_F(map_gcs, stack_switch) > +{ > + size_t cap_index; > + cap_index = (variant->stack_size / sizeof(unsigned long)); > + unsigned long *orig_gcspr_el0, *pivot_gcspr_el0; > + > + /* Skip over the stack terminator and point at the cap */ > + switch (variant->flags & (SHADOW_STACK_SET_MARKER | SHADOW_STACK_SET_TOKEN)) { > + case SHADOW_STACK_SET_MARKER | SHADOW_STACK_SET_TOKEN: > + cap_index -= 2; > + break; > + case SHADOW_STACK_SET_TOKEN: > + cap_index -= 1; > + break; > + case SHADOW_STACK_SET_MARKER: > + case 0: > + /* No cap, no test */ > + return; > + } > + pivot_gcspr_el0 = &self->stack[cap_index]; > + > + /* Pivot to the new GCS */ > + ksft_print_msg("Pivoting to %p from %p, target has value 0x%lx\n", > + pivot_gcspr_el0, get_gcspr(), > + *pivot_gcspr_el0); > + gcsss1(pivot_gcspr_el0); > + orig_gcspr_el0 = gcsss2(); > + ksft_print_msg("Pivoted to %p from %p, target has value 0x%lx\n", > + pivot_gcspr_el0, get_gcspr(), Not sure about the intent here, but perhaps "get_gcspr()" here should be "orig_gcspr_el0" instead? Ditto in the equivalent place at the map_gcs.stack_overflow test below. Also, it's strange that the tests defined after map_gcs.stack_overflow don't run when I execute this test program. I'm doing: $ ./run_kselftest.sh -t arm64:libc-gcs I.e., these tests aren't being run in my FVP: > +FIXTURE_VARIANT_ADD(map_invalid_gcs, too_small) > +FIXTURE_VARIANT_ADD(map_invalid_gcs, unligned_1) > +FIXTURE_VARIANT_ADD(map_invalid_gcs, unligned_2) > +FIXTURE_VARIANT_ADD(map_invalid_gcs, unligned_3) > +FIXTURE_VARIANT_ADD(map_invalid_gcs, unligned_4) > +FIXTURE_VARIANT_ADD(map_invalid_gcs, unligned_5) > +FIXTURE_VARIANT_ADD(map_invalid_gcs, unligned_6) > +FIXTURE_VARIANT_ADD(map_invalid_gcs, unligned_7) > +TEST_F(map_invalid_gcs, do_map) > +FIXTURE_VARIANT_ADD(invalid_mprotect, exec) > +FIXTURE_VARIANT_ADD(invalid_mprotect, bti) > +FIXTURE_VARIANT_ADD(invalid_mprotect, exec_bti) > +TEST_F(invalid_mprotect, do_map) > +TEST_F(invalid_mprotect, do_map_read) Finally, one last comment: > +int main(int argc, char **argv) > +{ > + unsigned long gcs_mode; > + int ret; > + > + if (!(getauxval(AT_HWCAP2) & HWCAP2_GCS)) > + ksft_exit_skip("SKIP GCS not supported\n"); > + > + /* > + * Force shadow stacks on, our tests *should* be fine with or > + * without libc support and with or without this having ended > + * up tagged for GCS and enabled by the dynamic linker. We > + * can't use the libc prctl() function since we can't return > + * from enabling the stack. Also lock GCS if not already > + * locked so we can test behaviour when it's locked. This is probably a leftover from a previous version: the test doesn't lock any GCS flag. > + */ > + ret = my_syscall2(__NR_prctl, PR_GET_SHADOW_STACK_STATUS, &gcs_mode); > + if (ret) { > + ksft_print_msg("Failed to read GCS state: %d\n", ret); > + return EXIT_FAILURE; > + } > + > + if (!(gcs_mode & PR_SHADOW_STACK_ENABLE)) { > + gcs_mode = PR_SHADOW_STACK_ENABLE; > + ret = my_syscall2(__NR_prctl, PR_SET_SHADOW_STACK_STATUS, > + gcs_mode); > + if (ret) { > + ksft_print_msg("Failed to configure GCS: %d\n", ret); > + return EXIT_FAILURE; > + } > + } > + > + /* Avoid returning in case libc doesn't understand GCS */ > + exit(test_harness_run(argc, argv)); > +} -- Thiago