Skip to content

Commit 48f8d9c

Browse files
brooniectmarinas
authored andcommitted
kselftest/arm64: Validate that GCS push and write permissions work
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 <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Catalin Marinas <[email protected]>
1 parent bb9ae1a commit 48f8d9c

File tree

4 files changed

+204
-1
lines changed

4 files changed

+204
-1
lines changed

tools/testing/selftests/arm64/gcs/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,5 @@ libc-gcs
33
gcs-locking
44
gcs-stress
55
gcs-stress-thread
6+
gcspushm
7+
gcsstr

tools/testing/selftests/arm64/gcs/Makefile

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
# nolibc.
77
#
88

9-
TEST_GEN_PROGS := basic-gcs libc-gcs gcs-locking gcs-stress
9+
TEST_GEN_PROGS := basic-gcs libc-gcs gcs-locking gcs-stress gcspushm gcsstr
1010
TEST_GEN_PROGS_EXTENDED := gcs-stress-thread
1111

1212
LDLIBS+=-lpthread
@@ -22,3 +22,9 @@ $(OUTPUT)/basic-gcs: basic-gcs.c
2222

2323
$(OUTPUT)/gcs-stress-thread: gcs-stress-thread.S
2424
$(CC) -nostdlib $^ -o $@
25+
26+
$(OUTPUT)/gcspushm: gcspushm.S
27+
$(CC) -nostdlib $^ -o $@
28+
29+
$(OUTPUT)/gcsstr: gcsstr.S
30+
$(CC) -nostdlib $^ -o $@
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
//
3+
// Copyright 2024 Arm Limited
4+
//
5+
// Give ourselves GCS push permissions then use them
6+
7+
#include <asm/unistd.h>
8+
9+
/* Shadow Stack/Guarded Control Stack interface */
10+
#define PR_GET_SHADOW_STACK_STATUS 74
11+
#define PR_SET_SHADOW_STACK_STATUS 75
12+
#define PR_LOCK_SHADOW_STACK_STATUS 76
13+
14+
# define PR_SHADOW_STACK_ENABLE (1UL << 0)
15+
# define PR_SHADOW_STACK_WRITE (1UL << 1)
16+
# define PR_SHADOW_STACK_PUSH (1UL << 2)
17+
18+
#define KSFT_SKIP 4
19+
20+
.macro function name
21+
.macro endfunction
22+
.type \name, @function
23+
.purgem endfunction
24+
.endm
25+
\name:
26+
.endm
27+
28+
// Print a single character x0 to stdout
29+
// Clobbers x0-x2,x8
30+
function putc
31+
str x0, [sp, #-16]!
32+
33+
mov x0, #1 // STDOUT_FILENO
34+
mov x1, sp
35+
mov x2, #1
36+
mov x8, #__NR_write
37+
svc #0
38+
39+
add sp, sp, #16
40+
ret
41+
endfunction
42+
.globl putc
43+
44+
// Print a NUL-terminated string starting at address x0 to stdout
45+
// Clobbers x0-x3,x8
46+
function puts
47+
mov x1, x0
48+
49+
mov x2, #0
50+
0: ldrb w3, [x0], #1
51+
cbz w3, 1f
52+
add x2, x2, #1
53+
b 0b
54+
55+
1: mov w0, #1 // STDOUT_FILENO
56+
mov x8, #__NR_write
57+
svc #0
58+
59+
ret
60+
endfunction
61+
.globl puts
62+
63+
// Utility macro to print a literal string
64+
// Clobbers x0-x4,x8
65+
.macro puts string
66+
.pushsection .rodata.str1.1, "aMS", @progbits, 1
67+
.L__puts_literal\@: .string "\string"
68+
.popsection
69+
70+
ldr x0, =.L__puts_literal\@
71+
bl puts
72+
.endm
73+
74+
.globl _start
75+
function _start
76+
// Run with GCS
77+
mov x0, PR_SET_SHADOW_STACK_STATUS
78+
mov x1, PR_SHADOW_STACK_ENABLE | PR_SHADOW_STACK_PUSH
79+
mov x2, xzr
80+
mov x3, xzr
81+
mov x4, xzr
82+
mov x5, xzr
83+
mov x8, #__NR_prctl
84+
svc #0
85+
cbz x0, 1f
86+
puts "Failed to enable GCS with push permission\n"
87+
mov x0, #KSFT_SKIP
88+
b 2f
89+
1:
90+
sys #3, c7, c7, #0, x0 // GCSPUSHM
91+
sysl x0, #3, c7, c7, #1 // GCSPOPM
92+
93+
mov x0, #0
94+
2:
95+
mov x8, #__NR_exit
96+
svc #0
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
//
3+
// Copyright 2024 Arm Limited
4+
//
5+
// Give ourselves GCS write permissions then use them
6+
7+
#include <asm/unistd.h>
8+
9+
/* Shadow Stack/Guarded Control Stack interface */
10+
#define PR_GET_SHADOW_STACK_STATUS 74
11+
#define PR_SET_SHADOW_STACK_STATUS 75
12+
#define PR_LOCK_SHADOW_STACK_STATUS 76
13+
14+
# define PR_SHADOW_STACK_ENABLE (1UL << 0)
15+
# define PR_SHADOW_STACK_WRITE (1UL << 1)
16+
# define PR_SHADOW_STACK_PUSH (1UL << 2)
17+
18+
#define GCSPR_EL0 S3_3_C2_C5_1
19+
20+
#define KSFT_SKIP 4
21+
22+
.macro function name
23+
.macro endfunction
24+
.type \name, @function
25+
.purgem endfunction
26+
.endm
27+
\name:
28+
.endm
29+
30+
// Print a single character x0 to stdout
31+
// Clobbers x0-x2,x8
32+
function putc
33+
str x0, [sp, #-16]!
34+
35+
mov x0, #1 // STDOUT_FILENO
36+
mov x1, sp
37+
mov x2, #1
38+
mov x8, #__NR_write
39+
svc #0
40+
41+
add sp, sp, #16
42+
ret
43+
endfunction
44+
.globl putc
45+
46+
// Print a NUL-terminated string starting at address x0 to stdout
47+
// Clobbers x0-x3,x8
48+
function puts
49+
mov x1, x0
50+
51+
mov x2, #0
52+
0: ldrb w3, [x0], #1
53+
cbz w3, 1f
54+
add x2, x2, #1
55+
b 0b
56+
57+
1: mov w0, #1 // STDOUT_FILENO
58+
mov x8, #__NR_write
59+
svc #0
60+
61+
ret
62+
endfunction
63+
.globl puts
64+
65+
// Utility macro to print a literal string
66+
// Clobbers x0-x4,x8
67+
.macro puts string
68+
.pushsection .rodata.str1.1, "aMS", @progbits, 1
69+
.L__puts_literal\@: .string "\string"
70+
.popsection
71+
72+
ldr x0, =.L__puts_literal\@
73+
bl puts
74+
.endm
75+
76+
.globl _start
77+
function _start
78+
// Run with GCS
79+
mov x0, PR_SET_SHADOW_STACK_STATUS
80+
mov x1, PR_SHADOW_STACK_ENABLE | PR_SHADOW_STACK_WRITE
81+
mov x2, xzr
82+
mov x3, xzr
83+
mov x4, xzr
84+
mov x5, xzr
85+
mov x8, #__NR_prctl
86+
svc #0
87+
cbz x0, 1f
88+
puts "Failed to enable GCS with write permission\n"
89+
mov x0, #KSFT_SKIP
90+
b 2f
91+
1:
92+
mrs x0, GCSPR_EL0
93+
sub x0, x0, #8
94+
.inst 0xd91f1c01 // GCSSTR x1, x0
95+
96+
mov x0, #0
97+
2:
98+
mov x8, #__NR_exit
99+
svc #0

0 commit comments

Comments
 (0)