blob: de6b3bc13096f712caad63f0c0be73e302c92b6f [file] [log] [blame]
// Copyright 2019 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
#ifndef ZIRCON_KERNEL_OBJECT_INCLUDE_OBJECT_USER_HANDLES_H_
#define ZIRCON_KERNEL_OBJECT_INCLUDE_OBJECT_USER_HANDLES_H_
#include <lib/user_copy/user_ptr.h>
#include <lib/zx/status.h>
#include <zircon/types.h>
#include <fbl/ref_ptr.h>
#include <ktl/algorithm.h>
#include <object/process_dispatcher.h>
// Extracts the handles that would be consumed on syscalls with handle_release semantics
// from |offset| to |offset + chunk_size| from |user_handles| and returns them
// in |handles| which must be at of at least size |chunk_size|.
zx_status_t get_user_handles_to_consume(user_in_ptr<const zx_handle_t> user_handles, size_t offset,
size_t chunk_size, zx_handle_t* handles);
zx_status_t get_user_handles_to_consume(user_inout_ptr<zx_handle_disposition_t> user_handles,
size_t offset, size_t chunk_size, zx_handle_t* handles);
// Removes the handles pointed by |user_handles| from |process|. Returns ZX_OK if all handles
// have been removed, error otherwise. It only stops early if get_user_handles() fails.
template <typename T>
zx_status_t RemoveUserHandles(T user_handles, size_t num_handles, ProcessDispatcher* process) {
zx_handle_t handles[kMaxMessageHandles];
size_t offset = 0u;
zx_status_t status = ZX_OK;
while (offset < num_handles) {
// We process |num_handles| in chunks of |kMaxMessageHandles| because we don't have
// a limit on how large |num_handles| can be.
auto chunk_size = ktl::min<size_t>(num_handles - offset, kMaxMessageHandles);
status = get_user_handles_to_consume(user_handles, offset, chunk_size, handles);
if (status != ZX_OK) {
break;
}
status = process->handle_table().RemoveHandles(ktl::span(handles, chunk_size));
offset += chunk_size;
}
return status;
}
// Returns a |raw_handle| that should be sent over |channel|. In case
// of error, the return value should be reflected back to the user.
zx::status<Handle*> get_handle_for_message_locked(ProcessDispatcher* process,
const Dispatcher* channel,
const zx_handle_t* handle_val)
TA_REQ(process->handle_table().get_lock());
zx::status<Handle*> get_handle_for_message_locked(ProcessDispatcher* process,
const Dispatcher* channel,
zx_handle_disposition_t* handle_disposition)
TA_REQ(process->handle_table().get_lock());
#endif // ZIRCON_KERNEL_OBJECT_INCLUDE_OBJECT_USER_HANDLES_H_