1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2021 The FreeBSD Foundation
5 *
6 * This software was developed by Mark Johnston under sponsorship from
7 * the FreeBSD Foundation.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are
11 * met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in
16 *    the documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31/*
32 * Basic regression tests for handling of O_PATH descriptors.
33 */
34
35#include <sys/param.h>
36#include <sys/capsicum.h>
37#include <sys/event.h>
38#include <sys/ioctl.h>
39#include <sys/memrange.h>
40#include <sys/mman.h>
41#include <sys/ptrace.h>
42#include <sys/socket.h>
43#include <sys/stat.h>
44#include <sys/time.h>
45#include <sys/uio.h>
46#include <sys/un.h>
47#include <sys/wait.h>
48
49#include <aio.h>
50#include <dirent.h>
51#include <errno.h>
52#include <fcntl.h>
53#include <poll.h>
54#include <signal.h>
55#include <stdio.h>
56#include <stdlib.h>
57#include <unistd.h>
58
59#include <atf-c.h>
60
61#define	FMT_ERR(s)		s ": %s", strerror(errno)
62
63#define	CHECKED_CLOSE(fd)	\
64	ATF_REQUIRE_MSG(close(fd) == 0, FMT_ERR("close"))
65
66/* Create a temporary regular file containing some data. */
67static void
68mktfile(char path[PATH_MAX], const char *template)
69{
70	char buf[BUFSIZ];
71	int fd;
72
73	snprintf(path, PATH_MAX, "%s", template);
74	fd = mkstemp(path);
75	ATF_REQUIRE_MSG(fd >= 0, FMT_ERR("mkstemp"));
76	memset(buf, 0, sizeof(buf));
77	ATF_REQUIRE_MSG(write(fd, buf, sizeof(buf)) == sizeof(buf),
78	    FMT_ERR("write"));
79	CHECKED_CLOSE(fd);
80}
81
82/* Make a temporary directory. */
83static void
84mktdir(char path[PATH_MAX], const char *template)
85{
86	snprintf(path, PATH_MAX, "%s", template);
87	ATF_REQUIRE_MSG(mkdtemp(path) == path, FMT_ERR("mkdtemp"));
88}
89
90/* Wait for a child process to exit with status 0. */
91static void
92waitchild(pid_t child, int exstatus)
93{
94	int error, status;
95
96	error = waitpid(child, &status, 0);
97	ATF_REQUIRE_MSG(error != -1, FMT_ERR("waitpid"));
98	ATF_REQUIRE_MSG(WIFEXITED(status), "child exited abnormally, status %d",
99	    status);
100	ATF_REQUIRE_MSG(WEXITSTATUS(status) == exstatus,
101	    "child exit status is %d, expected %d",
102	    WEXITSTATUS(status), exstatus);
103}
104
105ATF_TC_WITHOUT_HEAD(path_access);
106ATF_TC_BODY(path_access, tc)
107{
108	char path[PATH_MAX];
109	struct stat sb;
110	struct timespec ts[2];
111	struct timeval tv[2];
112	int pathfd;
113
114	mktfile(path, "path_access.XXXXXX");
115
116	pathfd = open(path, O_PATH);
117	ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open"));
118
119	ATF_REQUIRE_ERRNO(EBADF, fchmod(pathfd, 0666) == -1);
120	ATF_REQUIRE_ERRNO(EBADF, fchown(pathfd, getuid(), getgid()) == -1);
121	ATF_REQUIRE_ERRNO(EBADF, fchflags(pathfd, UF_NODUMP) == -1);
122	memset(tv, 0, sizeof(tv));
123	ATF_REQUIRE_ERRNO(EBADF, futimes(pathfd, tv) == -1);
124	memset(ts, 0, sizeof(ts));
125	ATF_REQUIRE_ERRNO(EBADF, futimens(pathfd, ts) == -1);
126
127	/* fpathconf(2) and fstat(2) are permitted. */
128	ATF_REQUIRE_MSG(fstat(pathfd, &sb) == 0, FMT_ERR("fstat"));
129	ATF_REQUIRE_MSG(fpathconf(pathfd, _PC_LINK_MAX) != -1,
130	    FMT_ERR("fpathconf"));
131
132	CHECKED_CLOSE(pathfd);
133}
134
135/* Basic tests to verify that AIO operations fail. */
136ATF_TC_WITHOUT_HEAD(path_aio);
137ATF_TC_BODY(path_aio, tc)
138{
139	struct aiocb aio;
140	char buf[BUFSIZ], path[PATH_MAX];
141	int pathfd;
142
143	mktfile(path, "path_aio.XXXXXX");
144
145	pathfd = open(path, O_PATH);
146	ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open"));
147
148	memset(&aio, 0, sizeof(aio));
149	aio.aio_buf = buf;
150	aio.aio_nbytes = sizeof(buf);
151	aio.aio_fildes = pathfd;
152	aio.aio_offset = 0;
153
154	ATF_REQUIRE_ERRNO(EBADF, aio_read(&aio) == -1);
155	ATF_REQUIRE_ERRNO(EBADF, aio_write(&aio) == -1);
156	ATF_REQUIRE_ERRNO(EBADF, aio_fsync(O_SYNC, &aio) == -1);
157	ATF_REQUIRE_ERRNO(EBADF, aio_fsync(O_DSYNC, &aio) == -1);
158
159	CHECKED_CLOSE(pathfd);
160}
161
162/* Basic tests to verify that Capsicum restrictions apply to path fds. */
163ATF_TC_WITHOUT_HEAD(path_capsicum);
164ATF_TC_BODY(path_capsicum, tc)
165{
166	char path[PATH_MAX];
167	cap_rights_t rights;
168	int truefd;
169	pid_t child;
170
171	mktfile(path, "path_capsicum.XXXXXX");
172
173	/* Make sure that filesystem namespace restrictions apply to O_PATH. */
174	child = fork();
175	ATF_REQUIRE_MSG(child != -1, FMT_ERR("fork"));
176	if (child == 0) {
177		if (cap_enter() != 0)
178			_exit(1);
179		if (open(path, O_PATH) >= 0)
180			_exit(2);
181		if (errno != ECAPMODE)
182			_exit(3);
183		if (open("/usr/bin/true", O_PATH | O_EXEC) >= 0)
184			_exit(4);
185		if (errno != ECAPMODE)
186			_exit(5);
187		_exit(0);
188	}
189	waitchild(child, 0);
190
191	/* Make sure that CAP_FEXECVE is required. */
192	child = fork();
193	ATF_REQUIRE_MSG(child != -1, FMT_ERR("fork"));
194	if (child == 0) {
195		truefd = open("/usr/bin/true", O_PATH | O_EXEC);
196		if (truefd < 0)
197			_exit(1);
198		cap_rights_init(&rights);
199		if (cap_rights_limit(truefd, &rights) != 0)
200			_exit(2);
201		(void)fexecve(truefd,
202		    (char * const[]){__DECONST(char *, "/usr/bin/true"), NULL},
203		    NULL);
204		if (errno != ENOTCAPABLE)
205			_exit(3);
206		_exit(4);
207	}
208	waitchild(child, 4);
209}
210
211/* Make sure that ptrace(PT_COREDUMP) cannot be used to write to a path fd. */
212ATF_TC_WITHOUT_HEAD(path_coredump);
213ATF_TC_BODY(path_coredump, tc)
214{
215	char path[PATH_MAX];
216	struct ptrace_coredump pc;
217	int error, pathfd, status;
218	pid_t child;
219
220	mktdir(path, "path_coredump.XXXXXX");
221
222	child = fork();
223	ATF_REQUIRE_MSG(child != -1, FMT_ERR("fork"));
224	if (child == 0) {
225		while (true)
226			(void)sleep(1);
227	}
228
229	pathfd = open(path, O_PATH);
230	ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open"));
231
232	error = ptrace(PT_ATTACH, child, 0, 0);
233	ATF_REQUIRE_MSG(error == 0, FMT_ERR("ptrace"));
234	error = waitpid(child, &status, 0);
235	ATF_REQUIRE_MSG(error != -1, FMT_ERR("waitpid"));
236	ATF_REQUIRE_MSG(WIFSTOPPED(status), "unexpected status %d", status);
237
238	pc.pc_fd = pathfd;
239	pc.pc_flags = 0;
240	pc.pc_limit = 0;
241	error = ptrace(PT_COREDUMP, child, (void *)&pc, sizeof(pc));
242	ATF_REQUIRE_ERRNO(EBADF, error == -1);
243
244	error = ptrace(PT_DETACH, child, 0, 0);
245	ATF_REQUIRE_MSG(error == 0, FMT_ERR("ptrace"));
246
247	ATF_REQUIRE_MSG(kill(child, SIGKILL) == 0, FMT_ERR("kill"));
248
249	CHECKED_CLOSE(pathfd);
250}
251
252/* Verify operations on directory path descriptors. */
253ATF_TC_WITHOUT_HEAD(path_directory);
254ATF_TC_BODY(path_directory, tc)
255{
256	struct dirent de;
257	struct stat sb;
258	char path[PATH_MAX];
259	int fd, pathfd;
260
261	mktdir(path, "path_directory.XXXXXX");
262
263	pathfd = open(path, O_PATH | O_DIRECTORY);
264	ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open"));
265
266	/* Should not be possible to list directory entries. */
267	ATF_REQUIRE_ERRNO(EBADF,
268	    getdirentries(pathfd, (char *)&de, sizeof(de), NULL) == -1);
269
270	/* It should be possible to create files under pathfd. */
271	fd = openat(pathfd, "test", O_RDWR | O_CREAT, 0600);
272	ATF_REQUIRE_MSG(fd >= 0, FMT_ERR("open"));
273	ATF_REQUIRE_MSG(fstatat(pathfd, "test", &sb, 0) == 0,
274	    FMT_ERR("fstatat"));
275	CHECKED_CLOSE(fd);
276
277	/* ... but doing so requires write access. */
278	if (geteuid() != 0) {
279		ATF_REQUIRE_ERRNO(EBADF, fchmod(pathfd, 0500) == -1);
280		ATF_REQUIRE_MSG(chmod(path, 0500) == 0, FMT_ERR("chmod"));
281		ATF_REQUIRE_ERRNO(EACCES,
282		    openat(pathfd, "test2", O_RDWR | O_CREAT, 0600) < 0);
283	}
284
285	/* fchdir(2) is permitted. */
286	ATF_REQUIRE_MSG(fchdir(pathfd) == 0, FMT_ERR("fchdir"));
287
288	CHECKED_CLOSE(pathfd);
289}
290
291/* Verify access permission checking for a directory path fd. */
292ATF_TC_WITH_CLEANUP(path_directory_not_root);
293ATF_TC_HEAD(path_directory_not_root, tc)
294{
295	atf_tc_set_md_var(tc, "require.user", "unprivileged");
296}
297ATF_TC_BODY(path_directory_not_root, tc)
298{
299	char path[PATH_MAX];
300	int pathfd;
301
302	mktdir(path, "path_directory.XXXXXX");
303
304	pathfd = open(path, O_PATH | O_DIRECTORY);
305	ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open"));
306
307	ATF_REQUIRE_ERRNO(EBADF, fchmod(pathfd, 0500) == -1);
308	ATF_REQUIRE_MSG(chmod(path, 0500) == 0, FMT_ERR("chmod"));
309	ATF_REQUIRE_ERRNO(EACCES,
310	    openat(pathfd, "test2", O_RDWR | O_CREAT, 0600) < 0);
311
312	CHECKED_CLOSE(pathfd);
313}
314ATF_TC_CLEANUP(path_directory_not_root, tc)
315{
316}
317
318/* Validate system calls that handle AT_EMPTY_PATH. */
319ATF_TC_WITHOUT_HEAD(path_empty);
320ATF_TC_BODY(path_empty, tc)
321{
322	char path[PATH_MAX];
323	struct timespec ts[2];
324	struct stat sb;
325	int pathfd;
326
327	mktfile(path, "path_empty.XXXXXX");
328
329	pathfd = open(path, O_PATH);
330	ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open"));
331
332	/* Various *at operations should work on path fds. */
333	ATF_REQUIRE_MSG(faccessat(pathfd, "", F_OK, AT_EMPTY_PATH) == 0,
334	    FMT_ERR("faccessat"));
335	ATF_REQUIRE_MSG(chflagsat(pathfd, "", UF_NODUMP, AT_EMPTY_PATH) == 0,
336	    FMT_ERR("chflagsat"));
337	ATF_REQUIRE_MSG(fchmodat(pathfd, "", 0600, AT_EMPTY_PATH) == 0,
338	    FMT_ERR("fchmodat"));
339	ATF_REQUIRE_MSG(fchownat(pathfd, "", getuid(), getgid(),
340	    AT_EMPTY_PATH) == 0, FMT_ERR("fchownat"));
341	ATF_REQUIRE_MSG(fstatat(pathfd, "", &sb, AT_EMPTY_PATH) == 0,
342	    FMT_ERR("fstatat"));
343	ATF_REQUIRE_MSG(sb.st_size == BUFSIZ,
344	    "unexpected size %ju", (uintmax_t)sb.st_size);
345	memset(ts, 0, sizeof(ts));
346	ATF_REQUIRE_MSG(utimensat(pathfd, "", ts, AT_EMPTY_PATH) == 0,
347	    FMT_ERR("utimensat"));
348
349	CHECKED_CLOSE(pathfd);
350}
351
352/* Verify that various operations on a path fd have access checks. */
353ATF_TC_WITH_CLEANUP(path_empty_not_root);
354ATF_TC_HEAD(path_empty_not_root, tc)
355{
356	atf_tc_set_md_var(tc, "require.user", "unprivileged");
357}
358ATF_TC_BODY(path_empty_not_root, tc)
359{
360	int pathfd;
361
362	pathfd = open("/dev/null", O_PATH);
363	ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open"));
364
365	ATF_REQUIRE_ERRNO(EPERM,
366	    chflagsat(pathfd, "", UF_NODUMP, AT_EMPTY_PATH) == -1);
367	ATF_REQUIRE_ERRNO(EPERM,
368	    fchownat(pathfd, "", getuid(), getgid(), AT_EMPTY_PATH) == -1);
369	ATF_REQUIRE_ERRNO(EPERM,
370	    fchmodat(pathfd, "", 0600, AT_EMPTY_PATH) == -1);
371	ATF_REQUIRE_ERRNO(EPERM,
372	    linkat(pathfd, "", AT_FDCWD, "test", AT_EMPTY_PATH) == -1);
373
374	CHECKED_CLOSE(pathfd);
375}
376ATF_TC_CLEANUP(path_empty_not_root, tc)
377{
378}
379
380/* Test linkat(2) with AT_EMPTY_PATH, which requires privileges. */
381ATF_TC_WITH_CLEANUP(path_empty_root);
382ATF_TC_HEAD(path_empty_root, tc)
383{
384	atf_tc_set_md_var(tc, "require.user", "root");
385}
386ATF_TC_BODY(path_empty_root, tc)
387{
388	char path[PATH_MAX];
389	struct stat sb, sb2;
390	int pathfd;
391
392	mktfile(path, "path_empty_root.XXXXXX");
393
394	pathfd = open(path, O_PATH);
395	ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open"));
396	ATF_REQUIRE_MSG(fstatat(pathfd, "", &sb, AT_EMPTY_PATH) == 0,
397	    FMT_ERR("fstatat"));
398
399	ATF_REQUIRE_MSG(linkat(pathfd, "", AT_FDCWD, "test", AT_EMPTY_PATH) ==
400	    0, FMT_ERR("linkat"));
401	ATF_REQUIRE_MSG(fstatat(AT_FDCWD, "test", &sb2, 0) == 0,
402	    FMT_ERR("fstatat"));
403	ATF_REQUIRE_MSG(sb.st_dev == sb2.st_dev, "st_dev mismatch");
404	ATF_REQUIRE_MSG(sb.st_ino == sb2.st_ino, "st_ino mismatch");
405
406	CHECKED_CLOSE(pathfd);
407
408}
409ATF_TC_CLEANUP(path_empty_root, tc)
410{
411}
412
413/* poll(2) never returns an event for path fds, but kevent(2) does. */
414ATF_TC_WITHOUT_HEAD(path_event);
415ATF_TC_BODY(path_event, tc)
416{
417	char buf[BUFSIZ], path[PATH_MAX];
418	struct kevent ev;
419	struct pollfd pollfd;
420	int kq, pathfd;
421
422	mktfile(path, "path_event.XXXXXX");
423
424	pathfd = open(path, O_PATH);
425	ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open"));
426
427	/* poll(2) should return POLLNVAL. */
428	pollfd.fd = pathfd;
429	pollfd.events = POLLIN;
430	pollfd.revents = 0;
431	ATF_REQUIRE_MSG(poll(&pollfd, 1, 0) == 1, FMT_ERR("poll"));
432	ATF_REQUIRE_MSG(pollfd.revents == POLLNVAL, "unexpected revents %x",
433	    pollfd.revents);
434	pollfd.events = POLLOUT;
435	pollfd.revents = 0;
436	ATF_REQUIRE_MSG(poll(&pollfd, 1, 0) == 1, FMT_ERR("poll"));
437	ATF_REQUIRE_MSG(pollfd.revents == POLLNVAL, "unexpected revents %x",
438	    pollfd.revents);
439
440	/* Try to get a EVFILT_READ event through a path fd. */
441	kq = kqueue();
442	ATF_REQUIRE_MSG(kq >= 0, FMT_ERR("kqueue"));
443	EV_SET(&ev, pathfd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, 0);
444	ATF_REQUIRE_MSG(kevent(kq, &ev, 1, NULL, 0, NULL) == 0,
445	    FMT_ERR("kevent"));
446	ATF_REQUIRE_MSG(kevent(kq, NULL, 0, &ev, 1, NULL) == 1,
447	    FMT_ERR("kevent"));
448	ATF_REQUIRE_MSG((ev.flags & EV_ERROR) == 0, "EV_ERROR is set");
449	ATF_REQUIRE_MSG(ev.data == sizeof(buf),
450	    "data is %jd", (intmax_t)ev.data);
451	EV_SET(&ev, pathfd, EVFILT_READ, EV_DELETE, 0, 0, 0);
452	ATF_REQUIRE_MSG(kevent(kq, &ev, 1, NULL, 0, NULL) == 0,
453	    FMT_ERR("kevent"));
454
455	/* Try to get a EVFILT_VNODE/NOTE_LINK event through a path fd. */
456	EV_SET(&ev, pathfd, EVFILT_VNODE, EV_ADD | EV_ENABLE, NOTE_LINK, 0, 0);
457	ATF_REQUIRE_MSG(kevent(kq, &ev, 1, NULL, 0, NULL) == 0,
458	    FMT_ERR("kevent"));
459	ATF_REQUIRE_MSG(funlinkat(AT_FDCWD, path, pathfd, 0) == 0,
460	    FMT_ERR("funlinkat"));
461	ATF_REQUIRE_MSG(kevent(kq, NULL, 0, &ev, 1, NULL) == 1,
462	    FMT_ERR("kevent"));
463	EV_SET(&ev, pathfd, EVFILT_VNODE, EV_DELETE, 0, 0, 0);
464	ATF_REQUIRE_MSG(kevent(kq, &ev, 1, NULL, 0, NULL) == 0,
465	    FMT_ERR("kevent"));
466
467	CHECKED_CLOSE(kq);
468	CHECKED_CLOSE(pathfd);
469}
470
471/* Check various fcntl(2) operations on a path desriptor. */
472ATF_TC_WITHOUT_HEAD(path_fcntl);
473ATF_TC_BODY(path_fcntl, tc)
474{
475	char path[PATH_MAX];
476	int flags, pathfd, pathfd2;
477
478	mktfile(path, "path_fcntl.XXXXXX");
479
480	pathfd = open(path, O_PATH);
481	ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open"));
482
483	/* O_PATH should appear in the fd flags. */
484	flags = fcntl(pathfd, F_GETFL);
485	ATF_REQUIRE_MSG(flags != -1, FMT_ERR("fcntl"));
486	ATF_REQUIRE_MSG((flags & O_PATH) != 0, "O_PATH not set");
487
488	ATF_REQUIRE_ERRNO(EBADF,
489	    fcntl(pathfd, F_SETFL, flags & ~O_PATH));
490	ATF_REQUIRE_ERRNO(EBADF,
491	    fcntl(pathfd, F_SETFL, flags | O_APPEND));
492
493	/* A dup'ed O_PATH fd had better have O_PATH set too. */
494	pathfd2 = fcntl(pathfd, F_DUPFD, 0);
495	ATF_REQUIRE_MSG(pathfd2 >= 0, FMT_ERR("fcntl"));
496	flags = fcntl(pathfd2, F_GETFL);
497	ATF_REQUIRE_MSG(flags != -1, FMT_ERR("fcntl"));
498	ATF_REQUIRE_MSG((flags & O_PATH) != 0, "O_PATH not set");
499	CHECKED_CLOSE(pathfd2);
500
501	/* Double check with dup(2). */
502	pathfd2 = dup(pathfd);
503	ATF_REQUIRE_MSG(pathfd2 >= 0, FMT_ERR("dup"));
504	flags = fcntl(pathfd2, F_GETFL);
505	ATF_REQUIRE_MSG(flags != -1, FMT_ERR("fcntl"));
506	ATF_REQUIRE_MSG((flags & O_PATH) != 0, "O_PATH not set");
507	CHECKED_CLOSE(pathfd2);
508
509	/* It should be possible to set O_CLOEXEC. */
510	ATF_REQUIRE_MSG(fcntl(pathfd, F_SETFD, FD_CLOEXEC) == 0,
511	    FMT_ERR("fcntl"));
512	ATF_REQUIRE_MSG(fcntl(pathfd, F_GETFD) == FD_CLOEXEC,
513	    FMT_ERR("fcntl"));
514
515	CHECKED_CLOSE(pathfd);
516}
517
518/* Verify that we can execute a file opened with O_PATH. */
519ATF_TC_WITHOUT_HEAD(path_fexecve);
520ATF_TC_BODY(path_fexecve, tc)
521{
522	char path[PATH_MAX];
523	pid_t child;
524	int fd, pathfd;
525
526	child = fork();
527	ATF_REQUIRE_MSG(child != -1, FMT_ERR("fork"));
528	if (child == 0) {
529		pathfd = open("/usr/bin/true", O_PATH | O_EXEC);
530		if (pathfd < 0)
531			_exit(1);
532		fexecve(pathfd,
533		    (char * const[]){__DECONST(char *, "/usr/bin/true"), NULL},
534		    NULL);
535		_exit(2);
536	}
537	waitchild(child, 0);
538
539	/*
540	 * Also verify that access permissions are checked when opening with
541	 * O_PATH.
542	 */
543	snprintf(path, sizeof(path), "path_fexecve.XXXXXX");
544	ATF_REQUIRE_MSG(mktemp(path) == path, FMT_ERR("mktemp"));
545
546	fd = open(path, O_CREAT | O_RDONLY, 0600);
547	ATF_REQUIRE_MSG(fd >= 0, FMT_ERR("open"));
548
549	pathfd = open(path, O_PATH | O_EXEC);
550	ATF_REQUIRE_ERRNO(EACCES, pathfd < 0);
551}
552
553/* Make sure that O_PATH restrictions apply to named pipes as well. */
554ATF_TC_WITHOUT_HEAD(path_fifo);
555ATF_TC_BODY(path_fifo, tc)
556{
557	char path[PATH_MAX], buf[BUFSIZ];
558	struct kevent ev;
559	int kq, pathfd;
560
561	snprintf(path, sizeof(path), "path_fifo.XXXXXX");
562	ATF_REQUIRE_MSG(mktemp(path) == path, FMT_ERR("mktemp"));
563
564	ATF_REQUIRE_MSG(mkfifo(path, 0666) == 0, FMT_ERR("mkfifo"));
565
566	pathfd = open(path, O_PATH);
567	ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open"));
568	memset(buf, 0, sizeof(buf));
569	ATF_REQUIRE_ERRNO(EBADF, write(pathfd, buf, sizeof(buf)));
570	ATF_REQUIRE_ERRNO(EBADF, read(pathfd, buf, sizeof(buf)));
571
572	kq = kqueue();
573	ATF_REQUIRE_MSG(kq >= 0, FMT_ERR("kqueue"));
574	EV_SET(&ev, pathfd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, 0);
575	ATF_REQUIRE_ERRNO(EBADF, kevent(kq, &ev, 1, NULL, 0, NULL) == -1);
576
577	CHECKED_CLOSE(pathfd);
578}
579
580/* Files may be unlinked using a path fd. */
581ATF_TC_WITHOUT_HEAD(path_funlinkat);
582ATF_TC_BODY(path_funlinkat, tc)
583{
584	char path[PATH_MAX];
585	struct stat sb;
586	int pathfd;
587
588	mktfile(path, "path_rights.XXXXXX");
589
590	pathfd = open(path, O_PATH);
591	ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open"));
592
593	ATF_REQUIRE_MSG(funlinkat(AT_FDCWD, path, pathfd, 0) == 0,
594	    FMT_ERR("funlinkat"));
595	ATF_REQUIRE_ERRNO(ENOENT, stat(path, &sb) == -1);
596
597	CHECKED_CLOSE(pathfd);
598}
599
600/* Verify that various I/O operations fail on an O_PATH descriptor. */
601ATF_TC_WITHOUT_HEAD(path_io);
602ATF_TC_BODY(path_io, tc)
603{
604	char path[PATH_MAX], path2[PATH_MAX];
605	char buf[BUFSIZ];
606	struct iovec iov;
607	int error, fd, pathfd, sd[2];
608
609	/* It shouldn't be possible to create new files with O_PATH. */
610	snprintf(path, sizeof(path), "path_io.XXXXXX");
611	ATF_REQUIRE_MSG(mktemp(path) == path, FMT_ERR("mktemp"));
612	ATF_REQUIRE_ERRNO(ENOENT, open(path, O_PATH | O_CREAT, 0600) < 0);
613
614	/* Create a non-empty file for use in the rest of the tests. */
615	mktfile(path, "path_io.XXXXXX");
616
617	pathfd = open(path, O_PATH);
618	ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open"));
619
620	/* Make sure that basic I/O operations aren't possible. */
621	iov.iov_base = path;
622	iov.iov_len = strlen(path);
623	ATF_REQUIRE_ERRNO(EBADF,
624	    write(pathfd, iov.iov_base, iov.iov_len) == -1);
625	ATF_REQUIRE_ERRNO(EBADF,
626	    pwrite(pathfd, iov.iov_base, iov.iov_len, 0) == -1);
627	ATF_REQUIRE_ERRNO(EBADF,
628	    writev(pathfd, &iov, 1) == -1);
629	ATF_REQUIRE_ERRNO(EBADF,
630	    pwritev(pathfd, &iov, 1, 0) == -1);
631	ATF_REQUIRE_ERRNO(EBADF,
632	    read(pathfd, path, 1) == -1);
633	ATF_REQUIRE_ERRNO(EBADF,
634	    pread(pathfd, path, 1, 0) == -1);
635	ATF_REQUIRE_ERRNO(EBADF,
636	    readv(pathfd, &iov, 1) == -1);
637	ATF_REQUIRE_ERRNO(EBADF,
638	    preadv(pathfd, &iov, 1, 0) == -1);
639
640	/* copy_file_range() should not be permitted. */
641	mktfile(path2, "path_io.XXXXXX");
642	fd = open(path2, O_RDWR);
643	ATF_REQUIRE_ERRNO(EBADF,
644	    copy_file_range(fd, NULL, pathfd, NULL, sizeof(buf), 0) == -1);
645	ATF_REQUIRE_ERRNO(EBADF,
646	    copy_file_range(pathfd, NULL, fd, NULL, sizeof(buf), 0) == -1);
647	CHECKED_CLOSE(fd);
648
649	/* sendfile() should not be permitted. */
650	ATF_REQUIRE_MSG(socketpair(PF_LOCAL, SOCK_STREAM, 0, sd) == 0,
651	    FMT_ERR("socketpair"));
652	ATF_REQUIRE_ERRNO(EBADF,
653	    sendfile(pathfd, sd[0], 0, 0, NULL, NULL, 0));
654	CHECKED_CLOSE(sd[0]);
655	CHECKED_CLOSE(sd[1]);
656
657	/* No seeking. */
658	ATF_REQUIRE_ERRNO(ESPIPE,
659	    lseek(pathfd, 0, SEEK_SET) == -1);
660
661	/* No operations on the file extent. */
662	ATF_REQUIRE_ERRNO(EINVAL,
663	    ftruncate(pathfd, 0) == -1);
664	error = posix_fallocate(pathfd, 0, sizeof(buf) * 2);
665	ATF_REQUIRE_MSG(error == ESPIPE, "posix_fallocate() returned %d", error);
666	error = posix_fadvise(pathfd, 0, sizeof(buf), POSIX_FADV_NORMAL);
667	ATF_REQUIRE_MSG(error == ESPIPE, "posix_fadvise() returned %d", error);
668
669	/* mmap() is not allowed. */
670	ATF_REQUIRE_ERRNO(ENODEV,
671	    mmap(NULL, PAGE_SIZE, PROT_READ, MAP_SHARED, pathfd, 0) ==
672	    MAP_FAILED);
673	ATF_REQUIRE_ERRNO(ENODEV,
674	    mmap(NULL, PAGE_SIZE, PROT_NONE, MAP_SHARED, pathfd, 0) ==
675	    MAP_FAILED);
676	ATF_REQUIRE_ERRNO(ENODEV,
677	    mmap(NULL, PAGE_SIZE, PROT_READ, MAP_PRIVATE, pathfd, 0) ==
678	    MAP_FAILED);
679
680	/* No fsync() or fdatasync(). */
681	ATF_REQUIRE_ERRNO(EBADF, fsync(pathfd) == -1);
682	ATF_REQUIRE_ERRNO(EBADF, fdatasync(pathfd) == -1);
683
684	CHECKED_CLOSE(pathfd);
685}
686
687/* ioctl(2) is not permitted on path fds. */
688ATF_TC_WITHOUT_HEAD(path_ioctl);
689ATF_TC_BODY(path_ioctl, tc)
690{
691	char path[PATH_MAX];
692	struct mem_extract me;
693	int pathfd, val;
694
695	mktfile(path, "path_ioctl.XXXXXX");
696
697	/* Standard file descriptor ioctls should fail. */
698	pathfd = open(path, O_PATH);
699	ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open"));
700
701	val = 0;
702	ATF_REQUIRE_ERRNO(EBADF, ioctl(pathfd, FIONBIO, &val) == -1);
703	ATF_REQUIRE_ERRNO(EBADF, ioctl(pathfd, FIONREAD, &val) == -1);
704	ATF_REQUIRE_ERRNO(EBADF, ioctl(pathfd, FIONWRITE, &val) == -1);
705	ATF_REQUIRE_ERRNO(EBADF, ioctl(pathfd, FIONSPACE, &val) == -1);
706
707	CHECKED_CLOSE(pathfd);
708
709	/* Device ioctls should fail. */
710	pathfd = open("/dev/mem", O_PATH);
711	ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open"));
712
713	me.me_vaddr = (uintptr_t)&me;
714	ATF_REQUIRE_ERRNO(EBADF, ioctl(pathfd, MEM_EXTRACT_PADDR, &me) == -1);
715
716	CHECKED_CLOSE(pathfd);
717}
718
719ATF_TC_WITHOUT_HEAD(path_lock);
720ATF_TC_BODY(path_lock, tc)
721{
722	char buf[BUFSIZ], path[PATH_MAX];
723	struct flock flk;
724	int fd, pathfd;
725
726	snprintf(path, sizeof(path), "path_rights.XXXXXX");
727	fd = mkostemp(path, O_SHLOCK);
728	ATF_REQUIRE_MSG(fd >= 0, FMT_ERR("mkostemp"));
729	memset(buf, 0, sizeof(buf));
730	ATF_REQUIRE_MSG(write(fd, buf, sizeof(buf)) == sizeof(buf),
731	    FMT_ERR("write()"));
732
733	/* Verify that O_EXLOCK is ignored when combined with O_PATH. */
734	pathfd = open(path, O_PATH | O_EXLOCK);
735	ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open"));
736
737	CHECKED_CLOSE(fd);
738
739	/* flock(2) is prohibited. */
740	ATF_REQUIRE_ERRNO(EOPNOTSUPP, flock(pathfd, LOCK_SH) == -1);
741	ATF_REQUIRE_ERRNO(EOPNOTSUPP, flock(pathfd, LOCK_EX) == -1);
742	ATF_REQUIRE_ERRNO(EOPNOTSUPP, flock(pathfd, LOCK_SH | LOCK_NB) == -1);
743	ATF_REQUIRE_ERRNO(EOPNOTSUPP, flock(pathfd, LOCK_EX | LOCK_NB) == -1);
744	ATF_REQUIRE_ERRNO(EOPNOTSUPP, flock(pathfd, LOCK_UN) == -1);
745
746	/* fcntl(2) file locks are prohibited. */
747	memset(&flk, 0, sizeof(flk));
748	flk.l_whence = SEEK_CUR;
749	ATF_REQUIRE_ERRNO(EBADF, fcntl(pathfd, F_GETLK, &flk) == -1);
750	flk.l_type = F_RDLCK;
751	ATF_REQUIRE_ERRNO(EBADF, fcntl(pathfd, F_SETLK, &flk) == -1);
752	ATF_REQUIRE_ERRNO(EBADF, fcntl(pathfd, F_SETLKW, &flk) == -1);
753	flk.l_type = F_WRLCK;
754	ATF_REQUIRE_ERRNO(EBADF, fcntl(pathfd, F_SETLK, &flk) == -1);
755	ATF_REQUIRE_ERRNO(EBADF, fcntl(pathfd, F_SETLKW, &flk) == -1);
756
757	CHECKED_CLOSE(pathfd);
758}
759
760/* Verify that we can send an O_PATH descriptor over a unix socket. */
761ATF_TC_WITHOUT_HEAD(path_rights);
762ATF_TC_BODY(path_rights, tc)
763{
764	char path[PATH_MAX];
765	struct cmsghdr *cmsg;
766	struct msghdr msg;
767	struct iovec iov;
768	int flags, pathfd, pathfd_copy, sd[2];
769	char c;
770
771	ATF_REQUIRE_MSG(socketpair(PF_LOCAL, SOCK_STREAM, 0, sd) == 0,
772	    FMT_ERR("socketpair"));
773
774	mktfile(path, "path_rights.XXXXXX");
775
776	pathfd = open(path, O_PATH);
777	ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open"));
778
779	/* Package up the O_PATH and send it over the socket pair. */
780	cmsg = malloc(CMSG_SPACE(sizeof(pathfd)));
781	ATF_REQUIRE_MSG(cmsg != NULL, FMT_ERR("malloc"));
782
783	cmsg->cmsg_len = CMSG_LEN(sizeof(pathfd));
784	cmsg->cmsg_level = SOL_SOCKET;
785	cmsg->cmsg_type = SCM_RIGHTS;
786	*(int *)(void *)CMSG_DATA(cmsg) = pathfd;
787
788	c = 0;
789	iov.iov_base = &c;
790	iov.iov_len = 1;
791
792	memset(&msg, 0, sizeof(msg));
793	msg.msg_iov = &iov;
794	msg.msg_iovlen = 1;
795	msg.msg_control = cmsg;
796	msg.msg_controllen = CMSG_SPACE(sizeof(pathfd));
797
798	ATF_REQUIRE_MSG(sendmsg(sd[0], &msg, 0) == sizeof(c),
799	    FMT_ERR("sendmsg"));
800
801	/* Grab the pathfd copy from the other end of the pair. */
802	memset(&msg, 0, sizeof(msg));
803	msg.msg_iov = &iov;
804	msg.msg_iovlen = 1;
805	msg.msg_control = cmsg;
806	msg.msg_controllen = CMSG_SPACE(sizeof(pathfd));
807
808	ATF_REQUIRE_MSG(recvmsg(sd[1], &msg, 0) == 1,
809	    FMT_ERR("recvmsg"));
810	pathfd_copy = *(int *)(void *)CMSG_DATA(cmsg);
811	ATF_REQUIRE_MSG(pathfd_copy != pathfd,
812	    "pathfd and pathfd_copy are equal");
813
814	/* Verify that the copy has O_PATH properties. */
815	flags = fcntl(pathfd_copy, F_GETFL);
816	ATF_REQUIRE_MSG(flags != -1, FMT_ERR("fcntl"));
817	ATF_REQUIRE_MSG((flags & O_PATH) != 0, "O_PATH is not set");
818	ATF_REQUIRE_ERRNO(EBADF,
819	    read(pathfd_copy, &c, 1) == -1);
820	ATF_REQUIRE_ERRNO(EBADF,
821	    write(pathfd_copy, &c, 1) == -1);
822
823	CHECKED_CLOSE(pathfd);
824	CHECKED_CLOSE(pathfd_copy);
825	CHECKED_CLOSE(sd[0]);
826	CHECKED_CLOSE(sd[1]);
827}
828
829/* Verify that a local socket can't be opened with O_PATH. */
830ATF_TC_WITHOUT_HEAD(path_unix);
831ATF_TC_BODY(path_unix, tc)
832{
833	char path[PATH_MAX];
834	struct sockaddr_un sun;
835	int pathfd, sd;
836
837	snprintf(path, sizeof(path), "path_unix.XXXXXX");
838	ATF_REQUIRE_MSG(mktemp(path) == path, FMT_ERR("mktemp"));
839
840	sd = socket(PF_LOCAL, SOCK_STREAM, 0);
841	ATF_REQUIRE_MSG(sd >= 0, FMT_ERR("socket"));
842
843	memset(&sun, 0, sizeof(sun));
844	sun.sun_family = PF_LOCAL;
845	(void)strlcpy(sun.sun_path, path, sizeof(sun.sun_path));
846	ATF_REQUIRE_MSG(bind(sd, (struct sockaddr *)&sun, SUN_LEN(&sun)) == 0,
847	    FMT_ERR("bind"));
848
849	pathfd = open(path, O_RDONLY);
850	ATF_REQUIRE_ERRNO(EOPNOTSUPP, pathfd < 0);
851
852	CHECKED_CLOSE(sd);
853}
854
855ATF_TP_ADD_TCS(tp)
856{
857	ATF_TP_ADD_TC(tp, path_access);
858	ATF_TP_ADD_TC(tp, path_aio);
859	ATF_TP_ADD_TC(tp, path_capsicum);
860	ATF_TP_ADD_TC(tp, path_coredump);
861	ATF_TP_ADD_TC(tp, path_directory);
862	ATF_TP_ADD_TC(tp, path_directory_not_root);
863	ATF_TP_ADD_TC(tp, path_empty);
864	ATF_TP_ADD_TC(tp, path_empty_not_root);
865	ATF_TP_ADD_TC(tp, path_empty_root);
866	ATF_TP_ADD_TC(tp, path_event);
867	ATF_TP_ADD_TC(tp, path_fcntl);
868	ATF_TP_ADD_TC(tp, path_fexecve);
869	ATF_TP_ADD_TC(tp, path_fifo);
870	ATF_TP_ADD_TC(tp, path_funlinkat);
871	ATF_TP_ADD_TC(tp, path_io);
872	ATF_TP_ADD_TC(tp, path_ioctl);
873	ATF_TP_ADD_TC(tp, path_lock);
874	ATF_TP_ADD_TC(tp, path_rights);
875	ATF_TP_ADD_TC(tp, path_unix);
876
877	return (atf_no_error());
878}
879