blob: afc05a88ec2e456c7c853754ab75afc0584c5ac4 [file]
// Copyright 2016 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::kernel::thread::AutoExpiringPreemptDisabler;
use crate::object::{HandleValue, ProcessDispatcher, remove_user_handles};
use crate::user_copy::UserInPtr;
use debug::ltracef;
use syscalls_macro::syscall;
use zx_status::Status;
use zx_types::{
ZX_HANDLE_INVALID, ZX_RIGHT_DUPLICATE, ZX_RIGHT_SAME_RIGHTS, zx_handle_t, zx_rights_t,
};
const LOCAL_TRACE: u32 = 0;
// zx_status_t zx_handle_close
#[syscall]
pub fn sys_handle_close(handle_value: HandleValue) -> Result<(), Status> {
ltracef!("handle {:x}\n", handle_value.raw_value());
// Closing the "never a handle" invalid handle is not an error
// It's like free(NULL).
if handle_value.raw_value() == ZX_HANDLE_INVALID {
return Ok(());
}
let up = ProcessDispatcher::get_current();
let _handle = up.handle_table().remove_handle(&up, handle_value).ok_or(Status::BAD_HANDLE)?;
Ok(())
}
// zx_status_t zx_handle_close_many
#[syscall]
pub fn sys_handle_close_many(
handles: UserInPtr<zx_handle_t>,
num_handles: usize,
) -> Result<(), Status> {
ltracef!("handles {:p}, num_handles {}\n", handles.as_ptr(), num_handles);
let up = ProcessDispatcher::get_current();
remove_user_handles(handles, num_handles, &up)
}
fn handle_dup_replace(
is_replace: bool,
handle_value: HandleValue,
mut rights: zx_rights_t,
out: &mut HandleValue,
) -> Result<(), Status> {
ltracef!("handle {:x}\n", handle_value.raw_value());
let up = ProcessDispatcher::get_current();
let _preempt_disable = AutoExpiringPreemptDisabler::with_default_timeslice_extension();
ksync::lock!(let mut guard = up.handle_table().write_lock());
let source = up
.handle_table()
.get_handle_entry_locked(guard.as_mut().token_mut(), &up, handle_value)
.ok_or(Status::BAD_HANDLE)?;
if !is_replace && !source.as_ref().has_rights(ZX_RIGHT_DUPLICATE) {
return Err(Status::ACCESS_DENIED);
}
if rights == ZX_RIGHT_SAME_RIGHTS {
rights = source.as_ref().rights();
} else if (source.as_ref().rights() & rights) != rights {
if is_replace {
let _ = source.remove();
}
return Err(Status::INVALID_ARGS);
}
let handle = source.as_ref().dup(rights)?;
if is_replace {
let _ = source.remove();
}
*out = up.handle_table().map_handle_to_value(handle.as_ref());
up.handle_table().add_handle_locked(guard.as_mut().token_mut(), handle);
Ok(())
}
// zx_status_t zx_handle_duplicate
#[syscall]
pub fn sys_handle_duplicate(
handle_value: HandleValue,
rights: zx_rights_t,
out: &mut HandleValue,
) -> Result<(), Status> {
handle_dup_replace(false, handle_value, rights, out)
}
// zx_status_t zx_handle_replace
#[syscall]
pub fn sys_handle_replace(
handle_value: HandleValue,
rights: zx_rights_t,
out: &mut HandleValue,
) -> Result<(), Status> {
handle_dup_replace(true, handle_value, rights, out)
}