xref: /xnu-10063.101.15/tests/iopolicy.c (revision 94d3b452840153a99b38a3a9659680b2a006908e)
1 /* compile: xcrun -sdk macosx.internal clang -ldarwintest -o iopolicy iopolicy.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 
14 #ifndef IOPOL_TYPE_VFS_DISALLOW_RW_FOR_O_EVTONLY
15 #define IOPOL_TYPE_VFS_DISALLOW_RW_FOR_O_EVTONLY 10
16 #endif
17 
18 #ifndef IOPOL_VFS_DISALLOW_RW_FOR_O_EVTONLY_OFF
19 #define IOPOL_VFS_DISALLOW_RW_FOR_O_EVTONLY_OFF 0
20 #endif
21 
22 #ifndef IOPOL_VFS_DISALLOW_RW_FOR_O_EVTONLY_ON
23 #define IOPOL_VFS_DISALLOW_RW_FOR_O_EVTONLY_ON 1
24 #endif
25 
26 T_GLOBAL_META(
27 	T_META_NAMESPACE("xnu.vfs.iopolicy"),
28 	T_META_RADAR_COMPONENT_NAME("xnu"),
29 	T_META_RADAR_COMPONENT_VERSION("vfs"),
30 	T_META_CHECK_LEAKS(false));
31 
32 #define TEST_FILE "testfile"
33 
34 static char g_testfile[MAXPATHLEN];
35 static char g_testdata[1024];
36 
37 static void
exit_cleanup(void)38 exit_cleanup(void)
39 {
40 	(void)remove(g_testfile);
41 }
42 
43 T_DECL(iopol_type_vfs_disallow_rw_for_o_evtonly,
44     "test IOPOL_TYPE_VFS_DISALLOW_RW_FOR_O_EVTONLY policy")
45 {
46 	char attrbuf[256];
47 	struct attrlist attrlist;
48 	struct kevent vnode_kevent;
49 	struct timespec kevent_timeout;
50 	const char *tmpdir = dt_tmpdir();
51 	void *mapped;
52 	int err, fd, kq;
53 
54 	T_SETUPBEGIN;
55 
56 	atexit(exit_cleanup);
57 
58 	T_ASSERT_POSIX_ZERO(chdir(tmpdir),
59 	    "Setup: changing to tmpdir: %s", tmpdir);
60 
61 	snprintf(g_testfile, MAXPATHLEN, "%s/%s", tmpdir, TEST_FILE);
62 
63 	T_WITH_ERRNO;
64 	fd = open(g_testfile, O_CREAT | O_RDWR, 0666);
65 	T_ASSERT_NE(fd, -1, "Create test file: %s", g_testfile);
66 
67 	T_WITH_ERRNO;
68 	err = (int)write(fd, g_testfile, sizeof(g_testfile));
69 	T_ASSERT_NE(err, -1, "Write: %s", g_testfile);
70 
71 	T_ASSERT_POSIX_SUCCESS(close(fd), "Close test file: %s", g_testfile);
72 
73 	kq = kqueue();
74 	T_ASSERT_NE(kq, -1, "Create kqueue");
75 
76 	T_SETUPEND;
77 
78 	T_WITH_ERRNO;
79 	err = setiopolicy_np(IOPOL_TYPE_VFS_DISALLOW_RW_FOR_O_EVTONLY,
80 	    IOPOL_SCOPE_THREAD, IOPOL_VFS_DISALLOW_RW_FOR_O_EVTONLY_ON);
81 	T_ASSERT_TRUE((err == -1) && (errno == EINVAL),
82 	    "setiopolicy_np(IOPOL_TYPE_VFS_DISALLOW_RW_FOR_O_EVTONLY, IOPOL_SCOPE_THREAD, 1)");
83 
84 	T_WITH_ERRNO;
85 	err = setiopolicy_np(IOPOL_TYPE_VFS_DISALLOW_RW_FOR_O_EVTONLY,
86 	    IOPOL_SCOPE_PROCESS, IOPOL_VFS_DISALLOW_RW_FOR_O_EVTONLY_ON);
87 	T_ASSERT_NE(err, -1,
88 	    "setiopolicy_np(IOPOL_TYPE_VFS_DISALLOW_RW_FOR_O_EVTONLY, IOPOL_SCOPE_PROCESS, 1)");
89 
90 	T_WITH_ERRNO;
91 	err = getiopolicy_np(IOPOL_TYPE_VFS_DISALLOW_RW_FOR_O_EVTONLY,
92 	    IOPOL_SCOPE_PROCESS);
93 	T_ASSERT_EQ(err, IOPOL_VFS_DISALLOW_RW_FOR_O_EVTONLY_ON,
94 	    "getiopolicy_np(IOPOL_TYPE_VFS_DISALLOW_RW_FOR_O_EVTONLY, IOPOL_SCOPE_PROCESS)");
95 
96 	T_WITH_ERRNO;
97 	err = setiopolicy_np(IOPOL_TYPE_VFS_DISALLOW_RW_FOR_O_EVTONLY,
98 	    IOPOL_SCOPE_PROCESS, IOPOL_VFS_DISALLOW_RW_FOR_O_EVTONLY_OFF);
99 	T_ASSERT_TRUE((err == -1) && (errno == EINVAL),
100 	    "setiopolicy_np(IOPOL_TYPE_VFS_DISALLOW_RW_FOR_O_EVTONLY, IOPOL_SCOPE_PROCESS, 0)");
101 
102 	T_WITH_ERRNO;
103 	fd = open(g_testfile, O_RDWR | O_EVTONLY, 0666);
104 	T_ASSERT_NE(fd, -1, "Open test fi1e in 'O_RDW|O_EVTONLY': %s", g_testfile);
105 
106 	T_WITH_ERRNO;
107 	err = (int)write(fd, g_testdata, sizeof(g_testdata));
108 	T_ASSERT_TRUE((err == -1) && (errno == EBADF),
109 	    "Trying to write: %s", g_testfile);
110 
111 	T_WITH_ERRNO;
112 	err = (int)read(fd, g_testdata, sizeof(g_testdata));
113 	T_ASSERT_TRUE((err == -1) && (errno == EBADF),
114 	    "Trying to read: %s", g_testfile);
115 
116 	T_WITH_ERRNO;
117 	mapped = mmap(NULL, sizeof(g_testdata), PROT_READ | PROT_WRITE, MAP_SHARED,
118 	    fd, 0);
119 	T_ASSERT_TRUE((err == -1) && (errno == EACCES),
120 	    "Trying to mmaped read/write: %s", g_testfile);
121 
122 	T_ASSERT_POSIX_SUCCESS(close(fd), "Close test file: %s", g_testfile);
123 
124 	T_WITH_ERRNO;
125 	fd = open(g_testfile, O_EVTONLY, 0666);
126 	T_ASSERT_NE(fd, -1, "Open test fi1e in 'O_EVTONLY': %s", g_testfile);
127 
128 	T_WITH_ERRNO;
129 	err = (int)read(fd, g_testdata, sizeof(g_testdata));
130 	T_ASSERT_TRUE((err == -1) && (errno == EBADF),
131 	    "Trying to read: %s", g_testfile);
132 
133 	T_WITH_ERRNO;
134 	memset(&attrlist, 0, sizeof(attrlist));
135 	attrlist.bitmapcount = ATTR_BIT_MAP_COUNT;
136 	attrlist.commonattr = (ATTR_CMN_OBJTYPE | ATTR_CMN_OBJID | ATTR_CMN_MODTIME);
137 
138 	err = fgetattrlist(fd, &attrlist, &attrbuf, sizeof(attrbuf), 0);
139 	T_ASSERT_NE(err, -1, "Perform getattrlist: %s", g_testfile);
140 
141 	kevent_timeout.tv_sec = kevent_timeout.tv_nsec = 0;
142 	EV_SET(&vnode_kevent, fd, EVFILT_VNODE, (EV_ADD | EV_ENABLE | EV_CLEAR),
143 	    NOTE_WRITE, 0, (void *)g_testfile);
144 	err = kevent(kq, &vnode_kevent, 1, NULL, 0, &kevent_timeout);
145 	T_ASSERT_GE(err, 0, "Register vnode event on kq: %d", kq);
146 
147 	kevent_timeout.tv_sec = 2;
148 	kevent_timeout.tv_nsec = 0;
149 	EV_SET(&vnode_kevent, fd, EVFILT_VNODE, EV_CLEAR, 0, 0, 0);
150 
151 	err = kevent(kq, NULL, 0, &vnode_kevent, 1, &kevent_timeout);
152 	T_ASSERT_NE(err, -1, "Listen for vnode event on kq: %d", kq);
153 
154 	T_ASSERT_POSIX_SUCCESS(close(fd), "Close test file: %s", g_testfile);
155 }
156