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