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
30static inline int
31landlock_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
39static 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
50static 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
57static 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 . */
96static void __maybe_unused disable_caps(struct __test_metadata *const _metadata)
97{
98	_init_caps(_metadata, false);
99}
100
101static void __maybe_unused drop_caps(struct __test_metadata *const _metadata)
102{
103	_init_caps(_metadata, true);
104}
105
106static 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
122static 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
128static 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
134static void __maybe_unused
135set_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
146static 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. */
155static 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. */
190static 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
220static void __maybe_unused
221enforce_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