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