blob: 851cbc144507d8b394c771373d5b9f8832c6b082 [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/fit/function.h>
#include <lib/zx/job.h>
#include <lib/zx/process.h>
#include <lib/zx/thread.h>
#include <lib/zx/vmar.h>
#include <lib/zx/vmo.h>
#include <zircon/syscalls/object.h>
#include <memory>
#include <string_view>
#include <utility>
#include <fbl/vector.h>
#include <zxtest/zxtest.h>
#include "helper.h"
namespace object_info_test {
namespace {
// ZX_INFO_JOB_PROCESS/ZX_INFO_JOB_CHILDREN tests
constexpr size_t kChildProcs = 3;
constexpr size_t kChildJobs = 2;
constexpr std::string_view kChildrenName = "child";
constexpr std::string_view kGrandChildrenName = "grandchild";
// Sets out_job to point towards the singleton instance of a job:
// - returned job
// - child process 1
// - child process 2
// - child process 3 (kChildProcs)
// - child job 1
// - grandchild process 1.1
// - grandchild job 1.1
// - child job 2 (kChildJobs)
// - grandchild process 2.1
// - grandchild job 2.1
class JobFixutre : public zxtest::Test {
public:
static void SetUpTestSuite() {
ASSERT_OK(zx::job::create(*zx::job::default_job(), 0, &root_), "Failed to create job.");
for (size_t i = 0; i < kChildProcs; ++i) {
zx::process process;
zx::vmar vmar;
ASSERT_OK(zx::process::create(root_, kChildrenName.data(), kChildrenName.size(), 0, &process,
&vmar),
"Failed to create %zu child", i);
child_processes_.push_back(std::move(process));
vmar_.push_back(std::move(vmar));
}
for (size_t i = 0; i < kChildJobs; ++i) {
zx::job job;
ASSERT_OK(zx::job::create(root_, 0, &job), "Failed to create %zu job", i);
zx::process process;
zx::vmar vmar;
ASSERT_OK(zx::process::create(job, kGrandChildrenName.data(), kGrandChildrenName.size(), 0,
&process, &vmar),
"Failed to create %zu process grandchild", i);
zx::job subjob;
ASSERT_OK(zx::job::create(job, 0, &subjob), "Failed to create grandchild %zu job", i);
child_jobs_.push_back(std::move(job));
child_processes_.push_back(std::move(process));
vmar_.push_back(std::move(vmar));
child_jobs_.push_back(std::move(subjob));
}
ASSERT_TRUE(root_.is_valid());
}
// Clean up job handles.
static void TearDownTestSuite() {
vmar_.reset();
for (auto& vmar : vmar_) {
vmar.destroy();
}
child_processes_.reset();
for (auto& proc : child_processes_) {
proc.kill();
}
for (auto& job : child_jobs_) {
job.kill();
}
child_jobs_.reset();
root_.kill();
root_.reset();
}
const zx::job& GetJob() { return root_; }
const auto& GetHandleProvider() const { return handle_provider; }
private:
static zx::job root_;
static fbl::Vector<zx::vmar> vmar_;
static fbl::Vector<zx::process> child_processes_;
static fbl::Vector<zx::job> child_jobs_;
fit::function<const zx::job&()> handle_provider = [this]() -> const zx::job& { return GetJob(); };
};
zx::job JobFixutre::root_;
fbl::Vector<zx::vmar> JobFixutre::vmar_;
fbl::Vector<zx::process> JobFixutre::child_processes_;
fbl::Vector<zx::job> JobFixutre::child_jobs_;
constexpr int kChildCount = 32;
// The jobch_helper_* (job child helper) functions allow testing both
// ZX_INFO_JOB_PROCESS and ZX_INFO_JOB_CHILDREN.
void CheckJobGetChild(const zx::job* job, uint32_t topic, size_t object_count,
size_t expected_count) {
zx_koid_t koids[object_count];
size_t actual;
size_t available;
ASSERT_OK(job->get_info(topic, koids, sizeof(zx_koid_t) * object_count, &actual, &available));
EXPECT_EQ(expected_count, actual);
EXPECT_EQ(expected_count, available);
// All returned koids should produce a valid handle when passed to
// zx_object_get_child.
for (size_t i = 0; i < actual; i++) {
zx::job child;
EXPECT_OK(job->get_child(koids[i], ZX_RIGHT_SAME_RIGHTS, &child), "koid %zu", koids[i]);
}
}
using JobGetInfoTest = JobFixutre;
constexpr auto process_provider = []() -> const zx::process& {
static const zx::unowned_process process = zx::process::self();
return *process;
};
constexpr auto job_provider = []() -> const zx::job& {
const static zx::unowned_job job = zx::job::default_job();
return *job;
};
constexpr auto thread_provider = []() -> const zx::thread& {
const static zx::unowned_thread thread = zx::thread::self();
return *thread;
};
TEST_F(JobGetInfoTest, InfoJobProcessesGetChild) {
ASSERT_NO_FATAL_FAILURE(
CheckJobGetChild(&GetJob(), ZX_INFO_JOB_PROCESSES, kChildCount, kChildProcs));
}
TEST_F(JobGetInfoTest, InfoJobChildJobsGetChild) {
ASSERT_NO_FATAL_FAILURE(
CheckJobGetChild(&GetJob(), ZX_INFO_JOB_CHILDREN, kChildCount, kChildJobs));
}
TEST_F(JobGetInfoTest, InfoJobProcessesOnSelfSuceeds) {
ASSERT_NO_FATAL_FAILURE(
(CheckSelfInfoSuceeds<zx_koid_t>(ZX_INFO_JOB_PROCESSES, 1, job_provider())));
}
TEST_F(JobGetInfoTest, InfoJobProcessesInvalidHandleFails) {
ASSERT_NO_FATAL_FAILURE(
(CheckInvalidHandleFails<zx_koid_t>(ZX_INFO_JOB_PROCESSES, 1, GetHandleProvider())));
}
TEST_F(JobGetInfoTest, InfoJobProcessesNullAvailSucceeds) {
ASSERT_NO_FATAL_FAILURE(
(CheckNullAvailSuceeds<zx_koid_t>(ZX_INFO_JOB_PROCESSES, 1, GetHandleProvider())));
}
TEST_F(JobGetInfoTest, InfoJobProcessesNullActualSucceeds) {
ASSERT_NO_FATAL_FAILURE(
(CheckNullActualSuceeds<zx_koid_t>(ZX_INFO_JOB_PROCESSES, 1, GetHandleProvider())));
}
TEST_F(JobGetInfoTest, InfoJobProcessesNullActualAndAvailSucceeds) {
ASSERT_NO_FATAL_FAILURE(
(CheckNullActualAndAvailSuceeds<zx_koid_t>(ZX_INFO_JOB_PROCESSES, 1, GetHandleProvider())));
}
TEST_F(JobGetInfoTest, InfoJobProcessesInvalidBufferPointerFails) {
ASSERT_NO_FATAL_FAILURE(
(CheckNullActualSuceeds<zx_koid_t>(ZX_INFO_JOB_PROCESSES, 1, GetHandleProvider())));
}
TEST_F(JobGetInfoTest, InfoJobProcessesBadActualgIsInvalidArg) {
ASSERT_NO_FATAL_FAILURE(
(CheckNullActualSuceeds<zx_koid_t>(ZX_INFO_JOB_PROCESSES, 1, GetHandleProvider())));
}
TEST_F(JobGetInfoTest, InfoJobProcessesBadAvailIsInvalidArg) {
ASSERT_NO_FATAL_FAILURE(
(CheckNullActualSuceeds<zx_koid_t>(ZX_INFO_JOB_PROCESSES, 1, GetHandleProvider())));
}
TEST_F(JobGetInfoTest, InfoJobProcessesZeroSizedBufferIsOk) {
ASSERT_NO_FATAL_FAILURE(
(CheckZeroSizeBufferSucceeds<zx_koid_t>(ZX_INFO_JOB_PROCESSES, GetHandleProvider())));
}
TEST_F(JobGetInfoTest, InfoJobProcessesSmallBufferIsOk) {
// We use only one entry count, because we know that the process created at the fixture has more
// mappings.
ASSERT_NO_FATAL_FAILURE(
(CheckSmallBufferSucceeds<zx_koid_t>(ZX_INFO_JOB_PROCESSES, 1, GetHandleProvider())));
}
TEST_F(JobGetInfoTest, InfoJobProcessesPartiallyUnmappedBufferIsInvalidArgs) {
ASSERT_NO_FATAL_FAILURE((CheckPartiallyUnmappedBufferIsError<zx_koid_t>(
ZX_INFO_JOB_PROCESSES, GetHandleProvider(), ZX_ERR_INVALID_ARGS)));
}
TEST_F(JobGetInfoTest, InfoJobProcessesRequiresEnumerateRights) {
ASSERT_NO_FATAL_FAILURE(CheckMissingRightsFail<zx_koid_t>(
ZX_INFO_JOB_PROCESSES, 32, ZX_RIGHT_ENUMERATE, GetHandleProvider()));
}
TEST_F(JobGetInfoTest, InfoJobProcessesProcessbHandleIsBadHandle) {
ASSERT_NO_FATAL_FAILURE(
CheckWrongHandleTypeFails<zx_koid_t>(ZX_INFO_JOB_PROCESSES, 32, process_provider));
}
TEST_F(JobGetInfoTest, InfoJobProcessesThreadHandleIsBadHandle) {
ASSERT_NO_FATAL_FAILURE(
CheckWrongHandleTypeFails<zx_koid_t>(ZX_INFO_JOB_PROCESSES, 32, thread_provider));
}
TEST_F(JobGetInfoTest, InfoJobChildrenOnSelfSuceeds) {
ASSERT_NO_FATAL_FAILURE(
(CheckSelfInfoSuceeds<zx_koid_t>(ZX_INFO_JOB_CHILDREN, 1, job_provider())));
}
TEST_F(JobGetInfoTest, InfoJobChildrenInvalidHandleFails) {
ASSERT_NO_FATAL_FAILURE(
(CheckInvalidHandleFails<zx_koid_t>(ZX_INFO_JOB_CHILDREN, 1, GetHandleProvider())));
}
TEST_F(JobGetInfoTest, InfoJobChildrenNullAvailSucceeds) {
ASSERT_NO_FATAL_FAILURE(
(CheckNullAvailSuceeds<zx_koid_t>(ZX_INFO_JOB_CHILDREN, 1, GetHandleProvider())));
}
TEST_F(JobGetInfoTest, InfoJobChildrenNullActualSucceeds) {
ASSERT_NO_FATAL_FAILURE(
(CheckNullActualSuceeds<zx_koid_t>(ZX_INFO_JOB_CHILDREN, 1, GetHandleProvider())));
}
TEST_F(JobGetInfoTest, InfoJobChildrenNullActualAndAvailSucceeds) {
ASSERT_NO_FATAL_FAILURE(
(CheckNullActualAndAvailSuceeds<zx_koid_t>(ZX_INFO_JOB_CHILDREN, 1, GetHandleProvider())));
}
TEST_F(JobGetInfoTest, InfoJobChildrenInvalidBufferPointerFails) {
ASSERT_NO_FATAL_FAILURE(
(CheckNullActualSuceeds<zx_koid_t>(ZX_INFO_JOB_CHILDREN, 1, GetHandleProvider())));
}
TEST_F(JobGetInfoTest, InfoJobChildrenBadActualgIsInvalidArg) {
ASSERT_NO_FATAL_FAILURE(
(CheckNullActualSuceeds<zx_koid_t>(ZX_INFO_JOB_CHILDREN, 1, GetHandleProvider())));
}
TEST_F(JobGetInfoTest, InfoJobChildrenBadAvailIsInvalidArg) {
ASSERT_NO_FATAL_FAILURE(
(CheckNullActualSuceeds<zx_koid_t>(ZX_INFO_JOB_CHILDREN, 1, GetHandleProvider())));
}
TEST_F(JobGetInfoTest, InfoJobChildrenZeroSizedBufferIsOk) {
ASSERT_NO_FATAL_FAILURE(
(CheckZeroSizeBufferSucceeds<zx_koid_t>(ZX_INFO_JOB_CHILDREN, GetHandleProvider())));
}
TEST_F(JobGetInfoTest, InfoJobChildrenSmallBufferIsOk) {
// We use only one entry count, because we know that the process created at the fixture has more
// mappings.
ASSERT_NO_FATAL_FAILURE(
(CheckSmallBufferSucceeds<zx_koid_t>(ZX_INFO_JOB_CHILDREN, 1, GetHandleProvider())));
}
TEST_F(JobGetInfoTest, InfoJobChildrenPartiallyUnmappedBufferIsInvalidArgs) {
ASSERT_NO_FATAL_FAILURE((CheckPartiallyUnmappedBufferIsError<zx_koid_t>(
ZX_INFO_JOB_CHILDREN, GetHandleProvider(), ZX_ERR_INVALID_ARGS)));
}
TEST_F(JobGetInfoTest, InfoJobChildrenRequiresEnumerateRights) {
ASSERT_NO_FATAL_FAILURE(CheckMissingRightsFail<zx_koid_t>(
ZX_INFO_JOB_CHILDREN, 32, ZX_RIGHT_ENUMERATE, GetHandleProvider()));
}
TEST_F(JobGetInfoTest, InfoJobChildrenJobHandleIsBadHandle) {
ASSERT_NO_FATAL_FAILURE(
CheckWrongHandleTypeFails<zx_koid_t>(ZX_INFO_JOB_CHILDREN, 32, process_provider));
}
TEST_F(JobGetInfoTest, InfoJobChildrenThreadHandleIsBadHandle) {
ASSERT_NO_FATAL_FAILURE(
CheckWrongHandleTypeFails<zx_koid_t>(ZX_INFO_JOB_CHILDREN, 32, thread_provider));
}
TEST_F(JobGetInfoTest, InfoHandleBasicOnSelfSuceeds) {
ASSERT_NO_FATAL_FAILURE(
(CheckSelfInfoSuceeds<zx_info_handle_basic_t>(ZX_INFO_HANDLE_BASIC, 1, job_provider())));
}
TEST_F(JobGetInfoTest, InfoHandleBasicInvalidHandleFails) {
ASSERT_NO_FATAL_FAILURE((CheckInvalidHandleFails<zx_info_handle_basic_t>(ZX_INFO_HANDLE_BASIC, 1,
GetHandleProvider())));
}
TEST_F(JobGetInfoTest, InfoHandleBasicNullAvailSucceeds) {
ASSERT_NO_FATAL_FAILURE((
CheckNullAvailSuceeds<zx_info_handle_basic_t>(ZX_INFO_HANDLE_BASIC, 1, GetHandleProvider())));
}
TEST_F(JobGetInfoTest, InfoHandleBasicNullActualSucceeds) {
ASSERT_NO_FATAL_FAILURE((CheckNullActualSuceeds<zx_info_handle_basic_t>(ZX_INFO_HANDLE_BASIC, 1,
GetHandleProvider())));
}
TEST_F(JobGetInfoTest, InfoHandleBasicNullActualAndAvailSucceeds) {
ASSERT_NO_FATAL_FAILURE((CheckNullActualAndAvailSuceeds<zx_info_handle_basic_t>(
ZX_INFO_HANDLE_BASIC, 1, GetHandleProvider())));
}
TEST_F(JobGetInfoTest, InfoHandleBasicInvalidBufferPointerFails) {
ASSERT_NO_FATAL_FAILURE((CheckNullActualSuceeds<zx_info_handle_basic_t>(ZX_INFO_HANDLE_BASIC, 1,
GetHandleProvider())));
}
TEST_F(JobGetInfoTest, InfoHandleBasicBadActualgIsInvalidArg) {
ASSERT_NO_FATAL_FAILURE((CheckNullActualSuceeds<zx_info_handle_basic_t>(ZX_INFO_HANDLE_BASIC, 1,
GetHandleProvider())));
}
TEST_F(JobGetInfoTest, InfoHandleBasicBadAvailIsInvalidArg) {
ASSERT_NO_FATAL_FAILURE((CheckNullActualSuceeds<zx_info_handle_basic_t>(ZX_INFO_HANDLE_BASIC, 1,
GetHandleProvider())));
}
TEST_F(JobGetInfoTest, InfoHandleBasicZeroSizedBufferFails) {
ASSERT_NO_FATAL_FAILURE((
CheckZeroSizeBufferFails<zx_info_handle_basic_t>(ZX_INFO_HANDLE_BASIC, GetHandleProvider())));
}
} // namespace
} // namespace object_info_test