blob: 8ce18ebad24945389a09827afe89627299778df4 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <lib/fidl/internal.h>
#ifdef __Fuchsia__
#include <zircon/syscalls.h>
#endif
// Coding tables for primitives are predefined and interned here.
// This file must be a .c to guarantee that these types are stored directly in
// .rodata, rather than requiring global ctors to have been run (fxbug.dev/39978).
const struct FidlCodedPrimitive fidl_internal_kBoolTable = {
.tag = kFidlTypePrimitive, .type = kFidlCodedPrimitiveSubtype_Bool};
const struct FidlCodedPrimitive fidl_internal_kInt8Table = {
.tag = kFidlTypePrimitive, .type = kFidlCodedPrimitiveSubtype_Int8};
const struct FidlCodedPrimitive fidl_internal_kInt16Table = {
.tag = kFidlTypePrimitive, .type = kFidlCodedPrimitiveSubtype_Int16};
const struct FidlCodedPrimitive fidl_internal_kInt32Table = {
.tag = kFidlTypePrimitive, .type = kFidlCodedPrimitiveSubtype_Int32};
const struct FidlCodedPrimitive fidl_internal_kInt64Table = {
.tag = kFidlTypePrimitive, .type = kFidlCodedPrimitiveSubtype_Int64};
const struct FidlCodedPrimitive fidl_internal_kUint8Table = {
.tag = kFidlTypePrimitive, .type = kFidlCodedPrimitiveSubtype_Uint8};
const struct FidlCodedPrimitive fidl_internal_kUint16Table = {
.tag = kFidlTypePrimitive, .type = kFidlCodedPrimitiveSubtype_Uint16};
const struct FidlCodedPrimitive fidl_internal_kUint32Table = {
.tag = kFidlTypePrimitive, .type = kFidlCodedPrimitiveSubtype_Uint32};
const struct FidlCodedPrimitive fidl_internal_kUint64Table = {
.tag = kFidlTypePrimitive, .type = kFidlCodedPrimitiveSubtype_Uint64};
const struct FidlCodedPrimitive fidl_internal_kFloat32Table = {
.tag = kFidlTypePrimitive, .type = kFidlCodedPrimitiveSubtype_Float32};
const struct FidlCodedPrimitive fidl_internal_kFloat64Table = {
.tag = kFidlTypePrimitive, .type = kFidlCodedPrimitiveSubtype_Float64};
zx_rights_t subtract_rights(zx_rights_t minuend, zx_rights_t subtrahend) {
return minuend & ~subtrahend;
}
#ifdef __Fuchsia__
zx_status_t FidlEnsureHandleRights(zx_handle_t* handle_ptr, zx_obj_type_t actual_type,
zx_obj_type_t actual_rights, zx_obj_type_t required_object_type,
zx_rights_t required_rights, const char** error) {
// Note: objects returned from the kernel should never have type
// ZX_OBJ_TYPE_NONE, however this is used for backwards compatibility in
// some places.
if (unlikely(required_object_type != actual_type && required_object_type != ZX_OBJ_TYPE_NONE &&
actual_type != ZX_OBJ_TYPE_NONE)) {
zx_handle_close(*handle_ptr);
*handle_ptr = ZX_HANDLE_INVALID;
if (error) {
*error = "object type does not match expected type";
}
return ZX_ERR_INVALID_ARGS;
}
// Special case: ZX_HANDLE_SAME_RIGHTS allows all handles through unchanged.
// Note: objects returned from the kernel should never have rights
// ZX_RIGHT_SAME_RIGHTS, however this is used for backwards compatibility
// in some places.
if (required_rights == ZX_RIGHT_SAME_RIGHTS || actual_rights == ZX_RIGHT_SAME_RIGHTS) {
return ZX_OK;
}
// Check that |actual_rights| contain all of the |required_rights|.
if (unlikely(subtract_rights(required_rights, actual_rights) != 0)) {
zx_handle_close(*handle_ptr);
*handle_ptr = ZX_HANDLE_INVALID;
if (error) {
*error = "missing required rights";
}
return ZX_ERR_INVALID_ARGS;
}
// Check if |actual_rights| has more rights than |required_rights|.
// If so, the rights need to be reduced.
if (unlikely(subtract_rights(actual_rights, required_rights))) {
zx_status_t status = zx_handle_replace(*handle_ptr, required_rights, handle_ptr);
if (unlikely(status != ZX_OK)) {
if (error)
*error = "zx_handle_replace failed";
return status;
}
}
return ZX_OK;
}
#else
zx_status_t FidlEnsureHandleRights(zx_handle_t* handle_ptr, zx_obj_type_t actual_type,
zx_obj_type_t actual_rights, zx_obj_type_t required_object_type,
zx_rights_t required_rights, const char** error) {
ZX_PANIC("handles only supported on fuchsia");
}
#endif
zx_status_t FidlHandleDispositionsToHandleInfos(zx_handle_disposition_t* handle_dispositions,
zx_handle_info_t* handle_infos,
uint32_t num_handles) {
for (size_t i = 0; i < num_handles; i++) {
zx_handle_disposition_t* handle_disposition = &handle_dispositions[i];
if (handle_disposition->operation != ZX_HANDLE_OP_MOVE) {
FidlHandleDispositionCloseMany(handle_dispositions, num_handles);
FidlHandleInfoCloseMany(handle_infos, i);
return ZX_ERR_INVALID_ARGS;
}
if (handle_disposition->result != ZX_OK) {
FidlHandleDispositionCloseMany(handle_dispositions, num_handles);
FidlHandleInfoCloseMany(handle_infos, i);
return ZX_ERR_INVALID_ARGS;
}
#ifdef __Fuchsia__
zx_info_handle_basic_t info;
zx_status_t status = zx_object_get_info(handle_disposition->handle, ZX_INFO_HANDLE_BASIC, &info,
sizeof(info), NULL, NULL);
if (status != ZX_OK) {
FidlHandleDispositionCloseMany(handle_dispositions, num_handles);
FidlHandleInfoCloseMany(handle_infos, i);
return status;
}
zx_handle_t handle = handle_disposition->handle;
handle_disposition->handle = ZX_HANDLE_INVALID;
status = FidlEnsureHandleRights(&handle, info.type, info.rights, handle_disposition->type,
handle_disposition->rights, NULL);
if (status != ZX_OK) {
FidlHandleDispositionCloseMany(handle_dispositions, num_handles);
FidlHandleInfoCloseMany(handle_infos, i);
return status;
}
handle_infos[i].handle = handle;
handle_infos[i].type = info.type;
handle_infos[i].rights = info.rights;
#else
ZX_PANIC("zx_object_get_info unsupported on host");
#endif
}
return ZX_OK;
}