| // 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 "system_instance.h" |
| |
| #include <lib/fdio/directory.h> |
| #include <zircon/status.h> |
| #include <zircon/syscalls/policy.h> |
| |
| #include "devfs.h" |
| #include "fdio.h" |
| #include "src/devices/lib/log/log.h" |
| #include "system_state_manager.h" |
| |
| DirectoryFilter::~DirectoryFilter() { |
| sync_completion_t done; |
| vfs_.Shutdown([&done](zx_status_t status) { |
| if (status != ZX_OK) { |
| LOGF(ERROR, "Failed to shutdown VFS: %s", zx_status_get_string(status)); |
| } |
| sync_completion_signal(&done); |
| }); |
| sync_completion_wait(&done, ZX_TIME_INFINITE); |
| } |
| |
| zx_status_t DirectoryFilter::Initialize(zx::channel forwarding_directory, |
| cpp20::span<const char*> allow_filter) { |
| forwarding_dir_ = std::move(forwarding_directory); |
| for (const auto& name : allow_filter) { |
| zx_status_t status = root_dir_->AddEntry( |
| name, fbl::MakeRefCounted<fs::Service>([this, name](zx::channel request) { |
| return fdio_service_connect_at(forwarding_dir_.get(), name, request.release()); |
| })); |
| if (status != ZX_OK) { |
| return status; |
| } |
| } |
| return ZX_OK; |
| } |
| |
| zx_status_t SystemInstance::CreateDriverHostJob(const zx::job& root_job, |
| zx::job* driver_host_job_out) { |
| zx::job driver_host_job; |
| zx_status_t status = zx::job::create(root_job, 0u, &driver_host_job); |
| if (status != ZX_OK) { |
| LOGF(ERROR, "Unable to create driver_host job: %s", zx_status_get_string(status)); |
| return status; |
| } |
| // TODO(fxbug.dev/53125): This currently manually restricts AMBIENT_MARK_VMO_EXEC and NEW_PROCESS |
| // since this job is created from the root job. The driver_host job should move to being created |
| // from something other than the root job. (Although note that it can't simply be created from |
| // driver_manager's own job, because that has timer slack job policy automatically applied by the |
| // ELF runner.) |
| static const zx_policy_basic_v2_t policy[] = { |
| {ZX_POL_BAD_HANDLE, ZX_POL_ACTION_ALLOW_EXCEPTION, ZX_POL_OVERRIDE_DENY}, |
| {ZX_POL_AMBIENT_MARK_VMO_EXEC, ZX_POL_ACTION_DENY, ZX_POL_OVERRIDE_DENY}, |
| {ZX_POL_NEW_PROCESS, ZX_POL_ACTION_DENY, ZX_POL_OVERRIDE_DENY}}; |
| status = driver_host_job.set_policy(ZX_JOB_POL_RELATIVE, ZX_JOB_POL_BASIC_V2, &policy, |
| std::size(policy)); |
| if (status != ZX_OK) { |
| LOGF(ERROR, "Failed to set driver_host job policy: %s", zx_status_get_string(status)); |
| return status; |
| } |
| status = driver_host_job.set_property(ZX_PROP_NAME, "zircon-drivers", 15); |
| if (status != ZX_OK) { |
| LOGF(ERROR, "Failed to set driver_host job property: %s", zx_status_get_string(status)); |
| return status; |
| } |
| *driver_host_job_out = std::move(driver_host_job); |
| return ZX_OK; |
| } |
| |
| void SystemInstance::InstallDevFsIntoNamespace() { |
| fdio_ns_t* ns; |
| zx_status_t r; |
| r = fdio_ns_get_installed(&ns); |
| ZX_ASSERT_MSG(r == ZX_OK, "driver_manager: cannot get namespace: %s\n", zx_status_get_string(r)); |
| r = fdio_ns_bind(ns, "/dev", CloneFs("dev").TakeChannel().release()); |
| ZX_ASSERT_MSG(r == ZX_OK, "driver_manager: cannot bind /dev to namespace: %s\n", |
| zx_status_get_string(r)); |
| } |
| |
| void SystemInstance::ServiceStarter(Coordinator* coordinator) { |
| coordinator->RegisterWithPowerManager(CloneFs("dev"), [](zx_status_t status) { |
| if (status != ZX_OK) { |
| LOGF(WARNING, "Unable to RegisterWithPowerManager: %d", status); |
| } |
| }); |
| |
| coordinator->StartLoadingNonBootDrivers(); |
| } |
| |
| fidl::ClientEnd<fuchsia_io::Directory> SystemInstance::CloneFs(const char* path) { |
| if (!strcmp(path, "dev")) { |
| return fidl::ClientEnd<fuchsia_io::Directory>(devfs_root_clone()); |
| } |
| auto endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>(); |
| if (endpoints.is_error()) { |
| return fidl::ClientEnd<fuchsia_io::Directory>(); |
| } |
| zx_status_t status = ZX_OK; |
| if (!strcmp(path, "svc")) { |
| status = fdio_service_connect("/svc", endpoints->server.TakeChannel().release()); |
| } else if (!strcmp(path, "driver_host_svc")) { |
| status = InitializeDriverHostSvcDir(); |
| if (status == ZX_OK) { |
| status = driver_host_svc_->Serve(std::move(endpoints->server)); |
| } |
| } else if (!strncmp(path, "dev/", 4)) { |
| zx::unowned_channel fs = devfs_root_borrow(); |
| path += 4; |
| status = fdio_open_at(fs->get(), path, |
| static_cast<uint32_t>(fuchsia_io::wire::OpenFlags::kRightReadable | |
| fuchsia_io::wire::OpenFlags::kRightWritable | |
| fuchsia_io::wire::OpenFlags::kDirectory), |
| endpoints->server.TakeChannel().release()); |
| } |
| if (status != ZX_OK) { |
| LOGF(ERROR, "CloneFs failed for '%s': %s", path, zx_status_get_string(status)); |
| return fidl::ClientEnd<fuchsia_io::Directory>(); |
| } |
| return std::move(endpoints->client); |
| } |
| |
| zx_status_t SystemInstance::InitializeDriverHostSvcDir() { |
| if (driver_host_svc_) { |
| return ZX_OK; |
| } |
| zx_status_t status = loop_.StartThread("driver_host_svc_loop"); |
| if (status != ZX_OK) { |
| return status; |
| } |
| driver_host_svc_.emplace(loop_.dispatcher()); |
| |
| zx::channel incoming_services; |
| { |
| zx::channel server_side; |
| status = zx::channel::create(0, &incoming_services, &server_side); |
| if (status != ZX_OK) { |
| return status; |
| } |
| |
| status = fdio_service_connect("/svc", server_side.release()); |
| if (status != ZX_OK) { |
| return status; |
| } |
| } |
| |
| const char* kAllowedServices[] = { |
| "fuchsia.logger.LogSink", |
| "fuchsia.scheduler.ProfileProvider", |
| "fuchsia.tracing.provider.Registry", |
| }; |
| return driver_host_svc_->Initialize(std::move(incoming_services), cpp20::span(kAllowedServices)); |
| } |