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:

  <route>
    <service name="ROM" unscoped_label="ld.lib.so">
      <parent label="test-platform"/> </service>
  </route>

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 <start> node of the
corresponding component:

  <start name="test-platform" ld="no"/>

Fixes 
This commit is contained in:
Norman Feske 2018-07-04 18:48:04 +02:00 committed by Christian Helmuth
parent c43ed44b17
commit 4b46abf813
35 changed files with 102 additions and 130 deletions

View File

@ -32,7 +32,7 @@ install_config {
<any-service> <parent/> <any-child/> </any-service>
</default-route>
<default caps="100"/>
<start name="lx_fs" caps="200">
<start name="lx_fs" caps="200" ld="no">
<resource name="RAM" quantum="4M"/>
<provides> <service name="File_system"/> </provides>
<config> <policy label_prefix="test-libc_vfs" root="/libc_vfs" writeable="yes" /> </config>

View File

@ -32,7 +32,7 @@ install_config {
<any-service> <parent/> <any-child/> </any-service>
</default-route>
<default caps="100"/>
<start name="test-lx_hybrid_ctors">
<start name="test-lx_hybrid_ctors" ld="no">
<resource name="RAM" quantum="1M"/>
</start>
</config>

View File

@ -25,7 +25,7 @@ install_config {
<default-route>
<any-service> <parent/> <any-child/> </any-service>
</default-route>
<start name="test-lx_hybrid_errno">
<start name="test-lx_hybrid_errno" ld="no">
<resource name="RAM" quantum="1M"/>
</start>
</config>

View File

@ -31,7 +31,7 @@ install_config {
<any-service> <parent/> <any-child/> </any-service>
</default-route>
<default caps="100"/>
<start name="test-lx_hybrid_exception">
<start name="test-lx_hybrid_exception" ld="no">
<resource name="RAM" quantum="1M"/>
</start>
</config>

View File

@ -28,7 +28,7 @@ install_config {
<any-service> <parent/> <any-child/> </any-service>
</default-route>
<default caps="100"/>
<start name="test-lx_hybrid_pthread_ipc">
<start name="test-lx_hybrid_pthread_ipc" ld="no">
<resource name="RAM" quantum="1M"/>
</start>
</config>

View File

@ -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<Linux_native_pd>(pd.native_pd()));
lx_pd.start(elf_ds);
lx_pd.start(ldso_ds);
}

View File

@ -24,7 +24,7 @@ set config {
<default-route>
<any-service> <parent/> </any-service>
</default-route>
<start name="test-platform" caps="12000">
<start name="test-platform" caps="12000" ld="no">
<resource name="RAM" quantum="128M"/>}
append config "

View File

@ -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<Parent>,
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<Parent>,
* \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<Parent>,
/**
* 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<Parent>,
* \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();
};

View File

@ -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());

View File

@ -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 */

View File

@ -56,7 +56,7 @@ append config {
<default caps="100"/>}
append_if [have_spec sdl] config {
<start name="fb_sdl">
<start name="fb_sdl" ld="no">
<resource name="RAM" quantum="4M"/>
<provides>
<service name="Input"/>

View File

@ -34,7 +34,7 @@ install_config {
<resource name="RAM" quantum="1M"/>
<provides><service name="Timer"/></provides>
</start>
<start name="lx_block">
<start name="lx_block" ld="no">
<resource name="RAM" quantum="2M"/>
<provides> <service name="Block"/> </provides>
<config file="gpt.img" block_size="512" writeable="yes"/>

View File

@ -202,7 +202,7 @@ install_config {
</start>
<start name="ahci-1">
<binary name="lx_block"/>
<binary name="lx_block" ld="no"/>
<resource name="RAM" quantum="2M"/>
<provides> <service name="Block"/> </provides>
<config file="ahci-1.img" block_size="512" writeable="yes"/>

View File

@ -49,7 +49,7 @@ set config {
}
append_if [have_spec sdl] config {
<start name="fb_sdl">
<start name="fb_sdl" ld="no">
<resource name="RAM" quantum="4M"/>
<provides>
<service name="Input"/>

View File

@ -53,7 +53,7 @@ set config {
}
append_if [have_spec linux] config {
<start name="fb_sdl" caps="200">
<start name="fb_sdl" caps="200" ld="no">
<resource name="RAM" quantum="4M"/>
<provides>
<service name="Input"/>

View File

@ -165,7 +165,7 @@ proc drivers_start_nodes { feature_arg } {
}
append_if [use_fb_sdl feature] start_nodes {
<start name="fb_sdl">
<start name="fb_sdl" ld="no">
<resource name="RAM" quantum="4M"/>
<provides>
<service name="Input"/>

View File

@ -38,7 +38,7 @@ append config {
<default caps="100"/>}
append_if [have_spec sdl] config {
<start name="fb_sdl">
<start name="fb_sdl" ld="no">
<resource name="RAM" quantum="4M"/>
<provides>
<service name="Input"/>

View File

@ -13,7 +13,7 @@
<service name="Input">
<default-policy> <child name="input_filter"/> </default-policy> </service>
<start name="fb_sdl" caps="100">
<start name="fb_sdl" caps="100" ld="no">
<resource name="RAM" quantum="4M"/>
<provides>
<service name="Input"/>

View File

@ -71,7 +71,7 @@ append_if [expr !$use_linux] config {
append_if $use_linux config {
<start name="ahci_drv">
<binary name="lx_block"/>
<binary name="lx_block" ld="no"/>
<resource name="RAM" quantum="2G"/>
<provides><service name="Block"/></provides>
<config file="block.raw" block_size="512" writeable="yes"/>

View File

@ -58,7 +58,7 @@ append config {
<default caps="100"/>}
append_if [have_spec sdl] config {
<start name="fb_sdl">
<start name="fb_sdl" ld="no">
<resource name="RAM" quantum="4M"/>
<provides>
<service name="Input"/>

View File

@ -61,7 +61,7 @@ append_if [have_spec gpio] config "
</start>"
append_if [have_spec sdl] config {
<start name="fb_sdl">
<start name="fb_sdl" ld="no">
<resource name="RAM" quantum="4M"/>
<provides>
<service name="Input"/>

View File

@ -46,7 +46,7 @@ append config {
</start>}
append_if [have_spec sdl] config {
<start name="fb_sdl">
<start name="fb_sdl" ld="no">
<resource name="RAM" quantum="4M"/>
<provides>
<service name="Input"/>

View File

@ -77,7 +77,7 @@ append_if [have_spec ps2] config {
<alias name="input_drv" child="ps2_drv"/>}
append_if [have_spec sdl] config {
<start name="fb_sdl">
<start name="fb_sdl" ld="no">
<resource name="RAM" quantum="4M"/>
<provides> <service name="Input"/> <service name="Framebuffer"/> </provides>
<route>

View File

@ -41,7 +41,7 @@ append config {
append_platform_drv_config
append_if [have_spec sdl] config {
<start name="fb_sdl">
<start name="fb_sdl" ld="no">
<resource name="RAM" quantum="4M"/>
<provides>
<service name="Input"/>

View File

@ -34,7 +34,7 @@ install_config {
<resource name="RAM" quantum="1M"/>
<provides><service name="Timer"/></provides>
</start>
<start name="lx_block">
<start name="lx_block" ld="no">
<resource name="RAM" quantum="2M"/>
<provides> <service name="Block"/> </provides>
<config file="lx_block.img" block_size="4K" writeable="yes"/>

View File

@ -50,7 +50,7 @@ set config {
<service name="LOG"> <parent/> </service>
</route>
</start>
<start name="fb_sdl">
<start name="fb_sdl" ld="no">
<resource name="RAM" quantum="6M"/>
<provides>
<service name="Framebuffer"/>

View File

@ -44,7 +44,7 @@ install_config {
</rom>
</config>
</start>
<start name="lx_fs">
<start name="lx_fs" ld="no">
<resource name="RAM" quantum="4M"/>
<provides> <service name="File_system" /> </provides>
<config>

View File

@ -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 '<start ld="no">' */
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())

View File

@ -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;

View File

@ -144,6 +144,7 @@
</xs:choice>
<xs:attribute name="name" type="xs:string" />
<xs:attribute name="ld" type="xs:string" />
<xs:attribute name="caps" type="xs:int" />
<xs:attribute name="priority" type="xs:int" />
</xs:complexType>

View File

@ -48,7 +48,7 @@ append config {
<default caps="100"/>}
append_if [have_spec sdl] config {
<start name="fb_sdl">
<start name="fb_sdl" ld="no">
<resource name="RAM" quantum="4M"/>
<provides>
<service name="Input"/>

View File

@ -216,8 +216,14 @@ append_if $use_usb_driver config {
</config>
</start>}
# 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 {
<start name="nic_drv" caps="130">
<start name="nic_drv" caps="130" } [nic_drv_ld_attr] {>
<binary name="} [nic_drv_binary] {"/>
<resource name="RAM" quantum="20M"/>
<provides><service name="Nic"/></provides>

View File

@ -250,7 +250,7 @@ append_if $use_framebuffer config {
if {!$use_fancy_stuff} {
append config {
<start name="seoul" priority="-3" caps="200">
<start name="seoul" priority="-3" caps="200" ld="no">
<binary name="seoul"/>}
append config "
<resource name=\"RAM\" quantum=\"$memory_vmm_vm\"/>"
@ -264,10 +264,9 @@ append_if [expr $use_nic_session && !$use_nic_bridge] config {
append_if $use_framebuffer config {
<service name="Framebuffer"><child name="fb_drv"/></service>}
append_if $use_genode_iso config {
<service name="ROM" unscoped_label="seoul"> <parent/> </service>
<service name="ROM" label="vm_seoul.cfg"> <parent/> </service>
<service name="ROM" label="platform_info"> <parent/> </service>
<service name="ROM" unscoped_label="seoul"> <parent/> </service>
<service name="ROM" unscoped_label="ld.lib.so"> <parent/> </service>
<service name="ROM"><child name="iso9660"/></service>}
append config {
<service name="Rtc"><child name="rtc_drv"/></service>

View File

@ -108,7 +108,7 @@ append_if [have_spec framebuffer] config {
</start>}
append_if [have_spec sdl] config {
<start name="fb_sdl" priority="-1">
<start name="fb_sdl" priority="-1" ld="no">
<resource name="RAM" quantum="4M"/>
<provides>
<service name="Input"/>

View File

@ -194,6 +194,8 @@ class Noux::Child_policy : public Genode::Child_policy
{
return &static_cast<Pd_session_component &>(pd).address_space_region_map();
}
bool forked() const override { return _forked; }
};
#endif /* _NOUX__CHILD_POLICY_H_ */