tests/tcg/aarch64: Add gcsstr
Add some infrastructure for testing gcs in userspace. Validate successful and trapped executions of GCSSTR. Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20251008215613.300150-72-richard.henderson@linaro.org [PMM: fixed hardcoded tabs] Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
parent
d2687ad312
commit
3f3cc39b7d
3 changed files with 124 additions and 0 deletions
|
|
@ -75,6 +75,11 @@ AARCH64_TESTS += $(SME_TESTS)
|
|||
$(SME_TESTS): CFLAGS += $(CROSS_AS_HAS_ARMV9_SME)
|
||||
endif
|
||||
|
||||
# GCS Tests
|
||||
GCS_TESTS += gcsstr
|
||||
AARCH64_TESTS += $(GCS_TESTS)
|
||||
$(GCS_TESTS): gcs.h
|
||||
|
||||
# System Registers Tests
|
||||
AARCH64_TESTS += sysregs
|
||||
|
||||
|
|
|
|||
71
tests/tcg/aarch64/gcs.h
Normal file
71
tests/tcg/aarch64/gcs.h
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Linux kernel fallback API definitions for GCS and test helpers.
|
||||
*
|
||||
* Copyright (c) 2025 Linaro Ltd
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
#ifndef PR_GET_SHADOW_STACK_STATUS
|
||||
#define PR_GET_SHADOW_STACK_STATUS 74
|
||||
#endif
|
||||
#ifndef PR_SET_SHADOW_STACK_STATUS
|
||||
#define PR_SET_SHADOW_STACK_STATUS 75
|
||||
#endif
|
||||
#ifndef PR_LOCK_SHADOW_STACK_STATUS
|
||||
#define PR_LOCK_SHADOW_STACK_STATUS 76
|
||||
#endif
|
||||
#ifndef PR_SHADOW_STACK_ENABLE
|
||||
# define PR_SHADOW_STACK_ENABLE (1 << 0)
|
||||
# define PR_SHADOW_STACK_WRITE (1 << 1)
|
||||
# define PR_SHADOW_STACK_PUSH (1 << 2)
|
||||
#endif
|
||||
#ifndef SHADOW_STACK_SET_TOKEN
|
||||
#define SHADOW_STACK_SET_TOKEN (1 << 0)
|
||||
#endif
|
||||
#ifndef SHADOW_STACK_SET_MARKER
|
||||
#define SHADOW_STACK_SET_MARKER (1 << 1)
|
||||
#endif
|
||||
#ifndef SEGV_CPERR
|
||||
#define SEGV_CPERR 10
|
||||
#endif
|
||||
#ifndef __NR_map_shadow_stack
|
||||
#define __NR_map_shadow_stack 453
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Macros, and implement the syscall inline, lest we fail
|
||||
* the checked return from any function call.
|
||||
*/
|
||||
#define enable_gcs(flags) \
|
||||
do { \
|
||||
register long num __asm__ ("x8") = __NR_prctl; \
|
||||
register long arg1 __asm__ ("x0") = PR_SET_SHADOW_STACK_STATUS; \
|
||||
register long arg2 __asm__ ("x1") = PR_SHADOW_STACK_ENABLE | flags; \
|
||||
register long arg3 __asm__ ("x2") = 0; \
|
||||
register long arg4 __asm__ ("x3") = 0; \
|
||||
register long arg5 __asm__ ("x4") = 0; \
|
||||
asm volatile("svc #0" \
|
||||
: "+r"(arg1) \
|
||||
: "r"(arg2), "r"(arg3), "r"(arg4), "r"(arg5), "r"(num) \
|
||||
: "memory", "cc"); \
|
||||
if (arg1) { \
|
||||
errno = -arg1; \
|
||||
perror("PR_SET_SHADOW_STACK_STATUS"); \
|
||||
exit(2); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define gcspr() \
|
||||
({ uint64_t *r; asm volatile("mrs %0, s3_3_c2_c5_1" : "=r"(r)); r; })
|
||||
48
tests/tcg/aarch64/gcsstr.c
Normal file
48
tests/tcg/aarch64/gcsstr.c
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "gcs.h"
|
||||
|
||||
/*
|
||||
* A single garbage store to the gcs stack.
|
||||
* The asm inside must be unique, so disallow inlining.
|
||||
*/
|
||||
void __attribute__((noinline))
|
||||
test_gcsstr(void)
|
||||
{
|
||||
register uint64_t *ptr __asm__("x0") = gcspr();
|
||||
/* GCSSTR x1, x0 */
|
||||
__asm__("inst_gcsstr: .inst 0xd91f1c01" : : "r"(--ptr));
|
||||
}
|
||||
|
||||
static void test_sigsegv(int sig, siginfo_t *info, void *vuc)
|
||||
{
|
||||
ucontext_t *uc = vuc;
|
||||
uint64_t inst_gcsstr;
|
||||
|
||||
__asm__("adr %0, inst_gcsstr" : "=r"(inst_gcsstr));
|
||||
assert(uc->uc_mcontext.pc == inst_gcsstr);
|
||||
assert(info->si_code == SEGV_CPERR);
|
||||
/* TODO: Dig for ESR and verify syndrome. */
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
struct sigaction sa = {
|
||||
.sa_sigaction = test_sigsegv,
|
||||
.sa_flags = SA_SIGINFO,
|
||||
};
|
||||
|
||||
/* Enable GCSSTR and test the store succeeds. */
|
||||
enable_gcs(PR_SHADOW_STACK_WRITE);
|
||||
test_gcsstr();
|
||||
|
||||
/* Disable GCSSTR and test the resulting sigsegv. */
|
||||
enable_gcs(0);
|
||||
if (sigaction(SIGSEGV, &sa, NULL) < 0) {
|
||||
perror("sigaction");
|
||||
exit(1);
|
||||
}
|
||||
test_gcsstr();
|
||||
abort();
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue