Loading...
Note: File does not exist in v3.15.
1/* SPDX-License-Identifier: GPL-2.0 */
2/*
3 * Landlock test helpers
4 *
5 * Copyright © 2017-2020 Mickaël Salaün <mic@digikod.net>
6 * Copyright © 2019-2020 ANSSI
7 * Copyright © 2021 Microsoft Corporation
8 */
9
10#include <errno.h>
11#include <linux/landlock.h>
12#include <linux/securebits.h>
13#include <sys/capability.h>
14#include <sys/socket.h>
15#include <sys/syscall.h>
16#include <sys/types.h>
17#include <sys/wait.h>
18#include <unistd.h>
19
20#include "../kselftest_harness.h"
21
22#ifndef __maybe_unused
23#define __maybe_unused __attribute__((__unused__))
24#endif
25
26/*
27 * TEST_F_FORK() is useful when a test drop privileges but the corresponding
28 * FIXTURE_TEARDOWN() requires them (e.g. to remove files from a directory
29 * where write actions are denied). For convenience, FIXTURE_TEARDOWN() is
30 * also called when the test failed, but not when FIXTURE_SETUP() failed. For
31 * this to be possible, we must not call abort() but instead exit smoothly
32 * (hence the step print).
33 */
34/* clang-format off */
35#define TEST_F_FORK(fixture_name, test_name) \
36 static void fixture_name##_##test_name##_child( \
37 struct __test_metadata *_metadata, \
38 FIXTURE_DATA(fixture_name) *self, \
39 const FIXTURE_VARIANT(fixture_name) *variant); \
40 TEST_F(fixture_name, test_name) \
41 { \
42 int status; \
43 const pid_t child = fork(); \
44 if (child < 0) \
45 abort(); \
46 if (child == 0) { \
47 _metadata->no_print = 1; \
48 fixture_name##_##test_name##_child(_metadata, self, variant); \
49 if (_metadata->skip) \
50 _exit(255); \
51 if (_metadata->passed) \
52 _exit(0); \
53 _exit(_metadata->step); \
54 } \
55 if (child != waitpid(child, &status, 0)) \
56 abort(); \
57 if (WIFSIGNALED(status) || !WIFEXITED(status)) { \
58 _metadata->passed = 0; \
59 _metadata->step = 1; \
60 return; \
61 } \
62 switch (WEXITSTATUS(status)) { \
63 case 0: \
64 _metadata->passed = 1; \
65 break; \
66 case 255: \
67 _metadata->passed = 1; \
68 _metadata->skip = 1; \
69 break; \
70 default: \
71 _metadata->passed = 0; \
72 _metadata->step = WEXITSTATUS(status); \
73 break; \
74 } \
75 } \
76 static void fixture_name##_##test_name##_child( \
77 struct __test_metadata __attribute__((unused)) *_metadata, \
78 FIXTURE_DATA(fixture_name) __attribute__((unused)) *self, \
79 const FIXTURE_VARIANT(fixture_name) \
80 __attribute__((unused)) *variant)
81/* clang-format on */
82
83#ifndef landlock_create_ruleset
84static inline int
85landlock_create_ruleset(const struct landlock_ruleset_attr *const attr,
86 const size_t size, const __u32 flags)
87{
88 return syscall(__NR_landlock_create_ruleset, attr, size, flags);
89}
90#endif
91
92#ifndef landlock_add_rule
93static inline int landlock_add_rule(const int ruleset_fd,
94 const enum landlock_rule_type rule_type,
95 const void *const rule_attr,
96 const __u32 flags)
97{
98 return syscall(__NR_landlock_add_rule, ruleset_fd, rule_type, rule_attr,
99 flags);
100}
101#endif
102
103#ifndef landlock_restrict_self
104static inline int landlock_restrict_self(const int ruleset_fd,
105 const __u32 flags)
106{
107 return syscall(__NR_landlock_restrict_self, ruleset_fd, flags);
108}
109#endif
110
111static void _init_caps(struct __test_metadata *const _metadata, bool drop_all)
112{
113 cap_t cap_p;
114 /* Only these three capabilities are useful for the tests. */
115 const cap_value_t caps[] = {
116 /* clang-format off */
117 CAP_DAC_OVERRIDE,
118 CAP_MKNOD,
119 CAP_NET_ADMIN,
120 CAP_NET_BIND_SERVICE,
121 CAP_SYS_ADMIN,
122 CAP_SYS_CHROOT,
123 /* clang-format on */
124 };
125 const unsigned int noroot = SECBIT_NOROOT | SECBIT_NOROOT_LOCKED;
126
127 if ((cap_get_secbits() & noroot) != noroot)
128 EXPECT_EQ(0, cap_set_secbits(noroot));
129
130 cap_p = cap_get_proc();
131 EXPECT_NE(NULL, cap_p)
132 {
133 TH_LOG("Failed to cap_get_proc: %s", strerror(errno));
134 }
135 EXPECT_NE(-1, cap_clear(cap_p))
136 {
137 TH_LOG("Failed to cap_clear: %s", strerror(errno));
138 }
139 if (!drop_all) {
140 EXPECT_NE(-1, cap_set_flag(cap_p, CAP_PERMITTED,
141 ARRAY_SIZE(caps), caps, CAP_SET))
142 {
143 TH_LOG("Failed to cap_set_flag: %s", strerror(errno));
144 }
145 }
146
147 /* Automatically resets ambient capabilities. */
148 EXPECT_NE(-1, cap_set_proc(cap_p))
149 {
150 TH_LOG("Failed to cap_set_proc: %s", strerror(errno));
151 }
152 EXPECT_NE(-1, cap_free(cap_p))
153 {
154 TH_LOG("Failed to cap_free: %s", strerror(errno));
155 }
156
157 /* Quickly checks that ambient capabilities are cleared. */
158 EXPECT_NE(-1, cap_get_ambient(caps[0]));
159}
160
161/* We cannot put such helpers in a library because of kselftest_harness.h . */
162static void __maybe_unused disable_caps(struct __test_metadata *const _metadata)
163{
164 _init_caps(_metadata, false);
165}
166
167static void __maybe_unused drop_caps(struct __test_metadata *const _metadata)
168{
169 _init_caps(_metadata, true);
170}
171
172static void _change_cap(struct __test_metadata *const _metadata,
173 const cap_flag_t flag, const cap_value_t cap,
174 const cap_flag_value_t value)
175{
176 cap_t cap_p;
177
178 cap_p = cap_get_proc();
179 EXPECT_NE(NULL, cap_p)
180 {
181 TH_LOG("Failed to cap_get_proc: %s", strerror(errno));
182 }
183 EXPECT_NE(-1, cap_set_flag(cap_p, flag, 1, &cap, value))
184 {
185 TH_LOG("Failed to cap_set_flag: %s", strerror(errno));
186 }
187 EXPECT_NE(-1, cap_set_proc(cap_p))
188 {
189 TH_LOG("Failed to cap_set_proc: %s", strerror(errno));
190 }
191 EXPECT_NE(-1, cap_free(cap_p))
192 {
193 TH_LOG("Failed to cap_free: %s", strerror(errno));
194 }
195}
196
197static void __maybe_unused set_cap(struct __test_metadata *const _metadata,
198 const cap_value_t cap)
199{
200 _change_cap(_metadata, CAP_EFFECTIVE, cap, CAP_SET);
201}
202
203static void __maybe_unused clear_cap(struct __test_metadata *const _metadata,
204 const cap_value_t cap)
205{
206 _change_cap(_metadata, CAP_EFFECTIVE, cap, CAP_CLEAR);
207}
208
209static void __maybe_unused
210set_ambient_cap(struct __test_metadata *const _metadata, const cap_value_t cap)
211{
212 _change_cap(_metadata, CAP_INHERITABLE, cap, CAP_SET);
213
214 EXPECT_NE(-1, cap_set_ambient(cap, CAP_SET))
215 {
216 TH_LOG("Failed to set ambient capability %d: %s", cap,
217 strerror(errno));
218 }
219}
220
221static void __maybe_unused clear_ambient_cap(
222 struct __test_metadata *const _metadata, const cap_value_t cap)
223{
224 EXPECT_EQ(1, cap_get_ambient(cap));
225 _change_cap(_metadata, CAP_INHERITABLE, cap, CAP_CLEAR);
226 EXPECT_EQ(0, cap_get_ambient(cap));
227}
228
229/* Receives an FD from a UNIX socket. Returns the received FD, or -errno. */
230static int __maybe_unused recv_fd(int usock)
231{
232 int fd_rx;
233 union {
234 /* Aligned ancillary data buffer. */
235 char buf[CMSG_SPACE(sizeof(fd_rx))];
236 struct cmsghdr _align;
237 } cmsg_rx = {};
238 char data = '\0';
239 struct iovec io = {
240 .iov_base = &data,
241 .iov_len = sizeof(data),
242 };
243 struct msghdr msg = {
244 .msg_iov = &io,
245 .msg_iovlen = 1,
246 .msg_control = &cmsg_rx.buf,
247 .msg_controllen = sizeof(cmsg_rx.buf),
248 };
249 struct cmsghdr *cmsg;
250 int res;
251
252 res = recvmsg(usock, &msg, MSG_CMSG_CLOEXEC);
253 if (res < 0)
254 return -errno;
255
256 cmsg = CMSG_FIRSTHDR(&msg);
257 if (cmsg->cmsg_len != CMSG_LEN(sizeof(fd_rx)))
258 return -EIO;
259
260 memcpy(&fd_rx, CMSG_DATA(cmsg), sizeof(fd_rx));
261 return fd_rx;
262}
263
264/* Sends an FD on a UNIX socket. Returns 0 on success or -errno. */
265static int __maybe_unused send_fd(int usock, int fd_tx)
266{
267 union {
268 /* Aligned ancillary data buffer. */
269 char buf[CMSG_SPACE(sizeof(fd_tx))];
270 struct cmsghdr _align;
271 } cmsg_tx = {};
272 char data_tx = '.';
273 struct iovec io = {
274 .iov_base = &data_tx,
275 .iov_len = sizeof(data_tx),
276 };
277 struct msghdr msg = {
278 .msg_iov = &io,
279 .msg_iovlen = 1,
280 .msg_control = &cmsg_tx.buf,
281 .msg_controllen = sizeof(cmsg_tx.buf),
282 };
283 struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
284
285 cmsg->cmsg_len = CMSG_LEN(sizeof(fd_tx));
286 cmsg->cmsg_level = SOL_SOCKET;
287 cmsg->cmsg_type = SCM_RIGHTS;
288 memcpy(CMSG_DATA(cmsg), &fd_tx, sizeof(fd_tx));
289
290 if (sendmsg(usock, &msg, 0) < 0)
291 return -errno;
292 return 0;
293}
294
295static void __maybe_unused
296enforce_ruleset(struct __test_metadata *const _metadata, const int ruleset_fd)
297{
298 ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0));
299 ASSERT_EQ(0, landlock_restrict_self(ruleset_fd, 0))
300 {
301 TH_LOG("Failed to enforce ruleset: %s", strerror(errno));
302 }
303}