]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
kselftest/arm64: Validate that GCS push and write permissions work
authorMark Brown <broonie@kernel.org>
Sat, 5 Oct 2024 00:17:18 +0000 (01:17 +0100)
committerCatalin Marinas <catalin.marinas@arm.com>
Wed, 16 Oct 2024 13:59:50 +0000 (14:59 +0100)
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 <broonie@kernel.org>
Link: https://lore.kernel.org/r/20241005-arm64-gcs-test-flags-v1-1-03cb9786c5cd@kernel.org
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
tools/testing/selftests/arm64/gcs/.gitignore
tools/testing/selftests/arm64/gcs/Makefile
tools/testing/selftests/arm64/gcs/gcspushm.S [new file with mode: 0644]
tools/testing/selftests/arm64/gcs/gcsstr.S [new file with mode: 0644]

index 1e8d1f6b27f2b4c6f8ea26fc55094469c39616d5..bbb8e40a7e524630fadc4cffe0defff128033829 100644 (file)
@@ -3,3 +3,5 @@ libc-gcs
 gcs-locking
 gcs-stress
 gcs-stress-thread
+gcspushm
+gcsstr
index d8b06ca51e22a99566f982f3aad3dceb30ffe05e..d2f3497a9103fc12ebc90c7f4e33ab9b846c6c8a 100644 (file)
@@ -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 (file)
index 0000000..bbe17c1
--- /dev/null
@@ -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 (file)
index 0000000..a42bba6
--- /dev/null
@@ -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