blob: 4d6d54246c9b9546d65844faaef3a9fbe4ed893a [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 <fidl/fuchsia.io/cpp/common_types.h>
#include <fidl/fuchsia.io/cpp/wire.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/async-loop/default.h>
#include <lib/fidl/cpp/wire/channel.h>
#include <lib/fidl/cpp/wire/wire_messaging_declarations.h>
#include <lib/sync/completion.h>
#include <lib/zx/result.h>
#include <lib/zx/time.h>
#include <lib/zx/vmo.h>
#include <zircon/errors.h>
#include <zircon/status.h>
#include <zircon/types.h>
#include <memory>
#include <utility>
#include <fbl/ref_ptr.h>
#include <gtest/gtest.h>
#include "src/storage/lib/vfs/cpp/managed_vfs.h"
#include "src/storage/lib/vfs/cpp/vfs_types.h"
namespace {
namespace fio = fuchsia_io;
class TestVNode : public fs::Vnode {
public:
fuchsia_io::NodeProtocolKinds GetProtocols() const final {
return fuchsia_io::NodeProtocolKinds::kFile;
}
zx_status_t GetVmo(fuchsia_io::wire::VmoFlags flags, zx::vmo* out_vmo) override {
zx::vmo vmo;
zx_status_t status = zx::vmo::create(4096, 0u, &vmo);
EXPECT_EQ(status, ZX_OK);
if (status != ZX_OK)
return status;
*out_vmo = std::move(vmo);
return ZX_OK;
}
};
TEST(ConnectionRightsTest, GetBackingMemory) {
async::Loop loop(&kAsyncLoopConfigNoAttachToCurrentThread);
ASSERT_EQ(loop.StartThread(), ZX_OK);
std::unique_ptr<fs::ManagedVfs> vfs = std::make_unique<fs::ManagedVfs>(loop.dispatcher());
struct TestCase {
fio::Flags serve_flags;
fio::VmoFlags get_backing_memory_flags;
zx_status_t result; // What we expect FileGetBuffer to return.
};
TestCase test_data[] = {
// If the connection has all rights, then everything should work.
{
.serve_flags =
fio::Flags::kPermReadBytes | fio::Flags::kPermWriteBytes | fio::Flags::kPermExecute,
.get_backing_memory_flags = fio::wire::VmoFlags::kRead,
.result = ZX_OK,
},
{
.serve_flags =
fio::Flags::kPermReadBytes | fio::Flags::kPermWriteBytes | fio::Flags::kPermExecute,
.get_backing_memory_flags = fio::wire::VmoFlags::kRead | fio::wire::VmoFlags::kWrite,
.result = ZX_OK,
},
{
.serve_flags =
fio::Flags::kPermReadBytes | fio::Flags::kPermWriteBytes | fio::Flags::kPermExecute,
.get_backing_memory_flags = fio::wire::VmoFlags::kRead | fio::wire::VmoFlags::kExecute,
.result = ZX_OK,
},
// If the connection is missing the EXECUTABLE right, then requests with
// fio::wire::VmoFlags::kExecute should fail.
{
.serve_flags = fio::Flags::kPermReadBytes | fio::Flags::kPermWriteBytes,
.get_backing_memory_flags = fio::wire::VmoFlags::kRead | fio::wire::VmoFlags::kExecute,
.result = ZX_ERR_ACCESS_DENIED,
},
// If the connection is missing the WRITABLE right, then requests with
// fio::wire::VmoFlags::kWrite should fail.
{
.serve_flags = fio::Flags::kPermReadBytes | fio::Flags::kPermExecute,
.get_backing_memory_flags = fio::wire::VmoFlags::kRead | fio::wire::VmoFlags::kWrite,
.result = ZX_ERR_ACCESS_DENIED,
},
};
{
auto vnode = fbl::MakeRefCounted<TestVNode>();
for (const auto& test_case : test_data) {
// Set up a vfs connection with the testcase's connection flags
auto file = fidl::Endpoints<fio::File>::Create();
auto serve_result = vfs->Serve(vnode, file.server.TakeChannel(), test_case.serve_flags);
ASSERT_EQ(serve_result, ZX_OK) << zx_status_get_string(serve_result);
// Call FileGetBuffer on the channel with the testcase's request flags. Check that we get the
// expected result.
const fidl::WireResult result =
fidl::WireCall(file.client)->GetBackingMemory(test_case.get_backing_memory_flags);
ASSERT_TRUE(result.ok()) << result.FormatDescription();
const auto& response = result.value();
// Verify that the result matches the value in our test table.
if (test_case.result == ZX_OK) {
EXPECT_TRUE(response.is_ok()) << zx_status_get_string(response.error_value());
} else {
EXPECT_TRUE(response.is_error());
EXPECT_EQ(response.error_value(), test_case.result);
}
}
}
// Tear down the VFS. On completion, it will no longer rely on the async loop. Then, tear down the
// async loop.
sync_completion_t completion;
vfs->Shutdown([&completion](zx_status_t status) {
EXPECT_EQ(status, ZX_OK);
sync_completion_signal(&completion);
});
sync_completion_wait(&completion, zx::time::infinite().get());
loop.Shutdown();
}
} // namespace