From 8cb0dc9c163c1fbf7c6a3528f5b51ccf00621e67 Mon Sep 17 00:00:00 2001
From: Norman Feske <norman.feske@genode-labs.com>
Date: Wed, 15 Feb 2017 16:42:49 +0100
Subject: [PATCH] init: session-label rewriting

This patch enhances init with the support for rewriting session labels
in the target node of a matching session route. For example, a Noux
instance may have the following session route for the "home" file
system:

<route>
  <service name="File_system" label="home">
    <child name="rump_fs"/>
  </service>
  ...
</route>

At the rump_fs file-system server, the label of the file-system session
will appear as "noux -> home". This information may be evaluated by
rump_fs's server-side policy. However, when renaming the noux instance,
we'd need to update this server-side policy.

With the new mechanism, the client's identity can be hidden from the
server. The label could instead represent the role of the client, or a
name of a physical resource. For example, the Noux route could be
changed to this:

<route>
  <service name="File_system" label="home">
    <child name="rump_fs" label="primary_user"/>
  </service>
  ...
</route>

When the rump_fs receives the session request, it is presented with the
label "primary_user". The fact that the client is "noux" is not taken
into account for the server-side policy selection.

Issue #2248
---
 repos/os/include/init/child.h        | 43 +++++++++++++++++-----------
 repos/os/include/init/child_policy.h | 18 ++++++------
 2 files changed, 36 insertions(+), 25 deletions(-)

diff --git a/repos/os/include/init/child.h b/repos/os/include/init/child.h
index 8d0977088c..17137368a0 100644
--- a/repos/os/include/init/child.h
+++ b/repos/os/include/init/child.h
@@ -156,7 +156,8 @@ namespace Init {
 	 * \param child_name    name of the originator of the session request
 	 * \param service_name  name of the requested service
 	 */
-	inline bool service_node_matches(Xml_node service_node, char const *args,
+	inline bool service_node_matches(Xml_node           const  service_node,
+	                                 Session_label      const &label,
 	                                 Child_policy::Name const &child_name,
 	                                 Service::Name      const &service_name)
 	{
@@ -184,15 +185,14 @@ namespace Init {
 				warning("service node contains both scoped and unscoped label attributes");
 
 			typedef String<Session_label::capacity()> Label;
-			Label const label = service_node.attribute_value(unscoped_attr, Label());
-			return label == label_from_args(args);
+			return label == service_node.attribute_value(unscoped_attr, Label());
 		}
 
 		if (!route_depends_on_child_provided_label)
 			return true;
 
 		char const * const scoped_label = skip_label_prefix(
-			child_name.string(), label_from_args(args).string());
+			child_name.string(), label.string());
 
 		if (!scoped_label)
 			return false;
@@ -602,21 +602,19 @@ class Init::Child : Child_policy, Child_service::Wakeup
 		Id_space<Parent::Server> &server_id_space() override {
 			return _session_requester.id_space(); }
 
-		Service &resolve_session_request(Service::Name const &service_name,
-		                                 Session_state::Args const &args) override
+		Route resolve_session_request(Service::Name const &service_name,
+		                              Session_label const &label) override
 		{
-			Session_label const label(label_from_args(args.string()));
-
 			Service *service = nullptr;
 
 			/* check for "config" ROM request */
-			if ((service = _config_policy.resolve_session_request(service_name.string(), args.string())))
-				return *service;
+			if ((service = _config_policy.resolve_session_request_with_label(service_name, label)))
+				return Route { *service, label };
 
 			/* check for "session_requests" ROM request */
 			if (service_name == Rom_session::service_name()
 			 && label.last_element() == Session_requester::rom_name())
-				return _session_requester.service();
+				return Route { _session_requester.service() };
 
 			try {
 				Xml_node route_node = _default_route_node;
@@ -629,16 +627,29 @@ class Init::Child : Child_policy, Child_service::Wakeup
 
 					bool service_wildcard = service_node.has_type("any-service");
 
-					if (!service_node_matches(service_node, args.string(), name(), service_name))
+					if (!service_node_matches(service_node, label, name(), service_name))
 						continue;
 
 					Xml_node target = service_node.sub_node();
 					for (; ; target = target.next()) {
 
+						/*
+						 * Determine session label to be provided to the server.
+						 *
+						 * By default, the client's identity (accompanied with
+						 * the a client-provided label) is presented as session
+						 * label to the server. However, the target node can
+						 * explicitly override the client's identity by a
+						 * custom label via the 'label' attribute.
+						 */
+						typedef String<Session_label::capacity()> Label;
+						Label const target_label =
+							target.attribute_value("label", Label(label.string()));
+
 						if (target.has_type("parent")) {
 
 							if ((service = find_service(_parent_services, service_name)))
-								return *service;
+								return Route { *service, target_label };
 
 							if (!service_wildcard) {
 								warning(name(), ": service lookup for "
@@ -658,7 +669,7 @@ class Init::Child : Child_policy, Child_service::Wakeup
 								 && s.child_name() == server_name)
 									service = &s; });
 							if (service)
-								return *service;
+								return Route { *service, target_label };
 
 							if (!service_wildcard) {
 								warning(name(), ": lookup to child "
@@ -675,7 +686,7 @@ class Init::Child : Child_policy, Child_service::Wakeup
 							}
 
 							if ((service = find_service(_child_services, service_name)))
-								return *service;
+								return Route { *service, target_label };
 
 							if (!service_wildcard) {
 								warning(name(), ": lookup for service "
@@ -695,7 +706,7 @@ class Init::Child : Child_policy, Child_service::Wakeup
 			if (!service)
 				throw Parent::Service_denied();
 
-			return *service;
+			return Route { *service };
 		}
 
 		void filter_session_args(Service::Name const &service,
diff --git a/repos/os/include/init/child_policy.h b/repos/os/include/init/child_policy.h
index d7967f9987..6085206fbb 100644
--- a/repos/os/include/init/child_policy.h
+++ b/repos/os/include/init/child_policy.h
@@ -162,18 +162,18 @@ class Init::Child_policy_provide_rom_file
 			_session(*ep, ds_cap), _module_name(module_name)
 		{ }
 
+		Service *resolve_session_request_with_label(Service::Name const &name,
+		                                            Session_label const &label)
+		{
+			return (name == "ROM" && label.last_element() == _module_name)
+			       ? &_service : nullptr;
+		}
+
 		Service *resolve_session_request(const char *service_name,
 		                                         const char *args)
 		{
-			/* ignore session requests for non-ROM services */
-			if (strcmp(service_name, "ROM")) return 0;
-
-			/* drop out if request refers to another file name */
-			{
-				Session_label const label = label_from_args(args);
-				return label.last_element() == _module_name
-				       ? &_service : nullptr;
-			}
+			return resolve_session_request_with_label(service_name,
+			                                          label_from_args(args));
 		}
 };