1 /* compile: xcrun -sdk macosx.internal clang -ldarwintest -o o_search o_search.c -g -Weverything */
2
3 #include <darwintest.h>
4 #include <darwintest_utils.h>
5 #include <darwintest_multiprocess.h>
6 #include <errno.h>
7 #include <stdint.h>
8 #include <stdlib.h>
9 #include <unistd.h>
10 #include <sys/attr.h>
11 #include <sys/event.h>
12 #include <sys/resource.h>
13 #include <dirent.h>
14
15 #ifndef O_EXEC
16 #define O_EXEC 0x40000000
17 #define O_SEARCH (O_EXEC | O_DIRECTORY)
18 #endif
19
20 T_GLOBAL_META(
21 T_META_NAMESPACE("xnu.vfs"),
22 T_META_RADAR_COMPONENT_NAME("xnu"),
23 T_META_RADAR_COMPONENT_VERSION("vfs"),
24 T_META_ASROOT(false),
25 T_META_CHECK_LEAKS(false));
26
27 #define TEST_FILE "testfile"
28 #define NUMDIRS 5
29
30 static char g_testfile[MAXPATHLEN];
31
32 extern ssize_t __getdirentries64(int, void *, size_t, off_t *);
33
34 static void
exit_cleanup(void)35 exit_cleanup(void)
36 {
37 (void)unlink(g_testfile);
38 }
39
40 T_DECL(o_search,
41 "test O_SEARCH for open",
42 T_META_ASROOT(false))
43 {
44 const char *tmpdir = dt_tmpdir();
45 void *mapped = MAP_FAILED;
46 off_t dirbyte = 0;
47 int retval = 0;
48 int fd = -1;
49 int tmpdir_fd = -1;
50 char namebuf[(sizeof(struct dirent) * (NUMDIRS + 2))];
51 char attrbuf[256];
52
53 T_SETUPBEGIN;
54
55 atexit(exit_cleanup);
56
57 T_ASSERT_POSIX_ZERO(chdir(tmpdir),
58 "Setup: changing to tmpdir: %s", tmpdir);
59
60 snprintf(g_testfile, MAXPATHLEN, "%s/%s", tmpdir, TEST_FILE);
61
62 T_ASSERT_POSIX_SUCCESS(fd = open(g_testfile, O_CREAT | O_RDWR, 0644), NULL);
63 T_ASSERT_POSIX_SUCCESS(retval = (int)write(fd, g_testfile, sizeof(g_testfile)), "Write: %s", g_testfile);
64 T_ASSERT_POSIX_SUCCESS(close(fd), "Close test file: %s", g_testfile);
65
66 T_SETUPEND;
67
68 T_WITH_ERRNO;
69 tmpdir_fd = open(tmpdir, O_EXEC);
70 T_ASSERT_TRUE((tmpdir_fd == -1) && (errno == EISDIR),
71 "Trying to open directory O_EXEC: %s, tmpdir_fd = %d, errno = %d", g_testfile, tmpdir_fd, errno);
72
73 T_ASSERT_POSIX_SUCCESS(tmpdir_fd = open(tmpdir, O_RDONLY), NULL);
74 T_ASSERT_POSIX_SUCCESS(retval = (int)__getdirentries64(tmpdir_fd, namebuf, sizeof(namebuf), &dirbyte), NULL);
75 T_ASSERT_POSIX_SUCCESS(close(tmpdir_fd), NULL);
76
77 T_ASSERT_POSIX_SUCCESS(tmpdir_fd = open(tmpdir, O_SEARCH), NULL);
78 retval = (int)__getdirentries64(tmpdir_fd, namebuf, sizeof(namebuf), &dirbyte);
79 T_ASSERT_TRUE((retval == -1) && (errno == EBADF),
80 "Trying to read directory opened with O_SEARCH: %s, retval = %d, errno = %d",
81 tmpdir, retval, errno);
82
83 fd = openat(tmpdir_fd, TEST_FILE, O_EXEC);
84 T_ASSERT_TRUE((fd == -1) && (errno == EACCES),
85 "Trying to open file for execute with perms 644: %s, retval = %d, errno = %d",
86 tmpdir, retval, errno);
87
88 T_ASSERT_POSIX_SUCCESS(retval = fchmodat(tmpdir_fd, TEST_FILE, 0744, 0), NULL);
89
90 fd = openat(tmpdir_fd, TEST_FILE, O_SEARCH);
91 T_ASSERT_TRUE((fd == -1) && (errno == ENOTDIR),
92 "Trying to open file for execute with perms 644: %s, retval = %d, errno = %d",
93 tmpdir, retval, errno);
94
95 T_ASSERT_POSIX_SUCCESS(fd = openat(tmpdir_fd, TEST_FILE, O_EXEC), NULL);
96
97 retval = (int)read(fd, &attrbuf, 2);
98 T_ASSERT_TRUE((retval == -1) && (errno == EBADF),
99 "Trying to read file opened with O_EXEC: %s, retval = %d, errno = %d",
100 g_testfile, retval, errno);
101
102 retval = (int)write(fd, &attrbuf, 2);
103 T_ASSERT_TRUE((retval == -1) && (errno == EBADF),
104 "Trying to write file opened with O_EXEC: %s, retval = %d, errno = %d",
105 g_testfile, retval, errno);
106
107 mapped = mmap(NULL, PAGE_SIZE, PROT_READ, MAP_SHARED,
108 fd, 0);
109 T_ASSERT_TRUE((mapped == MAP_FAILED) && (errno == EACCES),
110 "Trying to mmap file for read opened with O_EXEC: %s, mapped = %ld, errno = %d",
111 g_testfile, (long)mapped, errno);
112
113 mapped = mmap(NULL, PAGE_SIZE, PROT_WRITE, MAP_SHARED,
114 fd, 0);
115 T_ASSERT_TRUE((mapped == MAP_FAILED) && (errno == EACCES),
116 "Trying to mmap file for write opened with O_EXEC: %s, mapped = %ld, errno = %d",
117 g_testfile, (long)mapped, errno);
118
119 T_ASSERT_POSIX_SUCCESS(close(fd), NULL);
120 T_ASSERT_POSIX_SUCCESS(close(tmpdir_fd), NULL);
121 }
122