xref: /linux/tools/testing/selftests/landlock/common.h (revision 4b132aacb0768ac1e652cf517097ea6f237214b9)
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 	EXPECT_NE(-1, cap_clear(cap_p));
79 	if (!drop_all) {
80 		EXPECT_NE(-1, cap_set_flag(cap_p, CAP_PERMITTED,
81 					   ARRAY_SIZE(caps), caps, CAP_SET));
82 	}
83 
84 	/* Automatically resets ambient capabilities. */
85 	EXPECT_NE(-1, cap_set_proc(cap_p))
86 	{
87 		TH_LOG("Failed to set capabilities: %s", strerror(errno));
88 	}
89 	EXPECT_NE(-1, cap_free(cap_p));
90 
91 	/* Quickly checks that ambient capabilities are cleared. */
92 	EXPECT_NE(-1, cap_get_ambient(caps[0]));
93 }
94 
95 /* We cannot put such helpers in a library because of kselftest_harness.h . */
96 static void __maybe_unused disable_caps(struct __test_metadata *const _metadata)
97 {
98 	_init_caps(_metadata, false);
99 }
100 
101 static void __maybe_unused drop_caps(struct __test_metadata *const _metadata)
102 {
103 	_init_caps(_metadata, true);
104 }
105 
106 static void _change_cap(struct __test_metadata *const _metadata,
107 			const cap_flag_t flag, const cap_value_t cap,
108 			const cap_flag_value_t value)
109 {
110 	cap_t cap_p;
111 
112 	cap_p = cap_get_proc();
113 	EXPECT_NE(NULL, cap_p);
114 	EXPECT_NE(-1, cap_set_flag(cap_p, flag, 1, &cap, value));
115 	EXPECT_NE(-1, cap_set_proc(cap_p))
116 	{
117 		TH_LOG("Failed to set capability %d: %s", cap, strerror(errno));
118 	}
119 	EXPECT_NE(-1, cap_free(cap_p));
120 }
121 
122 static void __maybe_unused set_cap(struct __test_metadata *const _metadata,
123 				   const cap_value_t cap)
124 {
125 	_change_cap(_metadata, CAP_EFFECTIVE, cap, CAP_SET);
126 }
127 
128 static void __maybe_unused clear_cap(struct __test_metadata *const _metadata,
129 				     const cap_value_t cap)
130 {
131 	_change_cap(_metadata, CAP_EFFECTIVE, cap, CAP_CLEAR);
132 }
133 
134 static void __maybe_unused
135 set_ambient_cap(struct __test_metadata *const _metadata, const cap_value_t cap)
136 {
137 	_change_cap(_metadata, CAP_INHERITABLE, cap, CAP_SET);
138 
139 	EXPECT_NE(-1, cap_set_ambient(cap, CAP_SET))
140 	{
141 		TH_LOG("Failed to set ambient capability %d: %s", cap,
142 		       strerror(errno));
143 	}
144 }
145 
146 static void __maybe_unused clear_ambient_cap(
147 	struct __test_metadata *const _metadata, const cap_value_t cap)
148 {
149 	EXPECT_EQ(1, cap_get_ambient(cap));
150 	_change_cap(_metadata, CAP_INHERITABLE, cap, CAP_CLEAR);
151 	EXPECT_EQ(0, cap_get_ambient(cap));
152 }
153 
154 /* Receives an FD from a UNIX socket. Returns the received FD, or -errno. */
155 static int __maybe_unused recv_fd(int usock)
156 {
157 	int fd_rx;
158 	union {
159 		/* Aligned ancillary data buffer. */
160 		char buf[CMSG_SPACE(sizeof(fd_rx))];
161 		struct cmsghdr _align;
162 	} cmsg_rx = {};
163 	char data = '\0';
164 	struct iovec io = {
165 		.iov_base = &data,
166 		.iov_len = sizeof(data),
167 	};
168 	struct msghdr msg = {
169 		.msg_iov = &io,
170 		.msg_iovlen = 1,
171 		.msg_control = &cmsg_rx.buf,
172 		.msg_controllen = sizeof(cmsg_rx.buf),
173 	};
174 	struct cmsghdr *cmsg;
175 	int res;
176 
177 	res = recvmsg(usock, &msg, MSG_CMSG_CLOEXEC);
178 	if (res < 0)
179 		return -errno;
180 
181 	cmsg = CMSG_FIRSTHDR(&msg);
182 	if (cmsg->cmsg_len != CMSG_LEN(sizeof(fd_rx)))
183 		return -EIO;
184 
185 	memcpy(&fd_rx, CMSG_DATA(cmsg), sizeof(fd_rx));
186 	return fd_rx;
187 }
188 
189 /* Sends an FD on a UNIX socket. Returns 0 on success or -errno. */
190 static int __maybe_unused send_fd(int usock, int fd_tx)
191 {
192 	union {
193 		/* Aligned ancillary data buffer. */
194 		char buf[CMSG_SPACE(sizeof(fd_tx))];
195 		struct cmsghdr _align;
196 	} cmsg_tx = {};
197 	char data_tx = '.';
198 	struct iovec io = {
199 		.iov_base = &data_tx,
200 		.iov_len = sizeof(data_tx),
201 	};
202 	struct msghdr msg = {
203 		.msg_iov = &io,
204 		.msg_iovlen = 1,
205 		.msg_control = &cmsg_tx.buf,
206 		.msg_controllen = sizeof(cmsg_tx.buf),
207 	};
208 	struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
209 
210 	cmsg->cmsg_len = CMSG_LEN(sizeof(fd_tx));
211 	cmsg->cmsg_level = SOL_SOCKET;
212 	cmsg->cmsg_type = SCM_RIGHTS;
213 	memcpy(CMSG_DATA(cmsg), &fd_tx, sizeof(fd_tx));
214 
215 	if (sendmsg(usock, &msg, 0) < 0)
216 		return -errno;
217 	return 0;
218 }
219 
220 static void __maybe_unused
221 enforce_ruleset(struct __test_metadata *const _metadata, const int ruleset_fd)
222 {
223 	ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0));
224 	ASSERT_EQ(0, landlock_restrict_self(ruleset_fd, 0))
225 	{
226 		TH_LOG("Failed to enforce ruleset: %s", strerror(errno));
227 	}
228 }
229