~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/landlock/base_test.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 /*
  3  * Landlock tests - Common user space base
  4  *
  5  * Copyright © 2017-2020 Mickaël Salaün <mic@digikod.net>
  6  * Copyright © 2019-2020 ANSSI
  7  */
  8 
  9 #define _GNU_SOURCE
 10 #include <errno.h>
 11 #include <fcntl.h>
 12 #include <linux/keyctl.h>
 13 #include <linux/landlock.h>
 14 #include <string.h>
 15 #include <sys/prctl.h>
 16 #include <sys/socket.h>
 17 #include <sys/types.h>
 18 
 19 #include "common.h"
 20 
 21 #ifndef O_PATH
 22 #define O_PATH 010000000
 23 #endif
 24 
 25 TEST(inconsistent_attr)
 26 {
 27         const long page_size = sysconf(_SC_PAGESIZE);
 28         char *const buf = malloc(page_size + 1);
 29         struct landlock_ruleset_attr *const ruleset_attr = (void *)buf;
 30 
 31         ASSERT_NE(NULL, buf);
 32 
 33         /* Checks copy_from_user(). */
 34         ASSERT_EQ(-1, landlock_create_ruleset(ruleset_attr, 0, 0));
 35         /* The size if less than sizeof(struct landlock_attr_enforce). */
 36         ASSERT_EQ(EINVAL, errno);
 37         ASSERT_EQ(-1, landlock_create_ruleset(ruleset_attr, 1, 0));
 38         ASSERT_EQ(EINVAL, errno);
 39         ASSERT_EQ(-1, landlock_create_ruleset(ruleset_attr, 7, 0));
 40         ASSERT_EQ(EINVAL, errno);
 41 
 42         ASSERT_EQ(-1, landlock_create_ruleset(NULL, 1, 0));
 43         /* The size if less than sizeof(struct landlock_attr_enforce). */
 44         ASSERT_EQ(EFAULT, errno);
 45 
 46         ASSERT_EQ(-1, landlock_create_ruleset(
 47                               NULL, sizeof(struct landlock_ruleset_attr), 0));
 48         ASSERT_EQ(EFAULT, errno);
 49 
 50         ASSERT_EQ(-1, landlock_create_ruleset(ruleset_attr, page_size + 1, 0));
 51         ASSERT_EQ(E2BIG, errno);
 52 
 53         /* Checks minimal valid attribute size. */
 54         ASSERT_EQ(-1, landlock_create_ruleset(ruleset_attr, 8, 0));
 55         ASSERT_EQ(ENOMSG, errno);
 56         ASSERT_EQ(-1, landlock_create_ruleset(
 57                               ruleset_attr,
 58                               sizeof(struct landlock_ruleset_attr), 0));
 59         ASSERT_EQ(ENOMSG, errno);
 60         ASSERT_EQ(-1, landlock_create_ruleset(ruleset_attr, page_size, 0));
 61         ASSERT_EQ(ENOMSG, errno);
 62 
 63         /* Checks non-zero value. */
 64         buf[page_size - 2] = '.';
 65         ASSERT_EQ(-1, landlock_create_ruleset(ruleset_attr, page_size, 0));
 66         ASSERT_EQ(E2BIG, errno);
 67 
 68         ASSERT_EQ(-1, landlock_create_ruleset(ruleset_attr, page_size + 1, 0));
 69         ASSERT_EQ(E2BIG, errno);
 70 
 71         free(buf);
 72 }
 73 
 74 TEST(abi_version)
 75 {
 76         const struct landlock_ruleset_attr ruleset_attr = {
 77                 .handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE,
 78         };
 79         ASSERT_EQ(5, landlock_create_ruleset(NULL, 0,
 80                                              LANDLOCK_CREATE_RULESET_VERSION));
 81 
 82         ASSERT_EQ(-1, landlock_create_ruleset(&ruleset_attr, 0,
 83                                               LANDLOCK_CREATE_RULESET_VERSION));
 84         ASSERT_EQ(EINVAL, errno);
 85 
 86         ASSERT_EQ(-1, landlock_create_ruleset(NULL, sizeof(ruleset_attr),
 87                                               LANDLOCK_CREATE_RULESET_VERSION));
 88         ASSERT_EQ(EINVAL, errno);
 89 
 90         ASSERT_EQ(-1,
 91                   landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr),
 92                                           LANDLOCK_CREATE_RULESET_VERSION));
 93         ASSERT_EQ(EINVAL, errno);
 94 
 95         ASSERT_EQ(-1, landlock_create_ruleset(NULL, 0,
 96                                               LANDLOCK_CREATE_RULESET_VERSION |
 97                                                       1 << 31));
 98         ASSERT_EQ(EINVAL, errno);
 99 }
100 
101 /* Tests ordering of syscall argument checks. */
102 TEST(create_ruleset_checks_ordering)
103 {
104         const int last_flag = LANDLOCK_CREATE_RULESET_VERSION;
105         const int invalid_flag = last_flag << 1;
106         int ruleset_fd;
107         const struct landlock_ruleset_attr ruleset_attr = {
108                 .handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE,
109         };
110 
111         /* Checks priority for invalid flags. */
112         ASSERT_EQ(-1, landlock_create_ruleset(NULL, 0, invalid_flag));
113         ASSERT_EQ(EINVAL, errno);
114 
115         ASSERT_EQ(-1, landlock_create_ruleset(&ruleset_attr, 0, invalid_flag));
116         ASSERT_EQ(EINVAL, errno);
117 
118         ASSERT_EQ(-1, landlock_create_ruleset(NULL, sizeof(ruleset_attr),
119                                               invalid_flag));
120         ASSERT_EQ(EINVAL, errno);
121 
122         ASSERT_EQ(-1,
123                   landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr),
124                                           invalid_flag));
125         ASSERT_EQ(EINVAL, errno);
126 
127         /* Checks too big ruleset_attr size. */
128         ASSERT_EQ(-1, landlock_create_ruleset(&ruleset_attr, -1, 0));
129         ASSERT_EQ(E2BIG, errno);
130 
131         /* Checks too small ruleset_attr size. */
132         ASSERT_EQ(-1, landlock_create_ruleset(&ruleset_attr, 0, 0));
133         ASSERT_EQ(EINVAL, errno);
134         ASSERT_EQ(-1, landlock_create_ruleset(&ruleset_attr, 1, 0));
135         ASSERT_EQ(EINVAL, errno);
136 
137         /* Checks valid call. */
138         ruleset_fd =
139                 landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
140         ASSERT_LE(0, ruleset_fd);
141         ASSERT_EQ(0, close(ruleset_fd));
142 }
143 
144 /* Tests ordering of syscall argument checks. */
145 TEST(add_rule_checks_ordering)
146 {
147         const struct landlock_ruleset_attr ruleset_attr = {
148                 .handled_access_fs = LANDLOCK_ACCESS_FS_EXECUTE,
149         };
150         struct landlock_path_beneath_attr path_beneath_attr = {
151                 .allowed_access = LANDLOCK_ACCESS_FS_EXECUTE,
152                 .parent_fd = -1,
153         };
154         const int ruleset_fd =
155                 landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
156 
157         ASSERT_LE(0, ruleset_fd);
158 
159         /* Checks invalid flags. */
160         ASSERT_EQ(-1, landlock_add_rule(-1, 0, NULL, 1));
161         ASSERT_EQ(EINVAL, errno);
162 
163         /* Checks invalid ruleset FD. */
164         ASSERT_EQ(-1, landlock_add_rule(-1, 0, NULL, 0));
165         ASSERT_EQ(EBADF, errno);
166 
167         /* Checks invalid rule type. */
168         ASSERT_EQ(-1, landlock_add_rule(ruleset_fd, 0, NULL, 0));
169         ASSERT_EQ(EINVAL, errno);
170 
171         /* Checks invalid rule attr. */
172         ASSERT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
173                                         NULL, 0));
174         ASSERT_EQ(EFAULT, errno);
175 
176         /* Checks invalid path_beneath.parent_fd. */
177         ASSERT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
178                                         &path_beneath_attr, 0));
179         ASSERT_EQ(EBADF, errno);
180 
181         /* Checks valid call. */
182         path_beneath_attr.parent_fd =
183                 open("/tmp", O_PATH | O_NOFOLLOW | O_DIRECTORY | O_CLOEXEC);
184         ASSERT_LE(0, path_beneath_attr.parent_fd);
185         ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
186                                        &path_beneath_attr, 0));
187         ASSERT_EQ(0, close(path_beneath_attr.parent_fd));
188         ASSERT_EQ(0, close(ruleset_fd));
189 }
190 
191 /* Tests ordering of syscall argument and permission checks. */
192 TEST(restrict_self_checks_ordering)
193 {
194         const struct landlock_ruleset_attr ruleset_attr = {
195                 .handled_access_fs = LANDLOCK_ACCESS_FS_EXECUTE,
196         };
197         struct landlock_path_beneath_attr path_beneath_attr = {
198                 .allowed_access = LANDLOCK_ACCESS_FS_EXECUTE,
199                 .parent_fd = -1,
200         };
201         const int ruleset_fd =
202                 landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
203 
204         ASSERT_LE(0, ruleset_fd);
205         path_beneath_attr.parent_fd =
206                 open("/tmp", O_PATH | O_NOFOLLOW | O_DIRECTORY | O_CLOEXEC);
207         ASSERT_LE(0, path_beneath_attr.parent_fd);
208         ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
209                                        &path_beneath_attr, 0));
210         ASSERT_EQ(0, close(path_beneath_attr.parent_fd));
211 
212         /* Checks unprivileged enforcement without no_new_privs. */
213         drop_caps(_metadata);
214         ASSERT_EQ(-1, landlock_restrict_self(-1, -1));
215         ASSERT_EQ(EPERM, errno);
216         ASSERT_EQ(-1, landlock_restrict_self(-1, 0));
217         ASSERT_EQ(EPERM, errno);
218         ASSERT_EQ(-1, landlock_restrict_self(ruleset_fd, 0));
219         ASSERT_EQ(EPERM, errno);
220 
221         ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0));
222 
223         /* Checks invalid flags. */
224         ASSERT_EQ(-1, landlock_restrict_self(-1, -1));
225         ASSERT_EQ(EINVAL, errno);
226 
227         /* Checks invalid ruleset FD. */
228         ASSERT_EQ(-1, landlock_restrict_self(-1, 0));
229         ASSERT_EQ(EBADF, errno);
230 
231         /* Checks valid call. */
232         ASSERT_EQ(0, landlock_restrict_self(ruleset_fd, 0));
233         ASSERT_EQ(0, close(ruleset_fd));
234 }
235 
236 TEST(ruleset_fd_io)
237 {
238         struct landlock_ruleset_attr ruleset_attr = {
239                 .handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE,
240         };
241         int ruleset_fd;
242         char buf;
243 
244         drop_caps(_metadata);
245         ruleset_fd =
246                 landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
247         ASSERT_LE(0, ruleset_fd);
248 
249         ASSERT_EQ(-1, write(ruleset_fd, ".", 1));
250         ASSERT_EQ(EINVAL, errno);
251         ASSERT_EQ(-1, read(ruleset_fd, &buf, 1));
252         ASSERT_EQ(EINVAL, errno);
253 
254         ASSERT_EQ(0, close(ruleset_fd));
255 }
256 
257 /* Tests enforcement of a ruleset FD transferred through a UNIX socket. */
258 TEST(ruleset_fd_transfer)
259 {
260         struct landlock_ruleset_attr ruleset_attr = {
261                 .handled_access_fs = LANDLOCK_ACCESS_FS_READ_DIR,
262         };
263         struct landlock_path_beneath_attr path_beneath_attr = {
264                 .allowed_access = LANDLOCK_ACCESS_FS_READ_DIR,
265         };
266         int ruleset_fd_tx, dir_fd;
267         int socket_fds[2];
268         pid_t child;
269         int status;
270 
271         drop_caps(_metadata);
272 
273         /* Creates a test ruleset with a simple rule. */
274         ruleset_fd_tx =
275                 landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
276         ASSERT_LE(0, ruleset_fd_tx);
277         path_beneath_attr.parent_fd =
278                 open("/tmp", O_PATH | O_NOFOLLOW | O_DIRECTORY | O_CLOEXEC);
279         ASSERT_LE(0, path_beneath_attr.parent_fd);
280         ASSERT_EQ(0,
281                   landlock_add_rule(ruleset_fd_tx, LANDLOCK_RULE_PATH_BENEATH,
282                                     &path_beneath_attr, 0));
283         ASSERT_EQ(0, close(path_beneath_attr.parent_fd));
284 
285         /* Sends the ruleset FD over a socketpair and then close it. */
286         ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0,
287                                 socket_fds));
288         ASSERT_EQ(0, send_fd(socket_fds[0], ruleset_fd_tx));
289         ASSERT_EQ(0, close(socket_fds[0]));
290         ASSERT_EQ(0, close(ruleset_fd_tx));
291 
292         child = fork();
293         ASSERT_LE(0, child);
294         if (child == 0) {
295                 const int ruleset_fd_rx = recv_fd(socket_fds[1]);
296 
297                 ASSERT_LE(0, ruleset_fd_rx);
298                 ASSERT_EQ(0, close(socket_fds[1]));
299 
300                 /* Enforces the received ruleset on the child. */
301                 ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0));
302                 ASSERT_EQ(0, landlock_restrict_self(ruleset_fd_rx, 0));
303                 ASSERT_EQ(0, close(ruleset_fd_rx));
304 
305                 /* Checks that the ruleset enforcement. */
306                 ASSERT_EQ(-1, open("/", O_RDONLY | O_DIRECTORY | O_CLOEXEC));
307                 ASSERT_EQ(EACCES, errno);
308                 dir_fd = open("/tmp", O_RDONLY | O_DIRECTORY | O_CLOEXEC);
309                 ASSERT_LE(0, dir_fd);
310                 ASSERT_EQ(0, close(dir_fd));
311                 _exit(_metadata->exit_code);
312                 return;
313         }
314 
315         ASSERT_EQ(0, close(socket_fds[1]));
316 
317         /* Checks that the parent is unrestricted. */
318         dir_fd = open("/", O_RDONLY | O_DIRECTORY | O_CLOEXEC);
319         ASSERT_LE(0, dir_fd);
320         ASSERT_EQ(0, close(dir_fd));
321         dir_fd = open("/tmp", O_RDONLY | O_DIRECTORY | O_CLOEXEC);
322         ASSERT_LE(0, dir_fd);
323         ASSERT_EQ(0, close(dir_fd));
324 
325         ASSERT_EQ(child, waitpid(child, &status, 0));
326         ASSERT_EQ(1, WIFEXITED(status));
327         ASSERT_EQ(EXIT_SUCCESS, WEXITSTATUS(status));
328 }
329 
330 TEST(cred_transfer)
331 {
332         struct landlock_ruleset_attr ruleset_attr = {
333                 .handled_access_fs = LANDLOCK_ACCESS_FS_READ_DIR,
334         };
335         int ruleset_fd, dir_fd;
336         pid_t child;
337         int status;
338 
339         drop_caps(_metadata);
340 
341         dir_fd = open("/", O_RDONLY | O_DIRECTORY | O_CLOEXEC);
342         EXPECT_LE(0, dir_fd);
343         EXPECT_EQ(0, close(dir_fd));
344 
345         /* Denies opening directories. */
346         ruleset_fd =
347                 landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
348         ASSERT_LE(0, ruleset_fd);
349         EXPECT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0));
350         ASSERT_EQ(0, landlock_restrict_self(ruleset_fd, 0));
351         EXPECT_EQ(0, close(ruleset_fd));
352 
353         /* Checks ruleset enforcement. */
354         EXPECT_EQ(-1, open("/", O_RDONLY | O_DIRECTORY | O_CLOEXEC));
355         EXPECT_EQ(EACCES, errno);
356 
357         /* Needed for KEYCTL_SESSION_TO_PARENT permission checks */
358         EXPECT_NE(-1, syscall(__NR_keyctl, KEYCTL_JOIN_SESSION_KEYRING, NULL, 0,
359                               0, 0))
360         {
361                 TH_LOG("Failed to join session keyring: %s", strerror(errno));
362         }
363 
364         child = fork();
365         ASSERT_LE(0, child);
366         if (child == 0) {
367                 /* Checks ruleset enforcement. */
368                 EXPECT_EQ(-1, open("/", O_RDONLY | O_DIRECTORY | O_CLOEXEC));
369                 EXPECT_EQ(EACCES, errno);
370 
371                 /*
372                  * KEYCTL_SESSION_TO_PARENT is a no-op unless we have a
373                  * different session keyring in the child, so make that happen.
374                  */
375                 EXPECT_NE(-1, syscall(__NR_keyctl, KEYCTL_JOIN_SESSION_KEYRING,
376                                       NULL, 0, 0, 0));
377 
378                 /*
379                  * KEYCTL_SESSION_TO_PARENT installs credentials on the parent
380                  * that never go through the cred_prepare hook, this path uses
381                  * cred_transfer instead.
382                  */
383                 EXPECT_EQ(0, syscall(__NR_keyctl, KEYCTL_SESSION_TO_PARENT, 0,
384                                      0, 0, 0));
385 
386                 /* Re-checks ruleset enforcement. */
387                 EXPECT_EQ(-1, open("/", O_RDONLY | O_DIRECTORY | O_CLOEXEC));
388                 EXPECT_EQ(EACCES, errno);
389 
390                 _exit(_metadata->exit_code);
391                 return;
392         }
393 
394         EXPECT_EQ(child, waitpid(child, &status, 0));
395         EXPECT_EQ(1, WIFEXITED(status));
396         EXPECT_EQ(EXIT_SUCCESS, WEXITSTATUS(status));
397 
398         /* Re-checks ruleset enforcement. */
399         EXPECT_EQ(-1, open("/", O_RDONLY | O_DIRECTORY | O_CLOEXEC));
400         EXPECT_EQ(EACCES, errno);
401 }
402 
403 TEST_HARNESS_MAIN
404 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php