From ddc65a80874a9c7674a7d3f5f96ea370546e0cf0 Mon Sep 17 00:00:00 2001 From: Emery Hemingway Date: Tue, 3 Nov 2020 19:21:10 +0100 Subject: [PATCH] Refactor routing Patch init to simplify routing. Update Dhall library and NixOS modules accordingly. --- nixos-modules/genode-core.nix | 46 ++- nixos-modules/genode-init.nix | 73 ++-- nixos-modules/store-wrapper.dhall | 187 +++++---- nixos-modules/systemd-runner.dhall | 291 +++++++------- nixos-modules/systemd.nix | 78 +++- packages/dhall/genode.nix | 6 +- packages/genodelabs/sandbox.patch | 623 +++++++++++++++++++++++++---- tests/hello.nix | 3 +- tests/lighttpd.nix | 10 + tests/solo5/net_2if.dhall | 4 +- 10 files changed, 938 insertions(+), 383 deletions(-) create mode 100644 tests/lighttpd.nix diff --git a/nixos-modules/genode-core.nix b/nixos-modules/genode-core.nix index 5ada8f9..b562837 100644 --- a/nixos-modules/genode-core.nix +++ b/nixos-modules/genode-core.nix @@ -57,7 +57,6 @@ in { }; config = let - initInputs = unique config.genode.init.inputs; addManifest = drv: drv // { @@ -91,6 +90,12 @@ in { in (foldl' f "[" inputs) + "]"; }; + romDirectories = mapAttrs (name: value: + pkgs.symlinkJoin { + name = "${name}-rom"; + paths = value.inputs; + }) config.genode.init.children; + in { assertions = [{ @@ -104,38 +109,36 @@ in { "${config.system.build.tarball}/tarball/${config.system.build.tarball.fileName}.tar"; manifest = mergeManifests (map addManifest (config.genode.core.basePackages ++ [ config.system.build.tarball ] - ++ (with pkgs.genodePackages; [ init cached_fs_rom vfs ]))); + ++ (with pkgs.genodePackages; [ + init + cached_fs_rom + report_rom + vfs + ]))); + storeRomPolicies = let + policies = mapAttrsToList + (name: value: '', { mapKey = "${name}", mapValue = "${value}" }'') + romDirectories; + in "[${toString policies}]"; in localPackages.runCommand "boot.dhall" { } '' cat > $out << EOF ${./store-wrapper.dhall} (${config.genode.init.configFile}) "${config.system.build.tarball.fileName}.tar" $(stat --format '%s' ${tarball}) - ${config.system.build.storeManifest} ${manifest} + ${storeRomPolicies} + ${manifest} EOF ''; - system.build.storeManifest = mergeManifests (map addManifest initInputs); - # Create the tarball of the store to live in core ROM system.build.tarball = pkgs.callPackage "${modulesPath}/../lib/make-system-tarball.nix" { contents = [ ]; - storeContents = [ - { - # assume that the init config will depend - # on every store path needed to boot - object = config.genode.init.configFile; - symlink = "/config.dhall"; - } - { - object = pkgs.buildPackages.symlinkJoin { - name = config.system.name + ".rom"; - paths = config.genode.init.inputs; - }; - symlink = "/rom"; - } - ]; + storeContents = mapAttrsToList (name: object: { + symlink = "rom/${name}"; + inherit object; + }) romDirectories; compressCommand = "cat"; compressionExtension = ""; }; @@ -143,13 +146,12 @@ in { system.build.initXml = pkgs.buildPackages.runCommand "init.xml" { nativeBuildInputs = with pkgs.buildPackages; [ dhall xorg.lndir libxml2 ]; DHALL_GENODE = "${pkgs.genodePackages.dhallGenode}/binary.dhall"; - BOOT_CONFIG = config.genode.boot.configFile; } '' export XDG_CACHE_HOME=$NIX_BUILD_TOP lndir -silent \ ${pkgs.genodePackages.dhallGenode}/.cache \ $XDG_CACHE_HOME - dhall text <<< "(env:DHALL_GENODE).Init.render (env:BOOT_CONFIG).config" > $out + dhall text <<< "(env:DHALL_GENODE).Init.render (${config.genode.boot.configFile}).config" > $out xmllint --noout $out ''; diff --git a/nixos-modules/genode-init.nix b/nixos-modules/genode-init.nix index c6c97a0..71ead5e 100644 --- a/nixos-modules/genode-init.nix +++ b/nixos-modules/genode-init.nix @@ -3,14 +3,15 @@ with lib; let + cfg = config.genode.init; inputs = mkOption { description = "List of packages to build a ROM store with."; + default = [ ]; type = types.listOf types.package; }; in { options.genode.init = { - inherit inputs; configFile = mkOption { description = '' @@ -56,53 +57,49 @@ in { }); }; - subinits = mkOption { - default = { }; - type = with types; - attrsOf (submodule { - options = { - inherit inputs; - configFile = mkOption { - type = types.path; - description = '' - Dhall configuration of child init. - See https://git.sr.ht/~ehmry/dhall-genode/tree/master/Init/Type - ''; + subinits = + # Subinits are just a different kind of children. + # Eventually this will be nested "genode.init" instances. + mkOption { + default = { }; + type = with types; + attrsOf (submodule { + options = { + inherit inputs; + configFile = mkOption { + type = types.path; + description = '' + Dhall configuration of child init. + See https://git.sr.ht/~ehmry/dhall-genode/tree/master/Init/Type + ''; + }; }; - }; - }); - }; + }); + }; }; - config = { - - genode.init.inputs = with builtins; - [ pkgs.genodePackages.report_rom ] ++ concatLists (catAttrs "inputs" - ((attrValues config.genode.init.children) - ++ (attrValues config.genode.init.subinits))); + config.genode.init = { # TODO: convert the subinits to children - genode.init.configFile = pkgs.writeText "init.dhall" '' + children = mapAttrs (name: value: { + inherit (value) inputs; + configFile = pkgs.writeText "${name}.child.dhall" '' + let Genode = env:DHALL_GENODE + + in Genode.Init.toChild ${value.configFile} Genode.Init.Attributes.default + ''; + }) cfg.subinits; + + configFile = pkgs.writeText "init.dhall" '' let Genode = env:DHALL_GENODE - let baseConfig = ${config.genode.init.baseConfig} + let baseConfig = ${cfg.baseConfig} in baseConfig with children = baseConfig.children # toMap {${ - concatMapStrings (name: - ", `${name}` = (${ - config.genode.init.children.${name}.configFile - } : Genode.Init.Child.Type)") - (builtins.attrNames config.genode.init.children) - } ${ - concatMapStrings (name: '' - , `${name}` = - Genode.Init.toChild - (${ - config.genode.init.subinits.${name}.configFile - } : Genode.Init.Type) - Genode.Init.Attributes.default - '') (builtins.attrNames config.genode.init.subinits) + concatMapStrings + (name: ", `${name}` = (${cfg.children.${name}.configFile}) ") + (builtins.attrNames cfg.children) } } ''; diff --git a/nixos-modules/store-wrapper.dhall b/nixos-modules/store-wrapper.dhall index 1922540..6af1e2e 100644 --- a/nixos-modules/store-wrapper.dhall +++ b/nixos-modules/store-wrapper.dhall @@ -1,5 +1,4 @@ -let Genode = - env:DHALL_GENODE sha256:e90438be23b5100003cf018b783986df67bc6d0e3d35e800677d0d9109ff6aa9 +let Genode = env:DHALL_GENODE let Prelude = Genode.Prelude @@ -13,75 +12,10 @@ let TextMapType = Prelude.Map.Type Text let Manifest/Type = TextMapType (TextMapType Text) -let Manifest/toRoutes = - λ(manifest : Manifest/Type) → - Prelude.List.map - (Prelude.Map.Entry Text Text) - Init.ServiceRoute.Type - ( λ(entry : Prelude.Map.Entry Text Text) → - { service = - { name = "ROM" - , label = Init.LabelSelector.Type.Last entry.mapKey - } - , route = - Init.Route.Type.Child - { name = "store_rom" - , label = Some entry.mapValue - , diag = Some True - } - } - ) - ( Prelude.List.concat - (Prelude.Map.Entry Text Text) - (Prelude.Map.values Text (Prelude.Map.Type Text Text) manifest) - ) - -let parentROMs = - Prelude.List.map - Text - Init.ServiceRoute.Type - ( λ(label : Text) → - { service = { name = "ROM", label = Init.LabelSelector.last label } - , route = - Init.Route.Type.Parent { label = Some label, diag = None Bool } - } - ) - -let wrapStore - : Init.Type → Manifest/Type → Child.Type - = λ(init : Init.Type) → - λ(manifest : Manifest/Type) → - Init.toChild - init - Init.Attributes::{ - , exitPropagate = True - , resources = Init.Resources::{ ram = Genode.units.MiB 4 } - , routes = - [ Init.ServiceRoute.parent "IO_MEM" - , Init.ServiceRoute.parent "IO_PORT" - , Init.ServiceRoute.parent "IRQ" - , Init.ServiceRoute.parent "VM" - , Init.ServiceRoute.child "Timer" "timer" - , Init.ServiceRoute.child "Rtc" "rtc" - ] - # parentROMs - [ "ld.lib.so" - , "init" - , "platform_info" - , "core_log" - , "kernel_log" - , "vfs" - , "vfs.lib.so" - , "cached_fs_rom" - ] - # Manifest/toRoutes manifest - # [ Init.ServiceRoute.child "ROM" "store_rom" ] - } - in λ(subinit : Init.Type) → λ(storeName : Text) → λ(storeSize : Natural) → - λ(storeManifest : Manifest/Type) → + λ(storeRomPolicies : Prelude.Map.Type Text Text) → λ(bootManifest : Manifest/Type) → Genode.Boot::{ , config = Init::{ @@ -112,17 +46,14 @@ in λ(subinit : Init.Type) → , binary = "vfs" , config = Init.Config::{ , content = - [ XML.element - { name = "vfs" - , attributes = XML.emptyAttributes - , content = - [ XML.leaf - { name = "tar" - , attributes = toMap { name = storeName } - } + let VFS = Genode.VFS + + in [ VFS.vfs + [ VFS.leafAttrs + "tar" + (toMap { name = storeName }) + ] ] - } - ] , policies = [ Init.Config.Policy::{ , service = "File_system" @@ -148,9 +79,107 @@ in λ(subinit : Init.Type) → , resources = Init.Resources::{ , ram = storeSize + Genode.units.MiB 1 } + , config = Init.Config::{ + , policies = + [ Init.Config.Policy::{ + , service = "ROM" + , label = + Init.LabelSelector.prefix + "nixos -> /nix/store" + } + ] + # ( let Entry = Prelude.Map.Entry Text Text + + in Prelude.List.concatMap + Entry + Init.Config.Policy.Type + ( λ(e : Entry) → + [ Init.Config.Policy::{ + , service = "ROM" + , label = + Init.LabelSelector.prefix + "nixos -> ${e.mapKey}" + , attributes = toMap + { directory = + "${e.mapValue}/bin" + } + } + , Init.Config.Policy::{ + , service = "ROM" + , label = + Init.LabelSelector.Type.Partial + { prefix = Some + "nixos -> ${e.mapKey}" + , suffix = Some ".lib.so" + } + , attributes = toMap + { directory = + "${e.mapValue}/lib" + } + } + ] + ) + storeRomPolicies + ) + } + } + ) + , child + "nixos" + ( Init.toChild + subinit + Init.Attributes::{ + , exitPropagate = True + , resources = Init.Resources::{ + , ram = Genode.units.MiB 4 + } + , routes = + let parentROMs = + Prelude.List.concatMap + Text + Init.ServiceRoute.Type + ( λ(suffix : Text) → + Prelude.List.map + Text + Init.ServiceRoute.Type + ( λ(prefix : Text) → + { service = + { name = "ROM" + , label = + Init.LabelSelector.Type.Partial + { prefix = Some prefix + , suffix = Some suffix + } + } + , route = + Init.Route.parent + (Some suffix) + } + ) + ( Prelude.Map.keys + Text + Init.Child.Type + subinit.children + ) + ) + + in parentROMs + [ "ld.lib.so" + , "vfs.lib.so" + , "init" + , "platform_info" + , "core_log" + , "kernel_log" + ] + # [ Init.ServiceRoute.parent "IO_MEM" + , Init.ServiceRoute.parent "IO_PORT" + , Init.ServiceRoute.parent "IRQ" + , Init.ServiceRoute.parent "VM" + , Init.ServiceRoute.child "Timer" "timer" + , Init.ServiceRoute.child "Rtc" "rtc" + ] } ) - , child "init" (wrapStore subinit storeManifest) ] } , rom = diff --git a/nixos-modules/systemd-runner.dhall b/nixos-modules/systemd-runner.dhall index 42f6576..e11c5cc 100644 --- a/nixos-modules/systemd-runner.dhall +++ b/nixos-modules/systemd-runner.dhall @@ -4,6 +4,8 @@ let Prelude = Genode.Prelude let XML = Prelude.XML +let VFS = Genode.VFS + let Init = Genode.Init let Child = Init.Child @@ -11,149 +13,156 @@ let Child = Init.Child let parentRoutes = Prelude.List.map Text Init.ServiceRoute.Type Init.ServiceRoute.parent -in λ(params : { coreutils : Text, execStart : Text }) → - Init::{ - , verbose = True - , routes = parentRoutes [ "Timer", "Rtc", "File_system" ] - , children = toMap - { vfs = - Child.flat - Child.Attributes::{ - , binary = "vfs" - , exitPropagate = True - , provides = [ "File_system" ] - , resources = Genode.Init.Resources::{ - , caps = 256 - , ram = Genode.units.MiB 8 - } - , config = Init.Config::{ - , content = - [ XML.element - { name = "vfs" - , attributes = XML.emptyAttributes - , content = - let dir = - λ(name : Text) → - λ(content : List XML.Type) → - XML.element - { name = "dir" - , content - , attributes = toMap { name } - } +in λ ( params + : { name : Text + , coreutils : Text + , execStart : Text + , interface : Optional Text + } + ) → + let socketsVfs = + merge + { Some = + λ(interface : Text) → + [ VFS.dir + "sockets" + [ VFS.fs VFS.FS::{ label = "${interface}.sockets" } ] + ] + , None = [] : List XML.Type + } + params.interface - let leaf = - λ(name : Text) → - XML.leaf - { name, attributes = XML.emptyAttributes } - - in [ dir - "dev" - [ dir "pipes" [ leaf "pipe" ] - , dir - "sockets" - [ XML.leaf - { name = "fs" - , attributes = toMap - { label = "sockets" } - } - ] - , leaf "log" - , leaf "null" - , leaf "rtc" - , leaf "zero" - ] - , dir - "etc" - [ XML.element - { name = "inline" - , attributes = toMap - { name = "ExecStart" } - , content = - [ XML.text params.execStart ] - } - ] - , dir - "usr" - [ dir - "bin" - [ XML.leaf - { name = "symlink" - , attributes = toMap - { name = "env" - , target = - "${params.coreutils}/bin/env" - } - } - ] - ] - , dir "tmp" [ leaf "ram" ] - , dir - "nix" - [ dir - "store" - [ XML.leaf - { name = "fs" - , attributes = toMap - { label = "nix-store" } - } - ] - ] - ] + let init = + Init::{ + , routes = parentRoutes [ "Timer", "Rtc", "File_system" ] + , children = toMap + { vfs = + Child.flat + Child.Attributes::{ + , binary = "vfs" + , exitPropagate = True + , provides = [ "File_system" ] + , resources = Genode.Init.Resources::{ + , caps = 256 + , ram = Genode.units.MiB 8 } - ] - , policies = - [ Init.Config.Policy::{ - , service = "File_system" - , label = Init.LabelSelector.prefix "shell" - , attributes = toMap { root = "/", writeable = "yes" } - } - ] - } - } - , shell = - Child.flat - Child.Attributes::{ - , binary = "bash" - , exitPropagate = True - , resources = Genode.Init.Resources::{ - , caps = 256 - , ram = Genode.units.MiB 8 - } - , config = Genode.Init.Config::{ - , content = - [ XML.leaf - { name = "libc" - , attributes = toMap - { stdin = "/dev/null" - , stdout = "/dev/log" - , stderr = "/dev/log" - , pipe = "/dev/pipes" - , rtc = "/dev/rtc" - , socket = "/dev/sockets" - } - } - , XML.element - { name = "vfs" - , attributes = XML.emptyAttributes - , content = - [ XML.leaf - { name = "fs" - , attributes = XML.emptyAttributes - } + , config = Init.Config::{ + , content = + [ VFS.vfs + [ VFS.dir + "dev" + ( [ VFS.dir "pipes" [ VFS.leaf "pipe" ] + , VFS.leaf "log" + , VFS.leaf "null" + , VFS.leaf "rtc" + , VFS.leaf "zero" + ] + # socketsVfs + ) + , VFS.dir + "usr" + [ VFS.dir + "bin" + [ VFS.symlink + "env" + "${params.coreutils}/bin/env" + ] + ] + , VFS.dir "tmp" [ VFS.leaf "ram" ] + , VFS.dir + "nix" + [ VFS.dir + "store" + [ VFS.fs VFS.FS::{ label = "nix-store" } ] + ] ] + ] + , policies = + [ Init.Config.Policy::{ + , service = "File_system" + , label = Init.LabelSelector.prefix "shell" + , attributes = toMap + { root = "/", writeable = "yes" } } - ] - # Prelude.List.map - Text - XML.Type - ( λ(x : Text) → - XML.leaf - { name = "arg" - , attributes = toMap { value = x } - } - ) - [ "bash", "/etc/ExecStart" ] - } + , Init.Config.Policy::{ + , service = "File_system" + , label = Init.LabelSelector.prefix "vfs_rom" + , attributes = toMap + { root = "/", writeable = "yes" } + } + ] + } + } + , vfs_rom = + Child.flat + Child.Attributes::{ + , binary = "cached_fs_rom" + , provides = [ "ROM" ] + , resources = Genode.Init.Resources::{ + , ram = Genode.units.MiB 16 + } + , config = Init.Config::{ + , policies = + [ Init.Config.Policy::{ + , service = "ROM" + , diag = Some True + , label = Init.LabelSelector.prefix "shell" + } + ] + } + } + , shell = + Child.flat + Child.Attributes::{ + , binary = "bash" + , exitPropagate = True + , resources = Genode.Init.Resources::{ + , caps = 256 + , ram = Genode.units.MiB 8 + } + , config = Init.Config::{ + , content = + [ XML.leaf + { name = "libc" + , attributes = toMap + { stdin = "/dev/null" + , stdout = "/dev/log" + , stderr = "/dev/log" + , pipe = "/dev/pipes" + , rtc = "/dev/rtc" + , socket = "/dev/sockets" + } + } + , VFS.vfs [ VFS.leaf "fs" ] + ] + # Prelude.List.map + Text + XML.Type + ( λ(x : Text) → + XML.leaf + { name = "arg" + , attributes = toMap { value = x } + } + ) + [ "bash", "-c", params.execStart ] + } + , routes = + Prelude.List.map + Text + Init.ServiceRoute.Type + ( λ(label : Text) → + Init.ServiceRoute.parentLabel + "ROM" + (Some label) + (Some label) + ) + [ "libc.lib.so" + , "libm.lib.so" + , "posix.lib.so" + , "vfs.lib.so" + ] + } } - } - } + } + + in Init.toChild init Init.Attributes::{=} diff --git a/nixos-modules/systemd.nix b/nixos-modules/systemd.nix index c823a4e..d4d3b80 100644 --- a/nixos-modules/systemd.nix +++ b/nixos-modules/systemd.nix @@ -3,31 +3,65 @@ with lib; { options.systemd.services = lib.mkOption { type = types.attrsOf (types.submodule ({ name, config, ... }: { - options.genode.enable = lib.mkOption { - type = types.bool; - default = false; - description = "Translate this systemd unit to a Genode subsystem."; + options.genode = { + + enable = lib.mkOption { + type = types.bool; + default = false; + description = "Translate this systemd unit to a Genode subsystem."; + }; + + interface = lib.mkOption { + type = with types; nullOr str; + default = null; + example = "eth0"; + description = '' + Grant access to an IP stack for this interface. + Only UDP and TCP are supported. No raw device access. + ''; + }; + }; })); }; - config.services.klogd.enable = false; - # The default is determined by checking the Linux version - # which cannot be evaluated here. + config = { + + services.klogd.enable = false; + # The default is determined by checking the Linux version + # which cannot be evaluated here. + + genode.init.children = mapAttrs' (name: service: + let name' = "services." + name; + in { + name = name'; + value = { + inputs = with pkgs; + with genodePackages; [ + bash + cached_fs_rom + libc + posix + vfs + vfs_pipe + ]; + configFile = let + interface = if service.genode.interface == null then + "None Text" + else + ''Some "${service.genode.interface}"''; + in pkgs.writeText "${name'}.dhall" '' + ${./systemd-runner.dhall} { + , name = "${name'}" + , coreutils = "${pkgs.coreutils}" + , execStart = "${toString service.serviceConfig.ExecStart}" + , interface = ${interface} + } + ''; + }; + }) (filterAttrs (name: service: service.genode.enable) + config.systemd.services); + + }; - config.genode.init.subinits = mapAttrs' (name: service: - let name' = "services." + name; - in { - name = name'; - value = { - inputs = with pkgs; with genodePackages; [ bash libc posix vfs_pipe ]; - configFile = pkgs.writeText "${name'}.dhall" '' - ${./systemd-runner.dhall} { - , coreutils = "${pkgs.coreutils}" - , execStart = "${toString service.serviceConfig.ExecStart}" - } - ''; - }; - }) (filterAttrs (name: service: service.genode.enable) - config.systemd.services); } diff --git a/packages/dhall/genode.nix b/packages/dhall/genode.nix index 62a4ee5..2558341 100644 --- a/packages/dhall/genode.nix +++ b/packages/dhall/genode.nix @@ -6,12 +6,12 @@ dhallPackages.buildDhallPackage { code = let src = fetchgit { url = "https://git.sr.ht/~ehmry/dhall-genode"; - rev = "1a6b3609a778f1644bc2831c366c65cce854ae42"; - sha256 = "1zcnja7wmjx8rlm38x0lkgdz7cfwnd4m6jkasczrf7jqr53j73kv"; + rev = "882740d78425bb1a6c4b1b34b1b201ace9d71317"; + sha256 = "0cqlrbjb6023x7yynnglv11755xiw0wy4g16r88nsflcw119czqm"; }; in src + "/package.dhall"; - dependencies = [ dhallPackages.Prelude."13.0.0" ]; + dependencies = [ dhallPackages.Prelude ]; source = true; } diff --git a/packages/genodelabs/sandbox.patch b/packages/genodelabs/sandbox.patch index 050dd42..e15c8ab 100644 --- a/packages/genodelabs/sandbox.patch +++ b/packages/genodelabs/sandbox.patch @@ -1,84 +1,37 @@ -commit 20abcefd185d72ecc55e87ff78f8f784d927653d -Author: Emery Hemingway -Date: Sat Apr 25 16:08:45 2020 +0530 +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 - Init/sandbox: always route "ld.lib.so" ROM to parent - - A livelock may occur if init router the "ld.lib.so" ROM request of a - child to another child, and the child providing the ROM interacts with - Init during the creation of the session. +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 5361665eac..fa09cca31a 100644 +index e321df61fd..d25e3d9683 100644 --- a/repos/os/src/lib/sandbox/child.cc +++ b/repos/os/src/lib/sandbox/child.cc -@@ -448,6 +448,8 @@ Sandbox::Child::Route - Sandbox::Child::resolve_session_request(Service::Name const &service_name, - Session_label const &label) - { -+ auto no_filter = [] (Service &) -> bool { return false; }; -+ - /* check for "config" ROM request */ - if (service_name == Rom_session::service_name() && - label.last_element() == "config") { -@@ -498,9 +500,20 @@ Sandbox::Child::resolve_session_request(Service::Name const &service_name, - label == _unique_name && _unique_name != _binary_name) - return resolve_session_request(service_name, _binary_name); - -- /* supply binary as dynamic linker if '' */ -- if (!_use_ld && service_name == Rom_session::service_name() && label == "ld.lib.so") -- return resolve_session_request(service_name, _binary_name); -+ /* -+ * Check for the "ld.lib.so" ROM request -+ */ -+ if (service_name == Rom_session::service_name() && label == "ld.lib.so") { -+ if (_use_ld) { -+ /* forward request to parent */ -+ return Route { -+ find_service(_parent_services, Rom_session::service_name(), no_filter), -+ Session_label("ld.lib.so"), Session::Diag { false} }; -+ } else { -+ /* supply binary as dynamic linker if '' */ -+ return resolve_session_request(service_name, _binary_name); -+ } -+ } - - /* check for "session_requests" ROM request */ - if (service_name == Rom_session::service_name() -@@ -541,8 +554,6 @@ Sandbox::Child::resolve_session_request(Service::Name const &service_name, - Session::Diag const - target_diag { target.attribute_value("diag", false) }; - -- auto no_filter = [] (Service &) -> bool { return false; }; -- - if (target.has_type("parent")) { - - try { -commit ce74d9bb7740f14b362e72adcf8ac42e36693468 -Author: Emery Hemingway -Date: Sat Apr 25 17:10:03 2020 +0530 - - 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. - -diff --git a/repos/os/src/lib/sandbox/child.cc b/repos/os/src/lib/sandbox/child.cc -index fa09cca31a..85389474ef 100644 ---- a/repos/os/src/lib/sandbox/child.cc -+++ b/repos/os/src/lib/sandbox/child.cc -@@ -523,16 +523,21 @@ Sandbox::Child::resolve_session_request(Service::Name const &service_name, +@@ -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 (...) { } + @@ -96,7 +49,7 @@ index fa09cca31a..85389474ef 100644 continue; Xml_node target = service_node.sub_node(); -@@ -736,6 +741,7 @@ Sandbox::Child::Child(Env &env, +@@ -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, @@ -104,7 +57,7 @@ index fa09cca31a..85389474ef 100644 Default_caps_accessor &default_caps_accessor, Name_registry &name_registry, Ram_quota ram_limit, -@@ -753,6 +759,7 @@ Sandbox::Child::Child(Env &env, +@@ -722,6 +731,7 @@ Sandbox::Child::Child(Env &env, _list_element(this), _start_node(_alloc, start_node), _default_route_accessor(default_route_accessor), @@ -113,7 +66,7 @@ index fa09cca31a..85389474ef 100644 _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 4dd2803417..8e84e9bf75 100644 +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 @@ -139,7 +92,7 @@ index 4dd2803417..8e84e9bf75 100644 Default_caps_accessor &_default_caps_accessor; Ram_limit_accessor &_ram_limit_accessor; Cap_limit_accessor &_cap_limit_accessor; -@@ -475,6 +484,7 @@ class Sandbox::Child : Child_policy, Routed_service::Wakeup +@@ -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, @@ -226,3 +179,523 @@ index 7afcaebf00..36aab737f2 100644 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 + diff --git a/tests/hello.nix b/tests/hello.nix index 5293880..138fed4 100644 --- a/tests/hello.nix +++ b/tests/hello.nix @@ -18,7 +18,8 @@ in { genode.init.children.hello = { configFile = ./hello.dhall; - inputs = [ hello ]; + inputs = [ hello pkgs.genodePackages.vfs.lib ]; + # TODO: libc.lib.so has only relative linking to vfs.lib.so }; }; testScript = '' diff --git a/tests/lighttpd.nix b/tests/lighttpd.nix new file mode 100644 index 0000000..2904cad --- /dev/null +++ b/tests/lighttpd.nix @@ -0,0 +1,10 @@ +{ + name = "lighttpd"; + machine = { pkgs, ... }: { + imports = [ ../nixos-modules/systemd.nix ]; + services.lighttpd = { + enable = true; + }; + systemd.services.lighttpd.genode.enable = true; + }; +} diff --git a/tests/solo5/net_2if.dhall b/tests/solo5/net_2if.dhall index ff5f713..a9e63d6 100644 --- a/tests/solo5/net_2if.dhall +++ b/tests/solo5/net_2if.dhall @@ -33,13 +33,13 @@ let init = , service = "Nic" , attributes = toMap { ip_addr = "10.0.0.2" } , label = - Init.LabelSelector.Type.Scoped "solo5 -> service0" + Init.LabelSelector.Type.Full "solo5 -> service0" } , Init.Config.Policy::{ , service = "Nic" , attributes = toMap { ip_addr = "10.1.0.2" } , label = - Init.LabelSelector.Type.Scoped "solo5 -> service1" + Init.LabelSelector.Type.Full "solo5 -> service1" } ] }