1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
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. */
67 static void
mktfile(char path[PATH_MAX],const char * template)68 mktfile(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. */
83 static void
mktdir(char path[PATH_MAX],const char * template)84 mktdir(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. */
91 static void
waitchild(pid_t child,int exstatus)92 waitchild(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
105 ATF_TC_WITHOUT_HEAD(path_access);
ATF_TC_BODY(path_access,tc)106 ATF_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. */
136 ATF_TC_WITHOUT_HEAD(path_aio);
ATF_TC_BODY(path_aio,tc)137 ATF_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. */
163 ATF_TC_WITHOUT_HEAD(path_capsicum);
ATF_TC_BODY(path_capsicum,tc)164 ATF_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 /*
212 * Check that a pathfd can be converted to a regular fd using openat() in
213 * capability mode, but that rights on the pathfd are respected.
214 */
215 ATF_TC_WITHOUT_HEAD(path_capsicum_empty);
ATF_TC_BODY(path_capsicum_empty,tc)216 ATF_TC_BODY(path_capsicum_empty, tc)
217 {
218 char path[PATH_MAX];
219 cap_rights_t rights;
220 int dfd, fd, pathfd, pathdfd;
221
222 mktfile(path, "path_capsicum.XXXXXX");
223
224 pathdfd = open(".", O_PATH);
225 ATF_REQUIRE_MSG(pathdfd >= 0, FMT_ERR("open"));
226 pathfd = open(path, O_PATH);
227 ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open"));
228
229 ATF_REQUIRE(cap_enter() == 0);
230
231 dfd = openat(pathdfd, "", O_DIRECTORY | O_EMPTY_PATH);
232 ATF_REQUIRE(dfd >= 0);
233 CHECKED_CLOSE(dfd);
234
235 /*
236 * CAP_READ and CAP_LOOKUP should be sufficient to open a directory.
237 */
238 cap_rights_init(&rights, CAP_READ, CAP_LOOKUP);
239 ATF_REQUIRE(cap_rights_limit(pathdfd, &rights) == 0);
240 dfd = openat(pathdfd, "", O_DIRECTORY | O_EMPTY_PATH);
241 ATF_REQUIRE(dfd >= 0);
242 CHECKED_CLOSE(dfd);
243
244 /*
245 * ... CAP_READ on its own is not.
246 */
247 cap_rights_init(&rights, CAP_READ);
248 ATF_REQUIRE(cap_rights_limit(pathdfd, &rights) == 0);
249 dfd = openat(pathdfd, "", O_DIRECTORY | O_EMPTY_PATH);
250 ATF_REQUIRE_ERRNO(ENOTCAPABLE, dfd == -1);
251
252 /*
253 * Now try with a regular file.
254 */
255 fd = openat(pathfd, "", O_RDWR | O_EMPTY_PATH);
256 ATF_REQUIRE(fd >= 0);
257 CHECKED_CLOSE(fd);
258
259 cap_rights_init(&rights, CAP_READ, CAP_LOOKUP, CAP_WRITE);
260 ATF_REQUIRE(cap_rights_limit(pathfd, &rights) == 0);
261 fd = openat(pathfd, "", O_RDWR | O_EMPTY_PATH | O_APPEND);
262 ATF_REQUIRE(fd >= 0);
263 CHECKED_CLOSE(fd);
264
265 /*
266 * CAP_SEEK is needed to open a file for writing without O_APPEND.
267 */
268 cap_rights_init(&rights, CAP_READ, CAP_LOOKUP, CAP_WRITE);
269 ATF_REQUIRE(cap_rights_limit(pathfd, &rights) == 0);
270 fd = openat(pathfd, "", O_RDWR | O_EMPTY_PATH);
271 ATF_REQUIRE_ERRNO(ENOTCAPABLE, fd == -1);
272
273 /*
274 * CAP_LOOKUP isn't sufficient to open a file for reading.
275 */
276 cap_rights_init(&rights, CAP_LOOKUP);
277 ATF_REQUIRE(cap_rights_limit(pathfd, &rights) == 0);
278 fd = openat(pathfd, "", O_RDONLY | O_EMPTY_PATH);
279 ATF_REQUIRE_ERRNO(ENOTCAPABLE, fd == -1);
280
281 CHECKED_CLOSE(pathfd);
282 CHECKED_CLOSE(pathdfd);
283 }
284
285 /* Make sure that ptrace(PT_COREDUMP) cannot be used to write to a path fd. */
286 ATF_TC_WITHOUT_HEAD(path_coredump);
ATF_TC_BODY(path_coredump,tc)287 ATF_TC_BODY(path_coredump, tc)
288 {
289 char path[PATH_MAX];
290 struct ptrace_coredump pc;
291 int error, pathfd, status;
292 pid_t child;
293
294 mktdir(path, "path_coredump.XXXXXX");
295
296 child = fork();
297 ATF_REQUIRE_MSG(child != -1, FMT_ERR("fork"));
298 if (child == 0) {
299 while (true)
300 (void)sleep(1);
301 }
302
303 pathfd = open(path, O_PATH);
304 ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open"));
305
306 error = ptrace(PT_ATTACH, child, 0, 0);
307 ATF_REQUIRE_MSG(error == 0, FMT_ERR("ptrace"));
308 error = waitpid(child, &status, 0);
309 ATF_REQUIRE_MSG(error != -1, FMT_ERR("waitpid"));
310 ATF_REQUIRE_MSG(WIFSTOPPED(status), "unexpected status %d", status);
311
312 pc.pc_fd = pathfd;
313 pc.pc_flags = 0;
314 pc.pc_limit = 0;
315 error = ptrace(PT_COREDUMP, child, (void *)&pc, sizeof(pc));
316 ATF_REQUIRE_ERRNO(EBADF, error == -1);
317
318 error = ptrace(PT_DETACH, child, 0, 0);
319 ATF_REQUIRE_MSG(error == 0, FMT_ERR("ptrace"));
320
321 ATF_REQUIRE_MSG(kill(child, SIGKILL) == 0, FMT_ERR("kill"));
322
323 CHECKED_CLOSE(pathfd);
324 }
325
326 /* Verify operations on directory path descriptors. */
327 ATF_TC_WITHOUT_HEAD(path_directory);
ATF_TC_BODY(path_directory,tc)328 ATF_TC_BODY(path_directory, tc)
329 {
330 struct dirent de;
331 struct stat sb;
332 char path[PATH_MAX];
333 int fd, pathfd;
334
335 mktdir(path, "path_directory.XXXXXX");
336
337 pathfd = open(path, O_PATH | O_DIRECTORY);
338 ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open"));
339
340 /* Should not be possible to list directory entries. */
341 ATF_REQUIRE_ERRNO(EBADF,
342 getdirentries(pathfd, (char *)&de, sizeof(de), NULL) == -1);
343
344 /* It should be possible to create files under pathfd. */
345 fd = openat(pathfd, "test", O_RDWR | O_CREAT, 0600);
346 ATF_REQUIRE_MSG(fd >= 0, FMT_ERR("open"));
347 ATF_REQUIRE_MSG(fstatat(pathfd, "test", &sb, 0) == 0,
348 FMT_ERR("fstatat"));
349 CHECKED_CLOSE(fd);
350
351 /* ... but doing so requires write access. */
352 if (geteuid() != 0) {
353 ATF_REQUIRE_ERRNO(EBADF, fchmod(pathfd, 0500) == -1);
354 ATF_REQUIRE_MSG(chmod(path, 0500) == 0, FMT_ERR("chmod"));
355 ATF_REQUIRE_ERRNO(EACCES,
356 openat(pathfd, "test2", O_RDWR | O_CREAT, 0600) < 0);
357 }
358
359 /* fchdir(2) is permitted. */
360 ATF_REQUIRE_MSG(fchdir(pathfd) == 0, FMT_ERR("fchdir"));
361
362 CHECKED_CLOSE(pathfd);
363 }
364
365 /* Verify access permission checking for a directory path fd. */
366 ATF_TC_WITH_CLEANUP(path_directory_not_root);
ATF_TC_HEAD(path_directory_not_root,tc)367 ATF_TC_HEAD(path_directory_not_root, tc)
368 {
369 atf_tc_set_md_var(tc, "require.user", "unprivileged");
370 }
ATF_TC_BODY(path_directory_not_root,tc)371 ATF_TC_BODY(path_directory_not_root, tc)
372 {
373 char path[PATH_MAX];
374 int pathfd;
375
376 mktdir(path, "path_directory.XXXXXX");
377
378 pathfd = open(path, O_PATH | O_DIRECTORY);
379 ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open"));
380
381 ATF_REQUIRE_ERRNO(EBADF, fchmod(pathfd, 0500) == -1);
382 ATF_REQUIRE_MSG(chmod(path, 0500) == 0, FMT_ERR("chmod"));
383 ATF_REQUIRE_ERRNO(EACCES,
384 openat(pathfd, "test2", O_RDWR | O_CREAT, 0600) < 0);
385
386 CHECKED_CLOSE(pathfd);
387 }
ATF_TC_CLEANUP(path_directory_not_root,tc)388 ATF_TC_CLEANUP(path_directory_not_root, tc)
389 {
390 }
391
392 /* Validate system calls that handle AT_EMPTY_PATH. */
393 ATF_TC_WITHOUT_HEAD(path_empty);
ATF_TC_BODY(path_empty,tc)394 ATF_TC_BODY(path_empty, tc)
395 {
396 char path[PATH_MAX];
397 struct timespec ts[2];
398 struct stat sb;
399 int pathfd;
400
401 mktfile(path, "path_empty.XXXXXX");
402
403 pathfd = open(path, O_PATH);
404 ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open"));
405
406 /* Various *at operations should work on path fds. */
407 ATF_REQUIRE_MSG(faccessat(pathfd, "", F_OK, AT_EMPTY_PATH) == 0,
408 FMT_ERR("faccessat"));
409 ATF_REQUIRE_MSG(chflagsat(pathfd, "", UF_NODUMP, AT_EMPTY_PATH) == 0,
410 FMT_ERR("chflagsat"));
411 ATF_REQUIRE_MSG(fchmodat(pathfd, "", 0600, AT_EMPTY_PATH) == 0,
412 FMT_ERR("fchmodat"));
413 ATF_REQUIRE_MSG(fchownat(pathfd, "", getuid(), getgid(),
414 AT_EMPTY_PATH) == 0, FMT_ERR("fchownat"));
415 ATF_REQUIRE_MSG(fstatat(pathfd, "", &sb, AT_EMPTY_PATH) == 0,
416 FMT_ERR("fstatat"));
417 ATF_REQUIRE_MSG(sb.st_size == BUFSIZ,
418 "unexpected size %ju", (uintmax_t)sb.st_size);
419 memset(ts, 0, sizeof(ts));
420 ATF_REQUIRE_MSG(utimensat(pathfd, "", ts, AT_EMPTY_PATH) == 0,
421 FMT_ERR("utimensat"));
422
423 CHECKED_CLOSE(pathfd);
424 }
425
426 /* Verify that various operations on a path fd have access checks. */
427 ATF_TC_WITH_CLEANUP(path_empty_not_root);
ATF_TC_HEAD(path_empty_not_root,tc)428 ATF_TC_HEAD(path_empty_not_root, tc)
429 {
430 atf_tc_set_md_var(tc, "require.user", "unprivileged");
431 }
ATF_TC_BODY(path_empty_not_root,tc)432 ATF_TC_BODY(path_empty_not_root, tc)
433 {
434 int pathfd;
435
436 pathfd = open("/dev/null", O_PATH);
437 ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open"));
438
439 ATF_REQUIRE_ERRNO(EPERM,
440 chflagsat(pathfd, "", UF_NODUMP, AT_EMPTY_PATH) == -1);
441 ATF_REQUIRE_ERRNO(EPERM,
442 fchownat(pathfd, "", getuid(), getgid(), AT_EMPTY_PATH) == -1);
443 ATF_REQUIRE_ERRNO(EPERM,
444 fchmodat(pathfd, "", 0600, AT_EMPTY_PATH) == -1);
445 ATF_REQUIRE_ERRNO(EPERM,
446 linkat(pathfd, "", AT_FDCWD, "test", AT_EMPTY_PATH) == -1);
447
448 CHECKED_CLOSE(pathfd);
449 }
ATF_TC_CLEANUP(path_empty_not_root,tc)450 ATF_TC_CLEANUP(path_empty_not_root, tc)
451 {
452 }
453
454 /* Test linkat(2) with AT_EMPTY_PATH, which requires privileges. */
455 ATF_TC_WITH_CLEANUP(path_empty_root);
ATF_TC_HEAD(path_empty_root,tc)456 ATF_TC_HEAD(path_empty_root, tc)
457 {
458 atf_tc_set_md_var(tc, "require.user", "root");
459 }
ATF_TC_BODY(path_empty_root,tc)460 ATF_TC_BODY(path_empty_root, tc)
461 {
462 char path[PATH_MAX];
463 struct stat sb, sb2;
464 int pathfd;
465
466 mktfile(path, "path_empty_root.XXXXXX");
467
468 pathfd = open(path, O_PATH);
469 ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open"));
470 ATF_REQUIRE_MSG(fstatat(pathfd, "", &sb, AT_EMPTY_PATH) == 0,
471 FMT_ERR("fstatat"));
472
473 ATF_REQUIRE_MSG(linkat(pathfd, "", AT_FDCWD, "test", AT_EMPTY_PATH) ==
474 0, FMT_ERR("linkat"));
475 ATF_REQUIRE_MSG(fstatat(AT_FDCWD, "test", &sb2, 0) == 0,
476 FMT_ERR("fstatat"));
477 ATF_REQUIRE_MSG(sb.st_dev == sb2.st_dev, "st_dev mismatch");
478 ATF_REQUIRE_MSG(sb.st_ino == sb2.st_ino, "st_ino mismatch");
479
480 CHECKED_CLOSE(pathfd);
481
482 }
ATF_TC_CLEANUP(path_empty_root,tc)483 ATF_TC_CLEANUP(path_empty_root, tc)
484 {
485 }
486
487 /* poll(2) never returns an event for path fds, but kevent(2) does. */
488 ATF_TC_WITHOUT_HEAD(path_event);
ATF_TC_BODY(path_event,tc)489 ATF_TC_BODY(path_event, tc)
490 {
491 char buf[BUFSIZ], path[PATH_MAX];
492 struct kevent ev;
493 struct pollfd pollfd;
494 int kq, pathfd;
495
496 mktfile(path, "path_event.XXXXXX");
497
498 pathfd = open(path, O_PATH);
499 ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open"));
500
501 /* poll(2) should return POLLNVAL. */
502 pollfd.fd = pathfd;
503 pollfd.events = POLLIN;
504 pollfd.revents = 0;
505 ATF_REQUIRE_MSG(poll(&pollfd, 1, 0) == 1, FMT_ERR("poll"));
506 ATF_REQUIRE_MSG(pollfd.revents == POLLNVAL, "unexpected revents %x",
507 pollfd.revents);
508 pollfd.events = POLLOUT;
509 pollfd.revents = 0;
510 ATF_REQUIRE_MSG(poll(&pollfd, 1, 0) == 1, FMT_ERR("poll"));
511 ATF_REQUIRE_MSG(pollfd.revents == POLLNVAL, "unexpected revents %x",
512 pollfd.revents);
513
514 /* Try to get a EVFILT_READ event through a path fd. */
515 kq = kqueue();
516 ATF_REQUIRE_MSG(kq >= 0, FMT_ERR("kqueue"));
517 EV_SET(&ev, pathfd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, 0);
518 ATF_REQUIRE_MSG(kevent(kq, &ev, 1, NULL, 0, NULL) == 0,
519 FMT_ERR("kevent"));
520 ATF_REQUIRE_MSG(kevent(kq, NULL, 0, &ev, 1, NULL) == 1,
521 FMT_ERR("kevent"));
522 ATF_REQUIRE_MSG((ev.flags & EV_ERROR) == 0, "EV_ERROR is set");
523 ATF_REQUIRE_MSG(ev.data == sizeof(buf),
524 "data is %jd", (intmax_t)ev.data);
525 EV_SET(&ev, pathfd, EVFILT_READ, EV_DELETE, 0, 0, 0);
526 ATF_REQUIRE_MSG(kevent(kq, &ev, 1, NULL, 0, NULL) == 0,
527 FMT_ERR("kevent"));
528
529 /* Try to get a EVFILT_VNODE/NOTE_DELETE event through a path fd. */
530 EV_SET(&ev, pathfd, EVFILT_VNODE, EV_ADD | EV_ENABLE, NOTE_DELETE, 0,
531 0);
532 ATF_REQUIRE_MSG(kevent(kq, &ev, 1, NULL, 0, NULL) == 0,
533 FMT_ERR("kevent"));
534 ATF_REQUIRE_MSG(funlinkat(AT_FDCWD, path, pathfd, 0) == 0,
535 FMT_ERR("funlinkat"));
536 ATF_REQUIRE_MSG(kevent(kq, NULL, 0, &ev, 1, NULL) == 1,
537 FMT_ERR("kevent"));
538 ATF_REQUIRE_MSG(ev.fflags == NOTE_DELETE,
539 "unexpected fflags %#x", ev.fflags);
540 EV_SET(&ev, pathfd, EVFILT_VNODE, EV_DELETE, 0, 0, 0);
541 ATF_REQUIRE_MSG(kevent(kq, &ev, 1, NULL, 0, NULL) == 0,
542 FMT_ERR("kevent"));
543
544 CHECKED_CLOSE(kq);
545 CHECKED_CLOSE(pathfd);
546 }
547
548 /* Check various fcntl(2) operations on a path desriptor. */
549 ATF_TC_WITHOUT_HEAD(path_fcntl);
ATF_TC_BODY(path_fcntl,tc)550 ATF_TC_BODY(path_fcntl, tc)
551 {
552 char path[PATH_MAX];
553 int flags, pathfd, pathfd2;
554
555 mktfile(path, "path_fcntl.XXXXXX");
556
557 pathfd = open(path, O_PATH);
558 ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open"));
559
560 /* O_PATH should appear in the fd flags. */
561 flags = fcntl(pathfd, F_GETFL);
562 ATF_REQUIRE_MSG(flags != -1, FMT_ERR("fcntl"));
563 ATF_REQUIRE_MSG((flags & O_PATH) != 0, "O_PATH not set");
564
565 ATF_REQUIRE_ERRNO(EBADF,
566 fcntl(pathfd, F_SETFL, flags & ~O_PATH));
567 ATF_REQUIRE_ERRNO(EBADF,
568 fcntl(pathfd, F_SETFL, flags | O_APPEND));
569
570 /* A dup'ed O_PATH fd had better have O_PATH set too. */
571 pathfd2 = fcntl(pathfd, F_DUPFD, 0);
572 ATF_REQUIRE_MSG(pathfd2 >= 0, FMT_ERR("fcntl"));
573 flags = fcntl(pathfd2, F_GETFL);
574 ATF_REQUIRE_MSG(flags != -1, FMT_ERR("fcntl"));
575 ATF_REQUIRE_MSG((flags & O_PATH) != 0, "O_PATH not set");
576 CHECKED_CLOSE(pathfd2);
577
578 /* Double check with dup(2). */
579 pathfd2 = dup(pathfd);
580 ATF_REQUIRE_MSG(pathfd2 >= 0, FMT_ERR("dup"));
581 flags = fcntl(pathfd2, F_GETFL);
582 ATF_REQUIRE_MSG(flags != -1, FMT_ERR("fcntl"));
583 ATF_REQUIRE_MSG((flags & O_PATH) != 0, "O_PATH not set");
584 CHECKED_CLOSE(pathfd2);
585
586 /* It should be possible to set O_CLOEXEC. */
587 ATF_REQUIRE_MSG(fcntl(pathfd, F_SETFD, FD_CLOEXEC) == 0,
588 FMT_ERR("fcntl"));
589 ATF_REQUIRE_MSG(fcntl(pathfd, F_GETFD) == FD_CLOEXEC,
590 FMT_ERR("fcntl"));
591
592 CHECKED_CLOSE(pathfd);
593 }
594
595 /* Verify that we can execute a file opened with O_PATH. */
596 ATF_TC_WITHOUT_HEAD(path_fexecve);
ATF_TC_BODY(path_fexecve,tc)597 ATF_TC_BODY(path_fexecve, tc)
598 {
599 char path[PATH_MAX];
600 pid_t child;
601 int fd, pathfd;
602
603 child = fork();
604 ATF_REQUIRE_MSG(child != -1, FMT_ERR("fork"));
605 if (child == 0) {
606 pathfd = open("/usr/bin/true", O_PATH | O_EXEC);
607 if (pathfd < 0)
608 _exit(1);
609 fexecve(pathfd,
610 (char * const[]){__DECONST(char *, "/usr/bin/true"), NULL},
611 NULL);
612 _exit(2);
613 }
614 waitchild(child, 0);
615
616 /*
617 * Also verify that access permissions are checked when opening with
618 * O_PATH.
619 */
620 snprintf(path, sizeof(path), "path_fexecve.XXXXXX");
621 ATF_REQUIRE_MSG(mktemp(path) == path, FMT_ERR("mktemp"));
622
623 fd = open(path, O_CREAT | O_RDONLY, 0600);
624 ATF_REQUIRE_MSG(fd >= 0, FMT_ERR("open"));
625
626 pathfd = open(path, O_PATH | O_EXEC);
627 ATF_REQUIRE_ERRNO(EACCES, pathfd < 0);
628 }
629
630 /* Make sure that O_PATH restrictions apply to named pipes as well. */
631 ATF_TC_WITHOUT_HEAD(path_fifo);
ATF_TC_BODY(path_fifo,tc)632 ATF_TC_BODY(path_fifo, tc)
633 {
634 char path[PATH_MAX], buf[BUFSIZ];
635 struct kevent ev;
636 int kq, pathfd;
637
638 snprintf(path, sizeof(path), "path_fifo.XXXXXX");
639 ATF_REQUIRE_MSG(mktemp(path) == path, FMT_ERR("mktemp"));
640
641 ATF_REQUIRE_MSG(mkfifo(path, 0666) == 0, FMT_ERR("mkfifo"));
642
643 pathfd = open(path, O_PATH);
644 ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open"));
645 memset(buf, 0, sizeof(buf));
646 ATF_REQUIRE_ERRNO(EBADF, write(pathfd, buf, sizeof(buf)));
647 ATF_REQUIRE_ERRNO(EBADF, read(pathfd, buf, sizeof(buf)));
648
649 kq = kqueue();
650 ATF_REQUIRE_MSG(kq >= 0, FMT_ERR("kqueue"));
651 EV_SET(&ev, pathfd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, 0);
652 ATF_REQUIRE_ERRNO(EBADF, kevent(kq, &ev, 1, NULL, 0, NULL) == -1);
653
654 CHECKED_CLOSE(pathfd);
655 }
656
657 /* Files may be unlinked using a path fd. */
658 ATF_TC_WITHOUT_HEAD(path_funlinkat);
ATF_TC_BODY(path_funlinkat,tc)659 ATF_TC_BODY(path_funlinkat, tc)
660 {
661 char path[PATH_MAX];
662 struct stat sb;
663 int pathfd;
664
665 mktfile(path, "path_rights.XXXXXX");
666
667 pathfd = open(path, O_PATH);
668 ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open"));
669
670 ATF_REQUIRE_MSG(funlinkat(AT_FDCWD, path, pathfd, 0) == 0,
671 FMT_ERR("funlinkat"));
672 ATF_REQUIRE_ERRNO(ENOENT, stat(path, &sb) == -1);
673
674 CHECKED_CLOSE(pathfd);
675 }
676
677 /* Verify that various I/O operations fail on an O_PATH descriptor. */
678 ATF_TC_WITHOUT_HEAD(path_io);
ATF_TC_BODY(path_io,tc)679 ATF_TC_BODY(path_io, tc)
680 {
681 char path[PATH_MAX], path2[PATH_MAX];
682 char buf[BUFSIZ];
683 struct iovec iov;
684 size_t page_size;
685 int error, fd, pathfd, sd[2];
686
687 /* It is allowed to create new files with O_PATH. */
688 snprintf(path, sizeof(path), "path_io.XXXXXX");
689 ATF_REQUIRE_MSG(mktemp(path) == path, FMT_ERR("mktemp"));
690 pathfd = open(path, O_PATH | O_CREAT, 0600);
691 ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open(O_PATH|O_CREAT)"));
692 /* Ensure that this is indeed O_PATH fd */
693 ATF_REQUIRE_ERRNO(EBADF, write(pathfd, path, strlen(path)) == -1);
694 CHECKED_CLOSE(pathfd);
695
696 /* Create a non-empty file for use in the rest of the tests. */
697 mktfile(path, "path_io.XXXXXX");
698
699 pathfd = open(path, O_PATH);
700 ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open"));
701
702 /* Make sure that basic I/O operations aren't possible. */
703 iov.iov_base = path;
704 iov.iov_len = strlen(path);
705 ATF_REQUIRE_ERRNO(EBADF,
706 write(pathfd, iov.iov_base, iov.iov_len) == -1);
707 ATF_REQUIRE_ERRNO(EBADF,
708 pwrite(pathfd, iov.iov_base, iov.iov_len, 0) == -1);
709 ATF_REQUIRE_ERRNO(EBADF,
710 writev(pathfd, &iov, 1) == -1);
711 ATF_REQUIRE_ERRNO(EBADF,
712 pwritev(pathfd, &iov, 1, 0) == -1);
713 ATF_REQUIRE_ERRNO(EBADF,
714 read(pathfd, path, 1) == -1);
715 ATF_REQUIRE_ERRNO(EBADF,
716 pread(pathfd, path, 1, 0) == -1);
717 ATF_REQUIRE_ERRNO(EBADF,
718 readv(pathfd, &iov, 1) == -1);
719 ATF_REQUIRE_ERRNO(EBADF,
720 preadv(pathfd, &iov, 1, 0) == -1);
721
722 /* copy_file_range() should not be permitted. */
723 mktfile(path2, "path_io.XXXXXX");
724 fd = open(path2, O_RDWR);
725 ATF_REQUIRE_ERRNO(EBADF,
726 copy_file_range(fd, NULL, pathfd, NULL, sizeof(buf), 0) == -1);
727 ATF_REQUIRE_ERRNO(EBADF,
728 copy_file_range(pathfd, NULL, fd, NULL, sizeof(buf), 0) == -1);
729 CHECKED_CLOSE(fd);
730
731 /* sendfile() should not be permitted. */
732 ATF_REQUIRE_MSG(socketpair(PF_LOCAL, SOCK_STREAM, 0, sd) == 0,
733 FMT_ERR("socketpair"));
734 ATF_REQUIRE_ERRNO(EBADF,
735 sendfile(pathfd, sd[0], 0, 0, NULL, NULL, 0));
736 CHECKED_CLOSE(sd[0]);
737 CHECKED_CLOSE(sd[1]);
738
739 /* No seeking. */
740 ATF_REQUIRE_ERRNO(ESPIPE,
741 lseek(pathfd, 0, SEEK_SET) == -1);
742
743 /* No operations on the file extent. */
744 ATF_REQUIRE_ERRNO(EINVAL,
745 ftruncate(pathfd, 0) == -1);
746 error = posix_fallocate(pathfd, 0, sizeof(buf) * 2);
747 ATF_REQUIRE_MSG(error == ESPIPE, "posix_fallocate() returned %d", error);
748 error = posix_fadvise(pathfd, 0, sizeof(buf), POSIX_FADV_NORMAL);
749 ATF_REQUIRE_MSG(error == ESPIPE, "posix_fadvise() returned %d", error);
750
751 /* mmap() is not allowed. */
752 page_size = getpagesize();
753 ATF_REQUIRE_ERRNO(ENODEV,
754 mmap(NULL, page_size, PROT_READ, MAP_SHARED, pathfd, 0) ==
755 MAP_FAILED);
756 ATF_REQUIRE_ERRNO(ENODEV,
757 mmap(NULL, page_size, PROT_NONE, MAP_SHARED, pathfd, 0) ==
758 MAP_FAILED);
759 ATF_REQUIRE_ERRNO(ENODEV,
760 mmap(NULL, page_size, PROT_READ, MAP_PRIVATE, pathfd, 0) ==
761 MAP_FAILED);
762
763 /* No fsync() or fdatasync(). */
764 ATF_REQUIRE_ERRNO(EBADF, fsync(pathfd) == -1);
765 ATF_REQUIRE_ERRNO(EBADF, fdatasync(pathfd) == -1);
766
767 CHECKED_CLOSE(pathfd);
768 }
769
770 /* ioctl(2) is not permitted on path fds. */
771 ATF_TC_WITHOUT_HEAD(path_ioctl);
ATF_TC_BODY(path_ioctl,tc)772 ATF_TC_BODY(path_ioctl, tc)
773 {
774 char path[PATH_MAX];
775 struct mem_extract me;
776 int pathfd, val;
777
778 mktfile(path, "path_ioctl.XXXXXX");
779
780 /* Standard file descriptor ioctls should fail. */
781 pathfd = open(path, O_PATH);
782 ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open"));
783
784 val = 0;
785 ATF_REQUIRE_ERRNO(EBADF, ioctl(pathfd, FIONBIO, &val) == -1);
786 ATF_REQUIRE_ERRNO(EBADF, ioctl(pathfd, FIONREAD, &val) == -1);
787 ATF_REQUIRE_ERRNO(EBADF, ioctl(pathfd, FIONWRITE, &val) == -1);
788 ATF_REQUIRE_ERRNO(EBADF, ioctl(pathfd, FIONSPACE, &val) == -1);
789
790 CHECKED_CLOSE(pathfd);
791
792 /* Device ioctls should fail. */
793 pathfd = open("/dev/mem", O_PATH);
794 ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open"));
795
796 me.me_vaddr = (uintptr_t)&me;
797 ATF_REQUIRE_ERRNO(EBADF, ioctl(pathfd, MEM_EXTRACT_PADDR, &me) == -1);
798
799 CHECKED_CLOSE(pathfd);
800 }
801
802 ATF_TC_WITHOUT_HEAD(path_lock);
ATF_TC_BODY(path_lock,tc)803 ATF_TC_BODY(path_lock, tc)
804 {
805 char buf[BUFSIZ], path[PATH_MAX];
806 struct flock flk;
807 int fd, pathfd;
808
809 snprintf(path, sizeof(path), "path_rights.XXXXXX");
810 fd = mkostemp(path, O_SHLOCK);
811 ATF_REQUIRE_MSG(fd >= 0, FMT_ERR("mkostemp"));
812 memset(buf, 0, sizeof(buf));
813 ATF_REQUIRE_MSG(write(fd, buf, sizeof(buf)) == sizeof(buf),
814 FMT_ERR("write()"));
815
816 /* Verify that O_EXLOCK is ignored when combined with O_PATH. */
817 pathfd = open(path, O_PATH | O_EXLOCK);
818 ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open"));
819
820 CHECKED_CLOSE(fd);
821
822 /* flock(2) is prohibited. */
823 ATF_REQUIRE_ERRNO(EOPNOTSUPP, flock(pathfd, LOCK_SH) == -1);
824 ATF_REQUIRE_ERRNO(EOPNOTSUPP, flock(pathfd, LOCK_EX) == -1);
825 ATF_REQUIRE_ERRNO(EOPNOTSUPP, flock(pathfd, LOCK_SH | LOCK_NB) == -1);
826 ATF_REQUIRE_ERRNO(EOPNOTSUPP, flock(pathfd, LOCK_EX | LOCK_NB) == -1);
827 ATF_REQUIRE_ERRNO(EOPNOTSUPP, flock(pathfd, LOCK_UN) == -1);
828
829 /* fcntl(2) file locks are prohibited. */
830 memset(&flk, 0, sizeof(flk));
831 flk.l_whence = SEEK_CUR;
832 ATF_REQUIRE_ERRNO(EBADF, fcntl(pathfd, F_GETLK, &flk) == -1);
833 flk.l_type = F_RDLCK;
834 ATF_REQUIRE_ERRNO(EBADF, fcntl(pathfd, F_SETLK, &flk) == -1);
835 ATF_REQUIRE_ERRNO(EBADF, fcntl(pathfd, F_SETLKW, &flk) == -1);
836 flk.l_type = F_WRLCK;
837 ATF_REQUIRE_ERRNO(EBADF, fcntl(pathfd, F_SETLK, &flk) == -1);
838 ATF_REQUIRE_ERRNO(EBADF, fcntl(pathfd, F_SETLKW, &flk) == -1);
839
840 CHECKED_CLOSE(pathfd);
841 }
842
843 /*
844 * Verify fstatat(AT_EMPTY_PATH) on non-regular dirfd.
845 * Verify that fstatat(AT_EMPTY_PATH) on NULL path returns EFAULT.
846 */
847 ATF_TC_WITHOUT_HEAD(path_pipe_fstatat);
ATF_TC_BODY(path_pipe_fstatat,tc)848 ATF_TC_BODY(path_pipe_fstatat, tc)
849 {
850 struct stat sb;
851 int fd[2];
852
853 ATF_REQUIRE_MSG(pipe(fd) == 0, FMT_ERR("pipe"));
854 ATF_REQUIRE_MSG(fstatat(fd[0], "", &sb, AT_EMPTY_PATH) == 0,
855 FMT_ERR("fstatat pipe"));
856 ATF_REQUIRE_ERRNO(EFAULT, fstatat(fd[0], NULL, &sb,
857 AT_EMPTY_PATH) == -1);
858 CHECKED_CLOSE(fd[0]);
859 CHECKED_CLOSE(fd[1]);
860 }
861
862 /* Verify that we can send an O_PATH descriptor over a unix socket. */
863 ATF_TC_WITHOUT_HEAD(path_rights);
ATF_TC_BODY(path_rights,tc)864 ATF_TC_BODY(path_rights, tc)
865 {
866 char path[PATH_MAX];
867 struct cmsghdr *cmsg;
868 struct msghdr msg;
869 struct iovec iov;
870 int flags, pathfd, pathfd_copy, sd[2];
871 char c;
872
873 ATF_REQUIRE_MSG(socketpair(PF_LOCAL, SOCK_STREAM, 0, sd) == 0,
874 FMT_ERR("socketpair"));
875
876 mktfile(path, "path_rights.XXXXXX");
877
878 pathfd = open(path, O_PATH);
879 ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open"));
880
881 /* Package up the O_PATH and send it over the socket pair. */
882 cmsg = malloc(CMSG_SPACE(sizeof(pathfd)));
883 ATF_REQUIRE_MSG(cmsg != NULL, FMT_ERR("malloc"));
884
885 cmsg->cmsg_len = CMSG_LEN(sizeof(pathfd));
886 cmsg->cmsg_level = SOL_SOCKET;
887 cmsg->cmsg_type = SCM_RIGHTS;
888 *(int *)(void *)CMSG_DATA(cmsg) = pathfd;
889
890 c = 0;
891 iov.iov_base = &c;
892 iov.iov_len = 1;
893
894 memset(&msg, 0, sizeof(msg));
895 msg.msg_iov = &iov;
896 msg.msg_iovlen = 1;
897 msg.msg_control = cmsg;
898 msg.msg_controllen = CMSG_SPACE(sizeof(pathfd));
899
900 ATF_REQUIRE_MSG(sendmsg(sd[0], &msg, 0) == sizeof(c),
901 FMT_ERR("sendmsg"));
902
903 /* Grab the pathfd copy from the other end of the pair. */
904 memset(&msg, 0, sizeof(msg));
905 msg.msg_iov = &iov;
906 msg.msg_iovlen = 1;
907 msg.msg_control = cmsg;
908 msg.msg_controllen = CMSG_SPACE(sizeof(pathfd));
909
910 ATF_REQUIRE_MSG(recvmsg(sd[1], &msg, 0) == 1,
911 FMT_ERR("recvmsg"));
912 pathfd_copy = *(int *)(void *)CMSG_DATA(cmsg);
913 ATF_REQUIRE_MSG(pathfd_copy != pathfd,
914 "pathfd and pathfd_copy are equal");
915
916 /* Verify that the copy has O_PATH properties. */
917 flags = fcntl(pathfd_copy, F_GETFL);
918 ATF_REQUIRE_MSG(flags != -1, FMT_ERR("fcntl"));
919 ATF_REQUIRE_MSG((flags & O_PATH) != 0, "O_PATH is not set");
920 ATF_REQUIRE_ERRNO(EBADF,
921 read(pathfd_copy, &c, 1) == -1);
922 ATF_REQUIRE_ERRNO(EBADF,
923 write(pathfd_copy, &c, 1) == -1);
924
925 CHECKED_CLOSE(pathfd);
926 CHECKED_CLOSE(pathfd_copy);
927 CHECKED_CLOSE(sd[0]);
928 CHECKED_CLOSE(sd[1]);
929 }
930
931 /* Verify that a local socket can be opened with O_PATH. */
932 ATF_TC_WITHOUT_HEAD(path_unix);
ATF_TC_BODY(path_unix,tc)933 ATF_TC_BODY(path_unix, tc)
934 {
935 char buf[BUFSIZ], path[PATH_MAX];
936 struct kevent ev;
937 struct sockaddr_un sun;
938 struct stat sb;
939 int kq, pathfd, sd;
940
941 snprintf(path, sizeof(path), "path_unix.XXXXXX");
942 ATF_REQUIRE_MSG(mktemp(path) == path, FMT_ERR("mktemp"));
943
944 sd = socket(PF_LOCAL, SOCK_STREAM, 0);
945 ATF_REQUIRE_MSG(sd >= 0, FMT_ERR("socket"));
946
947 memset(&sun, 0, sizeof(sun));
948 sun.sun_family = PF_LOCAL;
949 (void)strlcpy(sun.sun_path, path, sizeof(sun.sun_path));
950 ATF_REQUIRE_MSG(bind(sd, (struct sockaddr *)&sun, SUN_LEN(&sun)) == 0,
951 FMT_ERR("bind"));
952
953 pathfd = open(path, O_PATH);
954 ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open"));
955
956 ATF_REQUIRE_MSG(fstatat(pathfd, "", &sb, AT_EMPTY_PATH) == 0,
957 FMT_ERR("fstatat"));
958 ATF_REQUIRE_MSG(sb.st_mode & S_IFSOCK, "socket mode %#x", sb.st_mode);
959 ATF_REQUIRE_MSG(sb.st_ino != 0, "socket has inode number 0");
960
961 memset(buf, 0, sizeof(buf));
962 ATF_REQUIRE_ERRNO(EBADF, write(pathfd, buf, sizeof(buf)));
963 ATF_REQUIRE_ERRNO(EBADF, read(pathfd, buf, sizeof(buf)));
964
965 /* kevent() is disallowed with sockets. */
966 kq = kqueue();
967 ATF_REQUIRE_MSG(kq >= 0, FMT_ERR("kqueue"));
968 EV_SET(&ev, pathfd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, 0);
969 ATF_REQUIRE_ERRNO(EBADF, kevent(kq, &ev, 1, NULL, 0, NULL) == -1);
970
971 /* Should not be able to open a socket without O_PATH. */
972 ATF_REQUIRE_ERRNO(EOPNOTSUPP, openat(pathfd, "", O_EMPTY_PATH) == -1);
973
974 ATF_REQUIRE_MSG(funlinkat(AT_FDCWD, path, pathfd, 0) == 0,
975 FMT_ERR("funlinkat"));
976
977 CHECKED_CLOSE(sd);
978 CHECKED_CLOSE(pathfd);
979 }
980
981 /*
982 * Check that we can perform operations using an O_PATH fd for an unlinked file.
983 */
984 ATF_TC_WITHOUT_HEAD(path_unlinked);
ATF_TC_BODY(path_unlinked,tc)985 ATF_TC_BODY(path_unlinked, tc)
986 {
987 char path[PATH_MAX];
988 struct stat sb;
989 int pathfd;
990
991 mktfile(path, "path_rights.XXXXXX");
992
993 pathfd = open(path, O_PATH);
994 ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open"));
995
996 ATF_REQUIRE_MSG(fstatat(pathfd, "", &sb, AT_EMPTY_PATH) == 0,
997 FMT_ERR("fstatat"));
998 ATF_REQUIRE(sb.st_nlink == 1);
999 ATF_REQUIRE_MSG(fstat(pathfd, &sb) == 0, FMT_ERR("fstat"));
1000 ATF_REQUIRE(sb.st_nlink == 1);
1001
1002 ATF_REQUIRE_MSG(unlink(path) == 0, FMT_ERR("unlink"));
1003
1004 ATF_REQUIRE_MSG(fstatat(pathfd, "", &sb, AT_EMPTY_PATH) == 0,
1005 FMT_ERR("fstatat"));
1006 ATF_REQUIRE(sb.st_nlink == 0);
1007 ATF_REQUIRE_MSG(fstat(pathfd, &sb) == 0, FMT_ERR("fstat"));
1008 ATF_REQUIRE(sb.st_nlink == 0);
1009
1010 CHECKED_CLOSE(pathfd);
1011 }
1012
ATF_TP_ADD_TCS(tp)1013 ATF_TP_ADD_TCS(tp)
1014 {
1015 ATF_TP_ADD_TC(tp, path_access);
1016 ATF_TP_ADD_TC(tp, path_aio);
1017 ATF_TP_ADD_TC(tp, path_capsicum);
1018 ATF_TP_ADD_TC(tp, path_capsicum_empty);
1019 ATF_TP_ADD_TC(tp, path_coredump);
1020 ATF_TP_ADD_TC(tp, path_directory);
1021 ATF_TP_ADD_TC(tp, path_directory_not_root);
1022 ATF_TP_ADD_TC(tp, path_empty);
1023 ATF_TP_ADD_TC(tp, path_empty_not_root);
1024 ATF_TP_ADD_TC(tp, path_empty_root);
1025 ATF_TP_ADD_TC(tp, path_event);
1026 ATF_TP_ADD_TC(tp, path_fcntl);
1027 ATF_TP_ADD_TC(tp, path_fexecve);
1028 ATF_TP_ADD_TC(tp, path_fifo);
1029 ATF_TP_ADD_TC(tp, path_funlinkat);
1030 ATF_TP_ADD_TC(tp, path_io);
1031 ATF_TP_ADD_TC(tp, path_ioctl);
1032 ATF_TP_ADD_TC(tp, path_lock);
1033 ATF_TP_ADD_TC(tp, path_pipe_fstatat);
1034 ATF_TP_ADD_TC(tp, path_rights);
1035 ATF_TP_ADD_TC(tp, path_unix);
1036 ATF_TP_ADD_TC(tp, path_unlinked);
1037
1038 return (atf_no_error());
1039 }
1040