1 // SPDX-License-Identifier: GPL-2.0
2
3 #ifdef __aarch64__
4 #include <asm/hwcap.h>
5 #endif
6
7 #include <linux/mman.h>
8 #include <linux/prctl.h>
9
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <sys/auxv.h>
13 #include <sys/prctl.h>
14 #include <sys/wait.h>
15 #include <unistd.h>
16
17 #include "../kselftest_harness.h"
18
19 #ifndef __aarch64__
20 # define PROT_BTI 0
21 #endif
22
TEST(prctl_flags)23 TEST(prctl_flags)
24 {
25 EXPECT_LT(prctl(PR_SET_MDWE, 7L, 0L, 0L, 0L), 0);
26 EXPECT_LT(prctl(PR_SET_MDWE, 0L, 7L, 0L, 0L), 0);
27 EXPECT_LT(prctl(PR_SET_MDWE, 0L, 0L, 7L, 0L), 0);
28 EXPECT_LT(prctl(PR_SET_MDWE, 0L, 0L, 0L, 7L), 0);
29
30 EXPECT_LT(prctl(PR_GET_MDWE, 7L, 0L, 0L, 0L), 0);
31 EXPECT_LT(prctl(PR_GET_MDWE, 0L, 7L, 0L, 0L), 0);
32 EXPECT_LT(prctl(PR_GET_MDWE, 0L, 0L, 7L, 0L), 0);
33 EXPECT_LT(prctl(PR_GET_MDWE, 0L, 0L, 0L, 7L), 0);
34 }
35
FIXTURE(mdwe)36 FIXTURE(mdwe)
37 {
38 void *p;
39 int flags;
40 size_t size;
41 pid_t pid;
42 };
43
FIXTURE_VARIANT(mdwe)44 FIXTURE_VARIANT(mdwe)
45 {
46 bool enabled;
47 bool forked;
48 };
49
FIXTURE_VARIANT_ADD(mdwe,stock)50 FIXTURE_VARIANT_ADD(mdwe, stock)
51 {
52 .enabled = false,
53 .forked = false,
54 };
55
FIXTURE_VARIANT_ADD(mdwe,enabled)56 FIXTURE_VARIANT_ADD(mdwe, enabled)
57 {
58 .enabled = true,
59 .forked = false,
60 };
61
FIXTURE_VARIANT_ADD(mdwe,forked)62 FIXTURE_VARIANT_ADD(mdwe, forked)
63 {
64 .enabled = true,
65 .forked = true,
66 };
67
FIXTURE_SETUP(mdwe)68 FIXTURE_SETUP(mdwe)
69 {
70 int ret, status;
71
72 self->p = NULL;
73 self->flags = MAP_SHARED | MAP_ANONYMOUS;
74 self->size = getpagesize();
75
76 if (!variant->enabled)
77 return;
78
79 ret = prctl(PR_SET_MDWE, PR_MDWE_REFUSE_EXEC_GAIN, 0L, 0L, 0L);
80 ASSERT_EQ(ret, 0) {
81 TH_LOG("PR_SET_MDWE failed or unsupported");
82 }
83
84 ret = prctl(PR_GET_MDWE, 0L, 0L, 0L, 0L);
85 ASSERT_EQ(ret, 1);
86
87 if (variant->forked) {
88 self->pid = fork();
89 ASSERT_GE(self->pid, 0) {
90 TH_LOG("fork failed\n");
91 }
92
93 if (self->pid > 0) {
94 ret = waitpid(self->pid, &status, 0);
95 ASSERT_TRUE(WIFEXITED(status));
96 exit(WEXITSTATUS(status));
97 }
98 }
99 }
100
FIXTURE_TEARDOWN(mdwe)101 FIXTURE_TEARDOWN(mdwe)
102 {
103 if (self->p && self->p != MAP_FAILED)
104 munmap(self->p, self->size);
105 }
106
TEST_F(mdwe,mmap_READ_EXEC)107 TEST_F(mdwe, mmap_READ_EXEC)
108 {
109 self->p = mmap(NULL, self->size, PROT_READ | PROT_EXEC, self->flags, 0, 0);
110 EXPECT_NE(self->p, MAP_FAILED);
111 }
112
TEST_F(mdwe,mmap_WRITE_EXEC)113 TEST_F(mdwe, mmap_WRITE_EXEC)
114 {
115 self->p = mmap(NULL, self->size, PROT_WRITE | PROT_EXEC, self->flags, 0, 0);
116 if (variant->enabled) {
117 EXPECT_EQ(self->p, MAP_FAILED);
118 } else {
119 EXPECT_NE(self->p, MAP_FAILED);
120 }
121 }
122
TEST_F(mdwe,mprotect_stay_EXEC)123 TEST_F(mdwe, mprotect_stay_EXEC)
124 {
125 int ret;
126
127 self->p = mmap(NULL, self->size, PROT_READ | PROT_EXEC, self->flags, 0, 0);
128 ASSERT_NE(self->p, MAP_FAILED);
129
130 ret = mprotect(self->p, self->size, PROT_READ | PROT_EXEC);
131 EXPECT_EQ(ret, 0);
132 }
133
TEST_F(mdwe,mprotect_add_EXEC)134 TEST_F(mdwe, mprotect_add_EXEC)
135 {
136 int ret;
137
138 self->p = mmap(NULL, self->size, PROT_READ, self->flags, 0, 0);
139 ASSERT_NE(self->p, MAP_FAILED);
140
141 ret = mprotect(self->p, self->size, PROT_READ | PROT_EXEC);
142 if (variant->enabled) {
143 EXPECT_LT(ret, 0);
144 } else {
145 EXPECT_EQ(ret, 0);
146 }
147 }
148
TEST_F(mdwe,mprotect_WRITE_EXEC)149 TEST_F(mdwe, mprotect_WRITE_EXEC)
150 {
151 int ret;
152
153 self->p = mmap(NULL, self->size, PROT_WRITE, self->flags, 0, 0);
154 ASSERT_NE(self->p, MAP_FAILED);
155
156 ret = mprotect(self->p, self->size, PROT_WRITE | PROT_EXEC);
157 if (variant->enabled) {
158 EXPECT_LT(ret, 0);
159 } else {
160 EXPECT_EQ(ret, 0);
161 }
162 }
163
TEST_F(mdwe,mmap_FIXED)164 TEST_F(mdwe, mmap_FIXED)
165 {
166 void *p;
167
168 self->p = mmap(NULL, self->size, PROT_READ, self->flags, 0, 0);
169 ASSERT_NE(self->p, MAP_FAILED);
170
171 /* MAP_FIXED unmaps the existing page before mapping which is allowed */
172 p = mmap(self->p, self->size, PROT_READ | PROT_EXEC,
173 self->flags | MAP_FIXED, 0, 0);
174 EXPECT_EQ(p, self->p);
175 }
176
TEST_F(mdwe,arm64_BTI)177 TEST_F(mdwe, arm64_BTI)
178 {
179 int ret;
180
181 #ifdef __aarch64__
182 if (!(getauxval(AT_HWCAP2) & HWCAP2_BTI))
183 #endif
184 SKIP(return, "HWCAP2_BTI not supported");
185
186 self->p = mmap(NULL, self->size, PROT_EXEC, self->flags, 0, 0);
187 ASSERT_NE(self->p, MAP_FAILED);
188
189 ret = mprotect(self->p, self->size, PROT_EXEC | PROT_BTI);
190 EXPECT_EQ(ret, 0);
191 }
192
193 TEST_HARNESS_MAIN
194