lkml.org 
[lkml]   [2023]   [Aug]   [7]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Date
    Subject[PATCH v4 34/36] selftests/arm64: Add GCS signal tests
    Do some testing of the signal handling for GCS, checking that a GCS
    frame has the expected information in it and that the expected signals
    are delivered with invalid operations.

    Signed-off-by: Mark Brown <broonie@kernel.org>
    ---
    tools/testing/selftests/arm64/signal/.gitignore | 1 +
    .../selftests/arm64/signal/test_signals_utils.h | 10 +++
    .../arm64/signal/testcases/gcs_exception_fault.c | 59 ++++++++++++++++
    .../selftests/arm64/signal/testcases/gcs_frame.c | 78 ++++++++++++++++++++++
    .../arm64/signal/testcases/gcs_write_fault.c | 67 +++++++++++++++++++
    5 files changed, 215 insertions(+)

    diff --git a/tools/testing/selftests/arm64/signal/.gitignore b/tools/testing/selftests/arm64/signal/.gitignore
    index 839e3a252629..26de12918890 100644
    --- a/tools/testing/selftests/arm64/signal/.gitignore
    +++ b/tools/testing/selftests/arm64/signal/.gitignore
    @@ -1,6 +1,7 @@
    # SPDX-License-Identifier: GPL-2.0-only
    mangle_*
    fake_sigreturn_*
    +gcs_*
    sme_*
    ssve_*
    sve_*
    diff --git a/tools/testing/selftests/arm64/signal/test_signals_utils.h b/tools/testing/selftests/arm64/signal/test_signals_utils.h
    index 1cea64986baa..d41f237db28d 100644
    --- a/tools/testing/selftests/arm64/signal/test_signals_utils.h
    +++ b/tools/testing/selftests/arm64/signal/test_signals_utils.h
    @@ -6,6 +6,7 @@

    #include <assert.h>
    #include <stdio.h>
    +#include <stdint.h>
    #include <string.h>

    #include "test_signals.h"
    @@ -45,6 +46,15 @@ void test_result(struct tdescr *td);
    _arg1; \
    })

    +static inline __attribute__((always_inline)) uint64_t get_gcspr_el0(void)
    +{
    + uint64_t val;
    +
    + asm volatile("mrs %0, S3_3_C2_C5_1" : "=r" (val));
    +
    + return val;
    +}
    +
    static inline bool feats_ok(struct tdescr *td)
    {
    if (td->feats_incompatible & td->feats_supported)
    diff --git a/tools/testing/selftests/arm64/signal/testcases/gcs_exception_fault.c b/tools/testing/selftests/arm64/signal/testcases/gcs_exception_fault.c
    new file mode 100644
    index 000000000000..532d533592a1
    --- /dev/null
    +++ b/tools/testing/selftests/arm64/signal/testcases/gcs_exception_fault.c
    @@ -0,0 +1,59 @@
    +// SPDX-License-Identifier: GPL-2.0
    +/*
    + * Copyright (C) 2023 ARM Limited
    + */
    +
    +#include <errno.h>
    +#include <signal.h>
    +#include <unistd.h>
    +
    +#include <sys/mman.h>
    +#include <sys/prctl.h>
    +
    +#include "test_signals_utils.h"
    +#include "testcases.h"
    +
    +/* This should be includable from some standard header, but which? */
    +#ifndef SEGV_CPERR
    +#define SEGV_CPERR 10
    +#endif
    +
    +static inline void gcsss1(uint64_t Xt)
    +{
    + asm volatile (
    + "sys #3, C7, C7, #2, %0\n"
    + :
    + : "rZ" (Xt)
    + : "memory");
    +}
    +
    +static int gcs_op_fault_trigger(struct tdescr *td)
    +{
    + /*
    + * The slot below our current GCS should be in a valid GCS but
    + * must not have a valid cap in it.
    + */
    + gcsss1(get_gcspr_el0() - 8);
    +
    + return 0;
    +}
    +
    +static int gcs_op_fault_signal(struct tdescr *td, siginfo_t *si,
    + ucontext_t *uc)
    +{
    + ASSERT_GOOD_CONTEXT(uc);
    +
    + return 1;
    +}
    +
    +struct tdescr tde = {
    + .name = "Invalid GCS operation",
    + .descr = "An invalid GCS operation generates the expected signal",
    + .feats_required = FEAT_GCS,
    + .timeout = 3,
    + .sig_ok = SIGSEGV,
    + .sig_ok_code = SEGV_CPERR,
    + .sanity_disabled = true,
    + .trigger = gcs_op_fault_trigger,
    + .run = gcs_op_fault_signal,
    +};
    diff --git a/tools/testing/selftests/arm64/signal/testcases/gcs_frame.c b/tools/testing/selftests/arm64/signal/testcases/gcs_frame.c
    new file mode 100644
    index 000000000000..d67cb26195a6
    --- /dev/null
    +++ b/tools/testing/selftests/arm64/signal/testcases/gcs_frame.c
    @@ -0,0 +1,78 @@
    +// SPDX-License-Identifier: GPL-2.0
    +/*
    + * Copyright (C) 2023 ARM Limited
    + */
    +
    +#include <signal.h>
    +#include <ucontext.h>
    +#include <sys/prctl.h>
    +
    +#include "test_signals_utils.h"
    +#include "testcases.h"
    +
    +static union {
    + ucontext_t uc;
    + char buf[1024 * 64];
    +} context;
    +
    +static int gcs_regs(struct tdescr *td, siginfo_t *si, ucontext_t *uc)
    +{
    + size_t offset;
    + struct _aarch64_ctx *head = GET_BUF_RESV_HEAD(context);
    + struct gcs_context *gcs;
    + unsigned long expected, gcspr;
    + int ret;
    +
    + ret = prctl(PR_GET_SHADOW_STACK_STATUS, &expected, 0, 0, 0);
    + if (ret != 0) {
    + fprintf(stderr, "Unable to query GCS status\n");
    + return 1;
    + }
    +
    + /* We expect a cap to be added to the GCS in the signal frame */
    + gcspr = get_gcspr_el0();
    + gcspr -= 8;
    + fprintf(stderr, "Expecting GCSPR_EL0 %lx\n", gcspr);
    +
    + if (!get_current_context(td, &context.uc, sizeof(context))) {
    + fprintf(stderr, "Failed getting context\n");
    + return 1;
    + }
    + fprintf(stderr, "Got context\n");
    +
    + head = get_header(head, GCS_MAGIC, GET_BUF_RESV_SIZE(context),
    + &offset);
    + if (!head) {
    + fprintf(stderr, "No GCS context\n");
    + return 1;
    + }
    +
    + gcs = (struct gcs_context *)head;
    +
    + /* Basic size validation is done in get_current_context() */
    +
    + if (gcs->features_enabled != expected) {
    + fprintf(stderr, "Features enabled %llx but expected %lx\n",
    + gcs->features_enabled, expected);
    + return 1;
    + }
    +
    + if (gcs->gcspr != gcspr) {
    + fprintf(stderr, "Got GCSPR %llx but expected %lx\n",
    + gcs->gcspr, gcspr);
    + return 1;
    + }
    +
    + fprintf(stderr, "GCS context validated\n");
    + td->pass = 1;
    +
    + return 0;
    +}
    +
    +struct tdescr tde = {
    + .name = "GCS basics",
    + .descr = "Validate a GCS signal context",
    + .feats_required = FEAT_GCS,
    + .timeout = 3,
    + .run = gcs_regs,
    +};
    diff --git a/tools/testing/selftests/arm64/signal/testcases/gcs_write_fault.c b/tools/testing/selftests/arm64/signal/testcases/gcs_write_fault.c
    new file mode 100644
    index 000000000000..126b1a294a29
    --- /dev/null
    +++ b/tools/testing/selftests/arm64/signal/testcases/gcs_write_fault.c
    @@ -0,0 +1,67 @@
    +// SPDX-License-Identifier: GPL-2.0
    +/*
    + * Copyright (C) 2023 ARM Limited
    + */
    +
    +#include <errno.h>
    +#include <signal.h>
    +#include <unistd.h>
    +
    +#include <sys/mman.h>
    +#include <sys/prctl.h>
    +
    +#include "test_signals_utils.h"
    +#include "testcases.h"
    +
    +static uint64_t *gcs_page;
    +
    +#ifndef __NR_map_shadow_stack
    +#define __NR_map_shadow_stack 452
    +#endif
    +
    +static bool alloc_gcs(struct tdescr *td)
    +{
    + long page_size = sysconf(_SC_PAGE_SIZE);
    +
    + gcs_page = (void *)syscall(__NR_map_shadow_stack, 0,
    + page_size, 0);
    + if (gcs_page == MAP_FAILED) {
    + fprintf(stderr, "Failed to map %ld byte GCS: %d\n",
    + page_size, errno);
    + return false;
    + }
    +
    + return true;
    +}
    +
    +static int gcs_write_fault_trigger(struct tdescr *td)
    +{
    + /* Verify that the page is readable (ie, not completely unmapped) */
    + fprintf(stderr, "Read value 0x%lx\n", gcs_page[0]);
    +
    + /* A regular write should trigger a fault */
    + gcs_page[0] = EINVAL;
    +
    + return 0;
    +}
    +
    +static int gcs_write_fault_signal(struct tdescr *td, siginfo_t *si,
    + ucontext_t *uc)
    +{
    + ASSERT_GOOD_CONTEXT(uc);
    +
    + return 1;
    +}
    +
    +
    +struct tdescr tde = {
    + .name = "GCS write fault",
    + .descr = "Normal writes to a GCS segfault",
    + .feats_required = FEAT_GCS,
    + .timeout = 3,
    + .sig_ok = SIGSEGV,
    + .sanity_disabled = true,
    + .init = alloc_gcs,
    + .trigger = gcs_write_fault_trigger,
    + .run = gcs_write_fault_signal,
    +};
    --
    2.30.2

    \
     
     \ /
      Last update: 2023-08-08 00:09    [W:3.659 / U:0.064 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site