From 4b46abf813b801bc9d1555795fc5b9ce13c588ee Mon Sep 17 00:00:00 2001 From: Norman Feske Date: Wed, 4 Jul 2018 18:48:04 +0200 Subject: [PATCH] base: rm first-class support for static binaries This patch removes the detection of statically linked executables from the base framework. It thereby fixes the corner cases encountered with Sculpt when obtaining the binaries of the runtime from the depot_rom service that is hosted within the runtime. Statically linked binaries and hybrid Linux/Genode (lx_hybrid) binaries can still be started by relabeling the ROM-session route of "ld.lib.so" to the binary name, pretending that the binary is the dynamic linker. This can be achieved via init's label rewriting mechanism: However, as this is quite cryptic and would need to be applied for all lx_hybrid components, the patch adds a shortcut to init's configuration. One can simply add the 'ld="no"' attribute to the node of the corresponding component: Fixes #2866 --- repos/base-linux/run/lx_fs.run | 2 +- repos/base-linux/run/lx_hybrid_ctors.run | 2 +- repos/base-linux/run/lx_hybrid_errno.run | 2 +- repos/base-linux/run/lx_hybrid_exception.run | 2 +- .../base-linux/run/lx_hybrid_pthread_ipc.run | 2 +- .../base-linux/src/lib/base/child_process.cc | 40 +++-------- repos/base-nova/run/platform.run | 2 +- repos/base/include/base/child.h | 40 +++++------ repos/base/src/lib/base/child.cc | 5 +- repos/base/src/lib/base/child_process.cc | 72 +++++++------------ repos/gems/run/cpu_load_display.run | 2 +- repos/gems/run/gpt_write.run | 2 +- repos/gems/run/leitzentrale.run | 2 +- repos/libports/run/avplay.run | 2 +- repos/libports/run/mesa.inc | 2 +- repos/libports/run/qt5_drivers.inc | 2 +- repos/libports/run/sdl.run | 2 +- .../drivers_interactive-linux/drivers.config | 2 +- repos/os/run/block_tester.run | 2 +- repos/os/run/demo.run | 2 +- repos/os/run/fb_bench.run | 2 +- repos/os/run/framebuffer.run | 2 +- repos/os/run/input.run | 2 +- repos/os/run/loader.run | 2 +- repos/os/run/lx_block.run | 2 +- repos/os/run/pointer.run | 2 +- repos/os/run/rom_to_file.run | 2 +- repos/os/src/init/child.cc | 4 ++ repos/os/src/init/child.h | 5 ++ repos/os/src/init/config.xsd | 1 + repos/ports/run/dosbox.run | 2 +- repos/ports/run/netperf.inc | 8 ++- repos/ports/run/seoul.inc | 5 +- repos/ports/run/virtualbox.run | 2 +- repos/ports/src/noux/child_policy.h | 2 + 35 files changed, 102 insertions(+), 130 deletions(-) diff --git a/repos/base-linux/run/lx_fs.run b/repos/base-linux/run/lx_fs.run index 5e8f6c653e..8162b567f3 100644 --- a/repos/base-linux/run/lx_fs.run +++ b/repos/base-linux/run/lx_fs.run @@ -32,7 +32,7 @@ install_config { - + diff --git a/repos/base-linux/run/lx_hybrid_ctors.run b/repos/base-linux/run/lx_hybrid_ctors.run index f5064a40c7..6fa4e07ecc 100644 --- a/repos/base-linux/run/lx_hybrid_ctors.run +++ b/repos/base-linux/run/lx_hybrid_ctors.run @@ -32,7 +32,7 @@ install_config { - + diff --git a/repos/base-linux/run/lx_hybrid_errno.run b/repos/base-linux/run/lx_hybrid_errno.run index 8f9548f761..2a47c87b8f 100644 --- a/repos/base-linux/run/lx_hybrid_errno.run +++ b/repos/base-linux/run/lx_hybrid_errno.run @@ -25,7 +25,7 @@ install_config { - + diff --git a/repos/base-linux/run/lx_hybrid_exception.run b/repos/base-linux/run/lx_hybrid_exception.run index 29ef601f51..18bc0d228f 100644 --- a/repos/base-linux/run/lx_hybrid_exception.run +++ b/repos/base-linux/run/lx_hybrid_exception.run @@ -31,7 +31,7 @@ install_config { - + diff --git a/repos/base-linux/run/lx_hybrid_pthread_ipc.run b/repos/base-linux/run/lx_hybrid_pthread_ipc.run index d151fd5dd2..1468b210ab 100644 --- a/repos/base-linux/run/lx_hybrid_pthread_ipc.run +++ b/repos/base-linux/run/lx_hybrid_pthread_ipc.run @@ -28,7 +28,7 @@ install_config { - + diff --git a/repos/base-linux/src/lib/base/child_process.cc b/repos/base-linux/src/lib/base/child_process.cc index 9427d8b37d..48fd021c3b 100644 --- a/repos/base-linux/src/lib/base/child_process.cc +++ b/repos/base-linux/src/lib/base/child_process.cc @@ -50,7 +50,7 @@ void Child::Initial_thread::start(addr_t) { } /* * On Linux, the ELF loading is performed by the kernel */ -Child::Process::Loaded_executable::Loaded_executable(Dataspace_capability, +Child::Process::Loaded_executable::Loaded_executable(Type, Dataspace_capability, Ram_session &, Region_map &, @@ -58,51 +58,27 @@ Child::Process::Loaded_executable::Loaded_executable(Dataspace_capability, Parent_capability) { } -Child::Process::Process(Dataspace_capability elf_ds, +Child::Process::Process(Type type, Dataspace_capability ldso_ds, - Pd_session_capability, Pd_session &pd, - Ram_session &ram, Initial_thread_base &, Region_map &local_rm, Region_map &remote_rm, Parent_capability parent_cap) : - loaded_executable(elf_ds, ldso_ds, ram, local_rm, remote_rm, parent_cap) + loaded_executable(type, ldso_ds, pd, local_rm, remote_rm, parent_cap) { /* skip loading when called during fork */ - if (!elf_ds.valid()) + if (type == TYPE_FORKED) return; - /* attach ELF locally */ - addr_t elf_addr; - try { elf_addr = local_rm.attach(elf_ds); } - catch (Region_map::Invalid_dataspace) { - error("local attach of ELF executable failed (Invalid_dataspace)"); throw; } - catch (Region_map::Region_conflict) { - error("local attach of ELF executable failed (Region_conflict)"); throw; } - - /* setup ELF object and read program entry pointer */ - Elf_binary elf(elf_addr); - if (!elf.valid()) - throw Invalid_executable(); - - bool const dynamically_linked = elf.dynamically_linked(); - - local_rm.detach(elf_addr); - /* * If the specified executable is a dynamically linked program, we load * the dynamic linker instead. */ - if (dynamically_linked) { - - if (!ldso_ds.valid()) { - error("attempt to start dynamic executable without dynamic linker"); - throw Missing_dynamic_linker(); - } - - elf_ds = ldso_ds; + if (!ldso_ds.valid()) { + error("attempt to start dynamic executable without dynamic linker"); + throw Missing_dynamic_linker(); } pd.assign_parent(parent_cap); @@ -110,7 +86,7 @@ Child::Process::Process(Dataspace_capability elf_ds, Linux_native_pd_client lx_pd(static_cap_cast(pd.native_pd())); - lx_pd.start(elf_ds); + lx_pd.start(ldso_ds); } diff --git a/repos/base-nova/run/platform.run b/repos/base-nova/run/platform.run index a674eb9cbf..0adfbcd627 100644 --- a/repos/base-nova/run/platform.run +++ b/repos/base-nova/run/platform.run @@ -24,7 +24,7 @@ set config { - + } append config " diff --git a/repos/base/include/base/child.h b/repos/base/include/base/child.h index ffab7cc505..ea001a4ea0 100644 --- a/repos/base/include/base/child.h +++ b/repos/base/include/base/child.h @@ -222,6 +222,11 @@ struct Genode::Child_policy * would otherwise produce a deadlock. */ virtual Region_map *address_space(Pd_session &) { return nullptr; } + + /** + * Return true if ELF loading should be inhibited + */ + virtual bool forked() const { return false; } }; @@ -344,6 +349,8 @@ class Genode::Child : protected Rpc_object, class Missing_dynamic_linker : Exception { }; class Invalid_executable : Exception { }; + enum Type { TYPE_LOADED, TYPE_FORKED }; + struct Loaded_executable { /** @@ -368,7 +375,7 @@ class Genode::Child : protected Rpc_object, * \throw Out_of_ram * \throw Out_of_caps */ - Loaded_executable(Dataspace_capability elf_ds, + Loaded_executable(Type type, Dataspace_capability ldso_ds, Ram_session &ram, Region_map &local_rm, @@ -379,11 +386,6 @@ class Genode::Child : protected Rpc_object, /** * Constructor * - * \param ram RAM session used to allocate the BSS and - * DATA segments for the new process - * \param parent parent of the new protection domain - * \param name name of protection domain - * * \throw Missing_dynamic_linker * \throw Invalid_executable * \throw Region_map::Region_conflict @@ -391,25 +393,21 @@ class Genode::Child : protected Rpc_object, * \throw Out_of_ram * \throw Out_of_caps * - * The other arguments correspond to those of 'Child::Child'. - * * On construction of a protection domain, the initial thread is * started immediately. * - * The argument 'elf_ds' may be invalid to create an empty process. - * In this case, all process initialization steps except for the - * creation of the initial thread must be done manually, i.e., as - * done for implementing fork. + * The 'type' 'TYPE_FORKED' creates an empty process. In this case, + * all process initialization steps except for the creation of the + * initial thread must be done manually, i.e., as done for + * implementing fork. */ - Process(Dataspace_capability elf_ds, - Dataspace_capability ldso_ds, - Pd_session_capability pd_cap, - Pd_session &pd, - Ram_session &ram, - Initial_thread_base &initial_thread, - Region_map &local_rm, - Region_map &remote_rm, - Parent_capability parent); + Process(Type type, + Dataspace_capability ldso_ds, + Pd_session &pd, + Initial_thread_base &initial_thread, + Region_map &local_rm, + Region_map &remote_rm, + Parent_capability parent); ~Process(); }; diff --git a/repos/base/src/lib/base/child.cc b/repos/base/src/lib/base/child.cc index 99b74f6048..b2132f1e3f 100644 --- a/repos/base/src/lib/base/child.cc +++ b/repos/base/src/lib/base/child.cc @@ -771,10 +771,11 @@ void Child::_try_construct_env_dependent_members() _policy.init(_cpu.session(), _cpu.cap()); + Process::Type const type = _policy.forked() + ? Process::TYPE_FORKED : Process::TYPE_LOADED; try { _initial_thread.construct(_cpu.session(), _pd.cap(), _policy.name()); - _process.construct(_binary.session().dataspace(), _linker_dataspace(), - _pd.cap(), _pd.session(), _pd.session(), + _process.construct(type, _linker_dataspace(), _pd.session(), *_initial_thread, _local_rm, Child_address_space(_pd.session(), _policy).region_map(), cap()); diff --git a/repos/base/src/lib/base/child_process.cc b/repos/base/src/lib/base/child_process.cc index 420005854f..63d4c99452 100644 --- a/repos/base/src/lib/base/child_process.cc +++ b/repos/base/src/lib/base/child_process.cc @@ -24,53 +24,32 @@ using namespace Genode; -Child::Process::Loaded_executable::Loaded_executable(Dataspace_capability elf_ds, +Child::Process::Loaded_executable::Loaded_executable(Type type, Dataspace_capability ldso_ds, - Ram_session &ram, + Pd_session &pd, Region_map &local_rm, Region_map &remote_rm, Parent_capability parent_cap) { /* skip loading when called during fork */ - if (!elf_ds.valid()) + if (type == TYPE_FORKED) return; - /* attach ELF locally */ - addr_t elf_addr; - try { elf_addr = local_rm.attach(elf_ds); } - catch (Region_map::Invalid_dataspace) { - error("local attach of ELF executable failed (invalid dataspace)"); throw; } - catch (Region_map::Region_conflict) { - error("local attach of ELF executable failed (region conflict)"); throw; } - - /* setup ELF object and read program entry pointer */ - Elf_binary elf(elf_addr); - if (!elf.valid()) - throw Invalid_executable(); - - /* - * If the specified executable is a dynamically linked program, we load - * the dynamic linker instead. - */ - if (elf.dynamically_linked()) { - - local_rm.detach(elf_addr); - - if (!ldso_ds.valid()) { - error("attempt to start dynamic executable without dynamic linker"); - throw Missing_dynamic_linker(); - } - - try { elf_addr = local_rm.attach(ldso_ds); } - catch (Region_map::Invalid_dataspace) { - error("dynamic linker is an invalid dataspace"); throw; } - catch (Region_map::Region_conflict) { - error("region conflict while attaching dynamic linker"); throw; } - - elf_ds = ldso_ds; - elf = Elf_binary(elf_addr); + /* locally attach ELF binary of the dynamic linker */ + if (!ldso_ds.valid()) { + error("attempt to start dynamic executable without dynamic linker"); + throw Missing_dynamic_linker(); } + addr_t elf_addr = 0; + try { elf_addr = local_rm.attach(ldso_ds); } + catch (Region_map::Invalid_dataspace) { + error("dynamic linker is an invalid dataspace"); throw; } + catch (Region_map::Region_conflict) { + error("region conflict while attaching dynamic linker"); throw; } + + Elf_binary elf(elf_addr); + entry = elf.entry(); /* setup region map for the new pd */ @@ -105,7 +84,7 @@ Child::Process::Loaded_executable::Loaded_executable(Dataspace_capability elf_ds /* alloc dataspace */ Dataspace_capability ds_cap; - try { ds_cap = ram.alloc(size); } + try { ds_cap = pd.alloc(size); } catch (Out_of_ram) { error("allocation of read-write segment failed"); throw; }; @@ -141,7 +120,9 @@ Child::Process::Loaded_executable::Loaded_executable(Dataspace_capability elf_ds off_t const offset = 0; try { remote_rm.attach_at(ds_cap, addr, size, offset); } catch (Region_map::Region_conflict) { - error("region conflict while remotely attaching ELF segment"); throw; } + error("region conflict while remotely attaching ELF segment"); + error("addr=", (void *)addr, " size=", (void *)size, " offset=", (void *)offset); + throw; } } else { @@ -153,12 +134,13 @@ Child::Process::Loaded_executable::Loaded_executable(Dataspace_capability elf_ds off_t const offset = seg.file_offset(); try { if (exec) - remote_rm.attach_executable(elf_ds, addr, size, offset); + remote_rm.attach_executable(ldso_ds, addr, size, offset); else - remote_rm.attach_at(elf_ds, addr, size, offset); + remote_rm.attach_at(ldso_ds, addr, size, offset); } catch (Region_map::Region_conflict) { error("region conflict while remotely attaching read-only ELF segment"); + error("addr=", (void *)addr, " size=", (void *)size, " offset=", (void *)offset); throw; } catch (Region_map::Invalid_dataspace) { @@ -194,17 +176,15 @@ void Child::Initial_thread::start(addr_t ip) } -Child::Process::Process(Dataspace_capability elf_ds, +Child::Process::Process(Type type, Dataspace_capability ldso_ds, - Pd_session_capability, Pd_session &pd, - Ram_session &ram, Initial_thread_base &initial_thread, Region_map &local_rm, Region_map &remote_rm, Parent_capability parent_cap) : - loaded_executable(elf_ds, ldso_ds, ram, local_rm, remote_rm, parent_cap) + loaded_executable(type, ldso_ds, pd, local_rm, remote_rm, parent_cap) { /* register parent interface for new protection domain */ pd.assign_parent(parent_cap); @@ -214,7 +194,7 @@ Child::Process::Process(Dataspace_capability elf_ds, * from another. In this case, the main thread will get manually * started after constructing the 'Process'. */ - if (!elf_ds.valid()) + if (type == TYPE_FORKED) return; /* start main thread */ diff --git a/repos/gems/run/cpu_load_display.run b/repos/gems/run/cpu_load_display.run index 41f52280b4..f3a6dd55e6 100644 --- a/repos/gems/run/cpu_load_display.run +++ b/repos/gems/run/cpu_load_display.run @@ -56,7 +56,7 @@ append config { } append_if [have_spec sdl] config { - + diff --git a/repos/gems/run/gpt_write.run b/repos/gems/run/gpt_write.run index 1ace87a057..43ed451a47 100644 --- a/repos/gems/run/gpt_write.run +++ b/repos/gems/run/gpt_write.run @@ -34,7 +34,7 @@ install_config { - + diff --git a/repos/gems/run/leitzentrale.run b/repos/gems/run/leitzentrale.run index 6e88ab8fe7..97ba031aab 100644 --- a/repos/gems/run/leitzentrale.run +++ b/repos/gems/run/leitzentrale.run @@ -202,7 +202,7 @@ install_config { - + diff --git a/repos/libports/run/avplay.run b/repos/libports/run/avplay.run index 1691a70392..d99b97dd9f 100644 --- a/repos/libports/run/avplay.run +++ b/repos/libports/run/avplay.run @@ -49,7 +49,7 @@ set config { } append_if [have_spec sdl] config { - + diff --git a/repos/libports/run/mesa.inc b/repos/libports/run/mesa.inc index ce8c82bbca..36704c8610 100644 --- a/repos/libports/run/mesa.inc +++ b/repos/libports/run/mesa.inc @@ -53,7 +53,7 @@ set config { } append_if [have_spec linux] config { - + diff --git a/repos/libports/run/qt5_drivers.inc b/repos/libports/run/qt5_drivers.inc index 40921a13ed..d6479742d2 100644 --- a/repos/libports/run/qt5_drivers.inc +++ b/repos/libports/run/qt5_drivers.inc @@ -165,7 +165,7 @@ proc drivers_start_nodes { feature_arg } { } append_if [use_fb_sdl feature] start_nodes { - + diff --git a/repos/libports/run/sdl.run b/repos/libports/run/sdl.run index 9d99f707c0..ab985fc2c8 100644 --- a/repos/libports/run/sdl.run +++ b/repos/libports/run/sdl.run @@ -38,7 +38,7 @@ append config { } append_if [have_spec sdl] config { - + diff --git a/repos/os/recipes/raw/drivers_interactive-linux/drivers.config b/repos/os/recipes/raw/drivers_interactive-linux/drivers.config index 5f4e874823..36676a10f5 100644 --- a/repos/os/recipes/raw/drivers_interactive-linux/drivers.config +++ b/repos/os/recipes/raw/drivers_interactive-linux/drivers.config @@ -13,7 +13,7 @@ - + diff --git a/repos/os/run/block_tester.run b/repos/os/run/block_tester.run index c718a7dbd8..b43dc94e1a 100644 --- a/repos/os/run/block_tester.run +++ b/repos/os/run/block_tester.run @@ -71,7 +71,7 @@ append_if [expr !$use_linux] config { append_if $use_linux config { - + diff --git a/repos/os/run/demo.run b/repos/os/run/demo.run index ebb0959869..e8ec816d4c 100644 --- a/repos/os/run/demo.run +++ b/repos/os/run/demo.run @@ -58,7 +58,7 @@ append config { } append_if [have_spec sdl] config { - + diff --git a/repos/os/run/fb_bench.run b/repos/os/run/fb_bench.run index 99afe92dc0..b48876d71e 100644 --- a/repos/os/run/fb_bench.run +++ b/repos/os/run/fb_bench.run @@ -61,7 +61,7 @@ append_if [have_spec gpio] config " " append_if [have_spec sdl] config { - + diff --git a/repos/os/run/framebuffer.run b/repos/os/run/framebuffer.run index 5430ac94ea..85fa2a340a 100644 --- a/repos/os/run/framebuffer.run +++ b/repos/os/run/framebuffer.run @@ -46,7 +46,7 @@ append config { } append_if [have_spec sdl] config { - + diff --git a/repos/os/run/input.run b/repos/os/run/input.run index 0eb19c0e24..8c1feb7f30 100644 --- a/repos/os/run/input.run +++ b/repos/os/run/input.run @@ -77,7 +77,7 @@ append_if [have_spec ps2] config { } append_if [have_spec sdl] config { - + diff --git a/repos/os/run/loader.run b/repos/os/run/loader.run index ad3c97b6e1..bba24425a0 100644 --- a/repos/os/run/loader.run +++ b/repos/os/run/loader.run @@ -41,7 +41,7 @@ append config { append_platform_drv_config append_if [have_spec sdl] config { - + diff --git a/repos/os/run/lx_block.run b/repos/os/run/lx_block.run index 0138bb9d07..df9181903c 100644 --- a/repos/os/run/lx_block.run +++ b/repos/os/run/lx_block.run @@ -34,7 +34,7 @@ install_config { - + diff --git a/repos/os/run/pointer.run b/repos/os/run/pointer.run index 210c94bdd7..a6e41863d0 100644 --- a/repos/os/run/pointer.run +++ b/repos/os/run/pointer.run @@ -50,7 +50,7 @@ set config { - + diff --git a/repos/os/run/rom_to_file.run b/repos/os/run/rom_to_file.run index e41d26059b..680e7fa222 100644 --- a/repos/os/run/rom_to_file.run +++ b/repos/os/run/rom_to_file.run @@ -44,7 +44,7 @@ install_config { - + diff --git a/repos/os/src/init/child.cc b/repos/os/src/init/child.cc index 67b386a7ab..eaa7a72418 100644 --- a/repos/os/src/init/child.cc +++ b/repos/os/src/init/child.cc @@ -496,6 +496,10 @@ Init::Child::Route Init::Child::resolve_session_request(Service::Name const &ser 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 "session_requests" ROM request */ if (service_name == Rom_session::service_name() && label.last_element() == Session_requester::rom_name()) diff --git a/repos/os/src/init/child.h b/repos/os/src/init/child.h index 986789ba6a..140a3f7e03 100644 --- a/repos/os/src/init/child.h +++ b/repos/os/src/init/child.h @@ -90,6 +90,11 @@ class Init::Child : Child_policy, Routed_service::Wakeup typedef String<80> Version; Version _version { _start_node->xml().attribute_value("version", Version()) }; + /* + * True if the binary is loaded with ld.lib.so + */ + bool const _use_ld = _start_node->xml().attribute_value("ld", true); + Default_route_accessor &_default_route_accessor; Default_caps_accessor &_default_caps_accessor; Ram_limit_accessor &_ram_limit_accessor; diff --git a/repos/os/src/init/config.xsd b/repos/os/src/init/config.xsd index 511aeaa95a..e5da52ba87 100644 --- a/repos/os/src/init/config.xsd +++ b/repos/os/src/init/config.xsd @@ -144,6 +144,7 @@ + diff --git a/repos/ports/run/dosbox.run b/repos/ports/run/dosbox.run index 94fbe430f0..e47b765e44 100644 --- a/repos/ports/run/dosbox.run +++ b/repos/ports/run/dosbox.run @@ -48,7 +48,7 @@ append config { } append_if [have_spec sdl] config { - + diff --git a/repos/ports/run/netperf.inc b/repos/ports/run/netperf.inc index eb3557978b..a4fce3829d 100644 --- a/repos/ports/run/netperf.inc +++ b/repos/ports/run/netperf.inc @@ -216,8 +216,14 @@ append_if $use_usb_driver config { } +# don't use the dynamic linker for loading the lx_hybrid nic_drv on Linux +proc nic_drv_ld_attr {} { + if {[have_spec linux]} { return {ld="no"} } + return "" +} + append_if $use_nic_driver config { - + diff --git a/repos/ports/run/seoul.inc b/repos/ports/run/seoul.inc index 1f7fbf8a22..76dbc6b49b 100644 --- a/repos/ports/run/seoul.inc +++ b/repos/ports/run/seoul.inc @@ -250,7 +250,7 @@ append_if $use_framebuffer config { if {!$use_fancy_stuff} { append config { - + } append config " " @@ -264,10 +264,9 @@ append_if [expr $use_nic_session && !$use_nic_bridge] config { append_if $use_framebuffer config { } append_if $use_genode_iso config { + - - } append config { diff --git a/repos/ports/run/virtualbox.run b/repos/ports/run/virtualbox.run index f366f697fb..814b0b2cfb 100644 --- a/repos/ports/run/virtualbox.run +++ b/repos/ports/run/virtualbox.run @@ -108,7 +108,7 @@ append_if [have_spec framebuffer] config { } append_if [have_spec sdl] config { - + diff --git a/repos/ports/src/noux/child_policy.h b/repos/ports/src/noux/child_policy.h index 51f9ad6263..caad94efa3 100644 --- a/repos/ports/src/noux/child_policy.h +++ b/repos/ports/src/noux/child_policy.h @@ -194,6 +194,8 @@ class Noux::Child_policy : public Genode::Child_policy { return &static_cast(pd).address_space_region_map(); } + + bool forked() const override { return _forked; } }; #endif /* _NOUX__CHILD_POLICY_H_ */