1 // Copyright 2016 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 <lib/zx/interrupt.h>
6 #include <lib/zx/resource.h>
7 #include <lib/zx/vmo.h>
8 #include <limits.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <unittest/unittest.h>
12 #include <zircon/syscalls.h>
13 #include <zircon/syscalls/object.h>
14 #include <zircon/syscalls/port.h>
15 #include <zircon/syscalls/resource.h>
16 #include <zircon/types.h>
17
18 __BEGIN_CDECLS;
19 extern zx_handle_t get_root_resource(void);
20 __END_CDECLS;
21
22 static const size_t mmio_test_size = (PAGE_SIZE * 4);
23 static uint64_t mmio_test_base;
24
root()25 const zx::unowned_resource root() {
26 static zx_handle_t root = get_root_resource();
27 return zx::unowned_resource(root);
28 }
29
30 // Physical memory is reserved during boot and its location varies based on
31 // system and architecture. What this 'test' does is scan MMIO space looking
32 // for a valid region to test against, ensuring that the only errors it sees
33 // are 'ZX_ERR_NOT_FOUND', which indicates that it is missing from the
34 // region allocator.
35 //
36 // TODO(ZX-2419): Figure out a way to test IRQs in the same manner, without
37 // hardcoding target-specific IRQ vectors in these tests. That information is
38 // stored in the kernel and is not exposed to userspace, so we can't simply
39 // guess/probe valid vectors like we can MMIO and still assume the tests are
40 // valid.
41
probe_address_space(void)42 static bool probe_address_space(void) {
43 BEGIN_TEST;
44
45 zx_status_t status;
46 // Scan mmio in chunks until we find a gap that isn't exclusively reserved physical memory.
47 uint64_t step = 0x100000000;
48 for (uint64_t base = 0; base < UINT64_MAX - step; base += step) {
49 zx::resource handle;
50 status = zx::resource::create(*root(), ZX_RSRC_KIND_MMIO, base,
51 mmio_test_size, NULL, 0, &handle);
52 if (status == ZX_OK) {
53 mmio_test_base = base;
54 break;
55 }
56
57 // If ZX_OK wasn't returned, then we should see ZX_ERR_NOT_FOUND and nothing else.
58 ASSERT_EQ(ZX_ERR_NOT_FOUND, status);
59 }
60
61 END_TEST;
62 }
63
64 // This is a basic smoketest for creating resources and verifying the internals
65 // returned by zx_object_get_info match what the caller passed for creation.
TestBasicActions(void)66 static bool TestBasicActions(void) {
67 BEGIN_TEST;
68
69 zx::resource new_root;
70 zx_info_resource_t info;
71 char root_name[] = "root";
72
73 // Create a root and verify the fields are still zero, but the name matches.
74 EXPECT_EQ(zx::resource::create(*root(), ZX_RSRC_KIND_ROOT, 0, 0,
75 root_name, sizeof(root_name), &new_root),
76 ZX_OK);
77 ASSERT_EQ(new_root.get_info(ZX_INFO_RESOURCE, &info, sizeof(info), NULL, NULL), ZX_OK);
78 EXPECT_EQ(info.kind, ZX_RSRC_KIND_ROOT);
79 EXPECT_EQ(info.base, 0u);
80 EXPECT_EQ(info.size, 0u);
81 EXPECT_EQ(info.flags, 0u);
82 EXPECT_EQ(0, strncmp(root_name, info.name, ZX_MAX_NAME_LEN));
83
84 // Check that a resource is created with all the parameters passed to the syscall, and use
85 // the new root resource created for good measure.
86 zx::resource mmio;
87 uint32_t kind = ZX_RSRC_KIND_MMIO;
88 uint32_t flags = ZX_RSRC_FLAG_EXCLUSIVE;
89 char mmio_name[] = "test_resource_name";
90 ASSERT_EQ(zx::resource::create(new_root, kind | flags, mmio_test_base, mmio_test_size,
91 mmio_name, sizeof(mmio_name), &mmio),
92 ZX_OK);
93 ASSERT_EQ(mmio.get_info(ZX_INFO_RESOURCE, &info, sizeof(info), NULL, NULL), ZX_OK);
94 EXPECT_EQ(info.kind, kind);
95 EXPECT_EQ(info.flags, flags);
96 EXPECT_EQ(info.base, mmio_test_base);
97 EXPECT_EQ(info.size, mmio_test_size);
98 EXPECT_EQ(0, strncmp(info.name, mmio_name, ZX_MAX_NAME_LEN));
99
100 END_TEST;
101 }
102
103 // This test covers every path that returns ZX_ERR_INVALID_ARGS from the the syscall.
TestInvalidArgs(void)104 static bool TestInvalidArgs(void) {
105 BEGIN_TEST;
106 zx::resource temp;
107 zx::resource fail_hnd;
108 // test privilege inversion by seeing if an MMIO resource can other resources.
109 EXPECT_EQ(zx::resource::create(*root(), ZX_RSRC_KIND_MMIO, mmio_test_base,
110 mmio_test_size, NULL, 0, &temp),
111 ZX_OK);
112 EXPECT_EQ(zx::resource::create(temp, ZX_RSRC_KIND_ROOT, 0, 0, NULL, 0, &fail_hnd),
113 ZX_ERR_ACCESS_DENIED);
114 EXPECT_EQ(zx::resource::create(temp, ZX_RSRC_KIND_MMIO, mmio_test_base, mmio_test_size, NULL,
115 0, &fail_hnd),
116 ZX_ERR_ACCESS_DENIED);
117
118 // test invalid kind
119 EXPECT_EQ(zx::resource::create(*root(), ZX_RSRC_KIND_COUNT, mmio_test_base,
120 mmio_test_size, NULL, 0, &temp),
121 ZX_ERR_INVALID_ARGS);
122 EXPECT_EQ(zx::resource::create(*root(), ZX_RSRC_KIND_COUNT + 1,
123 mmio_test_base, mmio_test_size, NULL, 0, &temp),
124 ZX_ERR_INVALID_ARGS);
125
126 // test invalid base
127 EXPECT_EQ(zx::resource::create(*root(), ZX_RSRC_KIND_MMIO, UINT64_MAX, 1024,
128 NULL, 0, &temp),
129 ZX_ERR_INVALID_ARGS);
130 // test invalid size
131 EXPECT_EQ(zx::resource::create(*root(), ZX_RSRC_KIND_MMIO, 1024, UINT64_MAX,
132 NULL, 0, &temp),
133 ZX_ERR_INVALID_ARGS);
134 // test invalid options
135 EXPECT_EQ(zx::resource::create(*root(), ZX_RSRC_KIND_MMIO | 0xFF0000, mmio_test_base,
136 mmio_test_size, NULL, 0, &temp),
137 ZX_ERR_INVALID_ARGS);
138
139 END_TEST;
140 }
141
TestExclusiveShared(void)142 static bool TestExclusiveShared(void) {
143 // Try to create a shared resource and ensure it blocks an exclusive
144 // resource.
145 BEGIN_TEST;
146 zx::resource mmio_1, mmio_2;
147 EXPECT_EQ(zx::resource::create(*root(), ZX_RSRC_KIND_MMIO | ZX_RSRC_FLAG_EXCLUSIVE,
148 mmio_test_base, mmio_test_size, NULL, 0, &mmio_1),
149 ZX_OK);
150 EXPECT_EQ(zx::resource::create(*root(), ZX_RSRC_KIND_MMIO, mmio_test_base,
151 mmio_test_size, NULL, 0, &mmio_2),
152 ZX_ERR_NOT_FOUND);
153 END_TEST;
154 }
155
TestSharedExclusive(void)156 static bool TestSharedExclusive(void) {
157 // Try to create a shared resource and ensure it blocks an exclusive
158 // resource.
159 BEGIN_TEST;
160 zx::resource mmio_1, mmio_2;
161 EXPECT_EQ(zx::resource::create(*root(), ZX_RSRC_KIND_MMIO, mmio_test_base,
162 mmio_test_size, NULL, 0, &mmio_1),
163 ZX_OK);
164 EXPECT_EQ(zx::resource::create(*root(), ZX_RSRC_KIND_MMIO | ZX_RSRC_FLAG_EXCLUSIVE,
165 mmio_test_base, mmio_test_size, NULL, 0, &mmio_2),
166 ZX_ERR_NOT_FOUND);
167 END_TEST;
168 }
169
TestVmoCreation(void)170 static bool TestVmoCreation(void) {
171 // Attempt to create a resource and then a vmo using that resource.
172 BEGIN_TEST;
173 zx::resource mmio;
174 zx::vmo vmo;
175 ASSERT_EQ(zx::resource::create(*root(), ZX_RSRC_KIND_MMIO, mmio_test_base,
176 mmio_test_size, NULL, 0, &mmio),
177 ZX_OK);
178 EXPECT_EQ(zx_vmo_create_physical(mmio.get(), mmio_test_base, PAGE_SIZE,
179 vmo.reset_and_get_address()),
180 ZX_OK);
181 END_TEST;
182 }
183
TestVmoCreationSmaller(void)184 static bool TestVmoCreationSmaller(void) {
185 // Attempt to create a resource smaller than a page and ensure it still expands access to the
186 // entire page.
187 BEGIN_TEST;
188 zx::resource mmio;
189 zx::vmo vmo;
190 ASSERT_EQ(zx::resource::create(*root(), ZX_RSRC_KIND_MMIO, mmio_test_base,
191 PAGE_SIZE/2, NULL, 0, &mmio),
192 ZX_OK);
193 EXPECT_EQ(zx_vmo_create_physical(mmio.get(), mmio_test_base, PAGE_SIZE,
194 vmo.reset_and_get_address()),
195 ZX_OK);
196 END_TEST;
197 }
198
TestVmoCreationUnaligned(void)199 static bool TestVmoCreationUnaligned(void) {
200 // Attempt to create an unaligned resource and ensure that the bounds are rounded appropriately
201 // to the proper PAGE_SIZE.
202 BEGIN_TEST;
203 zx::resource mmio;
204 zx::vmo vmo;
205 ASSERT_EQ(zx::resource::create(*root(), ZX_RSRC_KIND_MMIO,
206 mmio_test_base + 0x7800, 0x2000, NULL, 0, &mmio),
207 ZX_OK);
208 EXPECT_EQ(zx_vmo_create_physical(mmio.get(), mmio_test_base + 0x7000, 0x2000,
209 vmo.reset_and_get_address()),
210 ZX_OK);
211 END_TEST;
212 }
213
214 // Returns zero on failure.
get_vmo_rights(const zx::vmo & vmo)215 static zx_rights_t get_vmo_rights(const zx::vmo& vmo) {
216 zx_info_handle_basic_t info;
217 zx_status_t s = zx_object_get_info(vmo.get(), ZX_INFO_HANDLE_BASIC, &info,
218 sizeof(info), nullptr, nullptr);
219 if (s != ZX_OK) {
220 EXPECT_EQ(s, ZX_OK); // Poison the test
221 return 0;
222 }
223 return info.rights;
224 }
225
TestVmoReplaceAsExecutable()226 static bool TestVmoReplaceAsExecutable() {
227 BEGIN_TEST;
228
229 zx::resource vmex;
230 zx::vmo vmo, vmo2, vmo3;
231
232 // allocate an object
233 ASSERT_EQ(ZX_OK, zx_vmo_create(PAGE_SIZE, 0, vmo.reset_and_get_address()));
234
235 // set-exec with valid VMEX resource
236 ASSERT_EQ(0, zx::resource::create(*root(), ZX_RSRC_KIND_VMEX, 0, 0, NULL, 0, &vmex));
237 ASSERT_EQ(0, zx_handle_duplicate(vmo.get(), ZX_RIGHT_READ, vmo2.reset_and_get_address()));
238 ASSERT_EQ(0, zx_vmo_replace_as_executable(vmo2.get(), vmex.get(), vmo3.reset_and_get_address()));
239 EXPECT_EQ(ZX_RIGHT_READ|ZX_RIGHT_EXECUTE, get_vmo_rights(vmo3));
240
241 // set-exec with ZX_HANDLE_INVALID
242 // TODO(mdempsky): Disallow.
243 ASSERT_EQ(0, zx_handle_duplicate(vmo.get(), ZX_RIGHT_READ, vmo2.reset_and_get_address()));
244 ASSERT_EQ(0, zx_vmo_replace_as_executable(vmo2.get(), ZX_HANDLE_INVALID, vmo3.reset_and_get_address()));
245 EXPECT_EQ(ZX_RIGHT_READ|ZX_RIGHT_EXECUTE, get_vmo_rights(vmo3));
246
247 // verify invalid handle fails
248 ASSERT_EQ(0, zx_handle_duplicate(vmo.get(), ZX_RIGHT_READ, vmo2.reset_and_get_address()));
249 EXPECT_EQ(ZX_ERR_WRONG_TYPE, zx_vmo_replace_as_executable(vmo2.get(), vmo.get(), vmo3.reset_and_get_address()));
250
251 END_TEST;
252 }
253
254 #if defined(__x86_64__)
test_ioports(void)255 static bool test_ioports(void) {
256 BEGIN_TEST;
257 // On x86 create an ioport resource and attempt to have the privilege bits
258 // set for the process.
259 zx::resource io;
260 uint16_t io_base = 0xCF8;
261 uint32_t io_size = 8; // CF8 - CFC (inclusive to 4 bytes each)
262 char io_name[] = "ports!";
263 ASSERT_EQ(zx::resource::create(*root(), ZX_RSRC_KIND_IOPORT, io_base,
264 io_size, io_name, sizeof(io_name), &io),
265 ZX_OK);
266 EXPECT_EQ(zx_ioports_request(io.get(), io_base, io_size), ZX_OK);
267
268 END_TEST;
269 }
270 #endif
271
272 BEGIN_TEST_CASE(resource_tests)
273 RUN_TEST(probe_address_space);
274 RUN_TEST(TestBasicActions);
275 RUN_TEST(TestExclusiveShared);
276 RUN_TEST(TestSharedExclusive);
277 RUN_TEST(TestInvalidArgs);
278 RUN_TEST(TestVmoCreation);
279 RUN_TEST(TestVmoCreationSmaller);
280 RUN_TEST(TestVmoCreationUnaligned);
281 RUN_TEST(TestVmoReplaceAsExecutable);
282 #if defined(__x86_64__)
283 RUN_TEST(test_ioports);
284 #endif
285 END_TEST_CASE(resource_tests)
286