Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.10.11.
  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
 25TEST(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
 74TEST(abi_version)
 75{
 76	const struct landlock_ruleset_attr ruleset_attr = {
 77		.handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE,
 78	};
 79	ASSERT_EQ(6, 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. */
102TEST(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. */
145TEST(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. */
192TEST(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
236TEST(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. */
258TEST(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
330TEST(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
403TEST_HARNESS_MAIN