xref: /linux/tools/testing/selftests/landlock/common.h (revision db624e82c55f227b84ac9ebfa3de2f6f5fad666b)
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 /* TEST_F_FORK() should not be used for new tests. */
27 #define TEST_F_FORK(fixture_name, test_name) TEST_F(fixture_name, test_name)
28 
29 #ifndef landlock_create_ruleset
30 static inline int
31 landlock_create_ruleset(const struct landlock_ruleset_attr *const attr,
32 			const size_t size, const __u32 flags)
33 {
34 	return syscall(__NR_landlock_create_ruleset, attr, size, flags);
35 }
36 #endif
37 
38 #ifndef landlock_add_rule
39 static inline int landlock_add_rule(const int ruleset_fd,
40 				    const enum landlock_rule_type rule_type,
41 				    const void *const rule_attr,
42 				    const __u32 flags)
43 {
44 	return syscall(__NR_landlock_add_rule, ruleset_fd, rule_type, rule_attr,
45 		       flags);
46 }
47 #endif
48 
49 #ifndef landlock_restrict_self
50 static inline int landlock_restrict_self(const int ruleset_fd,
51 					 const __u32 flags)
52 {
53 	return syscall(__NR_landlock_restrict_self, ruleset_fd, flags);
54 }
55 #endif
56 
57 static void _init_caps(struct __test_metadata *const _metadata, bool drop_all)
58 {
59 	cap_t cap_p;
60 	/* Only these three capabilities are useful for the tests. */
61 	const cap_value_t caps[] = {
62 		/* clang-format off */
63 		CAP_DAC_OVERRIDE,
64 		CAP_MKNOD,
65 		CAP_NET_ADMIN,
66 		CAP_NET_BIND_SERVICE,
67 		CAP_SYS_ADMIN,
68 		CAP_SYS_CHROOT,
69 		/* clang-format on */
70 	};
71 	const unsigned int noroot = SECBIT_NOROOT | SECBIT_NOROOT_LOCKED;
72 
73 	if ((cap_get_secbits() & noroot) != noroot)
74 		EXPECT_EQ(0, cap_set_secbits(noroot));
75 
76 	cap_p = cap_get_proc();
77 	EXPECT_NE(NULL, cap_p)
78 	{
79 		TH_LOG("Failed to cap_get_proc: %s", strerror(errno));
80 	}
81 	EXPECT_NE(-1, cap_clear(cap_p))
82 	{
83 		TH_LOG("Failed to cap_clear: %s", strerror(errno));
84 	}
85 	if (!drop_all) {
86 		EXPECT_NE(-1, cap_set_flag(cap_p, CAP_PERMITTED,
87 					   ARRAY_SIZE(caps), caps, CAP_SET))
88 		{
89 			TH_LOG("Failed to cap_set_flag: %s", strerror(errno));
90 		}
91 	}
92 
93 	/* Automatically resets ambient capabilities. */
94 	EXPECT_NE(-1, cap_set_proc(cap_p))
95 	{
96 		TH_LOG("Failed to cap_set_proc: %s", strerror(errno));
97 	}
98 	EXPECT_NE(-1, cap_free(cap_p))
99 	{
100 		TH_LOG("Failed to cap_free: %s", strerror(errno));
101 	}
102 
103 	/* Quickly checks that ambient capabilities are cleared. */
104 	EXPECT_NE(-1, cap_get_ambient(caps[0]));
105 }
106 
107 /* We cannot put such helpers in a library because of kselftest_harness.h . */
108 static void __maybe_unused disable_caps(struct __test_metadata *const _metadata)
109 {
110 	_init_caps(_metadata, false);
111 }
112 
113 static void __maybe_unused drop_caps(struct __test_metadata *const _metadata)
114 {
115 	_init_caps(_metadata, true);
116 }
117 
118 static void _change_cap(struct __test_metadata *const _metadata,
119 			const cap_flag_t flag, const cap_value_t cap,
120 			const cap_flag_value_t value)
121 {
122 	cap_t cap_p;
123 
124 	cap_p = cap_get_proc();
125 	EXPECT_NE(NULL, cap_p)
126 	{
127 		TH_LOG("Failed to cap_get_proc: %s", strerror(errno));
128 	}
129 	EXPECT_NE(-1, cap_set_flag(cap_p, flag, 1, &cap, value))
130 	{
131 		TH_LOG("Failed to cap_set_flag: %s", strerror(errno));
132 	}
133 	EXPECT_NE(-1, cap_set_proc(cap_p))
134 	{
135 		TH_LOG("Failed to cap_set_proc: %s", strerror(errno));
136 	}
137 	EXPECT_NE(-1, cap_free(cap_p))
138 	{
139 		TH_LOG("Failed to cap_free: %s", strerror(errno));
140 	}
141 }
142 
143 static void __maybe_unused set_cap(struct __test_metadata *const _metadata,
144 				   const cap_value_t cap)
145 {
146 	_change_cap(_metadata, CAP_EFFECTIVE, cap, CAP_SET);
147 }
148 
149 static void __maybe_unused clear_cap(struct __test_metadata *const _metadata,
150 				     const cap_value_t cap)
151 {
152 	_change_cap(_metadata, CAP_EFFECTIVE, cap, CAP_CLEAR);
153 }
154 
155 static void __maybe_unused
156 set_ambient_cap(struct __test_metadata *const _metadata, const cap_value_t cap)
157 {
158 	_change_cap(_metadata, CAP_INHERITABLE, cap, CAP_SET);
159 
160 	EXPECT_NE(-1, cap_set_ambient(cap, CAP_SET))
161 	{
162 		TH_LOG("Failed to set ambient capability %d: %s", cap,
163 		       strerror(errno));
164 	}
165 }
166 
167 static void __maybe_unused clear_ambient_cap(
168 	struct __test_metadata *const _metadata, const cap_value_t cap)
169 {
170 	EXPECT_EQ(1, cap_get_ambient(cap));
171 	_change_cap(_metadata, CAP_INHERITABLE, cap, CAP_CLEAR);
172 	EXPECT_EQ(0, cap_get_ambient(cap));
173 }
174 
175 /* Receives an FD from a UNIX socket. Returns the received FD, or -errno. */
176 static int __maybe_unused recv_fd(int usock)
177 {
178 	int fd_rx;
179 	union {
180 		/* Aligned ancillary data buffer. */
181 		char buf[CMSG_SPACE(sizeof(fd_rx))];
182 		struct cmsghdr _align;
183 	} cmsg_rx = {};
184 	char data = '\0';
185 	struct iovec io = {
186 		.iov_base = &data,
187 		.iov_len = sizeof(data),
188 	};
189 	struct msghdr msg = {
190 		.msg_iov = &io,
191 		.msg_iovlen = 1,
192 		.msg_control = &cmsg_rx.buf,
193 		.msg_controllen = sizeof(cmsg_rx.buf),
194 	};
195 	struct cmsghdr *cmsg;
196 	int res;
197 
198 	res = recvmsg(usock, &msg, MSG_CMSG_CLOEXEC);
199 	if (res < 0)
200 		return -errno;
201 
202 	cmsg = CMSG_FIRSTHDR(&msg);
203 	if (cmsg->cmsg_len != CMSG_LEN(sizeof(fd_rx)))
204 		return -EIO;
205 
206 	memcpy(&fd_rx, CMSG_DATA(cmsg), sizeof(fd_rx));
207 	return fd_rx;
208 }
209 
210 /* Sends an FD on a UNIX socket. Returns 0 on success or -errno. */
211 static int __maybe_unused send_fd(int usock, int fd_tx)
212 {
213 	union {
214 		/* Aligned ancillary data buffer. */
215 		char buf[CMSG_SPACE(sizeof(fd_tx))];
216 		struct cmsghdr _align;
217 	} cmsg_tx = {};
218 	char data_tx = '.';
219 	struct iovec io = {
220 		.iov_base = &data_tx,
221 		.iov_len = sizeof(data_tx),
222 	};
223 	struct msghdr msg = {
224 		.msg_iov = &io,
225 		.msg_iovlen = 1,
226 		.msg_control = &cmsg_tx.buf,
227 		.msg_controllen = sizeof(cmsg_tx.buf),
228 	};
229 	struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
230 
231 	cmsg->cmsg_len = CMSG_LEN(sizeof(fd_tx));
232 	cmsg->cmsg_level = SOL_SOCKET;
233 	cmsg->cmsg_type = SCM_RIGHTS;
234 	memcpy(CMSG_DATA(cmsg), &fd_tx, sizeof(fd_tx));
235 
236 	if (sendmsg(usock, &msg, 0) < 0)
237 		return -errno;
238 	return 0;
239 }
240 
241 static void __maybe_unused
242 enforce_ruleset(struct __test_metadata *const _metadata, const int ruleset_fd)
243 {
244 	ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0));
245 	ASSERT_EQ(0, landlock_restrict_self(ruleset_fd, 0))
246 	{
247 		TH_LOG("Failed to enforce ruleset: %s", strerror(errno));
248 	}
249 }
250