| // Copyright 2018 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 "garnet/bin/appmgr/service_provider_dir_impl.h" |
| |
| #include <lib/async/default.h> |
| #include <lib/fdio/util.h> |
| #include <zircon/status.h> |
| |
| #include "lib/fxl/logging.h" |
| #include "lib/fxl/strings/substitute.h" |
| |
| namespace component { |
| |
| namespace { |
| constexpr char kSandboxDocUrl[] = |
| "https://fuchsia.googlesource.com/docs/+/master/the-book/" |
| "sandboxing.md#services"; |
| |
| std::string ServiceNotInSandbox(const std::string& component_url, |
| const std::string& service_name) { |
| return fxl::Substitute( |
| "Component $0 is not allowed to connect to $1 because this service " |
| "is not present in the component's sandbox.\nRefer to $2 for more " |
| "information.", |
| component_url, service_name, kSandboxDocUrl); |
| } |
| |
| std::string ErrorServingService(const std::string& component_url, |
| const std::string& service_name, |
| zx_status_t status) { |
| return fxl::Substitute("Cannot serve service $0 for component $1: $2", |
| service_name, component_url, |
| std::string(zx_status_get_string(status))); |
| } |
| |
| } // namespace |
| |
| ServiceProviderDirImpl::ServiceProviderDirImpl( |
| const std::vector<std::string>* services) |
| : vfs_(async_get_default_dispatcher()), |
| root_(fbl::AdoptRef(new fs::PseudoDir())), |
| weak_factory_(this) { |
| if (services != nullptr) { |
| has_services_whitelist_ = true; |
| services_whitelist_.insert(services->begin(), services->end()); |
| } |
| } |
| |
| ServiceProviderDirImpl::~ServiceProviderDirImpl() {} |
| |
| void ServiceProviderDirImpl::set_parent( |
| fbl::RefPtr<ServiceProviderDirImpl> parent) { |
| if (parent_) { |
| return; |
| } |
| parent_ = parent; |
| for (const auto& s : parent_->service_handles_) { |
| AddService(s.first, s.second); |
| } |
| } |
| |
| void ServiceProviderDirImpl::AddService(const std::string& service_name, |
| fbl::RefPtr<fs::Service> service) { |
| if (all_service_names_.count(service_name) > 0) { |
| // Don't allow duplicate services. This path can be reached if a child |
| // would inherit a service from its parent with a name that it already |
| // has. In that case, the child's service should take priority. |
| return; |
| } |
| if (IsServiceWhitelisted(service_name)) { |
| service_handles_.push_back({service_name, service}); |
| root_->AddEntry(service_name, std::move(service)); |
| all_service_names_.insert(service_name); |
| } |
| } |
| |
| void ServiceProviderDirImpl::AddBinding( |
| fidl::InterfaceRequest<fuchsia::sys::ServiceProvider> request) { |
| bindings_.AddBinding(this, std::move(request)); |
| } |
| |
| void ServiceProviderDirImpl::ConnectToService(fidl::StringPtr service_name, |
| zx::channel channel) { |
| if (!IsServiceWhitelisted(service_name.get())) { |
| FXL_LOG(WARNING) << ServiceNotInSandbox(component_url_, service_name.get()); |
| return; |
| } |
| fbl::RefPtr<fs::Vnode> child; |
| zx_status_t status = root_->Lookup(&child, service_name.get()); |
| if (status == ZX_OK) { |
| status = child->Serve(&vfs_, std::move(channel), 0); |
| if (status != ZX_OK) { |
| FXL_LOG(ERROR) << ErrorServingService(component_url_, service_name.get(), |
| status); |
| } |
| } else { |
| FXL_LOG(ERROR) << ErrorServingService(component_url_, service_name.get(), |
| status); |
| } |
| } |
| |
| zx_status_t ServiceProviderDirImpl::Getattr(vnattr_t* a) { |
| return root_->Getattr(a); |
| } |
| |
| zx_status_t ServiceProviderDirImpl::Readdir(fs::vdircookie_t* cookie, |
| void* dirents, size_t len, |
| size_t* out_actual) { |
| return root_->Readdir(cookie, dirents, len, out_actual); |
| } |
| |
| zx_status_t ServiceProviderDirImpl::Lookup(fbl::RefPtr<fs::Vnode>* out, |
| fbl::StringPiece name) { |
| const std::string sname(name.data(), name.length()); |
| if (!IsServiceWhitelisted(sname)) { |
| FXL_LOG(WARNING) << ServiceNotInSandbox(component_url_, sname); |
| } |
| return root_->Lookup(out, name); |
| } |
| |
| } // namespace component |