Test for combining loader with chroot

This commit is contained in:
Norman Feske 2012-06-06 17:31:52 +02:00
parent 17b60f8d41
commit ed867817b6
3 changed files with 316 additions and 0 deletions

139
os/run/chroot_loader.run Normal file
View File

@ -0,0 +1,139 @@
#
# \brief Test for using chroot on Linux
# \author Norman Feske
# \date 2012-06-06
#
#
if {![have_spec linux]} { puts "Run script requires Linux"; exit 0 }
#
# Build
#
build { core init app/chroot drivers/timer/linux test/timer
server/loader test/chroot_loader }
if {[catch { exec which setcap }]} {
puts stderr "Error: setcap not available, please install the libcap2-bin package"
return 0
}
create_boot_directory
#
# Generate config
#
set config {
<config>
<parent-provides>
<service name="ROM"/>
<service name="LOG"/>
<service name="CAP"/>
<service name="RAM"/>
<service name="CPU"/>
<service name="RM"/>
<service name="PD"/>
<service name="SIGNAL"/>
</parent-provides>
<default-route>
<any-service> <parent/> <any-child/> </any-service>
</default-route>
<start name="timer">
<resource name="RAM" quantum="1M"/>
<provides><service name="Timer"/></provides>
</start>
<start name="loader">
<resource name="RAM" quantum="1M"/>
<provides><service name="Loader"/></provides>
</start>
<start name="test-chroot_loader">
<resource name="RAM" quantum="32M"/>
<config>
<static_test chroot_path="chroot_path_1" />
<dynamic_test chroot_path="chroot_path_2" />
</config>
</start>
</config>
}
proc chroot_path { id } { return "/tmp/chroot-test-$id" }
proc chroot_cwd_path { id } { return "[chroot_path $id][pwd]/[run_dir]" }
proc chroot_genode_tmp_path { id } { return "[chroot_path $id]/tmp/genode-[exec id -u]" }
proc cleanup_chroot { } {
foreach id { 1 2 } {
catch { exec sudo umount -l [chroot_cwd_path $id] }
catch { exec sudo umount -l [chroot_genode_tmp_path $id] }
catch { exec sudo umount -l [chroot_path $id]/lib }
catch { exec rm -rf [chroot_path $id] }
}
}
# replace 'chroot_path' markers in config with actual paths
foreach id { 1 2 } {
regsub "chroot_path_$id" $config [chroot_path $id] config }
install_config $config
#
# Copy boot modules into run directory
#
# We cannot use the predefined 'build_boot_image' function here because
# this would create mere symlinks. However, we want to hardlink the
# run directory into the chroot environment. If the directory entries
# were symlinks, those would point to nowhere within the chroot.
#
foreach binary { core init chroot timer loader test-chroot_loader test-timer} {
exec cp -H bin/$binary [run_dir] }
#
# Grant chroot permission to 'chroot' tool
#
# CAP_SYS_ADMIN is needed for bind mounting genode runtime directories
# CAP_SYS_CHROOT is needed to perform the chroot syscall
#
exec sudo setcap cap_sys_admin,cap_sys_chroot=ep [run_dir]/chroot
#
# Setup chroot environment
#
# start with fresh directory
cleanup_chroot
foreach id { 1 2 } {
exec mkdir -p [chroot_path $id]
exec mkdir -p [chroot_path $id]/lib
# bind mount '/lib' as need libc within the chroot environment
exec sudo mount --bind /lib [chroot_path $id]/lib
}
#
# Execute test case
#
run_genode_until {.*--- chroot-loader test finished ---\s*\n} 60
#
# Validate log output
#
if {[regexp -all -- {--- timer test ---} $output] != 6} {
puts stderr "Number of spawned subsystems differs from 6"
exit 2
}
if {![regexp -- {chroot-1 -> test-timer] wait 2/10} $output]} {
puts stderr "Long-running timer test has made too little progress"
exit 3
}
#
# Remove artifacts created while running the test
#
cleanup_chroot
# vi: set ft=tcl :

View File

@ -0,0 +1,174 @@
/*
* \brief Test for dynamically starting chrooted subsystems via the loader
* \author Norman Feske
* \date 2012-06-06
*
* This test creates two subsystems, each residing in a dedicated chroot
* environment, by combining the loader service with the chroot mechanism.
* One subsystem runs infinitely. The other subsystem will be repeatedly
* started and killed.
*/
/* Genode includes */
#include <base/snprintf.h>
#include <loader_session/connection.h>
#include <os/config.h>
#include <timer_session/connection.h>
/*******************************************************
** Helpers for obtaining test parameters from config **
*******************************************************/
static char const *chroot_path_from_config(char const *node_name,
char *dst, Genode::size_t dst_len)
{
Genode::config()->xml_node().sub_node(node_name)
.attribute("chroot_path").value(dst, dst_len);
return dst;
}
static char const *chroot_path_of_static_test()
{
static char buf[1024];
return chroot_path_from_config("static_test", buf, sizeof(buf));
}
static char const *chroot_path_of_dynamic_test()
{
static char buf[1024];
return chroot_path_from_config("dynamic_test", buf, sizeof(buf));
}
/**********
** Test **
**********/
/**
* Return format string used as template for the subsystem configuration.
*
* Note the format-string argument used for inserting the chroot path.
*/
static char const *config_template()
{
return "<config verbose=\"yes\">\n"
" <root path=\"%s\" />\n"
" <parent-provides>\n"
" <service name=\"ROM\"/>\n"
" <service name=\"LOG\"/>\n"
" <service name=\"CAP\"/>\n"
" <service name=\"RAM\"/>\n"
" <service name=\"CPU\"/>\n"
" <service name=\"RM\"/>\n"
" <service name=\"PD\"/>\n"
" <service name=\"Timer\"/>\n"
" </parent-provides>\n"
" <default-route>\n"
" <any-service> <parent/> </any-service>\n"
" </default-route>\n"
" <start name=\"test-timer\">\n"
" <resource name=\"RAM\" quantum=\"1G\"/>\n"
" </start>\n"
"</config>\n";
}
/**
* Chroot subsystem corresponding to a loader session
*/
class Chroot_subsystem
{
private:
Loader::Connection _loader;
char _label[32];
/**
* Import data as ROM module into the subsystem-specific ROM service
*/
void _import_rom_module(char const *name, void *ptr, Genode::size_t size)
{
using namespace Genode;
Dataspace_capability ds = _loader.alloc_rom_module(name, size);
/* fill ROM module with data */
char *local_addr = env()->rm_session()->attach(ds);
memcpy(local_addr, ptr, size);
env()->rm_session()->detach(local_addr);
_loader.commit_rom_module(name);
}
public:
Chroot_subsystem(char const *chroot_path, Genode::size_t ram_quota)
:
_loader(ram_quota)
{
using namespace Genode;
/*
* Generate Genode configuration of the new subsystem and import
* it into the subsystem's loader session as a ROM module named
* "config".
*/
char buf[strlen(chroot_path) + strlen(config_template()) + 1];
snprintf(buf, sizeof(buf), config_template(), chroot_path);
_import_rom_module("config", buf, strlen(buf) + 1);
/*
* Name of the Genode binary is start as the root of the new
* subsystem.
*/
char const *chroot_binary_name = "chroot";
/*
* Generate unique label name using a counter
*
* The label appears in the LOG output of the loaded subsystem.
* Technically, it does need to be unique. It is solely used
* for validating the test in the run script.
*/
static int cnt = 0;
snprintf(_label, sizeof(_label), "%s-%d", chroot_binary_name, ++cnt);
/* start execution of new subsystem */
_loader.start(chroot_binary_name, Loader::Session::Name(_label));
}
};
int main(int, char **)
{
Genode::printf("--- chroot-loader test started ---\n");
static Chroot_subsystem static_subsystem(chroot_path_of_static_test(),
2*1024*1024);
static Timer::Connection timer;
for (unsigned i = 0; i < 5; i++) {
PLOG("dynamic test iteration %d", i);
Chroot_subsystem subsystem(chroot_path_of_dynamic_test(),
2*1024*1024);
/* grant the subsystem one second of life */
timer.msleep(1000);
/*
* The local 'dynamic_subsystem' instance will be destructed at the of
* the loop body.
*/
}
Genode::printf("--- chroot-loader test finished ---\n");
return 0;
}

View File

@ -0,0 +1,3 @@
TARGET = test-chroot_loader
SRC_CC = main.cc
LIBS += cxx env