Add trivial assembly programs which give themselves the appropriate
permissions and then execute GCSPUSHM and GCSSTR, they will report errors
by generating signals on the non-permitted instructions. Not using libc
minimises the interaction with any policy set for the system but we skip on
failure to get the permissions in case the system is locked down to make
them inaccessible.

Signed-off-by: Mark Brown <broo...@kernel.org>
---
 tools/testing/selftests/arm64/gcs/.gitignore |  2 +
 tools/testing/selftests/arm64/gcs/Makefile   |  8 ++-
 tools/testing/selftests/arm64/gcs/gcspushm.S | 96 +++++++++++++++++++++++++++
 tools/testing/selftests/arm64/gcs/gcsstr.S   | 99 ++++++++++++++++++++++++++++
 4 files changed, 204 insertions(+), 1 deletion(-)

diff --git a/tools/testing/selftests/arm64/gcs/.gitignore 
b/tools/testing/selftests/arm64/gcs/.gitignore
index 
1e8d1f6b27f2b4c6f8ea26fc55094469c39616d5..bbb8e40a7e524630fadc4cffe0defff128033829
 100644
--- a/tools/testing/selftests/arm64/gcs/.gitignore
+++ b/tools/testing/selftests/arm64/gcs/.gitignore
@@ -3,3 +3,5 @@ libc-gcs
 gcs-locking
 gcs-stress
 gcs-stress-thread
+gcspushm
+gcsstr
diff --git a/tools/testing/selftests/arm64/gcs/Makefile 
b/tools/testing/selftests/arm64/gcs/Makefile
index 
d8b06ca51e22a99566f982f3aad3dceb30ffe05e..d2f3497a9103fc12ebc90c7f4e33ab9b846c6c8a
 100644
--- a/tools/testing/selftests/arm64/gcs/Makefile
+++ b/tools/testing/selftests/arm64/gcs/Makefile
@@ -6,7 +6,7 @@
 # nolibc.
 #
 
-TEST_GEN_PROGS := basic-gcs libc-gcs gcs-locking gcs-stress
+TEST_GEN_PROGS := basic-gcs libc-gcs gcs-locking gcs-stress gcspushm gcsstr
 TEST_GEN_PROGS_EXTENDED := gcs-stress-thread
 
 LDLIBS+=-lpthread
@@ -22,3 +22,9 @@ $(OUTPUT)/basic-gcs: basic-gcs.c
 
 $(OUTPUT)/gcs-stress-thread: gcs-stress-thread.S
        $(CC) -nostdlib $^ -o $@
+
+$(OUTPUT)/gcspushm: gcspushm.S
+       $(CC) -nostdlib $^ -o $@
+
+$(OUTPUT)/gcsstr: gcsstr.S
+       $(CC) -nostdlib $^ -o $@
diff --git a/tools/testing/selftests/arm64/gcs/gcspushm.S 
b/tools/testing/selftests/arm64/gcs/gcspushm.S
new file mode 100644
index 
0000000000000000000000000000000000000000..bbe17c1325acc85d74dd3fe7cb586900226cde4c
--- /dev/null
+++ b/tools/testing/selftests/arm64/gcs/gcspushm.S
@@ -0,0 +1,96 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright 2024 Arm Limited
+//
+// Give ourselves GCS push permissions then use them
+
+#include <asm/unistd.h>
+
+/* Shadow Stack/Guarded Control Stack interface */
+#define PR_GET_SHADOW_STACK_STATUS     74
+#define PR_SET_SHADOW_STACK_STATUS      75
+#define PR_LOCK_SHADOW_STACK_STATUS     76
+
+# define PR_SHADOW_STACK_ENABLE         (1UL << 0)
+# define PR_SHADOW_STACK_WRITE         (1UL << 1)
+# define PR_SHADOW_STACK_PUSH          (1UL << 2)
+
+#define KSFT_SKIP 4
+
+.macro function name
+       .macro endfunction
+               .type \name, @function
+               .purgem endfunction
+       .endm
+\name:
+.endm
+
+// Print a single character x0 to stdout
+// Clobbers x0-x2,x8
+function putc
+       str     x0, [sp, #-16]!
+
+       mov     x0, #1                  // STDOUT_FILENO
+       mov     x1, sp
+       mov     x2, #1
+       mov     x8, #__NR_write
+       svc     #0
+
+       add     sp, sp, #16
+       ret
+endfunction
+.globl putc
+
+// Print a NUL-terminated string starting at address x0 to stdout
+// Clobbers x0-x3,x8
+function puts
+       mov     x1, x0
+
+       mov     x2, #0
+0:     ldrb    w3, [x0], #1
+       cbz     w3, 1f
+       add     x2, x2, #1
+       b       0b
+
+1:     mov     w0, #1                  // STDOUT_FILENO
+       mov     x8, #__NR_write
+       svc     #0
+
+       ret
+endfunction
+.globl puts
+
+// Utility macro to print a literal string
+// Clobbers x0-x4,x8
+.macro puts string
+       .pushsection .rodata.str1.1, "aMS", @progbits, 1
+.L__puts_literal\@: .string "\string"
+       .popsection
+
+       ldr     x0, =.L__puts_literal\@
+       bl      puts
+.endm
+
+.globl _start
+function _start
+       // Run with GCS
+       mov     x0, PR_SET_SHADOW_STACK_STATUS
+       mov     x1, PR_SHADOW_STACK_ENABLE | PR_SHADOW_STACK_PUSH
+       mov     x2, xzr
+       mov     x3, xzr
+       mov     x4, xzr
+       mov     x5, xzr
+       mov     x8, #__NR_prctl
+       svc     #0
+       cbz     x0, 1f
+       puts    "Failed to enable GCS with push permission\n"
+       mov     x0, #KSFT_SKIP
+       b       2f
+1:
+       sys     #3, c7, c7, #0, x0      // GCSPUSHM
+       sysl    x0, #3, c7, c7, #1      // GCSPOPM
+
+       mov     x0, #0
+2:
+       mov     x8, #__NR_exit
+       svc     #0
diff --git a/tools/testing/selftests/arm64/gcs/gcsstr.S 
b/tools/testing/selftests/arm64/gcs/gcsstr.S
new file mode 100644
index 
0000000000000000000000000000000000000000..a42bba6e30b18147887bb13046c96bd48850de2e
--- /dev/null
+++ b/tools/testing/selftests/arm64/gcs/gcsstr.S
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright 2024 Arm Limited
+//
+// Give ourselves GCS write permissions then use them
+
+#include <asm/unistd.h>
+
+/* Shadow Stack/Guarded Control Stack interface */
+#define PR_GET_SHADOW_STACK_STATUS     74
+#define PR_SET_SHADOW_STACK_STATUS      75
+#define PR_LOCK_SHADOW_STACK_STATUS     76
+
+# define PR_SHADOW_STACK_ENABLE         (1UL << 0)
+# define PR_SHADOW_STACK_WRITE         (1UL << 1)
+# define PR_SHADOW_STACK_PUSH          (1UL << 2)
+
+#define        GCSPR_EL0 S3_3_C2_C5_1
+
+#define KSFT_SKIP 4
+
+.macro function name
+       .macro endfunction
+               .type \name, @function
+               .purgem endfunction
+       .endm
+\name:
+.endm
+
+// Print a single character x0 to stdout
+// Clobbers x0-x2,x8
+function putc
+       str     x0, [sp, #-16]!
+
+       mov     x0, #1                  // STDOUT_FILENO
+       mov     x1, sp
+       mov     x2, #1
+       mov     x8, #__NR_write
+       svc     #0
+
+       add     sp, sp, #16
+       ret
+endfunction
+.globl putc
+
+// Print a NUL-terminated string starting at address x0 to stdout
+// Clobbers x0-x3,x8
+function puts
+       mov     x1, x0
+
+       mov     x2, #0
+0:     ldrb    w3, [x0], #1
+       cbz     w3, 1f
+       add     x2, x2, #1
+       b       0b
+
+1:     mov     w0, #1                  // STDOUT_FILENO
+       mov     x8, #__NR_write
+       svc     #0
+
+       ret
+endfunction
+.globl puts
+
+// Utility macro to print a literal string
+// Clobbers x0-x4,x8
+.macro puts string
+       .pushsection .rodata.str1.1, "aMS", @progbits, 1
+.L__puts_literal\@: .string "\string"
+       .popsection
+
+       ldr     x0, =.L__puts_literal\@
+       bl      puts
+.endm
+
+.globl _start
+function _start
+       // Run with GCS
+       mov     x0, PR_SET_SHADOW_STACK_STATUS
+       mov     x1, PR_SHADOW_STACK_ENABLE | PR_SHADOW_STACK_WRITE
+       mov     x2, xzr
+       mov     x3, xzr
+       mov     x4, xzr
+       mov     x5, xzr
+       mov     x8, #__NR_prctl
+       svc     #0
+       cbz     x0, 1f
+       puts    "Failed to enable GCS with write permission\n"
+       mov     x0, #KSFT_SKIP
+       b       2f
+1:
+       mrs     x0, GCSPR_EL0
+       sub     x0, x0, #8
+       .inst   0xd91f1c01      // GCSSTR x1, x0
+
+       mov     x0, #0
+2:
+       mov     x8, #__NR_exit
+       svc     #0

---
base-commit: bb9ae1a66c85eeb626864efd812c62026e126ec0
change-id: 20241004-arm64-gcs-test-flags-980a2ddfde6f

Best regards,
-- 
Mark Brown <broo...@kernel.org>


Reply via email to