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