blob: 0bf12dbb8f1304bcffb40d9f6d24681010043c47 [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.
#ifndef __CORE_TEST_OBJECT_INFO_HELPER_H__
#define __CORE_TEST_OBJECT_INFO_HELPER_H__
#include <lib/zx/process.h>
#include <lib/zx/vmo.h>
#include <zircon/syscalls/object.h>
#include <cinttypes>
#include <climits>
#include <type_traits>
#include <fbl/auto_call.h>
#include <zxtest/zxtest.h>
namespace object_info_test {
// Cannot obtain information about self, since the buffer lives within the same address space
// being inspected.
template <typename EntryType, typename HandleType>
void CheckSelfInfoFails(zx_object_info_topic_t topic, uint32_t entry_count,
const HandleType& self) {
EntryType entries[entry_count];
size_t actual;
size_t avail;
ASSERT_EQ(self.get_info(topic, entries, sizeof(EntryType) * entry_count, &actual, &avail),
ZX_ERR_ACCESS_DENIED);
}
template <typename EntryType, typename HandleType>
void CheckSelfInfoSuceeds(zx_object_info_topic_t topic, uint32_t entry_count,
const HandleType& self) {
EntryType entries[entry_count];
size_t actual;
size_t avail;
ASSERT_OK(self.get_info(topic, entries, sizeof(EntryType) * entry_count, &actual, &avail));
}
// Invalid handles should fail.
template <typename EntryType, typename HandleProvider>
void CheckInvalidHandleFails(zx_object_info_topic_t topic, uint32_t entry_count,
const HandleProvider& provider) {
EntryType entries[entry_count];
size_t actual;
size_t avail;
typename std::remove_reference<typename std::result_of<HandleProvider()>::type>::type handle;
ASSERT_EQ(handle.get_info(topic, entries, sizeof(EntryType) * entry_count, &actual, &avail),
ZX_ERR_BAD_HANDLE);
}
// Call should fail if the handle type does not support the requested topic.
template <typename EntryType, typename HandleProvider>
void CheckWrongHandleTypeFails(zx_object_info_topic_t topic, uint32_t entry_count,
const HandleProvider& provider) {
EntryType entries[entry_count];
size_t actual;
size_t avail;
const auto& handle = provider();
ASSERT_NOT_OK(handle.get_info(topic, entries, sizeof(EntryType) * entry_count, &actual, &avail));
}
// Call should succeed with the default rights.
template <typename EntryType, typename HandleProvider>
void CheckDefaultRightsSucceed(zx_object_info_topic_t topic, uint32_t entry_count,
zx_rights_t missing_rights, const HandleProvider& provider) {
const auto& handle = provider();
EntryType entries[entry_count];
size_t actual;
size_t avail;
ASSERT_OK(handle.get_info(topic, entries, sizeof(EntryType) * entry_count, &actual, &avail));
}
// Calls without enough rights, should fail with ZX_ERR_ACCESS_DENIED
template <typename EntryType, typename HandleProvider>
void CheckMissingRightsFail(zx_object_info_topic_t topic, uint32_t entry_count,
zx_rights_t missing_rights, const HandleProvider& provider) {
const auto& handle = provider();
EntryType entries[entry_count];
size_t actual;
size_t avail;
// Verify handle rights are present.
zx_info_handle_basic_t handle_info;
ASSERT_OK(
handle.get_info(ZX_INFO_HANDLE_BASIC, &handle_info, sizeof(handle_info), nullptr, nullptr));
ASSERT_EQ(handle_info.rights & missing_rights, missing_rights, "rights 0x%" PRIx32,
handle_info.rights);
// Create a handle without the important rights.
typename std::remove_cv<typename std::remove_reference<decltype(handle)>::type>::type
unpriviledged_handle;
ASSERT_OK(handle.duplicate(handle_info.rights & ~missing_rights, &unpriviledged_handle));
// Call should fail without these rights.
EXPECT_EQ(unpriviledged_handle.get_info(topic, entries, sizeof(EntryType) * entry_count, &actual,
&avail),
ZX_ERR_ACCESS_DENIED);
}
// Passing a zero-sized buffer to a topic that expects a single
// in/out entry should fail.
template <typename EntryType, typename HandleProvider>
void CheckZeroSizeBufferFails(zx_object_info_topic_t topic, const HandleProvider& provider) {
EntryType entry;
const auto& handle = provider();
size_t actual;
size_t avail;
EXPECT_EQ(handle.get_info(topic,
&entry, // buffer
0, // len
&actual, &avail),
ZX_ERR_BUFFER_TOO_SMALL);
EXPECT_EQ(0u, actual);
EXPECT_GT(avail, 0u);
}
// Passing a zero-sized buffer to a topic that expects a multiple
// in/out entry should succeed.
template <typename EntryType, typename HandleProvider>
void CheckZeroSizeBufferSucceeds(zx_object_info_topic_t topic, const HandleProvider& provider) {
EntryType entry;
const auto& handle = provider();
size_t actual;
size_t avail;
EXPECT_OK(handle.get_info(topic,
&entry, // buffer
0, // len
&actual, &avail));
EXPECT_EQ(0u, actual);
EXPECT_GT(avail, 0u);
}
// Passing a nullptr buffer to a topic that expects a single
// in/out entry should fail.
template <typename HandleProvider>
void CheckNullBufferSuceeds(zx_object_info_topic_t topic, const HandleProvider& provider) {
const auto& handle = provider();
size_t actual;
size_t avail;
EXPECT_OK(handle.get_info(topic,
nullptr, // buffer
0, // len
&actual, &avail));
EXPECT_EQ(0u, actual);
EXPECT_GT(avail, 0u);
}
// Passing a buffer shorter than avail should succeed.
template <typename EntryType, typename HandleProvider>
void CheckSmallBufferSucceeds(zx_object_info_topic_t topic, uint32_t entry_count,
const HandleProvider& provider) {
EntryType entries[entry_count];
size_t actual;
size_t avail;
const auto& handle = provider();
EXPECT_OK(handle.get_info(topic, entries, sizeof(EntryType) * entry_count, &actual, &avail));
EXPECT_EQ(1u, actual);
EXPECT_GT(avail, actual);
}
template <typename EntryType, typename HandleProvider>
void CheckNullActualSuceeds(zx_object_info_topic_t topic, uint32_t entry_count,
const HandleProvider& provider) {
EntryType entries[entry_count];
const auto& handle = provider();
size_t tmp;
ASSERT_OK(handle.get_info(topic, entries, sizeof(EntryType) * entry_count, nullptr, &tmp));
}
template <typename EntryType, typename HandleProvider>
void CheckNullAvailSuceeds(zx_object_info_topic_t topic, uint32_t entry_count,
const HandleProvider& provider) {
EntryType entries[entry_count];
const auto& handle = provider();
size_t tmp;
ASSERT_OK(handle.get_info(topic, entries, sizeof(EntryType) * entry_count, &tmp, nullptr));
}
template <typename EntryType, typename HandleProvider>
void CheckNullActualAndAvailSuceeds(zx_object_info_topic_t topic, uint32_t entry_count,
const HandleProvider& provider) {
EntryType entries[entry_count];
const auto& handle = provider();
ASSERT_OK(handle.get_info(topic, entries, sizeof(EntryType) * entry_count, nullptr, nullptr));
}
template <typename EntryType, typename HandleProvider>
void CheckInvalidBufferPointerFails(zx_object_info_topic_t topic, const HandleProvider& provider) {
const auto& handle = provider();
size_t actual;
size_t avail;
EXPECT_EQ(handle.get_info(topic, (EntryType*)1, sizeof(EntryType), &actual, &avail),
ZX_ERR_INVALID_ARGS);
}
template <typename EntryType, typename HandleProvider>
void CheckPartiallyUnmappedBufferIsError(zx_object_info_topic_t topic,
const HandleProvider& provider, zx_status_t error_status) {
// Create a two-page VMAR.
zx::vmar vmar;
uintptr_t vmar_addr;
const auto& handle = provider();
ASSERT_OK(zx::vmar::root_self()->allocate2(
ZX_VM_CAN_MAP_READ | ZX_VM_CAN_MAP_WRITE | ZX_VM_CAN_MAP_SPECIFIC, 0, 2 * PAGE_SIZE, &vmar,
&vmar_addr));
// Create a one-page VMO.
zx::vmo vmo;
ASSERT_OK(zx::vmo::create(PAGE_SIZE, 0u, &vmo));
// Map the first page of the VMAR.
uintptr_t vmo_addr;
ASSERT_OK(vmar.map(ZX_VM_SPECIFIC | ZX_VM_PERM_READ | ZX_VM_PERM_WRITE, 0, vmo, 0, PAGE_SIZE,
&vmo_addr));
// Once mapped, we need to destroy it before closing the handle.
auto cleanup = fbl::MakeAutoCall([&vmar]() { vmar.destroy(); });
ASSERT_EQ(vmar_addr, vmo_addr);
// Point to a spot in the mapped page just before the unmapped region:
// the first entry will hit mapped memory, the second entry will hit
// unmapped memory.
EntryType* entries = (EntryType*)(vmo_addr + PAGE_SIZE) - 1;
size_t actual;
size_t avail;
EXPECT_STATUS(handle.get_info(topic, entries, sizeof(EntryType) * 4, &actual, &avail),
error_status);
vmar.destroy();
}
template <typename EntryType, typename HandleProvider>
void BadActualIsInvalidArgs(zx_object_info_topic_t topic, size_t entry_count,
const HandleProvider& provider) {
const auto& handle = provider();
EntryType entries[entry_count];
size_t avail;
EXPECT_EQ(handle.get_info(topic, entries, sizeof(EntryType) * entry_count,
// Bad actual pointer value.
reinterpret_cast<size_t*>(1), &avail),
ZX_ERR_INVALID_ARGS);
}
template <typename EntryType, typename HandleProvider>
void BadAvailIsInvalidArgs(zx_object_info_topic_t topic, size_t entry_count,
const HandleProvider& provider) {
const auto& handle = provider();
EntryType entries[entry_count];
size_t actual;
EXPECT_EQ(handle.get_info(topic, entries, sizeof(EntryType) * entry_count, &actual,
// Bad actual pointer value.
reinterpret_cast<size_t*>(1)),
ZX_ERR_INVALID_ARGS);
}
} // namespace object_info_test
#endif