0

[Fuchsia] Rewrite OpenDirectory to take rights

This allows OpenDirectory to be used to open directories that are
neither readable nor writable but still enumerable such as /svc.

See fuchsia.io/Operations for more detail:
https://fuchsia.dev/reference/fidl/fuchsia.io#Operations.

Bug: fuchsia:101092
Change-Id: I72f64a39eac6c749ff856e37836b9fd7bb76cac6
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4645810
Reviewed-by: Wez <wez@chromium.org>
Owners-Override: Wez <wez@chromium.org>
Commit-Queue: Tamir Duberstein <tamird@google.com>
Commit-Queue: Wez <wez@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1164060}
This commit is contained in:
Tamir Duberstein
2023-06-29 12:09:35 +00:00
committed by Chromium LUCI CQ
parent e0bcd2bf0f
commit 294abf2972
24 changed files with 219 additions and 179 deletions

@ -14,6 +14,14 @@
#include "base/threading/scoped_blocking_call.h"
#include "build/build_config.h"
#if BUILDFLAG(IS_FUCHSIA)
#include <fuchsia/io/cpp/fidl.h>
#include <lib/fdio/directory.h>
#include <zircon/errors.h>
#include "base/files/scoped_file.h"
#endif
namespace base {
namespace {
@ -155,7 +163,40 @@ FilePath FileEnumerator::Next() {
root_path_ = root_path_.StripTrailingSeparators();
pending_paths_.pop();
#if BUILDFLAG(IS_FUCHSIA)
// Fuchsia directories can be enumerable without being readable; open
// without fuchsia.io/OpenFlags.RIGHT_READABLE to avoid spurious failures.
//
// TODO(https://crbug.com/1457942): Remove this workaround once opendir no
// longer requires READABLE.
ScopedFD fd;
if (zx_status_t status = fdio_open_fd(
root_path_.value().c_str(),
static_cast<uint32_t>(fuchsia::io::OpenFlags::DIRECTORY),
ScopedFD::Receiver(fd).get());
status != ZX_OK) {
if (error_policy_ == ErrorPolicy::IGNORE_ERRORS) {
continue;
}
auto status_to_file_error = [](zx_status_t status) {
switch (status) {
case ZX_ERR_NOT_FOUND:
return File::FILE_ERROR_NOT_FOUND;
case ZX_ERR_ACCESS_DENIED:
return File::FILE_ERROR_ACCESS_DENIED;
case ZX_ERR_NOT_DIR:
return File::FILE_ERROR_NOT_A_DIRECTORY;
default:
return File::FILE_ERROR_FAILED;
}
};
error_ = status_to_file_error(status);
return FilePath();
}
DIR* dir = fdopendir(fd.release());
#else
DIR* dir = opendir(root_path_.value().c_str());
#endif
if (!dir) {
if (errno == 0 || error_policy_ == ErrorPolicy::IGNORE_ERRORS)
continue;

@ -4,59 +4,56 @@
#include "base/fuchsia/file_utils.h"
#include <fcntl.h>
#include <fuchsia/io/cpp/fidl.h>
#include <lib/fdio/directory.h>
#include <lib/fdio/fd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <tuple>
#include <utility>
#include "base/files/scoped_file.h"
#include "base/fuchsia/fuchsia_logging.h"
namespace base {
namespace {
fidl::InterfaceHandle<::fuchsia::io::Directory> OpenDirectoryHandleInternal(
fidl::InterfaceHandle<::fuchsia::io::Directory> OpenDirectoryHandle(
const base::FilePath& path,
bool read_only) {
ScopedFD fd(open(path.value().c_str(),
O_DIRECTORY | (read_only ? O_RDONLY : O_RDWR)));
if (!fd.is_valid()) {
DPLOG(ERROR) << "Failed to open " << path;
return fidl::InterfaceHandle<::fuchsia::io::Directory>();
DirectoryHandleRights rights) {
fuchsia::io::OpenFlags open_flags = fuchsia::io::OpenFlags::DIRECTORY;
if (rights.readable) {
open_flags |= fuchsia::io::OpenFlags::RIGHT_READABLE;
}
if (rights.writable) {
open_flags |= fuchsia::io::OpenFlags::RIGHT_WRITABLE;
}
if (rights.executable) {
open_flags |= fuchsia::io::OpenFlags::RIGHT_EXECUTABLE;
}
const uint32_t flags = static_cast<uint32_t>(open_flags);
ScopedFD fd;
if (zx_status_t status = fdio_open_fd(path.value().c_str(), flags,
base::ScopedFD::Receiver(fd).get());
status != ZX_OK) {
ZX_DLOG(ERROR, status) << "fdio_open_fd(" << path << ", "
<< std::bitset<32>{flags} << ")";
return {};
}
zx::channel channel;
zx_status_t status =
fdio_fd_transfer(fd.get(), channel.reset_and_get_address());
if (status != ZX_ERR_UNAVAILABLE)
std::ignore = fd.release();
if (status != ZX_OK) {
if (zx_status_t status =
fdio_fd_transfer(fd.release(), channel.reset_and_get_address());
status != ZX_OK) {
ZX_DLOG(ERROR, status) << "fdio_fd_transfer";
return fidl::InterfaceHandle<::fuchsia::io::Directory>();
return {};
}
return fidl::InterfaceHandle<::fuchsia::io::Directory>(std::move(channel));
}
} // namespace
const char kPersistedDataDirectoryPath[] = "/data";
const char kPersistedCacheDirectoryPath[] = "/cache";
const char kServiceDirectoryPath[] = "/svc";
const char kPackageRootDirectoryPath[] = "/pkg";
fidl::InterfaceHandle<::fuchsia::io::Directory> OpenDirectoryHandle(
const base::FilePath& path) {
return OpenDirectoryHandleInternal(path, true);
}
fidl::InterfaceHandle<::fuchsia::io::Directory> OpenWritableDirectoryHandle(
const base::FilePath& path) {
return OpenDirectoryHandleInternal(path, false);
}
} // namespace base

@ -24,15 +24,27 @@ BASE_EXPORT extern const char kServiceDirectoryPath[];
// Package root directory, i.e. /pkg .
BASE_EXPORT extern const char kPackageRootDirectoryPath[];
// Returns a read-only fuchsia.io.Directory for the specified |path|, or an
// Describes the level of access requested.
//
// See fuchsia.io/OpenFlags and fuchsia.io/Directory.Open for details.
//
// Note that rights are hierarchical in Fuchsia filesystems, so this level of
// access applies to the directory connection itself as well as any connections
// derived from it using fuchsia.io/Directory.Open.
struct DirectoryHandleRights {
// fuchsia.io/OpenFlags.RIGHT_READABLE.
bool readable = false;
// fuchsia.io/OpenFlags.RIGHT_WRITABLE.
bool writable = false;
// fuchsia.io/OpenFlags.RIGHT_EXECUTABLE.
bool executable = false;
};
// Returns a fuchsia.io/Directory for the specified |path|, or an
// invalid InterfaceHandle if the path doesn't exist or it's not a directory.
BASE_EXPORT fidl::InterfaceHandle<::fuchsia::io::Directory> OpenDirectoryHandle(
const base::FilePath& path);
// Returns a write-capable fuchsia.io.Directory for the specified |path| or
// an invalid InterfaceHandle if the path doesn't exist or it's not a directory.
BASE_EXPORT fidl::InterfaceHandle<::fuchsia::io::Directory>
OpenWritableDirectoryHandle(const base::FilePath& path);
const base::FilePath& path,
DirectoryHandleRights rights);
} // namespace base

@ -21,23 +21,23 @@ class OpenDirectoryTest : public testing::Test {
};
TEST_F(OpenDirectoryTest, Open) {
auto dir = OpenDirectoryHandle(temp_dir.GetPath());
fidl::InterfaceHandle dir = OpenDirectoryHandle(temp_dir.GetPath(), {});
ASSERT_TRUE(dir);
}
// OpenDirectoryHandle() should fail when opening a directory that doesn't
// exist.
TEST_F(OpenDirectoryTest, OpenNonExistent) {
auto dir =
OpenDirectoryHandle(temp_dir.GetPath().AppendASCII("non_existent"));
fidl::InterfaceHandle dir =
OpenDirectoryHandle(temp_dir.GetPath().AppendASCII("non_existent"), {});
ASSERT_FALSE(dir);
}
// OpenDirectoryHandle() should open only directories.
TEST_F(OpenDirectoryTest, OpenFile) {
auto file_path = temp_dir.GetPath().AppendASCII("test_file");
FilePath file_path = temp_dir.GetPath().AppendASCII("test_file");
ASSERT_TRUE(WriteFile(file_path, "foo"));
auto dir = OpenDirectoryHandle(file_path);
fidl::InterfaceHandle dir = OpenDirectoryHandle(file_path, {});
ASSERT_FALSE(dir);
}

@ -11,10 +11,10 @@
#include <lib/sys/cpp/component_context.h>
#include "base/files/file_enumerator.h"
#include "base/fuchsia/file_utils.h"
#include "base/fuchsia/filtered_service_directory.h"
#include "base/fuchsia/fuchsia_logging.h"
#include "base/fuchsia/process_context.h"
#include "base/run_loop.h"
namespace base {
@ -34,7 +34,8 @@ TestComponentContextForProcess::TestComponentContextForProcess(
// Calling stat() in /svc is problematic; see https://fxbug.dev/100207. Tell
// the enumerator not to recurse, to return both files and directories, and
// to report only the names of entries.
base::FileEnumerator file_enum(base::FilePath("/svc"), /*recursive=*/false,
base::FileEnumerator file_enum(base::FilePath(base::kServiceDirectoryPath),
/*recursive=*/false,
base::FileEnumerator::NAMES_ONLY);
for (auto file = file_enum.Next(); !file.empty(); file = file_enum.Next()) {
AddService(file.BaseName().value());

@ -15,16 +15,12 @@
#include <zircon/syscalls.h>
#include "base/base_paths.h"
#include "base/files/file.h"
#include "base/files/file_path.h"
#include "base/fuchsia/fuchsia_logging.h"
#include "base/notreached.h"
#include "base/files/scoped_file.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/posix/safe_strerror.h"
#include "base/strings/strcat.h"
#include "base/strings/string_piece.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread_restrictions.h"
#include "base_paths.h"
@ -62,22 +58,24 @@ NativeLibrary LoadNativeLibraryWithOptions(const FilePath& library_path,
// TODO(crbug.com/1018538): Teach base::File about FLAG_WIN_EXECUTE on
// Fuchsia, and then use it here instead of using fdio_open_fd() directly.
base::ScopedFD fd;
zx_status_t status = fdio_open_fd(
computed_path.value().c_str(),
static_cast<uint32_t>(fuchsia::io::OpenFlags::RIGHT_READABLE |
fuchsia::io::OpenFlags::RIGHT_EXECUTABLE),
base::ScopedFD::Receiver(fd).get());
if (status != ZX_OK) {
if (zx_status_t status = fdio_open_fd(
computed_path.value().c_str(),
static_cast<uint32_t>(fuchsia::io::OpenFlags::RIGHT_READABLE |
fuchsia::io::OpenFlags::RIGHT_EXECUTABLE),
base::ScopedFD::Receiver(fd).get());
status != ZX_OK) {
if (error) {
error->message =
base::StringPrintf("fdio_open_fd: %s", zx_status_get_string(status));
error->message = base::StringPrintf("fdio_open_fd(%s): %s",
computed_path.value().c_str(),
zx_status_get_string(status));
}
return nullptr;
}
zx::vmo vmo;
status = fdio_get_vmo_exec(fd.get(), vmo.reset_and_get_address());
if (status != ZX_OK) {
if (zx_status_t status =
fdio_get_vmo_exec(fd.get(), vmo.reset_and_get_address());
status != ZX_OK) {
if (error) {
error->message = base::StringPrintf("fdio_get_vmo_exec: %s",
zx_status_get_string(status));

@ -17,19 +17,21 @@
#include "base/command_line.h"
#include "base/environment.h"
#include "base/files/file_path.h"
#include "base/memory/raw_ptr.h"
#include "base/process/process.h"
#include "base/process/process_handle.h"
#include "base/strings/string_piece.h"
#include "base/threading/thread_restrictions.h"
#include "build/blink_buildflags.h"
#include "build/build_config.h"
#if BUILDFLAG(IS_WIN)
#include "base/win/windows_types.h"
#elif BUILDFLAG(IS_POSIX)
#include "base/memory/raw_ptr.h"
#elif BUILDFLAG(IS_FUCHSIA)
#include <lib/fdio/spawn.h>
#include <zircon/types.h>
#include "base/fuchsia/file_utils.h"
#endif
#if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
@ -46,6 +48,10 @@ using MachPortsForRendezvous = std::map<uint32_t, MachRendezvousPort>;
#if BUILDFLAG(IS_WIN)
typedef std::vector<HANDLE> HandlesToInheritVector;
#elif BUILDFLAG(IS_FUCHSIA)
struct PathToClone {
base::FilePath path;
base::DirectoryHandleRights rights;
};
struct PathToTransfer {
base::FilePath path;
zx_handle_t handle;
@ -275,7 +281,7 @@ struct BASE_EXPORT LaunchOptions {
// depending on whether FDIO_SPAWN_CLONE_NAMESPACE is set.
// Process launch will fail if `paths_to_clone` and `paths_to_transfer`
// together contain conflicting paths (e.g. overlaps or duplicates).
std::vector<FilePath> paths_to_clone;
std::vector<PathToClone> paths_to_clone;
// Specifies handles which will be installed as files or directories in the
// child process' namespace.

@ -20,10 +20,7 @@
#include "base/fuchsia/file_utils.h"
#include "base/fuchsia/fuchsia_logging.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/process/environment_internal.h"
#include "base/scoped_generic.h"
#include "base/threading/scoped_blocking_call.h"
#include "base/trace_event/base_tracing.h"
namespace base {
@ -207,16 +204,17 @@ Process LaunchProcess(const std::vector<std::string>& argv,
for (const auto& path_to_clone : options.paths_to_clone) {
fidl::InterfaceHandle<::fuchsia::io::Directory> directory =
base::OpenDirectoryHandle(path_to_clone);
base::OpenDirectoryHandle(path_to_clone.path, path_to_clone.rights);
if (!directory) {
LOG(WARNING) << "Could not open handle for path: " << path_to_clone;
LOG(WARNING) << "Could not open handle for path: "
<< path_to_clone.path;
return base::Process();
}
zx::handle handle = directory.TakeChannel();
spawn_actions.push_back(FdioSpawnActionAddNamespaceEntry(
path_to_clone.value().c_str(), handle.get()));
path_to_clone.path.value().c_str(), handle.get()));
transferred_handles.push_back(std::move(handle));
}
}

@ -11,30 +11,23 @@
#include <tuple>
#include "base/command_line.h"
#include "base/debug/alias.h"
#include "base/debug/stack_trace.h"
#include "base/files/file_enumerator.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/files/scoped_file.h"
#include "base/functional/bind.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/posix/eintr_wrapper.h"
#include "base/process/kill.h"
#include "base/process/launch.h"
#include "base/process/memory.h"
#include "base/process/process.h"
#include "base/process/process_metrics.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece.h"
#include "base/strings/utf_string_conversions.h"
#include "base/synchronization/waitable_event.h"
#include "base/test/multiprocess_test.h"
#include "base/test/task_environment.h"
#include "base/test/test_timeouts.h"
#include "base/threading/platform_thread.h"
#include "base/threading/simple_thread.h"
#include "base/threading/thread.h"
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
@ -81,10 +74,7 @@
#include <zircon/syscalls.h>
#include "base/files/scoped_temp_dir.h"
#include "base/fuchsia/file_utils.h"
#include "base/fuchsia/filtered_service_directory.h"
#include "base/fuchsia/fuchsia_logging.h"
#include "base/fuchsia/process_context.h"
#include "base/test/bind.h"
#endif
namespace base {
@ -257,11 +247,12 @@ TEST_F(ProcessUtilTest, DISABLED_DuplicateTransferAndClonePaths_Fail) {
// Attach the tempdir to "data", but also try to duplicate the existing "data"
// directory.
options.paths_to_clone.push_back(FilePath(kPersistedDataDirectoryPath));
options.paths_to_clone.push_back(FilePath("/tmp"));
options.paths_to_transfer.push_back(
{FilePath(kPersistedDataDirectoryPath),
OpenDirectoryHandle(tmpdir.GetPath()).TakeChannel().release()});
options.paths_to_clone.push_back({FilePath(kPersistedDataDirectoryPath), {}});
options.paths_to_clone.push_back({FilePath("/tmp"), {}});
options.paths_to_transfer.push_back({
FilePath(kPersistedDataDirectoryPath),
OpenDirectoryHandle(tmpdir.GetPath(), {}).TakeChannel().release(),
});
// Verify that the process fails to launch.
Process process(SpawnChildWithOptions("ShouldNotBeLaunched", options));
@ -282,11 +273,12 @@ TEST_F(ProcessUtilTest, DISABLED_OverlappingPaths_Fail) {
// Attach the tempdir to "data", but also try to duplicate the existing "data"
// directory.
options.paths_to_clone.push_back(FilePath(kPersistedDataDirectoryPath));
options.paths_to_clone.push_back(FilePath("/tmp"));
options.paths_to_transfer.push_back(
{FilePath(kPersistedDataDirectoryPath).Append("staged"),
OpenDirectoryHandle(tmpdir.GetPath()).TakeChannel().release()});
options.paths_to_clone.push_back({FilePath(kPersistedDataDirectoryPath), {}});
options.paths_to_clone.push_back({FilePath("/tmp"), {}});
options.paths_to_transfer.push_back({
FilePath(kPersistedDataDirectoryPath).Append("staged"),
OpenDirectoryHandle(tmpdir.GetPath(), {}).TakeChannel().release(),
});
// Verify that the process fails to launch.
Process process(SpawnChildWithOptions("ShouldNotBeLaunched", options));
@ -316,11 +308,11 @@ TEST_F(ProcessUtilTest, TransferHandleToPath) {
// Mount the tempdir to "/foo".
zx::channel tmp_channel =
OpenDirectoryHandle(new_tmpdir.GetPath()).TakeChannel();
OpenDirectoryHandle(new_tmpdir.GetPath(), {}).TakeChannel();
ASSERT_TRUE(tmp_channel.is_valid());
LaunchOptions options;
options.paths_to_clone.push_back(FilePath("/tmp"));
options.paths_to_clone.push_back({FilePath("/tmp"), {.readable = true}});
options.paths_to_transfer.push_back(
{FilePath("/foo"), tmp_channel.release()});
options.spawn_flags = FDIO_SPAWN_CLONE_STDIO;
@ -372,7 +364,7 @@ TEST_F(ProcessUtilTest, CloneTmp) {
remove(signal_file.c_str());
LaunchOptions options;
options.paths_to_clone.push_back(FilePath("/tmp"));
options.paths_to_clone.push_back({FilePath("/tmp"), {.readable = true}});
options.spawn_flags = FDIO_SPAWN_CLONE_STDIO;
Process process(SpawnChildWithOptions("CheckOnlyTmpExists", options));
@ -392,7 +384,7 @@ MULTIPROCESS_TEST_MAIN(NeverCalled) {
TEST_F(ProcessUtilTest, TransferInvalidHandleFails) {
LaunchOptions options;
options.paths_to_clone.push_back(FilePath("/tmp"));
options.paths_to_clone.push_back({FilePath("/tmp"), {}});
options.paths_to_transfer.push_back({FilePath("/foo"), ZX_HANDLE_INVALID});
options.spawn_flags = FDIO_SPAWN_CLONE_STDIO;
@ -406,8 +398,8 @@ TEST_F(ProcessUtilTest, CloneInvalidDirFails) {
remove(signal_file.c_str());
LaunchOptions options;
options.paths_to_clone.push_back(FilePath("/tmp"));
options.paths_to_clone.push_back(FilePath("/definitely_not_a_dir"));
options.paths_to_clone.push_back({FilePath("/tmp"), {}});
options.paths_to_clone.push_back({FilePath("/definitely_not_a_dir"), {}});
options.spawn_flags = FDIO_SPAWN_CLONE_STDIO;
Process process(SpawnChildWithOptions("NeverCalled", options));
@ -423,9 +415,9 @@ TEST_F(ProcessUtilTest, CloneAlternateDir) {
remove(signal_file.c_str());
LaunchOptions options;
options.paths_to_clone.push_back(FilePath("/data"));
options.paths_to_clone.push_back({FilePath("/data"), {}});
// The DIR_TEMP path is used by GetSignalFilePath().
options.paths_to_clone.push_back(FilePath("/tmp"));
options.paths_to_clone.push_back({FilePath("/tmp"), {.readable = true}});
options.spawn_flags = FDIO_SPAWN_CLONE_STDIO;
Process process(SpawnChildWithOptions("CheckOnlyDataExists", options));
@ -471,8 +463,8 @@ TEST_F(ProcessUtilTest, HandlesToTransferClosedOnBadPathToMapFailure) {
LaunchOptions options;
options.handles_to_transfer.push_back({0, handles[0].get()});
options.spawn_flags = options.spawn_flags & ~FDIO_SPAWN_CLONE_NAMESPACE;
options.paths_to_clone.emplace_back(
"💩magical_path_that_will_never_exist_ever");
options.paths_to_clone.push_back(
{FilePath("💩magical_path_that_will_never_exist_ever"), {}});
// LaunchProces should fail to open() the path_to_map, and fail before
// fdio_spawn().

@ -13,7 +13,6 @@
#include <unordered_set>
#include <utility>
#include "base/at_exit.h"
#include "base/clang_profiling_buildflags.h"
#include "base/command_line.h"
#include "base/containers/adapters.h"
@ -27,14 +26,11 @@
#include "base/format_macros.h"
#include "base/functional/bind.h"
#include "base/hash/hash.h"
#include "base/lazy_instance.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/raw_ref.h"
#include "base/numerics/safe_conversions.h"
#include "base/process/kill.h"
#include "base/process/launch.h"
#include "base/ranges/algorithm.h"
#include "base/run_loop.h"
@ -44,13 +40,10 @@
#include "base/strings/string_piece.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/stringize_macros.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/system/sys_info.h"
#include "base/task/post_job.h"
#include "base/task/single_thread_task_runner.h"
#include "base/task/thread_pool.h"
#include "base/task/thread_pool/thread_pool_instance.h"
#include "base/test/gtest_util.h"
#include "base/test/gtest_xml_util.h"
@ -65,7 +58,6 @@
#include "base/time/time.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/libxml/chromium/libxml_utils.h"
#if BUILDFLAG(IS_POSIX)
@ -80,6 +72,7 @@
#if BUILDFLAG(IS_WIN)
#include "base/strings/string_util_win.h"
#include "base/strings/utf_string_conversions.h"
#include <windows.h>
@ -498,12 +491,20 @@ int LaunchChildTestProcessWithOptions(const CommandLine& command_line,
// Transfer handles to the new directories as /data and /cache in the child
// process' namespace.
new_options.paths_to_transfer.push_back(
{kDataPath,
base::OpenDirectoryHandle(test_data_dir).TakeChannel().release()});
new_options.paths_to_transfer.push_back(
{kCachePath,
base::OpenDirectoryHandle(test_cache_dir).TakeChannel().release()});
new_options.paths_to_transfer.push_back({
kDataPath,
base::OpenDirectoryHandle(test_data_dir,
{.readable = true, .writable = true})
.TakeChannel()
.release(),
});
new_options.paths_to_transfer.push_back({
kCachePath,
base::OpenDirectoryHandle(test_cache_dir,
{.readable = true, .writable = true})
.TakeChannel()
.release(),
});
#endif // BUILDFLAG(IS_FUCHSIA)
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
@ -717,10 +718,8 @@ ChildProcessResults DoLaunchChildTestProcess(
if (redirect_stdio) {
int output_file_fd = fileno(output_file.get());
CHECK_LE(0, output_file_fd);
options.fds_to_remap.push_back(
std::make_pair(output_file_fd, STDOUT_FILENO));
options.fds_to_remap.push_back(
std::make_pair(output_file_fd, STDERR_FILENO));
options.fds_to_remap.emplace_back(output_file_fd, STDOUT_FILENO);
options.fds_to_remap.emplace_back(output_file_fd, STDERR_FILENO);
}
#if !BUILDFLAG(IS_FUCHSIA)
@ -998,7 +997,7 @@ class TestLauncher::TestInfo {
public:
TestInfo() = default;
TestInfo(const TestInfo& other) = default;
TestInfo(const TestIdentifier& test_id);
explicit TestInfo(const TestIdentifier& test_id);
~TestInfo() = default;
// Returns test name excluding DISABLE_ prefix.

@ -16,7 +16,6 @@
#include "base/fuchsia/fuchsia_logging.h"
#include "base/fuchsia/process_context.h"
#include "base/logging.h"
#include "base/strings/string_piece.h"
namespace fuchsia_component_support {

@ -20,7 +20,6 @@
#include "base/test/gtest_util.h"
#include "base/test/task_environment.h"
#include "components/fuchsia_component_support/mock_realm.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace fuchsia_component_support {

@ -24,7 +24,7 @@ GetCastStreamingContentDirectories() {
fuchsia::web::ContentDirectoryProvider content_directory;
content_directory.set_directory(base::OpenDirectoryHandle(
pkg_path.AppendASCII(kContentDirectoryRelativePath)));
pkg_path.AppendASCII(kContentDirectoryRelativePath), {.readable = true}));
content_directory.set_name(kCastStreamingContentDirectoryName);
std::vector<fuchsia::web::ContentDirectoryProvider> content_directories;
content_directories.emplace_back(std::move(content_directory));

@ -16,9 +16,9 @@
#include <vector>
#include "base/files/file_util.h"
#include "base/fuchsia/file_utils.h"
#include "base/fuchsia/fuchsia_logging.h"
#include "base/notreached.h"
#include "base/strings/string_piece.h"
#include "base/sys_byteorder.h"
namespace {
@ -87,7 +87,7 @@ void CastResolver::Resolve(CastResolver::ResolveRequest& request,
fuchsia_component_decl::Use::WithDirectory({{
.source = Ref::WithParent({}),
.source_name = "svc",
.target_path = "/svc",
.target_path = base::kServiceDirectoryPath,
.rights = fuchsia_io::kRwStarDir,
.dependency_type =
fuchsia_component_decl::DependencyType::kStrong,

@ -118,7 +118,8 @@ void SetDataParamsForMainContext(fuchsia::web::CreateContextParams* params) {
LOG(ERROR) << "Failed to create profile directory: " << error_code;
base::Process::TerminateCurrentProcessImmediately(1);
}
params->set_data_directory(base::OpenDirectoryHandle(profile_path));
params->set_data_directory(
base::OpenDirectoryHandle(profile_path, {.readable = true}));
if (!params->data_directory()) {
LOG(ERROR) << "Unable to open data to transfer";
base::Process::TerminateCurrentProcessImmediately(1);
@ -149,7 +150,8 @@ void SetCdmParamsForMainContext(fuchsia::web::CreateContextParams* params) {
LOG(ERROR) << "Failed to create cache directory: " << error_code;
base::Process::TerminateCurrentProcessImmediately(1);
}
params->set_cdm_data_directory(base::OpenDirectoryHandle(cdm_data_path));
params->set_cdm_data_directory(
base::OpenDirectoryHandle(cdm_data_path, {.readable = true}));
if (!params->cdm_data_directory()) {
LOG(ERROR) << "Unable to open cdm_data to transfer";
base::Process::TerminateCurrentProcessImmediately(1);

@ -18,7 +18,6 @@
#include "base/auto_reset.h"
#include "base/base_paths.h"
#include "base/files/file_util.h"
#include "base/fuchsia/file_utils.h"
#include "base/fuchsia/fuchsia_logging.h"
#include "base/fuchsia/mem_buffer_util.h"
@ -27,7 +26,6 @@
#include "base/path_service.h"
#include "base/run_loop.h"
#include "base/strings/strcat.h"
#include "base/strings/string_piece.h"
#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "base/test/test_future.h"
@ -36,7 +34,6 @@
#include "build/build_config.h"
#include "build/chromecast_buildflags.h"
#include "components/fuchsia_component_support/dynamic_component_host.h"
#include "fuchsia_web/common/string_util.h"
#include "fuchsia_web/common/test/fit_adapter.h"
#include "fuchsia_web/common/test/frame_for_test.h"
#include "fuchsia_web/common/test/frame_test_util.h"
@ -45,7 +42,6 @@
#include "fuchsia_web/common/test/test_navigation_listener.h"
#include "fuchsia_web/common/test/url_request_rewrite_test_util.h"
#include "fuchsia_web/runners/cast/cast_runner.h"
#include "fuchsia_web/runners/cast/cast_runner_switches.h"
#include "fuchsia_web/runners/cast/test/cast_runner_features.h"
#include "fuchsia_web/runners/cast/test/cast_runner_launcher.h"
#include "fuchsia_web/runners/cast/test/fake_api_bindings.h"
@ -71,7 +67,8 @@ chromium::cast::ApplicationConfig CreateAppConfigWithTestData(
CHECK(base::PathService::Get(base::DIR_SRC_TEST_DATA_ROOT, &pkg_path));
provider.set_directory(base::OpenDirectoryHandle(
pkg_path.AppendASCII("fuchsia_web/runners/cast/testdata")));
pkg_path.AppendASCII("fuchsia_web/runners/cast/testdata"),
{.readable = true}));
std::vector<fuchsia::web::ContentDirectoryProvider> providers;
providers.emplace_back(std::move(provider));
@ -419,10 +416,7 @@ class CastRunnerIntegrationTest : public testing::Test {
~CastRunnerIntegrationTest() override = default;
CastRunnerIntegrationTest(const CastRunnerIntegrationTest&) = delete;
CastRunnerIntegrationTest& operator=(const CastRunnerIntegrationTest&) =
delete;
protected:
// testing::Test overrides.
void SetUp() override {
static constexpr base::StringPiece kTestServerRoot(

@ -20,14 +20,11 @@
#include "base/fuchsia/file_utils.h"
#include "base/fuchsia/fuchsia_logging.h"
#include "base/fuchsia/process_context.h"
#include "base/json/json_writer.h"
#include "base/logging.h"
#include "base/message_loop/message_pump_type.h"
#include "base/path_service.h"
#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
#include "base/task/single_thread_task_executor.h"
#include "base/values.h"
#include "build/build_config.h"
#include "components/fuchsia_component_support/annotations_manager.h"
#include "fuchsia_web/common/init_logging.h"
@ -159,7 +156,7 @@ int main(int argc, char** argv) {
base::FilePath pkg_path;
base::PathService::Get(base::DIR_SRC_TEST_DATA_ROOT, &pkg_path);
content_directory.set_directory(base::OpenDirectoryHandle(
pkg_path.AppendASCII("fuchsia_web/shell/data")));
pkg_path.AppendASCII("fuchsia_web/shell/data"), {.readable = true}));
content_directory.set_name("shell-data");
std::vector<fuchsia::web::ContentDirectoryProvider> content_directories;
content_directories.emplace_back(std::move(content_directory));
@ -192,7 +189,7 @@ int main(int argc, char** argv) {
base::File::Error error;
CHECK(base::CreateDirectoryAndGetError(cdm_data_path, &error)) << error;
create_context_params.set_cdm_data_directory(
base::OpenDirectoryHandle(cdm_data_path));
base::OpenDirectoryHandle(cdm_data_path, {.readable = true}));
CHECK(create_context_params.cdm_data_directory());
base::RunLoop run_loop;
@ -208,8 +205,8 @@ int main(int argc, char** argv) {
// embedder application. By passing a handle to this process' service
// directory to the ContextProvider, we are allowing the Context access to
// the same set of services available to this application.
create_context_params.set_service_directory(
base::OpenDirectoryHandle(base::FilePath(base::kServiceDirectoryPath)));
create_context_params.set_service_directory(base::OpenDirectoryHandle(
base::FilePath(base::kServiceDirectoryPath), {}));
web_context_provider = base::ComponentContextForProcess()
->svc()
->Connect<fuchsia::web::ContextProvider>();

@ -7,9 +7,6 @@
#include <lib/vfs/cpp/pseudo_dir.h>
#include <lib/vfs/cpp/vmo_file.h>
#include "base/strings/string_piece.h"
#include "fuchsia_web/webengine/test/web_engine_browser_test.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
@ -23,7 +20,7 @@
#include "fuchsia_web/common/test/frame_test_util.h"
#include "fuchsia_web/common/test/test_navigation_listener.h"
#include "fuchsia_web/webengine/browser/content_directory_loader_factory.h"
#include "fuchsia_web/webengine/switches.h"
#include "fuchsia_web/webengine/test/web_engine_browser_test.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/url_util.h"
@ -112,11 +109,14 @@ class ContentDirectoryTest : public WebEngineBrowserTest {
base::PathService::Get(base::DIR_SRC_TEST_DATA_ROOT, &pkg_path));
testdata_content_directory_ = std::make_unique<ScopedBindContentDirectory>(
"testdata", base::OpenDirectoryHandle(pkg_path.AppendASCII(
"fuchsia_web/webengine/test/data")));
"testdata", base::OpenDirectoryHandle(
pkg_path.AppendASCII("fuchsia_web/webengine/test/data"),
{.readable = true}));
alternate_content_directory_ = std::make_unique<ScopedBindContentDirectory>(
"alternate", base::OpenDirectoryHandle(pkg_path.AppendASCII(
"fuchsia_web/webengine/test/data")));
"alternate",
base::OpenDirectoryHandle(
pkg_path.AppendASCII("fuchsia_web/webengine/test/data"),
{.readable = true}));
WebEngineBrowserTest::SetUpOnMainThread();
}

@ -40,7 +40,6 @@
#include "components/fuchsia_component_support/mock_realm.h"
#include "fuchsia_web/webengine/switches.h"
#include "services/network/public/cpp/network_switches.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
@ -604,8 +603,8 @@ TEST_F(ContextProviderImplTest, WithProfileDir) {
// Pass a handle data dir to the context.
fuchsia::web::CreateContextParams create_params = BuildCreateContextParams();
create_params.set_data_directory(
base::OpenDirectoryHandle(profile_temp_dir.GetPath()));
create_params.set_data_directory(base::OpenDirectoryHandle(
profile_temp_dir.GetPath(), {.readable = true, .writable = true}));
fuchsia::web::ContextPtr context;
const std::string instance_name = CreateAndWaitForInstance(
@ -648,7 +647,8 @@ TEST_F(ContextProviderImplTest, FailsDataDirectoryIsFile) {
&temp_file_path));
fuchsia::web::CreateContextParams create_params = BuildCreateContextParams();
create_params.set_data_directory(base::OpenDirectoryHandle(temp_file_path));
create_params.set_data_directory(
base::OpenDirectoryHandle(temp_file_path, {}));
fidl::InterfacePtr<fuchsia::web::Context> context;
context_provider().Create(std::move(create_params), context.NewRequest());
@ -714,8 +714,8 @@ TEST_F(ContextProviderImplTest, WithDataQuotaBytes) {
ExpectChildInstance(binder_request, context_request);
fuchsia::web::CreateContextParams create_params = BuildCreateContextParams();
create_params.set_data_directory(
base::OpenDirectoryHandle(profile_temp_dir.GetPath()));
create_params.set_data_directory(base::OpenDirectoryHandle(
profile_temp_dir.GetPath(), {.readable = true}));
create_params.set_data_quota_bytes(kTestQuotaBytes);
fuchsia::web::ContextPtr context;
@ -741,8 +741,8 @@ TEST_F(ContextProviderImplTest, WithCdmDataQuotaBytes) {
ExpectChildInstance(binder_request, context_request);
fuchsia::web::CreateContextParams create_params = BuildCreateContextParams();
create_params.set_cdm_data_directory(
base::OpenDirectoryHandle(profile_temp_dir.GetPath()));
create_params.set_cdm_data_directory(base::OpenDirectoryHandle(
profile_temp_dir.GetPath(), {.readable = true}));
create_params.set_features(fuchsia::web::ContextFeatureFlags::HEADLESS |
fuchsia::web::ContextFeatureFlags::WIDEVINE_CDM);
create_params.set_cdm_data_quota_bytes(kTestQuotaBytes);

@ -75,8 +75,8 @@ struct TestContextAndFrame {
UserModeDebugging user_mode_debugging,
std::string url) {
// Create a Context, a Frame and navigate it to |url|.
auto directory =
base::OpenDirectoryHandle(base::FilePath(base::kServiceDirectoryPath));
auto directory = base::OpenDirectoryHandle(
base::FilePath(base::kServiceDirectoryPath), {});
if (!directory.is_valid())
return;

@ -11,9 +11,7 @@
#include "base/files/file_path.h"
#include "base/fuchsia/file_utils.h"
#include "base/fuchsia/fuchsia_logging.h"
#include "base/fuchsia/process_context.h"
#include "base/path_service.h"
#include "base/strings/string_piece.h"
#include "fuchsia_web/common/test/frame_test_util.h"
#include "net/test/embedded_test_server/default_handlers.h"
@ -25,7 +23,8 @@ fuchsia::web::ContentDirectoryProvider CreateTestDataDirectoryProvider() {
base::FilePath pkg_path;
CHECK(base::PathService::Get(base::DIR_SRC_TEST_DATA_ROOT, &pkg_path));
provider.set_directory(base::OpenDirectoryHandle(
pkg_path.AppendASCII("fuchsia_web/webengine/test/data")));
pkg_path.AppendASCII("fuchsia_web/webengine/test/data"),
{.readable = true}));
return provider;
}
@ -34,12 +33,14 @@ fuchsia::web::ContentDirectoryProvider CreateTestDataDirectoryProvider() {
WebEngineIntegrationTestBase::WebEngineIntegrationTestBase()
: task_environment_(base::test::TaskEnvironment::MainThreadType::IO),
filtered_service_directory_(std::make_shared<sys::ServiceDirectory>(
base::OpenDirectoryHandle(base::FilePath("/svc")))) {
base::OpenDirectoryHandle(base::FilePath(base::kServiceDirectoryPath),
{}))) {
// Push all services from /svc to the filtered service directory.
// Calling stat() in /svc is problematic; see https://fxbug.dev/100207. Tell
// the enumerator not to recurse, to return both files and directories, and
// to report only the names of entries.
base::FileEnumerator file_enum(base::FilePath("/svc"), /*recursive=*/false,
base::FileEnumerator file_enum(base::FilePath(base::kServiceDirectoryPath),
/*recursive=*/false,
base::FileEnumerator::NAMES_ONLY);
for (auto file = file_enum.Next(); !file.empty(); file = file_enum.Next()) {
zx_status_t status =

@ -207,7 +207,7 @@ class FuchsiaCdmManager::KeySystemClient {
}
fidl::InterfaceHandle<fuchsia::io::Directory> data_directory =
base::OpenDirectoryHandle(storage_path);
base::OpenDirectoryHandle(storage_path, {.readable = true});
if (!data_directory.is_valid()) {
DLOG(ERROR) << "Unable to OpenDirectory " << storage_path;
return absl::nullopt;

@ -30,7 +30,6 @@
#include <memory>
#include <utility>
#include "base/base_paths.h"
#include "base/clang_profiling_buildflags.h"
#include "base/command_line.h"
#include "base/containers/span.h"
@ -44,11 +43,9 @@
#include "base/no_destructor.h"
#include "base/path_service.h"
#include "base/process/launch.h"
#include "base/process/process.h"
#include "base/task/sequenced_task_runner.h"
#include "base/threading/thread.h"
#include "printing/buildflags/buildflags.h"
#include "sandbox/policy/mojom/sandbox.mojom.h"
#include "sandbox/policy/switches.h"
namespace sandbox {
@ -243,8 +240,8 @@ SandboxPolicyFuchsia::~SandboxPolicyFuchsia() = default;
void SandboxPolicyFuchsia::UpdateLaunchOptionsForSandbox(
base::LaunchOptions* options) {
// Always clone stderr to get logs output.
options->fds_to_remap.push_back(std::make_pair(STDERR_FILENO, STDERR_FILENO));
options->fds_to_remap.push_back(std::make_pair(STDOUT_FILENO, STDOUT_FILENO));
options->fds_to_remap.emplace_back(STDERR_FILENO, STDERR_FILENO);
options->fds_to_remap.emplace_back(STDOUT_FILENO, STDOUT_FILENO);
if (type_ == sandbox::mojom::Sandbox::kNoSandbox) {
options->spawn_flags = FDIO_SPAWN_CLONE_NAMESPACE | FDIO_SPAWN_CLONE_JOB;
@ -254,15 +251,19 @@ void SandboxPolicyFuchsia::UpdateLaunchOptionsForSandbox(
// Map /pkg (read-only files deployed from the package) into the child's
// namespace.
options->paths_to_clone.push_back(
base::FilePath(base::kPackageRootDirectoryPath));
options->paths_to_clone.push_back({
base::FilePath(base::kPackageRootDirectoryPath),
{.readable = true, .executable = true},
});
// If /config/data/tzdata/icu/ exists then it contains up-to-date timezone
// data which should be provided to all sub-processes, for consistency.
const auto kIcuTimezoneDataPath = base::FilePath("/config/data/tzdata/icu");
static bool icu_timezone_data_exists = base::PathExists(kIcuTimezoneDataPath);
if (icu_timezone_data_exists)
options->paths_to_clone.push_back(kIcuTimezoneDataPath);
if (icu_timezone_data_exists) {
options->paths_to_clone.push_back(
{kIcuTimezoneDataPath, {.readable = true}});
}
// Clear environmental variables to better isolate the child from
// this process.
@ -275,8 +276,10 @@ void SandboxPolicyFuchsia::UpdateLaunchOptionsForSandbox(
const SandboxConfig* config = GetConfigForSandboxType(type_);
CHECK(config);
if (config->features & kProvideSslConfig)
options->paths_to_clone.push_back(base::FilePath("/config/ssl"));
if (config->features & kProvideSslConfig) {
options->paths_to_clone.push_back(
{base::FilePath("/config/ssl"), {.readable = true}});
}
if (config->features & kProvideVulkanResources) {
static const char* const kPathsToCloneForVulkan[] = {
@ -290,7 +293,7 @@ void SandboxPolicyFuchsia::UpdateLaunchOptionsForSandbox(
// Vulkan paths aren't needed with newer Fuchsia versions, so they may not
// be available.
if (base::PathExists(path)) {
options->paths_to_clone.push_back(path);
options->paths_to_clone.push_back({path, {}});
}
}
}
@ -299,7 +302,7 @@ void SandboxPolicyFuchsia::UpdateLaunchOptionsForSandbox(
// |service_directory_client_| handle for it to mount at "/svc".
if (service_directory_client_) {
options->paths_to_transfer.push_back(base::PathToTransfer{
base::FilePath("/svc"),
base::FilePath(base::kServiceDirectoryPath),
service_directory_client_.TakeChannel().release()});
}

@ -26,7 +26,8 @@ fdio_ns_t* GetNamespace() {
void TransferableDirectory::OpenForTransfer() {
handle_ = mojo::PlatformHandle(
base::OpenWritableDirectoryHandle(path_).TakeChannel());
base::OpenDirectoryHandle(path_, {.readable = true, .writable = true})
.TakeChannel());
}
[[nodiscard]] base::OnceClosure TransferableDirectory::Mount() {