| 1 | /* |
| 2 | * Linux kernel fallback API definitions for GCS and test helpers. |
| 3 | * |
| 4 | * Copyright (c) 2025 Linaro Ltd |
| 5 | * SPDX-License-Identifier: GPL-2.0-or-later |
| 6 | */ |
| 7 | |
| 8 | #include <assert.h> |
| 9 | #include <string.h> |
| 10 | #include <stdlib.h> |
| 11 | #include <stdio.h> |
| 12 | #include <stdint.h> |
| 13 | #include <unistd.h> |
| 14 | #include <errno.h> |
| 15 | #include <signal.h> |
| 16 | #include <sys/mman.h> |
| 17 | #include <sys/prctl.h> |
| 18 | #include <sys/syscall.h> |
| 19 | |
| 20 | #ifndef PR_GET_SHADOW_STACK_STATUS |
| 21 | #define PR_GET_SHADOW_STACK_STATUS 74 |
| 22 | #endif |
| 23 | #ifndef PR_SET_SHADOW_STACK_STATUS |
| 24 | #define PR_SET_SHADOW_STACK_STATUS 75 |
| 25 | #endif |
| 26 | #ifndef PR_LOCK_SHADOW_STACK_STATUS |
| 27 | #define PR_LOCK_SHADOW_STACK_STATUS 76 |
| 28 | #endif |
| 29 | #ifndef PR_SHADOW_STACK_ENABLE |
| 30 | # define PR_SHADOW_STACK_ENABLE (1 << 0) |
| 31 | # define PR_SHADOW_STACK_WRITE (1 << 1) |
| 32 | # define PR_SHADOW_STACK_PUSH (1 << 2) |
| 33 | #endif |
| 34 | #ifndef SHADOW_STACK_SET_TOKEN |
| 35 | #define SHADOW_STACK_SET_TOKEN (1 << 0) |
| 36 | #endif |
| 37 | #ifndef SHADOW_STACK_SET_MARKER |
| 38 | #define SHADOW_STACK_SET_MARKER (1 << 1) |
| 39 | #endif |
| 40 | #ifndef SEGV_CPERR |
| 41 | #define SEGV_CPERR 10 |
| 42 | #endif |
| 43 | #ifndef __NR_map_shadow_stack |
| 44 | #define __NR_map_shadow_stack 453 |
| 45 | #endif |
| 46 | |
| 47 | /* |
| 48 | * Macros, and implement the syscall inline, lest we fail |
| 49 | * the checked return from any function call. |
| 50 | */ |
| 51 | #define enable_gcs(flags) \ |
| 52 | do { \ |
| 53 | register long num __asm__ ("x8") = __NR_prctl; \ |
| 54 | register long arg1 __asm__ ("x0") = PR_SET_SHADOW_STACK_STATUS; \ |
| 55 | register long arg2 __asm__ ("x1") = PR_SHADOW_STACK_ENABLE | flags; \ |
| 56 | register long arg3 __asm__ ("x2") = 0; \ |
| 57 | register long arg4 __asm__ ("x3") = 0; \ |
| 58 | register long arg5 __asm__ ("x4") = 0; \ |
| 59 | asm volatile("svc #0" \ |
| 60 | : "+r"(arg1) \ |
| 61 | : "r"(arg2), "r"(arg3), "r"(arg4), "r"(arg5), "r"(num) \ |
| 62 | : "memory", "cc"); \ |
| 63 | if (arg1) { \ |
| 64 | errno = -arg1; \ |
| 65 | perror("PR_SET_SHADOW_STACK_STATUS"); \ |
| 66 | exit(2); \ |
| 67 | } \ |
| 68 | } while (0) |
| 69 | |
| 70 | #define gcspr() \ |
| 71 | ({ uint64_t *r; asm volatile("mrs %0, s3_3_c2_c5_1" : "=r"(r)); r; }) |
| 72 | |
| 73 | #define gcsss1(val) \ |
| 74 | do { \ |
| 75 | asm volatile("sys #3, c7, c7, #2, %0" : : "r"(val) : "memory"); \ |
| 76 | } while (0) |
| 77 | |
| 78 | #define gcsss2() \ |
| 79 | ({ uint64_t *r; \ |
| 80 | asm volatile("sysl %0, #3, c7, c7, #3" : "=r"(r) : : "memory"); r; }) |