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, drop_all: false);
99}
100
101static void __maybe_unused drop_caps(struct __test_metadata *const _metadata)
102{
103 _init_caps(_metadata, drop_all: 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

source code of linux/tools/testing/selftests/landlock/common.h