1 // Copyright 2017 The Fuchsia Authors
2 //
3 // Use of this source code is governed by a MIT-style
4 // license that can be found in the LICENSE file or at
5 // https://opensource.org/licenses/MIT
6
7 #include <fbl/ref_ptr.h>
8 #include <kernel/range_check.h>
9 #include <object/process_dispatcher.h>
10 #include <object/resource_dispatcher.h>
11 #include <object/resource.h>
12 #include <zircon/syscalls/resource.h>
13 #include <trace.h>
14
15 #define LOCAL_TRACE 0
16
17 // TODO(ZX-2419): Take another look at validation and consider returning
18 // dispatchers or move validation into the parent dispatcher itself.
19
20 // Check if the resource referenced by |handle| is of kind |kind|, or ZX_RSRC_KIND_ROOT.
21 //
22 // Possible errors:
23 // ++ ZX_ERR_ACCESS_DENIED: |handle| is not the right |kind| of handle.
24 // ++ ZX_ERR_WRONG_TYPE: |handle| is not a valid handle.
validate_resource(zx_handle_t handle,uint32_t kind)25 zx_status_t validate_resource(zx_handle_t handle, uint32_t kind) {
26 auto up = ProcessDispatcher::GetCurrent();
27 fbl::RefPtr<ResourceDispatcher> resource;
28 auto status = up->GetDispatcher(handle, &resource);
29 if (status != ZX_OK) {
30 return status;
31 }
32
33 auto res_kind = resource->get_kind();
34 if (res_kind == kind || res_kind == ZX_RSRC_KIND_ROOT) {
35 return ZX_OK;
36 }
37
38 return ZX_ERR_WRONG_TYPE;
39 }
40
41 // Check if the resource referenced by |handle| is of kind |kind|, or ZX_RSRC_KIND_ROOT. If
42 // |kind| matches the resource's kind, then range validation between |base| and |size| will
43 // be made against the resource's backing address space allocation.
44 //
45 // Possible errors:
46 // ++ ZX_ERR_ACCESS_DENIED: |handle| is not a valid handle.
47 // ++ ZX_ERR_WRONG_TYPE: |handle| is not a valid Resource handle, or does not match |kind|.
48 // ++ ZX_ERR_OUT_OF_RANGE: The range specified by |base| and |Len| is not granted by this
49 // resource.
validate_ranged_resource(zx_handle_t handle,uint32_t kind,uintptr_t base,size_t size)50 zx_status_t validate_ranged_resource(zx_handle_t handle,
51 uint32_t kind,
52 uintptr_t base,
53 size_t size) {
54 auto up = ProcessDispatcher::GetCurrent();
55 fbl::RefPtr<ResourceDispatcher> resource;
56 auto status = up->GetDispatcher(handle, &resource);
57 if (status != ZX_OK) {
58 return status;
59 }
60
61 // Root gets access to everything and has no region to match against
62 if (resource->get_kind() == ZX_RSRC_KIND_ROOT) {
63 return ZX_OK;
64 }
65
66 if (resource->get_kind() != kind) {
67 return ZX_ERR_WRONG_TYPE;
68 }
69
70 // TODO(cja): when more ranged types are added we will need to move this sort of adjustment to
71 // specific validation methods.
72 uint64_t rbase = resource->get_base();
73 size_t rsize = resource->get_size();
74 if (resource->get_kind() == ZX_RSRC_KIND_MMIO) {
75 const uint64_t aligned_rbase = ROUNDDOWN(rbase, PAGE_SIZE);
76 rsize = PAGE_ALIGN((rbase - aligned_rbase) + rsize);
77 rbase = aligned_rbase;
78 }
79 LTRACEF("req [base %#lx size %#lx] and resource [base %#lx size %#lx]\n", base, size, rbase, rsize);
80
81 // Check for intersection and make sure the requested base+size fits within
82 // the resource's address space allocation.
83 uintptr_t ibase;
84 size_t isize;
85 if (!GetIntersect(base, size, rbase, rsize, &ibase, &isize) ||
86 isize != size ||
87 ibase != base) {
88 return ZX_ERR_OUT_OF_RANGE;
89 }
90
91 return ZX_OK;
92 }
93