| // Copyright 2020 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/wire.h> |
| #include <fidl/fuchsia.io/cpp/wire_test_base.h> |
| #include <lib/fdio/directory.h> |
| #include <lib/fidl/llcpp/connect_service.h> |
| #include <lib/zx/channel.h> |
| |
| #include <string> |
| |
| #include <fbl/unique_fd.h> |
| |
| #include "src/storage/fs_test/fs_test_fixture.h" |
| #include "src/storage/fs_test/misc.h" |
| |
| namespace fs_test { |
| namespace { |
| |
| namespace fio = fuchsia_io; |
| |
| using OpenTest = FilesystemTest; |
| |
| fidl::ClientEnd<fio::Directory> CreateDirectory(fio::wire::OpenFlags dir_flags, |
| const std::string& path) { |
| EXPECT_EQ(mkdir(path.c_str(), 0755), 0); |
| |
| auto endpoints = fidl::CreateEndpoints<fio::Directory>(); |
| EXPECT_EQ(endpoints.status_value(), ZX_OK); |
| EXPECT_EQ( |
| fdio_open(path.c_str(), static_cast<uint32_t>(dir_flags | fio::wire::OpenFlags::kDirectory), |
| endpoints->server.TakeChannel().release()), |
| ZX_OK); |
| |
| return std::move(endpoints->client); |
| } |
| |
| zx_status_t OpenFileWithCreate(const fidl::ClientEnd<fio::Directory>& dir, |
| const std::string& path) { |
| fio::wire::OpenFlags child_flags = fio::wire::OpenFlags::kCreate | |
| fio::wire::OpenFlags::kRightReadable | |
| fio::wire::OpenFlags::kDescribe; |
| auto child_endpoints = fidl::CreateEndpoints<fio::Node>(); |
| EXPECT_EQ(child_endpoints.status_value(), ZX_OK); |
| auto open_res = fidl::WireCall(dir)->Open(child_flags, fio::wire::kModeTypeFile, |
| fidl::StringView::FromExternal(path), |
| std::move(child_endpoints->server)); |
| EXPECT_EQ(open_res.status(), ZX_OK); |
| auto child = fidl::BindSyncClient(std::move(child_endpoints->client)); |
| |
| class EventHandler : public fidl::testing::WireSyncEventHandlerTestBase<fio::Node> { |
| public: |
| EventHandler() = default; |
| zx_status_t status() const { return status_; } |
| |
| void OnOpen(fidl::WireEvent<fio::Node::OnOpen>* event) override { status_ = event->s; } |
| |
| void NotImplemented_(const std::string& name) override { FAIL() << "Unexpected " << name; } |
| |
| private: |
| zx_status_t status_ = ZX_OK; |
| }; |
| |
| EventHandler event_handler; |
| auto handle_res = child.HandleOneEvent(event_handler); |
| EXPECT_EQ(handle_res.status(), ZX_OK); |
| |
| return event_handler.status(); |
| } |
| |
| TEST_P(OpenTest, OpenFileWithCreateCreatesInReadWriteDir) { |
| fio::wire::OpenFlags flags = |
| fio::wire::OpenFlags::kRightReadable | fio::wire::OpenFlags::kRightWritable; |
| auto parent = CreateDirectory(flags, GetPath("a")); |
| EXPECT_EQ(OpenFileWithCreate(parent, "b"), ZX_OK); |
| } |
| |
| TEST_P(OpenTest, OpenFileWithCreateFailsInReadOnlyDir) { |
| fio::wire::OpenFlags flags = fio::wire::OpenFlags::kRightReadable; |
| auto parent = CreateDirectory(flags, GetPath("a")); |
| EXPECT_EQ(OpenFileWithCreate(parent, "b"), ZX_ERR_ACCESS_DENIED); |
| } |
| |
| TEST_P(OpenTest, OpenFileWithCreateCreatesInReadWriteDirPosixOpen) { |
| // kOpenFlagPosixWritable expand the rights of the directory connection to include write rights if |
| // the parent connection has them. |
| fio::wire::OpenFlags flags = |
| fio::wire::OpenFlags::kRightReadable | fio::wire::OpenFlags::kRightWritable; |
| auto parent = CreateDirectory(flags, GetPath("a")); |
| |
| flags = fio::wire::OpenFlags::kRightReadable | fio::wire::OpenFlags::kPosixWritable | |
| fio::wire::OpenFlags::kDirectory; |
| uint32_t mode = fio::wire::kModeTypeDirectory; |
| std::string path = "."; |
| auto clone_endpoints = fidl::CreateEndpoints<fio::Node>(); |
| ASSERT_EQ(clone_endpoints.status_value(), ZX_OK); |
| auto clone_res = fidl::WireCall(parent)->Open(flags, mode, fidl::StringView::FromExternal(path), |
| std::move(clone_endpoints->server)); |
| ASSERT_EQ(clone_res.status(), ZX_OK); |
| fidl::ClientEnd<fio::Directory> clone_dir(clone_endpoints->client.TakeChannel()); |
| |
| EXPECT_EQ(OpenFileWithCreate(clone_dir, "b"), ZX_OK); |
| } |
| |
| TEST_P(OpenTest, OpenFileWithCreateFailsInReadOnlyDirPosixOpen) { |
| fio::wire::OpenFlags flags = fio::wire::OpenFlags::kRightReadable; |
| auto parent = CreateDirectory(flags, GetPath("a")); |
| |
| flags = fio::wire::OpenFlags::kRightReadable | fio::wire::OpenFlags::kPosixWritable | |
| fio::wire::OpenFlags::kDirectory; |
| uint32_t mode = fio::wire::kModeTypeDirectory; |
| std::string path = "."; |
| auto clone_endpoints = fidl::CreateEndpoints<fio::Node>(); |
| ASSERT_EQ(clone_endpoints.status_value(), ZX_OK); |
| auto clone_res = fidl::WireCall(parent)->Open(flags, mode, fidl::StringView::FromExternal(path), |
| std::move(clone_endpoints->server)); |
| ASSERT_EQ(clone_res.status(), ZX_OK); |
| fidl::ClientEnd<fio::Directory> clone_dir(clone_endpoints->client.TakeChannel()); |
| |
| EXPECT_EQ(OpenFileWithCreate(clone_dir, "b"), ZX_ERR_ACCESS_DENIED); |
| } |
| |
| TEST_P(OpenTest, OpenFileWithCreateFailsInReadWriteDirPosixClone) { |
| // kOpenFlagPosixWritable only does the rights expansion with the open call though. |
| fio::wire::OpenFlags flags = |
| fio::wire::OpenFlags::kRightReadable | fio::wire::OpenFlags::kRightWritable; |
| auto parent = CreateDirectory(flags, GetPath("a")); |
| |
| flags = fio::wire::OpenFlags::kRightReadable | fio::wire::OpenFlags::kPosixWritable | |
| fio::wire::OpenFlags::kDirectory; |
| auto clone_endpoints = fidl::CreateEndpoints<fio::Node>(); |
| ASSERT_EQ(clone_endpoints.status_value(), ZX_OK); |
| auto clone_res = fidl::WireCall(parent)->Clone(flags, std::move(clone_endpoints->server)); |
| ASSERT_EQ(clone_res.status(), ZX_OK); |
| fidl::ClientEnd<fio::Directory> clone_dir(clone_endpoints->client.TakeChannel()); |
| |
| EXPECT_EQ(OpenFileWithCreate(clone_dir, "b"), ZX_ERR_ACCESS_DENIED); |
| } |
| |
| TEST_P(OpenTest, OpenFileWithCreateFailsInReadOnlyDirPosixClone) { |
| fio::wire::OpenFlags flags = fio::wire::OpenFlags::kRightReadable; |
| auto parent = CreateDirectory(flags, GetPath("a")); |
| |
| flags = fio::wire::OpenFlags::kRightReadable | fio::wire::OpenFlags::kPosixWritable | |
| fio::wire::OpenFlags::kDirectory; |
| auto clone_endpoints = fidl::CreateEndpoints<fio::Node>(); |
| ASSERT_EQ(clone_endpoints.status_value(), ZX_OK); |
| auto clone_res = fidl::WireCall(parent)->Clone(flags, std::move(clone_endpoints->server)); |
| ASSERT_EQ(clone_res.status(), ZX_OK); |
| fidl::ClientEnd<fio::Directory> clone_dir(clone_endpoints->client.TakeChannel()); |
| |
| EXPECT_EQ(OpenFileWithCreate(clone_dir, "b"), ZX_ERR_ACCESS_DENIED); |
| } |
| |
| INSTANTIATE_TEST_SUITE_P(/*no prefix*/, OpenTest, testing::ValuesIn(AllTestFilesystems()), |
| testing::PrintToStringParamName()); |
| |
| } // namespace |
| } // namespace fs_test |