blob: 10197570d7a9b56bf820dacbbc11144222fe7260 [file]
// Copyright 2026 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
use crate::object::{
Dispatcher, HandleValue, ResourceDispatcher, StrictValidation, ZX_RSRC_FLAGS_MASK,
is_valid_kind, validate_ranged_resource_dispatcher,
};
use crate::user_copy::UserInPtr;
use core::mem::MaybeUninit;
use syscalls_macro::syscall;
use zx_status::Status;
use zx_types::{ZX_MAX_NAME_LEN, ZX_RIGHT_WRITE, ZX_RSRC_FLAG_EXCLUSIVE};
const ZX_RSRC_KIND_MASK: u32 = 0x0000_FFFF;
#[inline]
const fn zx_rsrc_extract_kind(options: u32) -> u32 {
options & ZX_RSRC_KIND_MASK
}
#[inline]
const fn zx_rsrc_extract_flags(options: u32) -> u32 {
options & !ZX_RSRC_KIND_MASK
}
/// Creates a new resource, child of the provided resource. On success, a new resource is created
/// and a handle is returned in `resource_out`.
///
/// For more information on resources, see `//docs/reference/kernel_objects/resource.md`.
///
/// The range low:high is inclusive on both ends, high must be greater than or equal to low.
///
/// `parent_rsrc` must be a resource of the same kind as `kind`, or a root resource. `base` and
/// `size` represent an inclusive range from `base` to `base + size` for the child resource.
#[syscall]
pub fn sys_resource_create(
parent_rsrc: HandleValue,
options: u32,
base: u64,
size: usize,
user_name: UserInPtr<u8>,
name_size: usize,
resource_out: &mut HandleValue,
) -> Result<(), Status> {
// Verify that the given base and size don't lead to an integer overflow.
if base.checked_add(size as u64).is_none() {
return Err(Status::INVALID_ARGS);
}
// Obtain the parent Resource. WRITE access is required to create a child resource.
let parent = Dispatcher::get_with_rights::<ResourceDispatcher>(parent_rsrc, ZX_RIGHT_WRITE)?;
let kind = zx_rsrc_extract_kind(options);
let flags = zx_rsrc_extract_flags(options);
if !is_valid_kind(kind) || (flags & !ZX_RSRC_FLAGS_MASK) != 0 {
return Err(Status::INVALID_ARGS);
}
// Validate the parent resource the same way we would validate any resource usage in another
// syscall.
if validate_ranged_resource_dispatcher(&parent, kind, base, size, StrictValidation::Yes)
.is_err()
{
return Err(Status::ACCESS_DENIED);
}
// If the resource is a slice of a larger resource then neither the new resource nor its
// parent are permitted to be exclusive resources. In this case, `parent_rsrc` will not be the
// root resource for `kind`.
if !parent.is_ranged_root(kind)
&& ((parent.get_flags() & ZX_RSRC_FLAG_EXCLUSIVE != 0)
|| (flags & ZX_RSRC_FLAG_EXCLUSIVE != 0))
{
return Err(Status::INVALID_ARGS);
}
// Extract the name from userspace if one was provided.
let mut buf = [MaybeUninit::<u8>::uninit(); ZX_MAX_NAME_LEN];
let name = user_name.copy_user_string(name_size, &mut buf)?;
// Create a new Resource
let (kernel_handle, rights) = ResourceDispatcher::create(kind, base, size, flags, name)?;
// Create a handle for the child
*resource_out = kernel_handle.make_and_add_handle(rights)?;
Ok(())
}