blob: b665e730ff6f53666d5566423098f82805c171dd [file] [log] [blame]
// Copyright 2023 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 <fidl/fuchsia.kernel/cpp/fidl.h>
#include <lib/component/incoming/cpp/protocol.h>
#include <lib/zx/channel.h>
#include <lib/zx/vmo.h>
#include <lib/zxio/cpp/create_with_type.h>
#include <lib/zxio/zxio.h>
#include <limits.h>
#include <zircon/compiler.h>
#include <zxtest/zxtest.h>
namespace {
constexpr size_t kSize = 300;
constexpr zx_off_t kInitialSeek = 4;
constexpr const char* ALPHABET = "abcdefghijklmnopqrstuvwxyz";
void GetVmo(zx::vmo& backing) {
ASSERT_OK(zx::vmo::create(kSize, 0u, &backing));
size_t len = strlen(ALPHABET);
ASSERT_OK(backing.write(ALPHABET, 0, len));
ASSERT_OK(backing.write(ALPHABET, len, len + len));
}
TEST(VmoTest, FlagsGetReadWrite) {
zx::vmo backing;
ASSERT_NO_FAILURES(GetVmo(backing));
zx::stream stream;
ASSERT_OK(zx::stream::create(ZX_STREAM_MODE_READ | ZX_STREAM_MODE_WRITE, backing, kInitialSeek,
&stream));
zxio_storage_t storage;
ASSERT_OK(zxio::CreateVmo(&storage, std::move(backing), std::move(stream)));
zxio_t* io = &storage.io;
uint32_t raw_flags{};
ASSERT_STATUS(ZX_OK, zxio_flags_get(io, &raw_flags));
fuchsia_io::wire::OpenFlags flags{raw_flags};
EXPECT_TRUE(flags & fuchsia_io::wire::OpenFlags::kRightReadable);
EXPECT_TRUE(flags & fuchsia_io::wire::OpenFlags::kRightWritable);
EXPECT_FALSE(flags & fuchsia_io::wire::OpenFlags::kRightExecutable);
ASSERT_OK(zxio_close(io, /*should_wait=*/true));
}
TEST(VmoTest, FlagsGetReadOnly) {
zx::vmo ro_vmo;
// Get a read only vmo.
{
zx::vmo rw_vmo;
ASSERT_NO_FAILURES(GetVmo(rw_vmo));
zx_info_handle_basic_t info;
ASSERT_OK(rw_vmo.get_info(ZX_INFO_HANDLE_BASIC, &info, sizeof(info), nullptr, nullptr));
ASSERT_OK(rw_vmo.duplicate(info.rights & ~ZX_RIGHT_WRITE, &ro_vmo));
}
zx::stream ro_stream;
ASSERT_OK(zx::stream::create(ZX_STREAM_MODE_READ, ro_vmo, kInitialSeek, &ro_stream));
zxio_storage_t storage;
ASSERT_OK(zxio::CreateVmo(&storage, std::move(ro_vmo), std::move(ro_stream)));
zxio_t* io = &storage.io;
uint32_t raw_flags{};
ASSERT_STATUS(ZX_OK, zxio_flags_get(io, &raw_flags));
fuchsia_io::wire::OpenFlags flags{raw_flags};
EXPECT_TRUE(flags & fuchsia_io::wire::OpenFlags::kRightReadable);
EXPECT_FALSE(flags & fuchsia_io::wire::OpenFlags::kRightWritable);
EXPECT_FALSE(flags & fuchsia_io::wire::OpenFlags::kRightExecutable);
ASSERT_OK(zxio_close(io, /*should_wait=*/true));
}
TEST(VmoTest, FlagsGetReadExec) {
zx::vmo exec_vmo;
// Get a read + exec vmo.
{
zx::vmo rw_vmo;
ASSERT_NO_FAILURES(GetVmo(rw_vmo));
zx_info_handle_basic_t info;
ASSERT_OK(rw_vmo.get_info(ZX_INFO_HANDLE_BASIC, &info, sizeof(info), nullptr, nullptr));
zx::vmo ro_vmo;
ASSERT_OK(rw_vmo.duplicate(info.rights & ~ZX_RIGHT_WRITE, &ro_vmo));
zx::result vmex_getter = component::Connect<fuchsia_kernel::VmexResource>();
ASSERT_OK(vmex_getter.status_value());
fit::result vmex_result = fidl::Call(*vmex_getter)->Get();
ASSERT_TRUE(vmex_result.is_ok(), "%s", vmex_result.error_value().FormatDescription().c_str());
zx::resource vmex = std::move(vmex_result.value().resource());
ASSERT_OK(ro_vmo.replace_as_executable(vmex, &exec_vmo));
}
zx::stream exec_stream;
ASSERT_OK(zx::stream::create(ZX_STREAM_MODE_READ, exec_vmo, kInitialSeek, &exec_stream));
zxio_storage_t storage_for_exec;
ASSERT_OK(zxio::CreateVmo(&storage_for_exec, std::move(exec_vmo), std::move(exec_stream)));
zxio_t* exec_io = &storage_for_exec.io;
uint32_t raw_flags{};
ASSERT_STATUS(ZX_OK, zxio_flags_get(exec_io, &raw_flags));
fuchsia_io::wire::OpenFlags flags{raw_flags};
EXPECT_TRUE(flags & fuchsia_io::wire::OpenFlags::kRightReadable);
EXPECT_FALSE(flags & fuchsia_io::wire::OpenFlags::kRightWritable);
EXPECT_TRUE(flags & fuchsia_io::wire::OpenFlags::kRightExecutable);
ASSERT_OK(zxio_close(exec_io, /*should_wait=*/true));
}
} // namespace