[cm][routing] Separate route step from open step
Defines an API for capability routing. This is essentially
one function, route_capability(), which takes an enum-valued
argument specifying the capability type (directory,
protocol, etc) and the relationship to the target (via
a use, expose, etc). Policy verification now occurs
in the routing step for all capability types.
The routing API also includes a helper function which
routes both a storage capability and its backing
directory.
In a follow-up, this will become the public API of the
routing lib.
Bug: 61861
Change-Id: I1b41c3808fb00c13d7cd448cd1ba71c79db07a2b
Reviewed-on: https://fuchsia-review.googlesource.com/c/fuchsia/+/514300
Reviewed-by: Adam Lesinski <adamlesinski@google.com>
Commit-Queue: Laura Peskin <pesk@google.com>
diff --git a/src/sys/component_manager/BUILD.gn b/src/sys/component_manager/BUILD.gn
index 0b71664..7d2e491 100644
--- a/src/sys/component_manager/BUILD.gn
+++ b/src/sys/component_manager/BUILD.gn
@@ -179,6 +179,7 @@
"src/model/rights.rs",
"src/model/routing/error.rs",
"src/model/routing/mod.rs",
+ "src/model/routing/open.rs",
"src/model/routing/service.rs",
"src/model/routing_fns.rs",
"src/model/runner.rs",
diff --git a/src/sys/component_manager/src/model/component.rs b/src/sys/component_manager/src/model/component.rs
index 68a97a1..c3e63d4 100644
--- a/src/sys/component_manager/src/model/component.rs
+++ b/src/sys/component_manager/src/model/component.rs
@@ -23,7 +23,9 @@
namespace::IncomingNamespace,
policy::GlobalPolicyChecker,
resolver::ResolvedComponent,
- routing::{self, OpenResourceError, RoutingError},
+ routing::{
+ self, OpenOptions, OpenResourceError, OpenRunnerOptions, RouteRequest, RoutingError,
+ },
runner::{NullRunner, RemoteRunner, Runner},
},
},
@@ -370,14 +372,15 @@
create_endpoints::<fcrunner::ComponentRunnerMarker>()
.map_err(|_| ModelError::InsufficientResources)?;
let mut server_channel = server_channel.into_channel();
- let capability_source = routing::route_runner(runner, self).await?;
- routing::open_capability_at_source(
- OPEN_RIGHT_READABLE,
- MODE_TYPE_SERVICE,
- PathBuf::new(),
- capability_source,
+ let options = OpenRunnerOptions {
+ flags: OPEN_RIGHT_READABLE,
+ open_mode: MODE_TYPE_SERVICE,
+ server_chan: &mut server_channel,
+ };
+ routing::route_and_open_capability(
+ RouteRequest::Runner(runner.clone()),
self,
- &mut server_channel,
+ OpenOptions::Runner(options),
)
.await?;
diff --git a/src/sys/component_manager/src/model/events/registry.rs b/src/sys/component_manager/src/model/events/registry.rs
index 1ffbaa0..5659489 100644
--- a/src/sys/component_manager/src/model/events/registry.rs
+++ b/src/sys/component_manager/src/model/events/registry.rs
@@ -21,7 +21,7 @@
HooksRegistration,
},
model::Model,
- routing,
+ routing::{route_capability, RouteRequest, RouteSource},
},
},
async_trait::async_trait,
@@ -389,15 +389,16 @@
event_decl: UseEventDecl,
component: &Arc<ComponentInstance>,
) -> Result<(CapabilityName, ExtendedMoniker), ModelError> {
- match routing::route_event(event_decl, component).await? {
- CapabilitySource::Framework {
+ let route_source = route_capability(RouteRequest::UseEvent(event_decl), component).await?;
+ match route_source {
+ RouteSource::Event(CapabilitySource::Framework {
capability: InternalCapability::Event(source_name),
component,
- } => Ok((source_name, component.moniker.into())),
- CapabilitySource::Builtin {
+ }) => Ok((source_name, component.moniker.into())),
+ RouteSource::Event(CapabilitySource::Builtin {
capability: InternalCapability::Event(source_name),
..
- } if source_name == "capability_ready".into() => {
+ }) if source_name == "capability_ready".into() => {
Ok((source_name, ExtendedMoniker::ComponentManager))
}
_ => unreachable!(),
diff --git a/src/sys/component_manager/src/model/namespace.rs b/src/sys/component_manager/src/model/namespace.rs
index bbb2345..6f082116 100644
--- a/src/sys/component_manager/src/model/namespace.rs
+++ b/src/sys/component_manager/src/model/namespace.rs
@@ -11,7 +11,10 @@
error::ModelError,
logging::{FmtArgsLogger, LOGGER as MODEL_LOGGER},
rights::Rights,
- routing,
+ routing::{
+ self, route_and_open_capability, OpenDirectoryOptions, OpenOptions,
+ OpenProtocolOptions, OpenServiceOptions, OpenStorageOptions, RouteRequest,
+ },
},
},
anyhow::{Context, Error},
@@ -351,40 +354,29 @@
}
};
let mut server_end = server_end.into_zx_channel();
- let res = match &use_ {
- UseDecl::Directory(use_directory_decl) => {
- async {
- let (source, cap_state) =
- routing::route_directory(use_directory_decl.clone(), &target).await?;
- let relative_path = cap_state.make_relative_path(String::new());
- routing::open_capability_at_source(
- flags,
- fio::MODE_TYPE_DIRECTORY,
- relative_path,
- source,
- &target,
- &mut server_end,
- )
- .await
- }
- .await
- }
- UseDecl::Storage(use_storage_decl) => {
+ let (route_request, open_options) = match &use_ {
+ UseDecl::Directory(use_dir_decl) => (
+ RouteRequest::UseDirectory(use_dir_decl.clone()),
+ OpenOptions::Directory(OpenDirectoryOptions {
+ flags,
+ open_mode: fio::MODE_TYPE_DIRECTORY,
+ relative_path: String::new(),
+ server_chan: &mut server_end,
+ }),
+ ),
+ UseDecl::Storage(use_storage_decl) => (
+ RouteRequest::UseStorage(use_storage_decl.clone()),
// TODO(fxbug.dev/50716): This BindReason is wrong. We need to refactor the Storage
// capability to plumb through the correct BindReason.
- routing::route_and_open_storage_capability(
- use_storage_decl.clone(),
- fio::MODE_TYPE_DIRECTORY,
- &target,
- &mut server_end,
- &BindReason::Eager,
- )
- .await
- }
+ OpenOptions::Storage(OpenStorageOptions {
+ open_mode: fio::MODE_TYPE_DIRECTORY,
+ server_chan: &mut server_end,
+ bind_reason: BindReason::Eager,
+ }),
+ ),
_ => panic!("not a directory or storage capability"),
};
-
- if let Err(e) = res {
+ if let Err(e) = route_and_open_capability(route_request, &target, open_options).await {
routing::report_routing_failure(
&target,
&ComponentCapability::Use(use_),
@@ -455,32 +447,43 @@
}
};
let mut server_end = server_end.into_channel();
- let res: Result<_, ModelError> = match &use_ {
- UseDecl::Service(service) => routing::route_service(service.clone(), &target).await.map_err(|err| err.into()),
- UseDecl::Protocol(protocol) => routing::route_protocol(protocol.clone(), &target).await,
- _ => panic!("add_service_or_protocol_use called with non-service or protocol capability"),
- };
- let res = match res {
- Ok(source) => {
- routing::open_capability_at_source(
- flags,
- mode,
- PathBuf::from(relative_path),
- source,
- &target,
- &mut server_end,
- )
- .await
+ let (route_request, open_options) = {
+ match &use_ {
+ UseDecl::Service(use_service_decl) => {
+ (RouteRequest::UseService(use_service_decl.clone()),
+ OpenOptions::Service(
+ OpenServiceOptions{
+ flags,
+ open_mode: mode,
+ relative_path,
+ server_chan: &mut server_end
+ }
+ ))
+ },
+ UseDecl::Protocol(use_protocol_decl) => {
+ (RouteRequest::UseProtocol(use_protocol_decl.clone()),
+ OpenOptions::Protocol(
+ OpenProtocolOptions{
+ flags,
+ open_mode:mode,
+ relative_path,
+ server_chan: &mut server_end
+ }
+ ))
+ },
+ _ => panic!("add_service_or_protocol_use called with non-service or protocol capability"),
}
- Err(err) => Err(err),
};
+
+ let res = routing::route_and_open_capability(route_request, &target, open_options).await;
if let Err(e) = res {
routing::report_routing_failure(
&target,
&ComponentCapability::Use(use_),
&e,
server_end,
- ).await;
+ )
+ .await;
}
})
.detach();
diff --git a/src/sys/component_manager/src/model/resolver.rs b/src/sys/component_manager/src/model/resolver.rs
index c723c1d..5837c60 100644
--- a/src/sys/component_manager/src/model/resolver.rs
+++ b/src/sys/component_manager/src/model/resolver.rs
@@ -6,7 +6,7 @@
crate::model::{
component::{ComponentInstance, WeakComponentInstance},
error::ModelError,
- routing,
+ routing::{route_and_open_capability, OpenOptions, OpenResolverOptions, RouteRequest},
},
::routing::component_instance::ComponentInstanceInterface,
anyhow::Error,
@@ -15,7 +15,7 @@
cm_rust::ResolverRegistration,
fidl_fuchsia_io as fio, fidl_fuchsia_mem as fmem, fidl_fuchsia_sys2 as fsys,
fuchsia_zircon::Status,
- std::{collections::HashMap, path::PathBuf, sync::Arc},
+ std::{collections::HashMap, sync::Arc},
thiserror::Error,
url::Url,
};
@@ -112,16 +112,15 @@
let (proxy, server_end) = fidl::endpoints::create_proxy::<fsys::ComponentResolverMarker>()
.map_err(ResolverError::internal)?;
let component = self.component.upgrade().map_err(ResolverError::routing_error)?;
- let capability_source = routing::route_resolver(self.registration.clone(), &component)
- .await
- .map_err(ResolverError::routing_error)?;
- routing::open_capability_at_source(
- fio::OPEN_RIGHT_READABLE | fio::OPEN_RIGHT_WRITABLE,
- fio::MODE_TYPE_SERVICE,
- PathBuf::new(),
- capability_source,
+ let open_options = OpenResolverOptions {
+ flags: fio::OPEN_RIGHT_READABLE | fio::OPEN_RIGHT_WRITABLE,
+ open_mode: fio::MODE_TYPE_SERVICE,
+ server_chan: &mut server_end.into_channel(),
+ };
+ route_and_open_capability(
+ RouteRequest::Resolver(self.registration.clone()),
&component,
- &mut server_end.into_channel(),
+ OpenOptions::Resolver(open_options),
)
.await
.map_err(ResolverError::routing_error)?;
diff --git a/src/sys/component_manager/src/model/routing/mod.rs b/src/sys/component_manager/src/model/routing/mod.rs
index d827a490..2e20d27 100644
--- a/src/sys/component_manager/src/model/routing/mod.rs
+++ b/src/sys/component_manager/src/model/routing/mod.rs
@@ -3,8 +3,10 @@
// found in the LICENSE file.
pub mod error;
+pub mod open;
pub use error::OpenResourceError;
pub use error::RoutingError;
+pub use open::*;
mod service;
@@ -60,6 +62,30 @@
const SERVICE_OPEN_FLAGS: u32 =
fio::OPEN_FLAG_DESCRIBE | fio::OPEN_RIGHT_READABLE | fio::OPEN_RIGHT_WRITABLE;
+/// Routes a capability from `target` to its source. Opens the capability if routing succeeds.
+///
+/// If the capability is not allowed to be routed to the `target`, per the
+/// [`crate::model::policy::GlobalPolicyChecker`], the capability is not opened and an error
+/// is returned.
+pub(super) async fn route_and_open_capability(
+ route_request: RouteRequest,
+ target: &Arc<ComponentInstance>,
+ open_options: OpenOptions<'_>,
+) -> Result<(), ModelError> {
+ match route_request {
+ RouteRequest::UseStorage(use_storage_decl) => {
+ let (storage_source_info, relative_moniker) =
+ route_storage_and_backing_directory(use_storage_decl, target).await?;
+ open_storage_capability(storage_source_info, relative_moniker, target, open_options)
+ .await
+ }
+ _ => {
+ let route_source = route_capability(route_request, target).await?;
+ open_capability_at_source(OpenRequest::new(route_source, target, open_options)).await
+ }
+ }
+}
+
/// Routes a capability from `target` to its source, starting from a `use_decl`.
///
/// If the capability is allowed to be routed to the `target`, per the
@@ -79,55 +105,15 @@
target: &Arc<ComponentInstance>,
server_chan: &mut zx::Channel,
) -> Result<(), ModelError> {
- match use_decl {
- UseDecl::Service(use_service_decl) => {
- let source = route_service(use_service_decl, target).await?;
- open_capability_at_source(
- flags,
- open_mode,
- PathBuf::from(relative_path),
- source,
- target,
- server_chan,
- )
- .await
- }
- UseDecl::Protocol(use_protocol_decl) => {
- let source = route_protocol(use_protocol_decl, target).await?;
- open_capability_at_source(flags, open_mode, PathBuf::new(), source, target, server_chan)
- .await
- }
- UseDecl::Directory(use_directory_decl) => {
- let (source, directory_state) = route_directory(use_directory_decl, target).await?;
- open_capability_at_source(
- flags,
- open_mode,
- directory_state.make_relative_path(relative_path),
- source,
- target,
- server_chan,
- )
- .await
- }
- UseDecl::Storage(use_storage_decl) => {
- // TODO(fxbug.dev/50716): This BindReason is wrong. We need to refactor the Storage
- // capability to plumb through the correct BindReason.
- route_and_open_storage_capability(
- use_storage_decl,
- open_mode,
- target,
- server_chan,
- &BindReason::Eager,
- )
- .await
- }
- UseDecl::Event(_) | UseDecl::EventStream(_) => {
- // These capabilities are not representable on a VFS.
- Err(ModelError::unsupported(
- "opening a capability that cannot be installed in a namespace",
- ))
- }
- }
+ let route_request = request_for_namespace_capability_use(use_decl)?;
+ let open_options = OpenOptions::for_namespace_capability(
+ &route_request,
+ flags,
+ open_mode,
+ relative_path,
+ server_chan,
+ )?;
+ route_and_open_capability(route_request, target, open_options).await
}
/// Routes a capability from `target` to its source, starting from an `expose_decl`.
@@ -149,34 +135,40 @@
target: &Arc<ComponentInstance>,
server_chan: &mut zx::Channel,
) -> Result<(), ModelError> {
- let (capability_source, relative_path) = match expose_decl {
- ExposeDecl::Service(expose_service_decl) => (
- route_service_from_expose(expose_service_decl, target).await?,
- PathBuf::from(relative_path),
- ),
- ExposeDecl::Protocol(expose_protocol_decl) => {
- (route_protocol_from_expose(expose_protocol_decl, target).await?, PathBuf::new())
- }
- ExposeDecl::Directory(expose_directory_decl) => {
- let (capability_source, directory_state) =
- route_directory_from_expose(expose_directory_decl, target).await?;
- (capability_source, directory_state.make_relative_path(relative_path))
- }
- ExposeDecl::Runner(_) | ExposeDecl::Resolver(_) => {
- return Err(ModelError::unsupported(
- "opening a capability that cannot be installed in a namespace",
- ))
- }
- };
- open_capability_at_source(
+ let route_request = request_for_namespace_capability_expose(expose_decl)?;
+ let open_options = OpenOptions::for_namespace_capability(
+ &route_request,
flags,
open_mode,
relative_path,
- capability_source,
- target,
server_chan,
- )
- .await
+ )?;
+ route_and_open_capability(route_request, target, open_options).await
+}
+
+/// Create a new `RouteRequest` from a `UseDecl`, checking that the capability type can
+/// be installed in a namespace.
+fn request_for_namespace_capability_use(use_decl: UseDecl) -> Result<RouteRequest, ModelError> {
+ match use_decl {
+ UseDecl::Directory(decl) => Ok(RouteRequest::UseDirectory(decl)),
+ UseDecl::Protocol(decl) => Ok(RouteRequest::UseProtocol(decl)),
+ UseDecl::Service(decl) => Ok(RouteRequest::UseService(decl)),
+ UseDecl::Storage(decl) => Ok(RouteRequest::UseStorage(decl)),
+ _ => Err(ModelError::unsupported("capability cannot be installed in a namespace")),
+ }
+}
+
+/// Create a new `RouteRequest` from an `ExposeDecl`, checking that the capability type can
+/// be installed in a namespace.
+fn request_for_namespace_capability_expose(
+ expose_decl: ExposeDecl,
+) -> Result<RouteRequest, ModelError> {
+ match expose_decl {
+ ExposeDecl::Directory(decl) => Ok(RouteRequest::ExposeDirectory(decl)),
+ ExposeDecl::Protocol(decl) => Ok(RouteRequest::ExposeProtocol(decl)),
+ ExposeDecl::Service(decl) => Ok(RouteRequest::ExposeService(decl)),
+ _ => Err(ModelError::unsupported("capability cannot be installed in a namespace")),
+ }
}
/// The default provider for a ComponentCapability.
@@ -273,22 +265,10 @@
/// Opens the capability at `source`, triggering a `CapabilityRouted` event and binding
/// to the source component instance if necessary.
///
-/// If the capability is not allowed to be routed to the `target`, per the
-/// [`crate::model::policy::GlobalPolicyChecker`], the capability is not opened and an error
-/// is returned.
-///
/// See [`fidl_fuchsia_io::Directory::Open`] for how the `flags`, `open_mode`, `relative_path`,
/// and `server_chan` parameters are used in the open call.
-pub async fn open_capability_at_source(
- flags: u32,
- open_mode: u32,
- relative_path: PathBuf,
- source: CapabilitySource,
- target: &Arc<ComponentInstance>,
- server_chan: &mut zx::Channel,
-) -> Result<(), ModelError> {
- target.try_get_policy_checker()?.can_route_capability(&source, &target.abs_moniker)?;
-
+async fn open_capability_at_source(open_request: OpenRequest<'_>) -> Result<(), ModelError> {
+ let OpenRequest { flags, open_mode, relative_path, source, target, server_chan } = open_request;
// When serving a collection, routing hasn't reached the source. The CapabilityRouted event
// should not fire, nor should hooks be able to modify the provider (which is hosted by
// component_manager). Once a component is routed to from the collection, CapabilityRouted will
@@ -404,6 +384,22 @@
}
}
+/// Routes a storage capability from `target` to its source and deletes its isolated storage.
+pub(super) async fn route_and_delete_storage(
+ use_storage_decl: UseStorageDecl,
+ target: &Arc<ComponentInstance>,
+) -> Result<(), ModelError> {
+ let (storage_source_info, relative_moniker) =
+ route_storage_and_backing_directory(use_storage_decl, target).await?;
+
+ storage::delete_isolated_storage(
+ storage_source_info,
+ relative_moniker,
+ target.instance_id().as_ref(),
+ )
+ .await
+}
+
/// Sets an epitaph on `server_end` for a capability routing failure, and logs the error. Logs a
/// failure to route a capability. Formats `err` as a `String`, but elides the type if the error is
/// a `RoutingError`, the common case.
@@ -432,6 +428,178 @@
.await
}
+/// Routes a storage capability from `target` to its source and opens its backing directory
+/// capability, binding to the component instance if necessary.
+///
+/// See [`fidl_fuchsia_io::Directory::Open`] for how the `flags`, `open_mode`, `relative_path`,
+/// and `server_chan` parameters are used in the open call.
+async fn open_storage_capability(
+ source: storage::StorageCapabilitySource,
+ relative_moniker: RelativeMoniker,
+ target: &Arc<ComponentInstance>,
+ options: OpenOptions<'_>,
+) -> Result<(), ModelError> {
+ let dir_source = source.storage_provider.clone();
+ let relative_moniker_2 = relative_moniker.clone();
+ match options {
+ OpenOptions::Storage(OpenStorageOptions { open_mode, server_chan, bind_reason }) => {
+ let storage_dir_proxy = storage::open_isolated_storage(
+ source,
+ relative_moniker,
+ target.instance_id().as_ref(),
+ open_mode,
+ &bind_reason,
+ )
+ .await
+ .map_err(|e| ModelError::from(e))?;
+
+ // clone the final connection to connect the channel we're routing to its destination
+ let server_chan = channel::take_channel(server_chan);
+ storage_dir_proxy
+ .clone(fio::CLONE_FLAG_SAME_RIGHTS, ServerEnd::new(server_chan))
+ .map_err(|e| {
+ let moniker = match &dir_source {
+ Some(r) => ExtendedMoniker::ComponentInstance(r.abs_moniker.clone()),
+ None => ExtendedMoniker::ComponentManager,
+ };
+ ModelError::from(OpenResourceError::open_storage_failed(
+ &moniker,
+ &relative_moniker_2,
+ "",
+ e,
+ ))
+ })?;
+ return Ok(());
+ }
+ _ => unreachable!("expected OpenStorageOptions"),
+ }
+}
+
+// Functions which route capabilities without opening.
+// TODO(https://fxbug.dev/61861): Move everything below this comment into src/sys/lib/routing.
+
+/// A request to route a capability, together with the data needed to do so.
+pub enum RouteRequest {
+ // Route a capability from an ExposeDecl.
+ ExposeDirectory(ExposeDirectoryDecl),
+ ExposeProtocol(ExposeProtocolDecl),
+ ExposeService(ExposeServiceDecl),
+
+ // Route a capability from a realm's environment.
+ Resolver(ResolverRegistration),
+ Runner(CapabilityName),
+
+ // Route the directory capability that backs a storage capability.
+ StorageBackingDirectory(StorageDecl),
+
+ // Route a capability from a UseDecl.
+ UseDirectory(UseDirectoryDecl),
+ UseEvent(UseEventDecl),
+ UseProtocol(UseProtocolDecl),
+ UseService(UseServiceDecl),
+ UseStorage(UseStorageDecl),
+}
+
+/// The data returned after successfully routing a capability to its source.
+#[derive(Debug)]
+pub enum RouteSource {
+ Directory(CapabilitySource, DirectoryState),
+ Event(CapabilitySource),
+ Protocol(CapabilitySource),
+ Resolver(CapabilitySource),
+ Runner(CapabilitySource),
+ Service(CapabilitySource),
+ Storage(CapabilitySource),
+ StorageBackingDirectory(storage::StorageCapabilitySource),
+}
+
+/// Routes a capability to its source.
+///
+/// If the capability is not allowed to be routed to the `target`, per the
+/// [`crate::model::policy::GlobalPolicyChecker`], then an error is returned.
+pub(super) async fn route_capability(
+ request: RouteRequest,
+ target: &Arc<ComponentInstance>,
+) -> Result<RouteSource, RoutingError> {
+ match request {
+ // Route from an ExposeDecl
+ RouteRequest::ExposeDirectory(expose_directory_decl) => {
+ route_directory_from_expose(expose_directory_decl, target).await
+ }
+ RouteRequest::ExposeProtocol(expose_protocol_decl) => {
+ route_protocol_from_expose(expose_protocol_decl, target).await
+ }
+ RouteRequest::ExposeService(expose_service_decl) => {
+ route_service_from_expose(expose_service_decl, target).await
+ }
+
+ // Route a resolver or runner from an environment
+ RouteRequest::Resolver(resolver_registration) => {
+ route_resolver(resolver_registration, target).await
+ }
+ RouteRequest::Runner(runner_name) => route_runner(&runner_name, target).await,
+
+ // Route the backing directory for a storage capability
+ RouteRequest::StorageBackingDirectory(storage_decl) => {
+ route_storage_backing_directory(storage_decl, target).await
+ }
+
+ // Route from a UseDecl
+ RouteRequest::UseDirectory(use_directory_decl) => {
+ route_directory(use_directory_decl, target).await
+ }
+ RouteRequest::UseEvent(use_event_decl) => route_event(use_event_decl, target).await,
+ RouteRequest::UseProtocol(use_protocol_decl) => {
+ route_protocol(use_protocol_decl, target).await
+ }
+ RouteRequest::UseService(use_service_decl) => route_service(use_service_decl, target).await,
+ RouteRequest::UseStorage(use_storage_decl) => route_storage(use_storage_decl, target).await,
+ }
+}
+
+/// Routes a storage capability and its backing directory capability to their sources,
+/// returning the data needed to open the storage capability.
+///
+/// If either capability is not allowed to be routed to the `target`, per the
+/// [`crate::model::policy::GlobalPolicyChecker`], then an error is returned.
+pub(super) async fn route_storage_and_backing_directory(
+ use_decl: UseStorageDecl,
+ target: &Arc<ComponentInstance>,
+) -> Result<(storage::StorageCapabilitySource, RelativeMoniker), RoutingError> {
+ // First route the storage capability to its source.
+ let storage_source = {
+ match route_capability(RouteRequest::UseStorage(use_decl), target).await? {
+ RouteSource::Storage(source) => source,
+ _ => unreachable!("expected RouteSource::Storage"),
+ }
+ };
+
+ let (storage_decl, storage_component_instance) = match storage_source {
+ CapabilitySource::Component {
+ capability: ComponentCapability::Storage(storage_decl),
+ component,
+ } => (storage_decl, component.upgrade()?),
+ _ => unreachable!("unexpected storage source"),
+ };
+ let relative_moniker = RelativeMoniker::from_absolute(
+ &storage_component_instance.abs_moniker,
+ &target.abs_moniker,
+ );
+
+ // Now route the backing directory capability.
+ match route_capability(
+ RouteRequest::StorageBackingDirectory(storage_decl),
+ &storage_component_instance,
+ )
+ .await?
+ {
+ RouteSource::StorageBackingDirectory(storage_source_info) => {
+ Ok((storage_source_info, relative_moniker))
+ }
+ _ => unreachable!("expected RouteSource::StorageBackingDirectory"),
+ }
+}
+
make_noop_visitor!(ProtocolVisitor, {
OfferDecl => OfferProtocolDecl,
ExposeDecl => ExposeProtocolDecl,
@@ -439,10 +607,10 @@
});
/// Routes a Protocol capability from `target` to its source, starting from `use_decl`.
-pub async fn route_protocol(
+async fn route_protocol(
use_decl: UseProtocolDecl,
target: &Arc<ComponentInstance>,
-) -> Result<CapabilitySource, ModelError> {
+) -> Result<RouteSource, RoutingError> {
let allowed_sources = AllowedSourcesBuilder::new()
.framework(InternalCapability::Protocol)
.builtin(InternalCapability::Protocol)
@@ -499,34 +667,40 @@
&env_name,
&target.abs_moniker,
)?;
- return Ok(source);
+ return Ok(RouteSource::Protocol(source));
} else {
- Ok(RoutingStrategy::new()
+ let source = RoutingStrategy::new()
.use_::<UseProtocolDecl>()
.offer::<OfferProtocolDecl>()
.expose::<ExposeProtocolDecl>()
.route(use_decl, target.clone(), allowed_sources, &mut ProtocolVisitor)
- .await?)
+ .await?;
+
+ target.try_get_policy_checker()?.can_route_capability(&source, target.abs_moniker())?;
+ Ok(RouteSource::Protocol(source))
}
}
/// Routes a Protocol capability from `target` to its source, starting from `expose_decl`.
-pub async fn route_protocol_from_expose(
+async fn route_protocol_from_expose(
expose_decl: ExposeProtocolDecl,
target: &Arc<ComponentInstance>,
-) -> Result<CapabilitySource, RoutingError> {
+) -> Result<RouteSource, RoutingError> {
let allowed_sources = AllowedSourcesBuilder::new()
.framework(InternalCapability::Protocol)
.builtin(InternalCapability::Protocol)
.namespace()
.component()
.capability();
- RoutingStrategy::new()
+ let source = RoutingStrategy::new()
.use_::<UseProtocolDecl>()
.offer::<OfferProtocolDecl>()
.expose::<ExposeProtocolDecl>()
.route_from_expose(expose_decl, target.clone(), allowed_sources, &mut ProtocolVisitor)
- .await
+ .await?;
+
+ target.try_get_policy_checker()?.can_route_capability(&source, target.abs_moniker())?;
+ Ok(RouteSource::Protocol(source))
}
make_noop_visitor!(ServiceVisitor, {
@@ -535,34 +709,40 @@
CapabilityDecl => ServiceDecl,
});
-pub async fn route_service(
+async fn route_service(
use_decl: UseServiceDecl,
target: &Arc<ComponentInstance>,
-) -> Result<CapabilitySource, RoutingError> {
+) -> Result<RouteSource, RoutingError> {
let allowed_sources = AllowedSourcesBuilder::new().component().collection();
- RoutingStrategy::new()
+ let source = RoutingStrategy::new()
.use_::<UseServiceDecl>()
.offer::<OfferServiceDecl>()
.expose::<ExposeServiceDecl>()
.route(use_decl, target.clone(), allowed_sources, &mut ServiceVisitor)
- .await
+ .await?;
+
+ target.try_get_policy_checker()?.can_route_capability(&source, target.abs_moniker())?;
+ Ok(RouteSource::Service(source))
}
async fn route_service_from_expose(
expose_decl: ExposeServiceDecl,
target: &Arc<ComponentInstance>,
-) -> Result<CapabilitySource, RoutingError> {
+) -> Result<RouteSource, RoutingError> {
let allowed_sources = AllowedSourcesBuilder::new().component().collection();
- RoutingStrategy::new()
+ let source = RoutingStrategy::new()
.use_::<UseServiceDecl>()
.offer::<OfferServiceDecl>()
.expose::<ExposeServiceDecl>()
.route_from_expose(expose_decl, target.clone(), allowed_sources, &mut ServiceVisitor)
- .await
+ .await?;
+
+ target.try_get_policy_checker()?.can_route_capability(&source, target.abs_moniker())?;
+ Ok(RouteSource::Service(source))
}
/// The accumulated state of routing a Directory capability.
-#[derive(Clone)]
+#[derive(Clone, Debug)]
pub struct DirectoryState {
rights: WalkState<Rights>,
subdir: PathBuf,
@@ -638,10 +818,10 @@
/// Routes a Directory capability from `target` to its source, starting from `use_decl`.
/// Returns the capability source, along with a `DirectoryState` accumulated from traversing
/// the route.
-pub async fn route_directory(
+async fn route_directory(
use_decl: UseDirectoryDecl,
target: &Arc<ComponentInstance>,
-) -> Result<(CapabilitySource, DirectoryState), RoutingError> {
+) -> Result<RouteSource, RoutingError> {
let mut state = DirectoryState::new(use_decl.rights.clone(), use_decl.subdir.clone());
if let UseSource::Framework = &use_decl.source {
state.finalize(*READ_RIGHTS, None)?;
@@ -657,16 +837,18 @@
.expose::<ExposeDirectoryDecl>()
.route(use_decl, target.clone(), allowed_sources, &mut state)
.await?;
- Ok((source, state))
+
+ target.try_get_policy_checker()?.can_route_capability(&source, target.abs_moniker())?;
+ Ok(RouteSource::Directory(source, state))
}
/// Routes a Directory capability from `target` to its source, starting from `expose_decl`.
/// Returns the capability source, along with a `DirectoryState` accumulated from traversing
/// the route.
-pub async fn route_directory_from_expose(
+async fn route_directory_from_expose(
expose_decl: ExposeDirectoryDecl,
target: &Arc<ComponentInstance>,
-) -> Result<(CapabilitySource, DirectoryState), RoutingError> {
+) -> Result<RouteSource, RoutingError> {
let mut state = DirectoryState { rights: WalkState::new(), subdir: PathBuf::new() };
let allowed_sources = AllowedSourcesBuilder::new()
.framework(InternalCapability::Directory)
@@ -679,69 +861,9 @@
.expose::<ExposeDirectoryDecl>()
.route_from_expose(expose_decl, target.clone(), allowed_sources, &mut state)
.await?;
- Ok((source, state))
-}
-/// Routes a storage capability from `target` to its source and opens its backing directory
-/// capability, binding to the component instance if necessary.
-///
-/// If the capability is not allowed to be routed to the `target`, per the
-/// [`crate::model::policy::GlobalPolicyChecker`], the capability is not opened and an error
-/// is returned.
-///
-/// See [`fidl_fuchsia_io::Directory::Open`] for how the `flags`, `open_mode`, `relative_path`,
-/// and `server_chan` parameters are used in the open call.
-pub async fn route_and_open_storage_capability(
- use_decl: UseStorageDecl,
- open_mode: u32,
- target: &Arc<ComponentInstance>,
- server_chan: &mut zx::Channel,
- bind_reason: &BindReason,
-) -> Result<(), ModelError> {
- let (storage_source_info, relative_moniker) = route_storage(use_decl, target).await?;
- let dir_source = storage_source_info.storage_provider.clone();
- let relative_moniker_2 = relative_moniker.clone();
- let storage_dir_proxy = storage::open_isolated_storage(
- storage_source_info,
- relative_moniker,
- target.instance_id().as_ref(),
- open_mode,
- bind_reason,
- )
- .await
- .map_err(|e| ModelError::from(e))?;
-
- // clone the final connection to connect the channel we're routing to its destination
- let server_chan = channel::take_channel(server_chan);
- storage_dir_proxy.clone(fio::CLONE_FLAG_SAME_RIGHTS, ServerEnd::new(server_chan)).map_err(
- |e| {
- let moniker = match &dir_source {
- Some(r) => ExtendedMoniker::ComponentInstance(r.abs_moniker.clone()),
- None => ExtendedMoniker::ComponentManager,
- };
- ModelError::from(OpenResourceError::open_storage_failed(
- &moniker,
- &relative_moniker_2,
- "",
- e,
- ))
- },
- )?;
- Ok(())
-}
-
-/// Routes a storage capability from `target` to its source and deletes its isolated storage.
-pub(super) async fn route_and_delete_storage(
- use_decl: UseStorageDecl,
- target: &Arc<ComponentInstance>,
-) -> Result<(), ModelError> {
- let (storage_source_info, relative_moniker) = route_storage(use_decl, target).await?;
- storage::delete_isolated_storage(
- storage_source_info,
- relative_moniker,
- target.instance_id().as_ref(),
- )
- .await
+ target.try_get_policy_checker()?.can_route_capability(&source, target.abs_moniker())?;
+ Ok(RouteSource::Directory(source, state))
}
make_noop_visitor!(StorageVisitor, {
@@ -754,39 +876,24 @@
async fn route_storage(
use_decl: UseStorageDecl,
target: &Arc<ComponentInstance>,
-) -> Result<(storage::StorageCapabilitySource, RelativeMoniker), ModelError> {
+) -> Result<RouteSource, RoutingError> {
let allowed_sources = AllowedSourcesBuilder::new().component();
- let storage_source = RoutingStrategy::new()
+ let source = RoutingStrategy::new()
.use_::<UseStorageDecl>()
.offer::<OfferStorageDecl>()
.route(use_decl, target.clone(), allowed_sources, &mut StorageVisitor)
.await?;
- target.try_get_policy_checker()?.can_route_capability(&storage_source, &target.abs_moniker)?;
- let (storage_decl, storage_component_instance) = match storage_source {
- CapabilitySource::Component {
- capability: ComponentCapability::Storage(storage_decl),
- component,
- } => (storage_decl, component.upgrade()?),
- _ => unreachable!("unexpected storage source"),
- };
- let relative_moniker = RelativeMoniker::from_absolute(
- &storage_component_instance.abs_moniker,
- &target.abs_moniker,
- );
- // The storage capability was routed to its source. Now route the backing directory capability.
- Ok((
- route_storage_backing_directory(storage_decl, storage_component_instance).await?,
- relative_moniker,
- ))
+ target.try_get_policy_checker()?.can_route_capability(&source, target.abs_moniker())?;
+ Ok(RouteSource::Storage(source))
}
/// Routes the backing Directory capability of a Storage capability from `target` to its source,
/// starting from `storage_decl`.
-pub async fn route_storage_backing_directory(
+async fn route_storage_backing_directory(
storage_decl: StorageDecl,
- target: Arc<ComponentInstance>,
-) -> Result<storage::StorageCapabilitySource, RoutingError> {
+ target: &Arc<ComponentInstance>,
+) -> Result<RouteSource, RoutingError> {
// Storage rights are always READ+WRITE.
let mut state = DirectoryState::new(*READ_RIGHTS | *WRITE_RIGHTS, None);
let allowed_sources = AllowedSourcesBuilder::new().component().namespace();
@@ -794,9 +901,11 @@
.registration::<StorageDeclAsRegistration>()
.offer::<OfferDirectoryDecl>()
.expose::<ExposeDirectoryDecl>()
- .route(storage_decl.clone().into(), target, allowed_sources, &mut state)
+ .route(storage_decl.clone().into(), target.clone(), allowed_sources, &mut state)
.await?;
+ target.try_get_policy_checker()?.can_route_capability(&source, target.abs_moniker())?;
+
let (dir_source_path, dir_source_instance) = match source {
CapabilitySource::Component { capability, component } => (
capability.source_path().expect("directory has no source path?").clone(),
@@ -810,12 +919,12 @@
let dir_subdir = if state.subdir == Path::new("") { None } else { Some(state.subdir) };
- Ok(storage::StorageCapabilitySource {
+ Ok(RouteSource::StorageBackingDirectory(storage::StorageCapabilitySource {
storage_provider: dir_source_instance,
backing_directory_path: dir_source_path,
backing_directory_subdir: dir_subdir,
storage_subdir: storage_decl.subdir.clone(),
- })
+ }))
}
make_noop_visitor!(RunnerVisitor, {
@@ -826,10 +935,10 @@
/// Finds a Runner capability that matches `runner` in the `target`'s environment, and then
/// routes the Runner capability from the environment's component instance to its source.
-pub async fn route_runner(
+async fn route_runner(
runner: &CapabilityName,
target: &Arc<ComponentInstance>,
-) -> Result<CapabilitySource, RoutingError> {
+) -> Result<RouteSource, RoutingError> {
// Find the component instance in which the runner was registered with the environment.
let (env_component_instance, registration_decl) =
match target.environment().get_registered_runner(&runner)? {
@@ -838,10 +947,10 @@
}
Some((ExtendedInstance::AboveRoot(top_instance), reg)) => {
// Root environment.
- return Ok(CapabilitySource::Builtin {
+ return Ok(RouteSource::Runner(CapabilitySource::Builtin {
capability: InternalCapability::Runner(reg.source_name.clone()),
top_instance: Arc::downgrade(&top_instance),
- });
+ }));
}
None => {
return Err(RoutingError::UseFromEnvironmentNotFound {
@@ -855,12 +964,15 @@
let allowed_sources =
AllowedSourcesBuilder::new().builtin(InternalCapability::Runner).component();
- RoutingStrategy::new()
+ let source = RoutingStrategy::new()
.registration::<RunnerRegistration>()
.offer::<OfferRunnerDecl>()
.expose::<ExposeRunnerDecl>()
.route(registration_decl, env_component_instance, allowed_sources, &mut RunnerVisitor)
- .await
+ .await?;
+
+ target.try_get_policy_checker()?.can_route_capability(&source, target.abs_moniker())?;
+ Ok(RouteSource::Runner(source))
}
make_noop_visitor!(ResolverVisitor, {
@@ -870,18 +982,22 @@
});
/// Routes a Resolver capability from `target` to its source, starting from `registration_decl`.
-pub async fn route_resolver(
+async fn route_resolver(
registration: ResolverRegistration,
target: &Arc<ComponentInstance>,
-) -> Result<CapabilitySource, RoutingError> {
+) -> Result<RouteSource, RoutingError> {
let allowed_sources =
AllowedSourcesBuilder::new().builtin(InternalCapability::Resolver).component();
- RoutingStrategy::new()
+
+ let source = RoutingStrategy::new()
.registration::<ResolverRegistration>()
.offer::<OfferResolverDecl>()
.expose::<ExposeResolverDecl>()
.route(registration, target.clone(), allowed_sources, &mut ResolverVisitor)
- .await
+ .await?;
+
+ target.try_get_policy_checker()?.can_route_capability(&source, target.abs_moniker())?;
+ Ok(RouteSource::Resolver(source))
}
/// State accumulated from routing an Event capability to its source.
@@ -916,10 +1032,10 @@
}
/// Routes an Event capability from `target` to its source, starting from `use_decl`.
-pub async fn route_event(
+async fn route_event(
use_decl: UseEventDecl,
target: &Arc<ComponentInstance>,
-) -> Result<CapabilitySource, ModelError> {
+) -> Result<RouteSource, RoutingError> {
let mut state = EventState {
filter_state: WalkState::at(EventFilter::new(use_decl.filter.clone())),
modes_state: WalkState::at(EventModeSet::new(use_decl.mode.clone())),
@@ -933,6 +1049,7 @@
.offer::<OfferEventDecl>()
.route(use_decl, target.clone(), allowed_sources, &mut state)
.await?;
- target.try_get_policy_checker()?.can_route_capability(&source, &target.abs_moniker)?;
- Ok(source)
+
+ target.try_get_policy_checker()?.can_route_capability(&source, target.abs_moniker())?;
+ Ok(RouteSource::Event(source))
}
diff --git a/src/sys/component_manager/src/model/routing/open.rs b/src/sys/component_manager/src/model/routing/open.rs
new file mode 100644
index 0000000..024174e
--- /dev/null
+++ b/src/sys/component_manager/src/model/routing/open.rs
@@ -0,0 +1,198 @@
+// Copyright 2021 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.
+
+use {
+ crate::{
+ capability::CapabilitySource,
+ model::{
+ component::{BindReason, ComponentInstance},
+ error::ModelError,
+ routing::{RouteRequest, RouteSource},
+ },
+ },
+ fuchsia_zircon as zx,
+ std::{path::PathBuf, sync::Arc},
+};
+
+/// A container for the data needed to open a capability.
+pub enum OpenOptions<'a> {
+ Directory(OpenDirectoryOptions<'a>),
+ Protocol(OpenProtocolOptions<'a>),
+ Resolver(OpenResolverOptions<'a>),
+ Runner(OpenRunnerOptions<'a>),
+ Service(OpenServiceOptions<'a>),
+ Storage(OpenStorageOptions<'a>),
+}
+
+impl<'a> OpenOptions<'a> {
+ /// Creates an `OpenOptions` for a capability that can be installed in a namespace,
+ /// or an error if `route_request` specifies a capability that cannot be installed
+ /// in a namespace.
+ pub fn for_namespace_capability(
+ route_request: &RouteRequest,
+ flags: u32,
+ open_mode: u32,
+ relative_path: String,
+ server_chan: &'a mut zx::Channel,
+ ) -> Result<Self, ModelError> {
+ match route_request {
+ RouteRequest::UseDirectory(_) | RouteRequest::ExposeDirectory(_) => {
+ Ok(Self::Directory(OpenDirectoryOptions {
+ flags,
+ open_mode,
+ relative_path,
+ server_chan,
+ }))
+ }
+ RouteRequest::UseProtocol(_) | RouteRequest::ExposeProtocol(_) => {
+ Ok(Self::Protocol(OpenProtocolOptions {
+ flags,
+ open_mode,
+ relative_path,
+ server_chan,
+ }))
+ }
+ RouteRequest::UseService(_) | RouteRequest::ExposeService(_) => {
+ Ok(Self::Service(OpenServiceOptions {
+ flags,
+ open_mode,
+ relative_path,
+ server_chan,
+ }))
+ }
+ // TODO(fxbug.dev/50716): This BindReason is wrong. We need to refactor the Storage
+ // capability to plumb through the correct BindReason.
+ RouteRequest::UseStorage(_) => Ok(Self::Storage(OpenStorageOptions {
+ open_mode,
+ server_chan,
+ bind_reason: BindReason::Eager,
+ })),
+ _ => Err(ModelError::unsupported("capability cannot be installed in a namespace")),
+ }
+ }
+}
+
+pub struct OpenDirectoryOptions<'a> {
+ pub flags: u32,
+ pub open_mode: u32,
+ pub relative_path: String,
+ pub server_chan: &'a mut zx::Channel,
+}
+
+pub struct OpenProtocolOptions<'a> {
+ pub flags: u32,
+ pub open_mode: u32,
+ pub relative_path: String,
+ pub server_chan: &'a mut zx::Channel,
+}
+
+pub struct OpenResolverOptions<'a> {
+ pub flags: u32,
+ pub open_mode: u32,
+ pub server_chan: &'a mut zx::Channel,
+}
+
+pub struct OpenRunnerOptions<'a> {
+ pub flags: u32,
+ pub open_mode: u32,
+ pub server_chan: &'a mut zx::Channel,
+}
+
+pub struct OpenServiceOptions<'a> {
+ pub flags: u32,
+ pub open_mode: u32,
+ pub relative_path: String,
+ pub server_chan: &'a mut zx::Channel,
+}
+
+pub struct OpenStorageOptions<'a> {
+ pub open_mode: u32,
+ pub server_chan: &'a mut zx::Channel,
+ pub bind_reason: BindReason,
+}
+
+/// A request to open a capability at its source.
+pub struct OpenRequest<'a> {
+ pub flags: u32,
+ pub open_mode: u32,
+ pub relative_path: PathBuf,
+ pub source: CapabilitySource,
+ pub target: &'a Arc<ComponentInstance>,
+ pub server_chan: &'a mut zx::Channel,
+}
+
+impl<'a> OpenRequest<'a> {
+ /// Creates a request to open a capability with source `route_source` for `target`.
+ pub fn new(
+ route_source: RouteSource,
+ target: &'a Arc<ComponentInstance>,
+ options: OpenOptions<'a>,
+ ) -> Self {
+ match route_source {
+ RouteSource::Directory(source, directory_state) => {
+ if let OpenOptions::Directory(open_dir_options) = options {
+ return Self {
+ flags: open_dir_options.flags,
+ open_mode: open_dir_options.open_mode,
+ relative_path: directory_state
+ .make_relative_path(open_dir_options.relative_path),
+ source,
+ target,
+ server_chan: open_dir_options.server_chan,
+ };
+ }
+ }
+ RouteSource::Protocol(source) => {
+ if let OpenOptions::Protocol(open_protocol_options) = options {
+ return Self {
+ flags: open_protocol_options.flags,
+ open_mode: open_protocol_options.open_mode,
+ relative_path: PathBuf::from(open_protocol_options.relative_path),
+ source,
+ target,
+ server_chan: open_protocol_options.server_chan,
+ };
+ }
+ }
+ RouteSource::Service(source) => {
+ if let OpenOptions::Service(open_service_options) = options {
+ return Self {
+ flags: open_service_options.flags,
+ open_mode: open_service_options.open_mode,
+ relative_path: PathBuf::from(open_service_options.relative_path),
+ source,
+ target,
+ server_chan: open_service_options.server_chan,
+ };
+ }
+ }
+ RouteSource::Resolver(source) => {
+ if let OpenOptions::Resolver(open_resolver_options) = options {
+ return Self {
+ flags: open_resolver_options.flags,
+ open_mode: open_resolver_options.open_mode,
+ relative_path: PathBuf::new(),
+ source,
+ target,
+ server_chan: open_resolver_options.server_chan,
+ };
+ }
+ }
+ RouteSource::Runner(source) => {
+ if let OpenOptions::Runner(open_runner_options) = options {
+ return Self {
+ flags: open_runner_options.flags,
+ open_mode: open_runner_options.open_mode,
+ relative_path: PathBuf::new(),
+ source,
+ target,
+ server_chan: open_runner_options.server_chan,
+ };
+ }
+ }
+ _ => panic!("unsupported route source"),
+ }
+ panic!("route source type did not match option type")
+ }
+}
diff --git a/src/sys/component_manager/src/model/routing/service.rs b/src/sys/component_manager/src/model/routing/service.rs
index f848027..4d855d5e 100644
--- a/src/sys/component_manager/src/model/routing/service.rs
+++ b/src/sys/component_manager/src/model/routing/service.rs
@@ -8,7 +8,7 @@
model::{
component::{ComponentInstance, WeakComponentInstance},
error::ModelError,
- routing::open_capability_at_source,
+ routing::{open_capability_at_source, OpenRequest},
},
},
::routing::capability_source::CollectionCapabilityProvider,
@@ -123,14 +123,14 @@
} else {
Path::new(DEFAULT_INSTANCE).join(path.into_string())
};
- if let Err(err) = open_capability_at_source(
+ if let Err(err) = open_capability_at_source(OpenRequest {
flags,
- mode,
+ open_mode: mode,
relative_path,
source,
- &target,
- &mut server_end,
- )
+ target: &target,
+ server_chan: &mut server_end,
+ })
.await
{
let _ = server_end.close_with_epitaph(err.as_zx_status());
diff --git a/src/sys/component_manager/src/model/storage/admin_protocol.rs b/src/sys/component_manager/src/model/storage/admin_protocol.rs
index 2fa0120..8902fb9 100644
--- a/src/sys/component_manager/src/model/storage/admin_protocol.rs
+++ b/src/sys/component_manager/src/model/storage/admin_protocol.rs
@@ -18,7 +18,8 @@
component::{BindReason, WeakComponentInstance},
error::ModelError,
hooks::{Event, EventPayload, EventType, Hook, HooksRegistration},
- routing, storage,
+ routing::{route_capability, RouteRequest, RouteSource},
+ storage,
},
},
anyhow::{format_err, Error},
@@ -175,8 +176,14 @@
})?;
let storage_moniker = component.abs_moniker.clone();
- let storage_capability_source_info =
- routing::route_storage_backing_directory(storage_decl, component.clone()).await?;
+ let storage_capability_source_info = {
+ match route_capability(RouteRequest::StorageBackingDirectory(storage_decl), &component)
+ .await?
+ {
+ RouteSource::StorageBackingDirectory(storage_source) => storage_source,
+ _ => unreachable!("expected RouteSource::StorageBackingDirectory"),
+ }
+ };
let mut stream = ServerEnd::<fsys::StorageAdminMarker>::new(server_end)
.into_stream()
diff --git a/src/sys/component_manager/src/model/storage/mod.rs b/src/sys/component_manager/src/model/storage/mod.rs
index d1f7d52..b9a7855 100644
--- a/src/sys/component_manager/src/model/storage/mod.rs
+++ b/src/sys/component_manager/src/model/storage/mod.rs
@@ -116,7 +116,7 @@
/// Information returned by the route_storage_capability function on the source of a storage
/// capability.
-#[derive(Clone)]
+#[derive(Clone, Debug)]
pub struct StorageCapabilitySource {
/// The component that's providing the backing directory capability for this storage
/// capability. If None, then the backing directory comes from component_manager's namespace.
diff --git a/src/sys/component_manager/src/model/tests/routing.rs b/src/sys/component_manager/src/model/tests/routing.rs
index 2cba38c..dff1ed5 100644
--- a/src/sys/component_manager/src/model/tests/routing.rs
+++ b/src/sys/component_manager/src/model/tests/routing.rs
@@ -17,7 +17,7 @@
events::registry::EventSubscription,
hooks::{Event, EventPayload, EventType, Hook, HooksRegistration},
rights,
- routing::{self, RoutingError},
+ routing::{self, RouteRequest, RouteSource, RoutingError},
testing::{routing_test_helpers::*, test_helpers::*},
},
},
@@ -2619,16 +2619,14 @@
// Now attempt to route the service from "c". Should fail because "b" does not exist so we
// cannot follow it.
- let err = routing::route_protocol(use_protocol_decl, &realm_c)
+ let err = routing::route_capability(RouteRequest::UseProtocol(use_protocol_decl), &realm_c)
.await
.expect_err("routing unexpectedly succeeded");
assert_matches!(
err,
- ModelError::RoutingError {
- err: RoutingError::ComponentInstanceError(
- ComponentInstanceError::InstanceNotFound { moniker }
- )
- } if moniker == vec!["coll:b:1"].into()
+ RoutingError::ComponentInstanceError(
+ ComponentInstanceError::InstanceNotFound { moniker }
+ ) if moniker == vec!["coll:b:1"].into()
);
}
@@ -4407,12 +4405,12 @@
let root_instance = test.model.look_up(&AbsoluteMoniker::root()).await.expect("root instance");
let expected_source_moniker = AbsoluteMoniker::parse_string_without_instances("/b").unwrap();
assert_matches!(
- routing::route_protocol_from_expose(expose_decl, &root_instance).await,
- Ok(
+ routing::route_capability(RouteRequest::ExposeProtocol(expose_decl), &root_instance).await,
+ Ok(RouteSource::Protocol(
CapabilitySource::Component {
capability: ComponentCapability::Protocol(protocol_decl),
component,
- }
+ })
) if protocol_decl == expected_protocol_decl && component.moniker == expected_source_moniker
);
}
@@ -4906,13 +4904,14 @@
let test = RoutingTestBuilder::new("a", components).build().await;
let b_component = test.model.look_up(&vec!["b:0"].into()).await.expect("b instance");
let a_component = test.model.look_up(&AbsoluteMoniker::root()).await.expect("root instance");
- let source =
- routing::route_service(use_decl, &b_component).await.expect("failed to route service");
+ let source = routing::route_capability(RouteRequest::UseService(use_decl), &b_component)
+ .await
+ .expect("failed to route service");
match source {
- CapabilitySource::Component {
+ RouteSource::Service(CapabilitySource::Component {
capability: ComponentCapability::Service(ServiceDecl { name, source_path }),
component,
- } => {
+ }) => {
assert_eq!(name, CapabilityName("foo".into()));
assert_eq!(source_path, "/svc/foo".parse::<CapabilityPath>().unwrap());
assert!(Arc::ptr_eq(&component.upgrade().unwrap(), &a_component));
@@ -4973,15 +4972,16 @@
let test = RoutingTestBuilder::new("a", components).build().await;
let b_component = test.model.look_up(&vec!["b:0"].into()).await.expect("b instance");
let c_component = test.model.look_up(&vec!["c:0"].into()).await.expect("c instance");
- let source =
- routing::route_service(use_decl, &b_component).await.expect("failed to route service");
+ let source = routing::route_capability(RouteRequest::UseService(use_decl), &b_component)
+ .await
+ .expect("failed to route service");
// Verify this source comes from `c`.
match source {
- CapabilitySource::Component {
+ RouteSource::Service(CapabilitySource::Component {
capability: ComponentCapability::Service(ServiceDecl { name, source_path }),
component,
- } => {
+ }) => {
assert_eq!(name, CapabilityName("foo".into()));
assert_eq!(source_path, "/svc/foo".parse::<CapabilityPath>().unwrap());
assert!(Arc::ptr_eq(&component.upgrade().unwrap(), &c_component));
@@ -5018,10 +5018,16 @@
let test = RoutingTestBuilder::new("a", components).build().await;
let b_component = test.model.look_up(&vec!["b:0"].into()).await.expect("b instance");
let a_component = test.model.look_up(&AbsoluteMoniker::root()).await.expect("root instance");
- let source =
- routing::route_service(use_decl, &b_component).await.expect("failed to route service");
+ let source = routing::route_capability(RouteRequest::UseService(use_decl), &b_component)
+ .await
+ .expect("failed to route service");
match source {
- CapabilitySource::Collection { collection_name, source_name, component, .. } => {
+ RouteSource::Service(CapabilitySource::Collection {
+ collection_name,
+ source_name,
+ component,
+ ..
+ }) => {
assert_eq!(collection_name, "coll");
assert_eq!(source_name, CapabilityName("foo".into()));
assert!(Arc::ptr_eq(&component.upgrade().unwrap(), &a_component));
@@ -5119,10 +5125,13 @@
let client_component =
test.model.look_up(&vec!["client:0"].into()).await.expect("client instance");
- let source =
- routing::route_service(use_decl, &client_component).await.expect("failed to route service");
+ let source = routing::route_capability(RouteRequest::UseService(use_decl), &client_component)
+ .await
+ .expect("failed to route service");
let capability_provider = match source {
- CapabilitySource::Collection { capability_provider, .. } => capability_provider,
+ RouteSource::Service(CapabilitySource::Collection { capability_provider, .. }) => {
+ capability_provider
+ }
_ => panic!("bad capability source"),
};
diff --git a/src/sys/lib/routing/src/error.rs b/src/sys/lib/routing/src/error.rs
index af76834..541a361 100644
--- a/src/sys/lib/routing/src/error.rs
+++ b/src/sys/lib/routing/src/error.rs
@@ -349,7 +349,10 @@
/// Convert this error into its approximate `zx::Status` equivalent.
pub fn as_zx_status(&self) -> zx::Status {
- zx::Status::UNAVAILABLE
+ match self {
+ RoutingError::PolicyError(_) => zx::Status::ACCESS_DENIED,
+ _ => zx::Status::UNAVAILABLE,
+ }
}
pub fn source_instance_stopped(moniker: &AbsoluteMoniker) -> Self {