blob: cc6fede030ebd5777059963acb54616be2e28e1b [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 "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));
}