blob: 07c96ae8bcac20120e683b0f7efd727c063368b7 [file] [log] [blame]
// Copyright 2017 The Fuchsia Authors
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT
#include <fbl/ref_ptr.h>
#include <kernel/range_check.h>
#include <object/process_dispatcher.h>
#include <object/resource_dispatcher.h>
#include <object/resource.h>
#include <zircon/syscalls/resource.h>
#include <trace.h>
#define LOCAL_TRACE 0
// TODO(ZX-2419): Take another look at validation and consider returning
// dispatchers or move validation into the parent dispatcher itself.
// Check if the resource referenced by |handle| is of kind |kind|, or ZX_RSRC_KIND_ROOT.
//
// Possible errors:
// ++ ZX_ERR_ACCESS_DENIED: |handle| is not the right |kind| of handle.
// ++ ZX_ERR_WRONG_TYPE: |handle| is not a valid handle.
zx_status_t validate_resource(zx_handle_t handle, uint32_t kind) {
auto up = ProcessDispatcher::GetCurrent();
fbl::RefPtr<ResourceDispatcher> resource;
auto status = up->GetDispatcher(handle, &resource);
if (status != ZX_OK) {
return status;
}
auto res_kind = resource->get_kind();
if (res_kind == kind || res_kind == ZX_RSRC_KIND_ROOT) {
return ZX_OK;
}
return ZX_ERR_WRONG_TYPE;
}
// Check if the resource referenced by |handle| is of kind |kind|, or ZX_RSRC_KIND_ROOT. If
// |kind| matches the resource's kind, then range validation between |base| and |size| will
// be made against the resource's backing address space allocation.
//
// Possible errors:
// ++ ZX_ERR_ACCESS_DENIED: |handle| is not a valid handle.
// ++ ZX_ERR_WRONG_TYPE: |handle| is not a valid Resource handle, or does not match |kind|.
// ++ ZX_ERR_OUT_OF_RANGE: The range specified by |base| and |Len| is not granted by this
// resource.
zx_status_t validate_ranged_resource(zx_handle_t handle,
uint32_t kind,
uintptr_t base,
size_t size) {
auto up = ProcessDispatcher::GetCurrent();
fbl::RefPtr<ResourceDispatcher> resource;
auto status = up->GetDispatcher(handle, &resource);
if (status != ZX_OK) {
return status;
}
// Root gets access to everything and has no region to match against
if (resource->get_kind() == ZX_RSRC_KIND_ROOT) {
return ZX_OK;
}
if (resource->get_kind() != kind) {
return ZX_ERR_WRONG_TYPE;
}
// TODO(cja): when more ranged types are added we will need to move this sort of adjustment to
// specific validation methods.
uint64_t rbase = resource->get_base();
size_t rsize = resource->get_size();
if (resource->get_kind() == ZX_RSRC_KIND_MMIO) {
const uint64_t aligned_rbase = ROUNDDOWN(rbase, PAGE_SIZE);
rsize = PAGE_ALIGN((rbase - aligned_rbase) + rsize);
rbase = aligned_rbase;
}
LTRACEF("req [base %#lx size %#lx] and resource [base %#lx size %#lx]\n", base, size, rbase, rsize);
// Check for intersection and make sure the requested base+size fits within
// the resource's address space allocation.
uintptr_t ibase;
size_t isize;
if (!GetIntersect(base, size, rbase, rsize, &ibase, &isize) ||
isize != size ||
ibase != base) {
return ZX_ERR_OUT_OF_RANGE;
}
return ZX_OK;
}