From f2153f9b2f47ef201d685266151a0fc7634f8713 Mon Sep 17 00:00:00 2001 From: Norman Feske Date: Tue, 9 May 2023 11:34:51 +0200 Subject: [PATCH] sandbox: allow for customized PD access By default, the sandbox uses the Env::pd() as reference PD session of the sandbox children. However, to accomodate use cases where the interplay of the reference PD session and the child's address space needs to be intercepted, this patch adds a constructor that takes an interface for the controlled access of PD intrinsics as argument. Issue #4917 --- repos/os/include/sandbox/sandbox.h | 34 ++++++++++++++++ repos/os/lib/symbols/sandbox | 2 + repos/os/src/lib/sandbox/child.cc | 31 +++++++++------ repos/os/src/lib/sandbox/child.h | 60 ++++++++++++++++++++++++++--- repos/os/src/lib/sandbox/library.cc | 49 ++++++++++++++++++++--- 5 files changed, 155 insertions(+), 21 deletions(-) diff --git a/repos/os/include/sandbox/sandbox.h b/repos/os/include/sandbox/sandbox.h index 9f2b7ce60f..54548611b5 100644 --- a/repos/os/include/sandbox/sandbox.h +++ b/repos/os/include/sandbox/sandbox.h @@ -44,6 +44,30 @@ class Genode::Sandbox : Noncopyable virtual void handle_sandbox_state() = 0; }; + /** + * Interface for accessing the PD intrinsics relevant to differentiate + * the regular use of core's PD service from a locally implemented PD + * service. + */ + struct Pd_intrinsics : Interface, Noncopyable + { + struct Intrinsics + { + Pd_session &ref_pd; + Capability ref_pd_cap; + Cpu_session &ref_cpu; + Capability ref_cpu_cap; + Region_map &address_space; + }; + + struct Fn : Interface { virtual void call(Intrinsics &) const = 0; }; + + /** + * Call 'Fn' with the 'Intrinsics' that apply for the specified PD + */ + virtual void with_intrinsics(Capability, Pd_session &, Fn const &) = 0; + }; + private: friend class Local_service_base; @@ -60,6 +84,15 @@ class Genode::Sandbox : Noncopyable Sandbox(Env &, State_handler &); + /** + * Constructor designated for monitoring PD-session operations + * + * The 'Pd_intrinsics' argument allows for the customization of the + * reference PD session used for quota transfers between the sandboxed + * children and the local runtime. + */ + Sandbox(Env &, State_handler &, Pd_intrinsics &); + void apply_config(Xml_node const &); /** @@ -196,6 +229,7 @@ struct Genode::Sandbox::Local_service : private Local_service_base Local_service(Sandbox &sandbox, Wakeup &wakeup) : Local_service_base(sandbox, ST::service_name(), wakeup) { } + using Local_session = ST; using Upgrade_response = Local_service_base::Upgrade_response; using Close_response = Local_service_base::Close_response; using Request = Local_service_base::Request; diff --git a/repos/os/lib/symbols/sandbox b/repos/os/lib/symbols/sandbox index 2e87285bb6..0025452386 100644 --- a/repos/os/lib/symbols/sandbox +++ b/repos/os/lib/symbols/sandbox @@ -6,4 +6,6 @@ _ZN6Genode7Sandbox18Local_service_baseC1ERS0_RKNS_6StringILm32EEERNS1_6WakeupE T _ZN6Genode7Sandbox18Local_service_baseC2ERS0_RKNS_6StringILm32EEERNS1_6WakeupE T _ZN6Genode7SandboxC1ERNS_3EnvERNS0_13State_handlerE T _ZN6Genode7SandboxC2ERNS_3EnvERNS0_13State_handlerE T +_ZN6Genode7SandboxC1ERNS_3EnvERNS0_13State_handlerERNS0_13Pd_intrinsicsE T +_ZN6Genode7SandboxC2ERNS_3EnvERNS0_13State_handlerERNS0_13Pd_intrinsicsE T _ZNK6Genode7Sandbox21generate_state_reportERNS_13Xml_generatorE T diff --git a/repos/os/src/lib/sandbox/child.cc b/repos/os/src/lib/sandbox/child.cc index b6d5cfb62c..9150e267fc 100644 --- a/repos/os/src/lib/sandbox/child.cc +++ b/repos/os/src/lib/sandbox/child.cc @@ -443,8 +443,6 @@ Sandbox::Child::Sample_state_result Sandbox::Child::sample_state() void Sandbox::Child::init(Pd_session &session, Pd_session_capability cap) { - session.ref_account(_env.pd_session_cap()); - size_t const initial_session_costs = session_alloc_batch_size()*_child.session_factory().session_costs(); @@ -472,13 +470,20 @@ void Sandbox::Child::init(Pd_session &session, Pd_session_capability cap) cap_quota = avail_caps; } - try { _env.pd().transfer_quota(cap, cap_quota); } - catch (Out_of_caps) { - error(name(), ": unable to initialize cap quota of PD"); } + _with_pd_intrinsics([&] (Pd_intrinsics::Intrinsics &intrinsics) { - try { _env.pd().transfer_quota(cap, ram_quota); } - catch (Out_of_ram) { - error(name(), ": unable to initialize RAM quota of PD"); } + _ref_pd_cap = intrinsics.ref_pd_cap; + + session.ref_account(intrinsics.ref_pd_cap); + + try { intrinsics.ref_pd.transfer_quota(cap, cap_quota); } + catch (Out_of_caps) { + error(name(), ": unable to initialize cap quota of PD"); } + + try { intrinsics.ref_pd.transfer_quota(cap, ram_quota); } + catch (Out_of_ram) { + error(name(), ": unable to initialize RAM quota of PD"); } + }); } @@ -491,9 +496,11 @@ void Sandbox::Child::init(Cpu_session &session, Cpu_session_capability cap) warning(name(), ": configured CPU quota of ", assigned, " exceeds " "available quota, proceeding with a quota of ", effective); - session.ref_account(_env.cpu_session_cap()); + _with_pd_intrinsics([&] (Pd_intrinsics::Intrinsics &intrinsics) { + session.ref_account(intrinsics.ref_cpu_cap); }); - _cpu_quota_transfer.transfer_cpu_quota(cap, effective); + _cpu_quota_transfer.transfer_cpu_quota(_child.pd_session_cap(), _child.pd(), + cap, effective); } @@ -745,7 +752,8 @@ Sandbox::Child::Child(Env &env, Affinity::Space const &affinity_space, Registry &parent_services, Registry &child_services, - Registry &local_services) + Registry &local_services, + Pd_intrinsics &pd_intrinsics) : _env(env), _alloc(alloc), _verbose(verbose), _id(id), _report_update_trigger(report_update_trigger), @@ -761,6 +769,7 @@ Sandbox::Child::Child(Env &env, _heartbeat_enabled(start_node.has_sub_node("heartbeat")), _resources(_resources_from_start_node(start_node, prio_levels, affinity_space, default_caps_accessor.default_caps())), + _pd_intrinsics(pd_intrinsics), _parent_services(parent_services), _child_services(child_services), _local_services(local_services), diff --git a/repos/os/src/lib/sandbox/child.h b/repos/os/src/lib/sandbox/child.h index 4634415809..674d7c8f8a 100644 --- a/repos/os/src/lib/sandbox/child.h +++ b/repos/os/src/lib/sandbox/child.h @@ -68,11 +68,35 @@ class Sandbox::Child : Child_policy, Routed_service::Wakeup struct Cpu_quota_transfer : Interface { - virtual void transfer_cpu_quota(Cpu_session_capability, Cpu_quota) = 0; + virtual void transfer_cpu_quota(Capability, Pd_session &, + Capability, Cpu_quota) = 0; }; enum class Sample_state_result { CHANGED, UNCHANGED }; + /* + * Helper for passing lambda functions as 'Pd_intrinsics::Fn' + */ + + using Pd_intrinsics = Genode::Sandbox::Pd_intrinsics; + + template + static void with_pd_intrinsics(Pd_intrinsics &pd_intrinsics, + Capability cap, PD_SESSION &pd, + FN const &fn) + { + struct Impl : Pd_intrinsics::Fn + { + using Intrinsics = Pd_intrinsics::Intrinsics; + + FN const &_fn; + Impl(FN const &fn) : _fn(fn) { } + void call(Intrinsics &intrinsics) const override { _fn(intrinsics); } + }; + + pd_intrinsics.with_intrinsics(cap, pd, Impl { fn }); + } + private: friend class Child_registry; @@ -280,6 +304,16 @@ class Sandbox::Child : Child_policy, Routed_service::Wakeup Ram_quota _configured_ram_quota() const; Cap_quota _configured_cap_quota() const; + Pd_intrinsics &_pd_intrinsics; + + template + void _with_pd_intrinsics(FN const &fn) + { + with_pd_intrinsics(_pd_intrinsics, _child.pd_session_cap(), _child.pd(), fn); + } + + Capability _ref_pd_cap { }; /* defined by 'init' */ + using Local_service = Genode::Sandbox::Local_service_base; Registry &_parent_services; @@ -293,7 +327,7 @@ class Sandbox::Child : Child_policy, Routed_service::Wakeup Child &_child; Dynamic_rom_session _session { _child._env.ep().rpc_ep(), - _child.ref_pd(), _child._env.rm(), + _child._env.ram(), _child._env.rm(), *this }; Service::Single_session_factory _factory { _session }; @@ -557,7 +591,8 @@ class Sandbox::Child : Child_policy, Routed_service::Wakeup Affinity::Space const &affinity_space, Registry &parent_services, Registry &child_services, - Registry &local_services); + Registry &local_services, + Pd_intrinsics &pd_intrinsics); virtual ~Child(); @@ -680,8 +715,17 @@ class Sandbox::Child : Child_policy, Routed_service::Wakeup Child_policy::Name name() const override { return _unique_name; } - Pd_session &ref_pd() override { return _env.pd(); } - Pd_session_capability ref_pd_cap() const override { return _env.pd_session_cap(); } + Pd_session &ref_pd() override + { + Pd_session *_ref_pd_ptr = nullptr; + _with_pd_intrinsics([&] (Pd_intrinsics::Intrinsics &intrinsics) { + _ref_pd_ptr = &intrinsics.ref_pd; }); + return *_ref_pd_ptr; + } + + Pd_session_capability ref_pd_cap() const override { return _ref_pd_cap; } + + Ram_allocator &session_md_ram() override { return _env.ram(); } void init(Pd_session &, Pd_session_capability) override; void init(Cpu_session &, Cpu_session_capability) override; @@ -732,6 +776,12 @@ class Sandbox::Child : Child_policy, Routed_service::Wakeup bool initiate_env_sessions() const override { return false; } + void _with_address_space(Pd_session &, With_address_space_fn const &fn) override + { + _with_pd_intrinsics([&] (Pd_intrinsics::Intrinsics &intrinsics) { + fn.call(intrinsics.address_space); }); + } + void yield_response() override { apply_downgrade(); diff --git a/repos/os/src/lib/sandbox/library.cc b/repos/os/src/lib/sandbox/library.cc index ddfef7ae9e..ab1e7f00d6 100644 --- a/repos/os/src/lib/sandbox/library.cc +++ b/repos/os/src/lib/sandbox/library.cc @@ -54,6 +54,8 @@ struct Genode::Sandbox::Library : ::Sandbox::State_reporter::Producer, Env &_env; Heap &_heap; + Pd_intrinsics &_pd_intrinsics; + Registry _parent_services { }; Registry _child_services { }; Registry &_local_services; @@ -143,7 +145,8 @@ struct Genode::Sandbox::Library : ::Sandbox::State_reporter::Producer, /** * Child::Cpu_quota_transfer interface */ - void transfer_cpu_quota(Cpu_session_capability cap, Cpu_quota quota) override + void transfer_cpu_quota(Capability pd_cap, Pd_session &pd, + Capability cpu, Cpu_quota quota) override { Cpu_quota const remaining { 100 - min(100u, _transferred_cpu.percent) }; @@ -154,7 +157,8 @@ struct Genode::Sandbox::Library : ::Sandbox::State_reporter::Producer, size_t const fraction = Cpu_session::quota_lim_upscale(quota.percent, remaining.percent); - _env.cpu().transfer_quota(cap, fraction); + Child::with_pd_intrinsics(_pd_intrinsics, pd_cap, pd, [&] (auto &intrinsics) { + intrinsics.ref_cpu.transfer_quota(cpu, fraction); }); _transferred_cpu.percent += quota.percent; } @@ -247,11 +251,38 @@ struct Genode::Sandbox::Library : ::Sandbox::State_reporter::Producer, return *new (_heap) Parent_service(_parent_services, _env, name); } + /** + * Default way of using the 'Env::pd' as the child's 'ref_pd' and accessing + * the child's address space via RPC. + */ + struct Default_pd_intrinsics : Pd_intrinsics + { + Env &_env; + + void with_intrinsics(Capability, Pd_session &pd, Fn const &fn) override + { + Region_map_client region_map(pd.address_space()); + + Intrinsics intrinsics { _env.pd(), _env.pd_session_cap(), + _env.cpu(), _env.cpu_session_cap(), region_map }; + fn.call(intrinsics); + } + + Default_pd_intrinsics(Env &env) : _env(env) { } + + } _default_pd_intrinsics { _env }; + + Library(Env &env, Heap &heap, Registry &local_services, + State_handler &state_handler, Pd_intrinsics &pd_intrinsics) + : + _env(env), _heap(heap), _pd_intrinsics(pd_intrinsics), + _local_services(local_services), _state_reporter(_env, *this, state_handler) + { } + Library(Env &env, Heap &heap, Registry &local_services, State_handler &state_handler) : - _env(env), _heap(heap), _local_services(local_services), - _state_reporter(_env, *this, state_handler) + Library(env, heap, local_services, state_handler, _default_pd_intrinsics) { } void apply_config(Xml_node const &); @@ -341,7 +372,8 @@ bool Genode::Sandbox::Library::ready_to_create_child(Start_model::Name const Child::Id { ++_child_cnt }, _state_reporter, start_node, *this, *this, _children, *this, *this, *this, *this, _prio_levels, _effective_affinity_space(), - _parent_services, _child_services, _local_services); + _parent_services, _child_services, _local_services, + _pd_intrinsics); _children.insert(&child); _avail_cpu.percent -= min(_avail_cpu.percent, child.cpu_quota().percent); @@ -627,6 +659,13 @@ void Genode::Sandbox::generate_state_report(Xml_generator &xml) const } +Genode::Sandbox::Sandbox(Env &env, State_handler &state_handler, Pd_intrinsics &pd_intrinsics) +: + _heap(env.ram(), env.rm()), + _library(*new (_heap) Library(env, _heap, _local_services, state_handler, pd_intrinsics)) +{ } + + Genode::Sandbox::Sandbox(Env &env, State_handler &state_handler) : _heap(env.ram(), env.rm()),