1 // Copyright 2018 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <assert.h>
6 #include <fcntl.h>
7 #include <stdio.h>
8 #include <unistd.h>
9 
10 #include <lib/fzl/time.h>
11 #include <lib/zx/bti.h>
12 #include <lib/zx/channel.h>
13 #include <lib/zx/debuglog.h>
14 #include <lib/zx/event.h>
15 #include <lib/zx/eventpair.h>
16 #include <lib/zx/fifo.h>
17 #include <lib/zx/guest.h>
18 #include <lib/zx/handle.h>
19 #include <lib/zx/interrupt.h>
20 #include <lib/zx/job.h>
21 #include <lib/zx/log.h>
22 #include <lib/zx/port.h>
23 #include <lib/zx/process.h>
24 #include <lib/zx/socket.h>
25 #include <lib/zx/thread.h>
26 #include <lib/zx/time.h>
27 #include <lib/zx/timer.h>
28 #include <lib/zx/vmar.h>
29 #include <unittest/unittest.h>
30 #include <zircon/syscalls.h>
31 #include <zircon/syscalls/object.h>
32 #include <zircon/syscalls/port.h>
33 
34 template <typename Handle>
duplicating(const Handle & handle)35 bool duplicating(const Handle& handle) {
36     BEGIN_TEST;
37 
38     zx_status_t expected_status = ZX_OK;
39     if (!zx::object_traits<Handle>::supports_duplication) {
40         expected_status = ZX_ERR_ACCESS_DENIED;
41     }
42 
43     zx_handle_t copy = ZX_HANDLE_INVALID;
44     zx_status_t status = zx_handle_duplicate(handle.get(), ZX_RIGHT_SAME_RIGHTS, &copy);
45     if (copy != ZX_HANDLE_INVALID) {
46         zx_handle_close(copy);
47     }
48 
49     ASSERT_EQ(status, expected_status);
50 
51     END_TEST;
52 }
53 
54 template <typename Handle>
user_signaling(const Handle & handle)55 bool user_signaling(const Handle& handle) {
56     BEGIN_TEST;
57 
58     zx_status_t expected_status = ZX_OK;
59     if (!zx::object_traits<Handle>::supports_user_signal) {
60         expected_status = ZX_ERR_ACCESS_DENIED;
61     }
62 
63     zx_handle_t copy = ZX_HANDLE_INVALID;
64     zx_status_t status = zx_object_signal(handle.get(), 0u, ZX_USER_SIGNAL_0);
65     if (copy != ZX_HANDLE_INVALID) {
66         zx_handle_close(copy);
67     }
68 
69     ASSERT_EQ(status, expected_status);
70 
71     END_TEST;
72 }
73 
74 template <typename Handle>
waiting(const Handle & handle)75 bool waiting(const Handle& handle) {
76     BEGIN_TEST;
77 
78     zx_status_t expected_status = ZX_OK;
79     if (!zx::object_traits<Handle>::supports_wait) {
80         expected_status = ZX_ERR_ACCESS_DENIED;
81     }
82 
83     zx_handle_t copy = ZX_HANDLE_INVALID;
84     zx_status_t status = zx_object_wait_one(handle.get(), ZX_USER_SIGNAL_0, 0u, nullptr);
85     if (copy != ZX_HANDLE_INVALID) {
86         zx_handle_close(copy);
87     }
88 
89     ASSERT_EQ(status, expected_status);
90 
91     END_TEST;
92 }
93 
94 template <typename Handle>
peering(const Handle & handle)95 bool peering(const Handle& handle) {
96     BEGIN_TEST;
97 
98     zx_status_t expected_status = ZX_OK;
99     if (!zx::object_traits<Handle>::has_peer_handle) {
100         expected_status = ZX_ERR_ACCESS_DENIED;
101     }
102 
103     zx_status_t status = zx_object_signal_peer(handle.get(), 0u, ZX_USER_SIGNAL_0);
104 
105     ASSERT_EQ(status, expected_status);
106 
107     END_TEST;
108 }
109 
traits_test()110 bool traits_test() {
111     BEGIN_TEST;
112 
113     {
114         zx::event event;
115         ASSERT_EQ(zx::event::create(0u, &event), ZX_OK);
116         duplicating(event);
117         user_signaling(event);
118         waiting(event);
119         peering(event);
120     }
121 
122     {
123         zx::thread thread;
124         ASSERT_EQ(zx::thread::create(*zx::process::self(), "", 0u, 0u, &thread), ZX_OK);
125         duplicating(thread);
126         user_signaling(thread);
127         waiting(thread);
128         peering(thread);
129     }
130 
131     {
132         zx::process process;
133         zx::vmar vmar;
134         ASSERT_EQ(zx::process::create(*zx::job::default_job(), "", 0u, 0u, &process, &vmar), ZX_OK);
135         duplicating(process);
136         user_signaling(process);
137         waiting(process);
138         peering(process);
139     }
140 
141     {
142         zx::job job;
143         ASSERT_EQ(zx::job::create(*zx::job::default_job(), 0u, &job), ZX_OK);
144         duplicating(job);
145         user_signaling(job);
146         waiting(job);
147         peering(job);
148     }
149 
150     {
151         zx::vmo vmo;
152         ASSERT_EQ(zx::vmo::create(4096u, 0u, &vmo), ZX_OK);
153         duplicating(vmo);
154         user_signaling(vmo);
155         waiting(vmo);
156         peering(vmo);
157     }
158 
159     {
160         // Creating a zx::bti is too hard in a generic testing
161         // environment. Instead, we just assert it's got the traits we
162         // want.
163         ASSERT_EQ(zx::object_traits<zx::bti>::supports_duplication, true);
164         ASSERT_EQ(zx::object_traits<zx::bti>::supports_user_signal, true);
165         ASSERT_EQ(zx::object_traits<zx::bti>::supports_wait, true);
166         ASSERT_EQ(zx::object_traits<zx::bti>::has_peer_handle, false);
167     }
168 
169     {
170         // Creating a zx::resource is too hard in a generic testing
171         // environment. Instead, we just assert it's got the traits we
172         // want.
173         ASSERT_EQ(zx::object_traits<zx::resource>::supports_duplication, true);
174         ASSERT_EQ(zx::object_traits<zx::resource>::supports_user_signal, true);
175         ASSERT_EQ(zx::object_traits<zx::resource>::supports_wait, true);
176         ASSERT_EQ(zx::object_traits<zx::resource>::has_peer_handle, false);
177     }
178 
179     {
180         zx::timer timer;
181         ASSERT_EQ(zx::timer::create(0u, ZX_CLOCK_MONOTONIC, &timer), ZX_OK);
182         duplicating(timer);
183         user_signaling(timer);
184         waiting(timer);
185         peering(timer);
186     }
187 
188     {
189         zx::channel channel, channel2;
190         ASSERT_EQ(zx::channel::create(0u, &channel, &channel2), ZX_OK);
191         duplicating(channel);
192         user_signaling(channel);
193         waiting(channel);
194         peering(channel);
195     }
196 
197     {
198         zx::eventpair eventpair, eventpair2;
199         ASSERT_EQ(zx::eventpair::create(0u, &eventpair, &eventpair2), ZX_OK);
200         duplicating(eventpair);
201         user_signaling(eventpair);
202         waiting(eventpair);
203         peering(eventpair);
204     }
205 
206     {
207         zx::fifo fifo, fifo2;
208         ASSERT_EQ(zx::fifo::create(16u, 16u, 0u, &fifo, &fifo2), ZX_OK);
209         duplicating(fifo);
210         user_signaling(fifo);
211         waiting(fifo);
212         peering(fifo);
213     }
214 
215     {
216         zx::log log;
217         ASSERT_EQ(zx::log::create(0u, &log), ZX_OK);
218         duplicating(log);
219         user_signaling(log);
220         waiting(log);
221         peering(log);
222     }
223 
224     {
225         zx::debuglog debuglog;
226         ASSERT_EQ(zx::debuglog::create(zx::resource(), 0u, &debuglog), ZX_OK);
227         duplicating(debuglog);
228         user_signaling(debuglog);
229         waiting(debuglog);
230         peering(debuglog);
231     }
232 
233     {
234         // Creating a zx::pmt is too hard in a generic testing
235         // environment. Instead, we just assert it's got the traits we
236         // want.
237         ASSERT_EQ(zx::object_traits<zx::pmt>::supports_duplication, false);
238         ASSERT_EQ(zx::object_traits<zx::pmt>::supports_user_signal, false);
239         ASSERT_EQ(zx::object_traits<zx::pmt>::supports_wait, false);
240         ASSERT_EQ(zx::object_traits<zx::pmt>::has_peer_handle, false);
241     }
242 
243     {
244         zx::socket socket, socket2;
245         ASSERT_EQ(zx::socket::create(0u, &socket, &socket2), ZX_OK);
246         duplicating(socket);
247         user_signaling(socket);
248         waiting(socket);
249         peering(socket);
250     }
251 
252     {
253         zx::port port;
254         ASSERT_EQ(zx::port::create(0u, &port), ZX_OK);
255         duplicating(port);
256         user_signaling(port);
257         waiting(port);
258         peering(port);
259     }
260 
261     {
262         zx::vmar vmar;
263         uintptr_t addr;
264         ASSERT_EQ(zx::vmar::root_self()->allocate(0u, 4096u, 0u, &vmar, &addr), ZX_OK);
265         duplicating(vmar);
266         user_signaling(vmar);
267         waiting(vmar);
268         peering(vmar);
269     }
270 
271     {
272         // Creating a zx::interrupt is too hard in a generic testing
273         // environment. Instead, we just assert it's got the traits we
274         // want.
275         ASSERT_EQ(zx::object_traits<zx::interrupt>::supports_duplication, true);
276         ASSERT_EQ(zx::object_traits<zx::interrupt>::supports_user_signal, false);
277         ASSERT_EQ(zx::object_traits<zx::interrupt>::supports_wait, true);
278         ASSERT_EQ(zx::object_traits<zx::interrupt>::has_peer_handle, false);
279     }
280 
281     {
282         // Creating a zx::guest is too hard in a generic testing
283         // environment. Instead, we just assert it's got the traits we
284         // want.
285         ASSERT_EQ(zx::object_traits<zx::guest>::supports_duplication, true);
286         ASSERT_EQ(zx::object_traits<zx::guest>::supports_user_signal, false);
287         ASSERT_EQ(zx::object_traits<zx::guest>::supports_wait, false);
288         ASSERT_EQ(zx::object_traits<zx::guest>::has_peer_handle, false);
289     }
290 
291     {
292         // Creating a zx::iommu is too hard in a generic testing
293         // environment. Instead, we just assert it's got the traits we
294         // want.
295         ASSERT_EQ(zx::object_traits<zx::resource>::supports_duplication, true);
296         ASSERT_EQ(zx::object_traits<zx::resource>::supports_user_signal, true);
297         ASSERT_EQ(zx::object_traits<zx::resource>::supports_wait, true);
298         ASSERT_EQ(zx::object_traits<zx::resource>::has_peer_handle, false);
299     }
300 
301     END_TEST;
302 }
303 
304 BEGIN_TEST_CASE(libzx_traits_tests)
305 
306 RUN_TEST(traits_test)
307 
308 END_TEST_CASE(libzx_traits_tests)
309