From dc4594b0bb0effdd261c70147a47ff0f0b8ee1f3 Mon Sep 17 00:00:00 2001 From: Emery Hemingway Date: Sat, 25 Apr 2020 17:10:03 +0530 Subject: [PATCH 1/3] init/sandbox: support Apply routing rules to a child from a node at the top-level of a sandbox config, unless the corresponding start node has as node. If neither are present routes are taken from as a fallback. Unlike the and the rules are checked by labels prefixed by child name, so may contain child-specific rules. --- repos/os/src/lib/sandbox/child.cc | 12 +++++++++++- repos/os/src/lib/sandbox/child.h | 10 ++++++++++ repos/os/src/lib/sandbox/library.cc | 14 +++++++++++++- repos/os/src/lib/sandbox/utils.h | 8 +++++--- 4 files changed, 39 insertions(+), 5 deletions(-) diff --git a/repos/os/src/lib/sandbox/child.cc b/repos/os/src/lib/sandbox/child.cc index e321df61fd..d25e3d9683 100644 --- a/repos/os/src/lib/sandbox/child.cc +++ b/repos/os/src/lib/sandbox/child.cc @@ -487,17 +487,25 @@ Sandbox::Child::resolve_session_request(Service::Name const &service_name, Session::Label(), Session::Diag{false} }; try { + /* Lookup route in … */ Xml_node route_node = _default_route_accessor.default_route(); + /* …unless is present… */ + route_node = _routes_accessor.routes(route_node); try { + /* …otherwise use . */ route_node = _start_node->xml().sub_node("route"); } catch (...) { } + Xml_node service_node = route_node.sub_node(); + /* is processed with the "«child» -> " prefix */ + bool skip_prefix = route_node.type() != "routes"; + for (; ; service_node = service_node.next()) { bool service_wildcard = service_node.has_type("any-service"); - if (!service_node_matches(service_node, label, name(), service_name)) + if (!service_node_matches(service_node, label, name(), service_name, skip_prefix)) continue; Xml_node target = service_node.sub_node(); @@ -705,6 +713,7 @@ Sandbox::Child::Child(Env &env, Report_update_trigger &report_update_trigger, Xml_node start_node, Default_route_accessor &default_route_accessor, + Routes_accessor &routes_accessor, Default_caps_accessor &default_caps_accessor, Name_registry &name_registry, Ram_quota ram_limit, @@ -722,6 +731,7 @@ Sandbox::Child::Child(Env &env, _list_element(this), _start_node(_alloc, start_node), _default_route_accessor(default_route_accessor), + _routes_accessor(routes_accessor), _default_caps_accessor(default_caps_accessor), _ram_limit_accessor(ram_limit_accessor), _cap_limit_accessor(cap_limit_accessor), diff --git a/repos/os/src/lib/sandbox/child.h b/repos/os/src/lib/sandbox/child.h index 2c213e662c..81836a2045 100644 --- a/repos/os/src/lib/sandbox/child.h +++ b/repos/os/src/lib/sandbox/child.h @@ -52,6 +52,14 @@ class Sandbox::Child : Child_policy, Routed_service::Wakeup struct Default_route_accessor : Interface { virtual Xml_node default_route() = 0; }; struct Default_caps_accessor : Interface { virtual Cap_quota default_caps() = 0; }; + struct Routes_accessor : Interface + { + virtual Xml_node routes(Xml_node _default) + { + return _default; + } + }; + template struct Resource_limit_accessor : Interface { @@ -98,6 +106,7 @@ class Sandbox::Child : Child_policy, Routed_service::Wakeup bool const _use_ld = _start_node->xml().attribute_value("ld", true); Default_route_accessor &_default_route_accessor; + Routes_accessor &_routes_accessor; Default_caps_accessor &_default_caps_accessor; Ram_limit_accessor &_ram_limit_accessor; Cap_limit_accessor &_cap_limit_accessor; @@ -473,6 +482,7 @@ class Sandbox::Child : Child_policy, Routed_service::Wakeup Report_update_trigger &report_update_trigger, Xml_node start_node, Default_route_accessor &default_route_accessor, + Routes_accessor &route_accessor, Default_caps_accessor &default_caps_accessor, Name_registry &name_registry, Ram_quota ram_limit, diff --git a/repos/os/src/lib/sandbox/library.cc b/repos/os/src/lib/sandbox/library.cc index 28b60c491f..30d0f2dfc1 100644 --- a/repos/os/src/lib/sandbox/library.cc +++ b/repos/os/src/lib/sandbox/library.cc @@ -23,6 +23,7 @@ struct Genode::Sandbox::Library : ::Sandbox::State_reporter::Producer, ::Sandbox::Child::Default_route_accessor, + ::Sandbox::Child::Routes_accessor, ::Sandbox::Child::Default_caps_accessor, ::Sandbox::Child::Ram_limit_accessor, ::Sandbox::Child::Cap_limit_accessor @@ -52,6 +53,8 @@ struct Genode::Sandbox::Library : ::Sandbox::State_reporter::Producer, Constructible _default_route { }; + Constructible _routes { }; + Cap_quota _default_caps { 0 }; unsigned _child_cnt = 0; @@ -140,6 +143,12 @@ struct Genode::Sandbox::Library : ::Sandbox::State_reporter::Producer, : Xml_node(""); } + /** + * Routes_accessor interface + */ + Xml_node routes(Xml_node _default) override { + return _routes.constructed() ? _routes->xml() : _default; } + /** * Default_caps_accessor interface */ @@ -314,6 +323,9 @@ void Genode::Sandbox::Library::apply_config(Xml_node const &config) _default_route.construct(_heap, config.sub_node("default-route")); } catch (...) { } + try { _routes.construct(_heap, config.sub_node("routes")); } + catch (...) { } + _default_caps = Cap_quota { 0 }; try { _default_caps = Cap_quota { config.sub_node("default") @@ -404,7 +416,7 @@ void Genode::Sandbox::Library::apply_config(Xml_node const &config) Child &child = *new (_heap) Child(_env, _heap, *_verbose, Child::Id { ++_child_cnt }, _state_reporter, - start_node, *this, *this, _children, + start_node, *this, *this, *this, _children, Ram_quota { avail_ram.value - used_ram.value }, Cap_quota { avail_caps.value - used_caps.value }, *this, *this, prio_levels, affinity_space, diff --git a/repos/os/src/lib/sandbox/utils.h b/repos/os/src/lib/sandbox/utils.h index 7afcaebf00..36aab737f2 100644 --- a/repos/os/src/lib/sandbox/utils.h +++ b/repos/os/src/lib/sandbox/utils.h @@ -59,7 +59,8 @@ namespace Sandbox { 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) + Service::Name const &service_name, + bool skip_child_prefix = true) { bool const service_matches = service_node.has_type("any-service") || @@ -98,8 +99,9 @@ namespace Sandbox { if (!route_depends_on_child_provided_label) return true; - char const * const scoped_label = skip_label_prefix( - child_name.string(), label.string()); + char const * const scoped_label = skip_child_prefix + ? skip_label_prefix(child_name.string(), label.string()) + : label.string(); if (!scoped_label) return false; -- 2.28.0 From 13f2b3357f0e366a61d8b440fb56a52e5d2dfaff Mon Sep 17 00:00:00 2001 From: Emery Hemingway Date: Wed, 4 Nov 2020 11:03:49 +0100 Subject: [PATCH 2/3] init/sandbox: do not parse if is present --- repos/os/src/lib/sandbox/library.cc | 124 +++++++++++++++++++--------- 1 file changed, 85 insertions(+), 39 deletions(-) diff --git a/repos/os/src/lib/sandbox/library.cc b/repos/os/src/lib/sandbox/library.cc index 30d0f2dfc1..caa9840ea6 100644 --- a/repos/os/src/lib/sandbox/library.cc +++ b/repos/os/src/lib/sandbox/library.cc @@ -184,47 +184,93 @@ struct Genode::Sandbox::Library : ::Sandbox::State_reporter::Producer, void Genode::Sandbox::Library::_update_parent_services_from_config(Xml_node const &config) { - Xml_node const node = config.has_sub_node("parent-provides") - ? config.sub_node("parent-provides") - : Xml_node(""); - - /* remove services that are no longer present in config */ - _parent_services.for_each([&] (Parent_service &service) { - - Service::Name const name = service.name(); - - bool obsolete = true; + if (config.has_sub_node("routes")) { + if (config.has_sub_node("parent-provides")) + warning("ignoring and parsing instead"); + + Xml_node const node = config.sub_node("routes"); + + /* remove services that are no longer present in config */ + _parent_services.for_each([&] (Parent_service &service) { + + Service::Name const name = service.name(); + + bool obsolete = true; + node.for_each_sub_node("service", [&] (Xml_node service) { + if (obsolete && name == service.attribute_value("name", Service::Name())) { + obsolete = !service.has_sub_node("parent"); }}); + + if (obsolete) + service.abandon(); + }); + + /* used to prepend the list of new parent services with title */ + bool first_log = true; + + /* register new services */ node.for_each_sub_node("service", [&] (Xml_node service) { - if (name == service.attribute_value("name", Service::Name())) { - obsolete = false; }}); - - if (obsolete) - service.abandon(); - }); - - /* used to prepend the list of new parent services with title */ - bool first_log = true; - - /* register new services */ - node.for_each_sub_node("service", [&] (Xml_node service) { - - Service::Name const name = service.attribute_value("name", Service::Name()); - - bool registered = false; - _parent_services.for_each([&] (Parent_service const &service) { - if (service.name() == name) - registered = true; }); - - if (!registered) { - new (_heap) ::Sandbox::Parent_service(_parent_services, _env, name); - if (_verbose->enabled()) { - if (first_log) - log("parent provides"); - log(" service \"", name, "\""); - first_log = false; + if (service.has_sub_node("child")) return; + + Service::Name const name = service.attribute_value("name", Service::Name()); + + bool registered = false; + _parent_services.for_each([&] (Parent_service const &service) { + if (service.name() == name) + registered = true; }); + + if (!registered) { + new (_heap) ::Sandbox::Parent_service(_parent_services, _env, name); + if (_verbose->enabled()) { + if (first_log) + log("parent provides"); + log(" service \"", name, "\""); + first_log = false; + } } - } - }); + }); + } else { + Xml_node const node = config.has_sub_node("parent-provides") + ? config.sub_node("parent-provides") + : Xml_node(""); + + /* remove services that are no longer present in config */ + _parent_services.for_each([&] (Parent_service &service) { + + Service::Name const name = service.name(); + + bool obsolete = true; + node.for_each_sub_node("service", [&] (Xml_node service) { + if (name == service.attribute_value("name", Service::Name())) { + obsolete = false; }}); + + if (obsolete) + service.abandon(); + }); + + /* used to prepend the list of new parent services with title */ + bool first_log = true; + + /* register new services */ + node.for_each_sub_node("service", [&] (Xml_node service) { + + Service::Name const name = service.attribute_value("name", Service::Name()); + + bool registered = false; + _parent_services.for_each([&] (Parent_service const &service) { + if (service.name() == name) + registered = true; }); + + if (!registered) { + new (_heap) ::Sandbox::Parent_service(_parent_services, _env, name); + if (_verbose->enabled()) { + if (first_log) + log("parent provides"); + log(" service \"", name, "\""); + first_log = false; + } + } + }); + } } -- 2.28.0 From f89d8cbc3aa5fe9f7162ad66819fd2cedd76ba02 Mon Sep 17 00:00:00 2001 From: Emery Hemingway Date: Wed, 4 Nov 2020 20:02:03 +0100 Subject: [PATCH 3/3] init/sandbox: simplify routing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove , , and configuration options. Allow label rewriting with and . Routes are now selected by longest match rather than first match. --- repos/os/src/lib/sandbox/child.cc | 131 ++++++++++------------------ repos/os/src/lib/sandbox/child.h | 3 - repos/os/src/lib/sandbox/library.cc | 12 +-- repos/os/src/lib/sandbox/utils.h | 57 ++++++------ 4 files changed, 76 insertions(+), 127 deletions(-) diff --git a/repos/os/src/lib/sandbox/child.cc b/repos/os/src/lib/sandbox/child.cc index d25e3d9683..46aa22411c 100644 --- a/repos/os/src/lib/sandbox/child.cc +++ b/repos/os/src/lib/sandbox/child.cc @@ -11,6 +11,7 @@ * under the terms of the GNU Affero General Public License version 3. */ +#include #include /* local includes */ @@ -486,105 +487,65 @@ Sandbox::Child::resolve_session_request(Service::Name const &service_name, return Route { _session_requester.service(), Session::Label(), Session::Diag{false} }; - try { - /* Lookup route in … */ - Xml_node route_node = _default_route_accessor.default_route(); - /* …unless is present… */ - route_node = _routes_accessor.routes(route_node); - try { - /* …otherwise use . */ - route_node = _start_node->xml().sub_node("route"); } - catch (...) { } - - Xml_node service_node = route_node.sub_node(); - - /* is processed with the "«child» -> " prefix */ - bool skip_prefix = route_node.type() != "routes"; - - for (; ; service_node = service_node.next()) { - - bool service_wildcard = service_node.has_type("any-service"); - - if (!service_node_matches(service_node, label, name(), service_name, skip_prefix)) - 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 Label; - Label const target_label = - target.attribute_value("label", Label(label.string())); - - Session::Diag const - target_diag { target.attribute_value("diag", false) }; - - auto no_filter = [] (Service &) -> bool { return false; }; - - if (target.has_type("parent")) { - - try { - return Route { find_service(_parent_services, service_name, no_filter), - target_label, target_diag }; - } catch (Service_denied) { } + { + Xml_node service_node(""); + Xml_node routes_node = _routes_accessor.routes(service_node); + Xml_node_label_score best_score; + + routes_node.for_each_sub_node([&] (Xml_node const &node) { + if (service_node_matches(node, label, service_name)) { + Xml_node_label_score score(node, label); + if (score.stronger(best_score) + || service_node.has_type("deny")) { + best_score = score; + service_node = node; } + } + }); - if (target.has_type("local")) { + if (service_node.has_type("deny")) { + warning(name(), ": no route to service \"", service_name, "\" (label=\"", label, "\")"); + throw Service_denied(); + } - try { - return Route { find_service(_local_services, service_name, no_filter), - target_label, target_diag }; - } catch (Service_denied) { } - } + for (Xml_node target_node = service_node.sub_node(); ; + target_node = target_node.next()) { - if (target.has_type("child")) { + Session_label the_label_part_of_label(skip_label_prefix(name().string(), label.string())); + if (the_label_part_of_label == "") the_label_part_of_label = label; - typedef Name_registry::Name Name; - Name server_name = target.attribute_value("name", Name()); - server_name = _name_registry.deref_alias(server_name); + auto target_label = Sandbox::target_label( + target_node, name(), the_label_part_of_label); - auto filter_server_name = [&] (Routed_service &s) -> bool { - return s.child_name() != server_name; }; + Session::Diag const + target_diag { target_node.attribute_value("diag", false) }; - try { - return Route { find_service(_child_services, service_name, filter_server_name), - target_label, target_diag }; + auto no_filter = [] (Service &) -> bool { return false; }; - } catch (Service_denied) { } - } + if (target_node.has_type("parent")) + return Route { find_service(_parent_services, service_name, no_filter), + target_label, target_diag }; - if (target.has_type("any-child")) { + if (target_node.has_type("local")) + return Route { find_service(_local_services, service_name, no_filter), + target_label, target_diag }; - if (is_ambiguous(_child_services, service_name)) { - error(name(), ": ambiguous routes to " - "service \"", service_name, "\""); - throw Service_denied(); - } - try { - return Route { find_service(_child_services, service_name, no_filter), - target_label, target_diag }; + if (target_node.has_type("child")) { - } catch (Service_denied) { } - } + typedef Name_registry::Name Name; + Name server_name = target_node.attribute_value("name", Name()); + server_name = _name_registry.deref_alias(server_name); - if (!service_wildcard) { - warning(name(), ": lookup for service \"", service_name, "\" failed"); - throw Service_denied(); - } + auto filter_server_name = [&] (Routed_service &s) -> bool { + return s.child_name() != server_name; }; - if (target.last()) - break; + return Route { find_service(_child_services, service_name, filter_server_name), + target_label, target_diag }; } + + if (target_node.last()) break; } - } catch (Xml_node::Nonexistent_sub_node) { } + } warning(name(), ": no route to service \"", service_name, "\" (label=\"", label, "\")"); throw Service_denied(); @@ -712,7 +673,6 @@ Sandbox::Child::Child(Env &env, Id id, Report_update_trigger &report_update_trigger, Xml_node start_node, - Default_route_accessor &default_route_accessor, Routes_accessor &routes_accessor, Default_caps_accessor &default_caps_accessor, Name_registry &name_registry, @@ -730,7 +690,6 @@ Sandbox::Child::Child(Env &env, _report_update_trigger(report_update_trigger), _list_element(this), _start_node(_alloc, start_node), - _default_route_accessor(default_route_accessor), _routes_accessor(routes_accessor), _default_caps_accessor(default_caps_accessor), _ram_limit_accessor(ram_limit_accessor), diff --git a/repos/os/src/lib/sandbox/child.h b/repos/os/src/lib/sandbox/child.h index 81836a2045..f9d04cfdaf 100644 --- a/repos/os/src/lib/sandbox/child.h +++ b/repos/os/src/lib/sandbox/child.h @@ -49,7 +49,6 @@ class Sandbox::Child : Child_policy, Routed_service::Wakeup */ struct Id { unsigned value; }; - struct Default_route_accessor : Interface { virtual Xml_node default_route() = 0; }; struct Default_caps_accessor : Interface { virtual Cap_quota default_caps() = 0; }; struct Routes_accessor : Interface @@ -105,7 +104,6 @@ class Sandbox::Child : Child_policy, Routed_service::Wakeup */ bool const _use_ld = _start_node->xml().attribute_value("ld", true); - Default_route_accessor &_default_route_accessor; Routes_accessor &_routes_accessor; Default_caps_accessor &_default_caps_accessor; Ram_limit_accessor &_ram_limit_accessor; @@ -481,7 +479,6 @@ class Sandbox::Child : Child_policy, Routed_service::Wakeup Id id, Report_update_trigger &report_update_trigger, Xml_node start_node, - Default_route_accessor &default_route_accessor, Routes_accessor &route_accessor, Default_caps_accessor &default_caps_accessor, Name_registry &name_registry, diff --git a/repos/os/src/lib/sandbox/library.cc b/repos/os/src/lib/sandbox/library.cc index caa9840ea6..7b4e72c60e 100644 --- a/repos/os/src/lib/sandbox/library.cc +++ b/repos/os/src/lib/sandbox/library.cc @@ -22,7 +22,6 @@ #include struct Genode::Sandbox::Library : ::Sandbox::State_reporter::Producer, - ::Sandbox::Child::Default_route_accessor, ::Sandbox::Child::Routes_accessor, ::Sandbox::Child::Default_caps_accessor, ::Sandbox::Child::Ram_limit_accessor, @@ -134,15 +133,6 @@ struct Genode::Sandbox::Library : ::Sandbox::State_reporter::Producer, _children.report_state(xml, detail); } - /** - * Default_route_accessor interface - */ - Xml_node default_route() override - { - return _default_route.constructed() ? _default_route->xml() - : Xml_node(""); - } - /** * Routes_accessor interface */ @@ -462,7 +452,7 @@ void Genode::Sandbox::Library::apply_config(Xml_node const &config) Child &child = *new (_heap) Child(_env, _heap, *_verbose, Child::Id { ++_child_cnt }, _state_reporter, - start_node, *this, *this, *this, _children, + start_node, *this, *this, _children, Ram_quota { avail_ram.value - used_ram.value }, Cap_quota { avail_caps.value - used_caps.value }, *this, *this, prio_levels, affinity_space, diff --git a/repos/os/src/lib/sandbox/utils.h b/repos/os/src/lib/sandbox/utils.h index 36aab737f2..639a4be4dd 100644 --- a/repos/os/src/lib/sandbox/utils.h +++ b/repos/os/src/lib/sandbox/utils.h @@ -58,12 +58,9 @@ namespace Sandbox { */ 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, - bool skip_child_prefix = true) + Service::Name const &service_name) { bool const service_matches = - service_node.has_type("any-service") || (service_node.has_type("service") && service_node.attribute_value("name", Service::Name()) == service_name); @@ -72,7 +69,6 @@ namespace Sandbox { typedef String Label; - char const *unscoped_attr = "unscoped_label"; char const *label_last_attr = "label_last"; bool const route_depends_on_child_provided_label = @@ -81,34 +77,13 @@ namespace Sandbox { service_node.has_attribute("label_suffix") || service_node.has_attribute(label_last_attr); - if (service_node.has_attribute(unscoped_attr)) { - - /* - * If an 'unscoped_label' attribute is provided, don't consider any - * scoped label attribute. - */ - if (route_depends_on_child_provided_label) - warning("service node contains both scoped and unscoped label attributes"); - - return label == service_node.attribute_value(unscoped_attr, Label()); - } - if (service_node.has_attribute(label_last_attr)) return service_node.attribute_value(label_last_attr, Label()) == label.last_element(); if (!route_depends_on_child_provided_label) return true; - char const * const scoped_label = skip_child_prefix - ? skip_label_prefix(child_name.string(), label.string()) - : label.string(); - - if (!scoped_label) - return false; - - Session_label const session_label(scoped_label); - - return !Xml_node_label_score(service_node, session_label).conflict(); + return !Xml_node_label_score(service_node, label).conflict(); } @@ -131,6 +106,34 @@ namespace Sandbox { return cnt > 1; } + + /* + * 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 or + * by specifying a 'prefix' and 'suffix attributes. + */ + typedef String Label; + inline Label target_label(Xml_node const node, + Child_policy::Name const &child_name, + Session_label const &label) + { + if (node.has_attribute("label")) + return Session_label(node.attribute_value("label", Label()).string()); + + Label head = node.attribute_value("prefix", Label(child_name.string())); + Label tail = node.attribute_value("suffix", Label(child_name == label ? "" : label)); + + if (head == "") return tail; + if (tail == "") return head; + + return Label(prefixed_label(head, tail).string()); + } + + /** * Find service with certain values in given registry * -- 2.28.0