Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
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
23TEST(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
36FIXTURE(mdwe)
37{
38 void *p;
39 int flags;
40 size_t size;
41 pid_t pid;
42};
43
44FIXTURE_VARIANT(mdwe)
45{
46 bool enabled;
47 bool forked;
48};
49
50FIXTURE_VARIANT_ADD(mdwe, stock)
51{
52 .enabled = false,
53 .forked = false,
54};
55
56FIXTURE_VARIANT_ADD(mdwe, enabled)
57{
58 .enabled = true,
59 .forked = false,
60};
61
62FIXTURE_VARIANT_ADD(mdwe, forked)
63{
64 .enabled = true,
65 .forked = true,
66};
67
68FIXTURE_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
101FIXTURE_TEARDOWN(mdwe)
102{
103 if (self->p && self->p != MAP_FAILED)
104 munmap(self->p, self->size);
105}
106
107TEST_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
113TEST_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
123TEST_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
134TEST_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
149TEST_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
164TEST_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 p = mmap(self->p + self->size, self->size, PROT_READ | PROT_EXEC,
172 self->flags | MAP_FIXED, 0, 0);
173 if (variant->enabled) {
174 EXPECT_EQ(p, MAP_FAILED);
175 } else {
176 EXPECT_EQ(p, self->p);
177 }
178}
179
180TEST_F(mdwe, arm64_BTI)
181{
182 int ret;
183
184#ifdef __aarch64__
185 if (!(getauxval(AT_HWCAP2) & HWCAP2_BTI))
186#endif
187 SKIP(return, "HWCAP2_BTI not supported");
188
189 self->p = mmap(NULL, self->size, PROT_EXEC, self->flags, 0, 0);
190 ASSERT_NE(self->p, MAP_FAILED);
191
192 ret = mprotect(self->p, self->size, PROT_EXEC | PROT_BTI);
193 EXPECT_EQ(ret, 0);
194}
195
196TEST_HARNESS_MAIN