base-linux: remove chroot support

Fixes #1903
This commit is contained in:
Norman Feske 2016-03-08 15:58:05 +01:00
parent 76db3b9c06
commit 9a3185f8ed
33 changed files with 17 additions and 1146 deletions

View File

@ -73,8 +73,6 @@ namespace Genode {
typedef Native_capability_tpl<Cap_dst_policy> Native_capability;
typedef Fiasco::l4_threadid_t Native_connection_state;
struct Native_pd_args { };
}
#endif /* _INCLUDE__BASE__NATIVE_TYPES_H_ */

View File

@ -193,8 +193,6 @@ namespace Genode {
typedef int Native_connection_state;
struct Native_pd_args { };
}
#endif /* _INCLUDE__BASE__NATIVE_TYPES_H_ */

View File

@ -40,8 +40,6 @@ namespace Genode
*/
struct Native_region;
struct Native_pd_args { };
/**
* Get the the minimal supported page-size log 2
*/

View File

@ -33,7 +33,7 @@ struct Genode::Pd_connection : Connection<Pd_session>, Pd_session_client
*
* \param label session label
*/
Pd_connection(char const *label = "", Native_pd_args const *pd_args = 0)
Pd_connection(char const *label = "")
: Connection<Pd_session>(session("ram_quota=%u, label=\"%s\"",
RAM_QUOTA, label)),
Pd_session_client(cap()) { }

View File

@ -114,35 +114,6 @@ namespace Genode {
};
enum { PARENT_SOCKET_HANDLE = 100 };
class Native_pd_args
{
public:
enum { ROOT_PATH_MAX_LEN = 256 };
private:
char _root[ROOT_PATH_MAX_LEN];
unsigned _uid;
unsigned _gid;
public:
Native_pd_args() : _uid(0), _gid(0) { _root[0] = 0; }
Native_pd_args(char const *root, unsigned uid, unsigned gid)
:
_uid(uid), _gid(gid)
{
Genode::strncpy(_root, root, sizeof(_root));
}
char const *root() const { return _root; }
unsigned uid() const { return _uid; }
unsigned gid() const { return _gid; }
};
}
#endif /* _INCLUDE__BASE__NATIVE_TYPES_H_ */

View File

@ -1,102 +0,0 @@
/*
* \brief Connection to PD service
* \author Norman Feske
* \date 2012-11-21
*
* In contrast to the generic version of 'pd_session/connection.h', the
* Linux-specific version supplies additional argument to core's PD service:
*
* :'root': is the path of a chroot environment of the process
* :'uid': is the user ID of the process
* :'gid': is the designated group ID of the process
*/
/*
* Copyright (C) 2012-2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _INCLUDE__PD_SESSION__CONNECTION_H_
#define _INCLUDE__PD_SESSION__CONNECTION_H_
#include <pd_session/client.h>
#include <base/connection.h>
namespace Genode {
class Pd_connection : public Connection<Pd_session>, public Pd_session_client
{
private:
template <Genode::size_t STRING_MAX_LEN>
struct Arg
{
char string[STRING_MAX_LEN];
Arg() { string[0] = 0; }
};
/**
* Convert root path argument to session-construction parameter
*/
struct Root_arg : Arg<Native_pd_args::ROOT_PATH_MAX_LEN>
{
Root_arg(Native_pd_args const *args)
{
if (args && args->root() && args->root()[0])
Genode::snprintf(string, sizeof(string), ", root=\"%s\"",
args->root());
}
};
/**
* Convert UID argument to session-construction parameter
*/
struct Uid_arg : Arg<64>
{
Uid_arg(Native_pd_args const *args)
{
if (args && args->uid())
Genode::snprintf(string, sizeof(string), ", uid=%u",
args->uid());
}
};
/**
* Convert GID argument to session-construction parameter
*/
struct Gid_arg : Arg<64>
{
Gid_arg(Native_pd_args const *args)
{
if (args && args->gid())
Genode::snprintf(string, sizeof(string), ", gid=%u",
args->gid());
}
};
public:
enum { RAM_QUOTA = 4*1024 };
/**
* Constructor
*
* \param label session label
* \param pd_args Linux-specific PD-session arguments
*/
Pd_connection(char const *label = "", Native_pd_args const *pd_args = 0)
:
Connection<Pd_session>(
session("ram_quota=36K, label=\"%s\"%s%s%s", label,
Root_arg(pd_args).string,
Uid_arg(pd_args).string,
Gid_arg(pd_args).string)),
Pd_session_client(cap())
{ }
};
}
#endif /* _INCLUDE__PD_SESSION__CONNECTION_H_ */

View File

@ -1,59 +0,0 @@
#
# \brief Test for supplying Linux-specific PD-session arguments to core
# \author Norman Feske
# \date 2012-11-21
#
build "core init test/printf"
assert_spec linux
create_boot_directory
install_config {
<config>
<parent-provides>
<service name="LOG"/>
<service name="RAM"/>
<service name="CAP"/>
<service name="PD"/>
<service name="RM"/>
<service name="CPU"/>
<service name="ROM"/>
</parent-provides>
<default-route>
<any-service> <parent/> </any-service>
</default-route>
<start name="init" uid="11">
<resource name="RAM" quantum="10M"/>
<config>
<parent-provides>
<service name="LOG"/>
</parent-provides>
<start name="test-printf" root="/tmp/somewhere" uid="33" gid="44">
<resource name="RAM" quantum="10M"/>
</start>
</config>
</start>
</config>
}
build_boot_image "core init test-printf"
#
# The chroot to '/tmp/somewhere' is expected to fail. We just want to validate
# that the PD-session arguments are properly propagated into core. Hence, we
# can take the error message as exit condition of the test run.
#
run_genode_until {chroot path does not point to valid directory} 10
# keep only the lines containing the relevant core output
grep_output {^ .*:}
compare_output_to {
uid: 11
root: /tmp/somewhere
uid: 11
gid: 44
}

View File

@ -123,41 +123,6 @@ inline int lx_pollpid()
}
/*********************
** Chroot handling **
*********************/
inline int lx_chroot(char const *path)
{
return lx_syscall(SYS_chroot, path);
}
inline int lx_chdir(char const *path)
{
return lx_syscall(SYS_chdir, path);
}
inline int lx_getcwd(char *dst, size_t dst_len)
{
return lx_syscall(SYS_getcwd, dst, dst_len);
}
inline int lx_bindmount(char const *source, char const *target)
{
enum { MS_BIND = 4096 };
return lx_syscall(SYS_mount, source, target, 0, MS_BIND, 0);
}
inline int lx_umount(char const *target)
{
return lx_syscall(SYS_umount2, target, 0);
}
/********************************************
** Communication over Unix-domain sockets **
********************************************/

View File

@ -26,166 +26,6 @@
using namespace Genode;
/***********************************
** Utilities for chroot handling **
***********************************/
enum { MAX_PATH_LEN = 256 };
/**
* Return true if specified path is an existing directory
*/
static bool is_directory(char const *path)
{
struct stat64 s;
if (lx_stat(path, &s) != 0)
return false;
if (!(s.st_mode & S_IFDIR))
return false;
return true;
}
static bool is_path_delimiter(char c) { return c == '/'; }
static bool has_trailing_path_delimiter(char const *path)
{
char last_char = 0;
for (; *path; path++)
last_char = *path;
return is_path_delimiter(last_char);
}
/**
* Return number of path elements of given path
*/
static Genode::size_t num_path_elements(char const *path)
{
Genode::size_t count = 0;
/*
* If path starts with non-slash, the first characters belongs to a path
* element.
*/
if (*path && !is_path_delimiter(*path))
count = 1;
/* count slashes */
for (; *path; path++)
if (is_path_delimiter(*path))
count++;
return count;
}
static bool leading_path_elements(char const *path, unsigned num,
char *dst, Genode::size_t dst_len)
{
/* counter of path delimiters */
unsigned count = 0;
unsigned i = 0;
if (is_path_delimiter(path[0]))
num++;
for (; path[i] && (count < num) && (i < dst_len); i++)
{
if (is_path_delimiter(path[i]))
count++;
if (count == num)
break;
dst[i] = path[i];
}
if (i + 1 < dst_len) {
dst[i] = 0;
return true;
}
/* string is cut, append null termination anyway */
dst[dst_len - 1] = 0;
return false;
}
static void mirror_path_to_chroot(char const *chroot_path, char const *path)
{
char target_path[MAX_PATH_LEN];
Genode::snprintf(target_path, sizeof(target_path), "%s%s",
chroot_path, path);
/*
* Create directory hierarchy pointing to the target path except for the
* last element. The last element will be bind-mounted to refer to the
* original 'path'.
*/
for (unsigned i = 1; i <= num_path_elements(target_path); i++)
{
char buf[MAX_PATH_LEN];
leading_path_elements(target_path, i, buf, sizeof(buf));
/* skip existing directories */
if (is_directory(buf))
continue;
/* create new directory */
lx_mkdir(buf, 0777);
}
lx_umount(target_path);
int ret = 0;
if ((ret = lx_bindmount(path, target_path)))
PERR("bind mount failed (errno=%d)", ret);
}
/**
* Setup content of chroot environment as prerequisite to 'execve' new
* processes within the environment. I.e., the current working directory
* containing the ROM modules must be mounted at the same location within the
* chroot environment.
*/
static bool setup_chroot_environment(char const *chroot_path)
{
using namespace Genode;
static char cwd_path[MAX_PATH_LEN];
lx_getcwd(cwd_path, sizeof(cwd_path));
/*
* Validate chroot path
*/
if (!is_directory(chroot_path)) {
PERR("chroot path does not point to valid directory");
return false;
}
if (has_trailing_path_delimiter(chroot_path)) {
PERR("chroot path has trailing slash");
return false;
}
/*
* Hardlink directories needed for running Genode within the chroot
* environment.
*/
mirror_path_to_chroot(chroot_path, cwd_path);
return true;
}
/***************
** Utilities **
***************/
@ -196,23 +36,16 @@ static bool setup_chroot_environment(char const *chroot_path)
struct Execve_args
{
char const *filename;
char const *root;
char * const *argv;
char * const *envp;
unsigned int const uid;
unsigned int const gid;
int const parent_sd;
Execve_args(char const *filename,
char const *root,
char * const *argv,
char * const *envp,
unsigned int uid,
unsigned int gid,
int parent_sd)
:
filename(filename), root(root), argv(argv), envp(envp),
uid(uid), gid(gid), parent_sd(parent_sd)
filename(filename), argv(argv), envp(envp), parent_sd(parent_sd)
{ }
};
@ -224,57 +57,6 @@ static int _exec_child(Execve_args *arg)
{
lx_dup2(arg->parent_sd, PARENT_SOCKET_HANDLE);
/* change to chroot environment */
if (arg->root && arg->root[0]) {
char cwd[1024];
PDBG("arg->root='%s'", arg->root);
if (setup_chroot_environment(arg->root) == false) {
PERR("Could not setup chroot environment");
return -1;
}
if (!lx_getcwd(cwd, sizeof(cwd))) {
PERR("Failed to getcwd");
return -1;
}
PLOG("changing root of %s (PID %d) to %s",
arg->filename, lx_getpid(), arg->root);
int ret = lx_chroot(arg->root);
if (ret < 0) {
PERR("Syscall chroot failed (errno %d)", ret);
return -1;
}
ret = lx_chdir(cwd);
if (ret < 0) {
PERR("chdir to new chroot failed");
return -1;
}
}
/*
* Set UID and GID
*
* We must set the GID prior setting the UID because setting the GID won't
* be possible anymore once we set the UID to non-root.
*/
if (arg->gid) {
int const ret = lx_setgid(arg->gid);
if (ret)
PWRN("Could not set PID %d (%s) to GID %u (error %d)",
lx_getpid(), arg->filename, arg->gid, ret);
}
if (arg->uid) {
int const ret = lx_setuid(arg->uid);
if (ret)
PWRN("Could not set PID %d (%s) to UID %u (error %d)",
lx_getpid(), arg->filename, arg->uid, ret);
}
return lx_execve(arg->filename, arg->argv, arg->envp);
}
@ -381,7 +163,7 @@ void Native_pd_component::_start(Dataspace_component &ds)
* Argument frame as passed to 'clone'. Because, we can only pass a single
* pointer, all arguments are embedded within the 'execve_args' struct.
*/
Execve_args arg(filename, _root, argv_buf, env, _uid, _gid,
Execve_args arg(filename, argv_buf, env,
_pd_session._parent.dst().socket);
_pid = lx_create_process((int (*)(void *))_exec_child,
@ -398,37 +180,6 @@ Native_pd_component::Native_pd_component(Pd_session_component &pd_session,
_pd_session(pd_session)
{
_pd_session._thread_ep.manage(this);
/*
* Read Linux-specific session arguments
*/
Arg_string::find_arg(args, "root").string(_root, sizeof(_root), "");
_uid = Arg_string::find_arg(args, "uid").ulong_value(0);
_gid = Arg_string::find_arg(args, "gid").ulong_value(0);
bool const is_chroot = (Genode::strcmp(_root, "") != 0);
/*
* If a UID is specified but no GID, we use the UID as GID. This way, a
* configuration error where the UID is defined but the GID is left
* undefined won't result in the execution of the new process with the
* root user's GID.
*/
if (_gid == 0)
_gid = _uid;
/*
* Print Linux-specific session arguments if specified
*
* This output used for the automated 'lx_pd_args' test.
*/
if (is_chroot || _uid || _gid)
printf("PD session for '%s'\n", _pd_session._label.string);
if (is_chroot) printf(" root: %s\n", _root);
if (_uid) printf(" uid: %u\n", _uid);
if (_gid) printf(" gid: %u\n", _gid);
}

View File

@ -237,8 +237,6 @@ namespace Genode {
};
typedef int Native_connection_state;
struct Native_pd_args { };
}
#endif /* _INCLUDE__BASE__NATIVE_TYPES_H_ */

View File

@ -89,8 +89,6 @@ namespace Genode {
typedef Native_capability_tpl<Cap_dst_policy> Native_capability;
typedef Okl4::L4_ThreadId_t Native_connection_state;
struct Native_pd_args { };
}
#endif /* _INCLUDE__BASE__NATIVE_TYPES_H_ */

View File

@ -73,8 +73,6 @@ namespace Genode {
typedef Native_capability_tpl<Cap_dst_policy> Native_capability;
typedef Pistachio::L4_ThreadId_t Native_connection_state;
struct Native_pd_args { };
}
#endif /* _INCLUDE__BASE__NATIVE_TYPES_H_ */

View File

@ -126,8 +126,6 @@ namespace Genode {
};
};
struct Native_pd_args { };
typedef int Native_connection_state;
}

View File

@ -29,7 +29,7 @@ struct Genode::Pd_connection : Connection<Pd_session>, Pd_session_client
*
* \param label session label
*/
Pd_connection(char const *label = "", Native_pd_args const *pd_args = 0)
Pd_connection(char const *label = "")
: Connection<Pd_session>(session("ram_quota=%u, label=\"%s\"",
RAM_QUOTA, label)),
Pd_session_client(cap())

View File

@ -111,14 +111,6 @@ struct Genode::Child_policy
virtual Ram_session *ref_ram_session() { return env()->ram_session(); }
virtual Ram_session_capability ref_ram_cap() const { return env()->ram_session_cap(); }
/**
* Return platform-specific PD-session arguments
*
* This method is used on Linux to supply additional PD-session
* argument to core, i.e., the chroot path, the UID, and the GID.
*/
virtual Native_pd_args const *pd_args() const { return 0; }
/**
* Respond to the release of resources by the child
*

View File

@ -29,7 +29,7 @@ struct Genode::Pd_connection : Connection<Pd_session>, Pd_session_client
*
* \param label session label
*/
Pd_connection(char const *label = "", Native_pd_args const *pd_args = 0)
Pd_connection(char const *label = "")
: Connection<Pd_session>(session("ram_quota=%u, label=\"%s\"",
RAM_QUOTA, label)),
Pd_session_client(cap())

View File

@ -320,29 +320,6 @@ optional sub node '<exit>' with the attribute 'propagate' set to "yes".
The exit value specified by the exiting child is forwarded to init's parent.
Executing children in chroot environments on Linux
==================================================
On the Linux base platform, each process started by init can be assigned to
a chroot environment by specifying the new root location as 'root' attribute
to the corresponding '<start>' node. Root environments can be nested. The
root path of a nested init instance will be appended to the root path of
the outer instance.
When using the chroot mechanism, core will mirror the current working
directory within the chroot environment via the a bind mount operation. This
step is needed to enable execve to obtain the ELF binary of the new process.
In order to use the chroot mechanism when starting Genode's core as a non-root
user process, the core executable must be equipped with the 'CAP_SYS_ADMIN' and
'CAP_SYS_CHROOT' capabilities. 'CAP_SYS_ADMIN' is needed for bind mounting.
'CAP_SYS_CHROOT' is needed to perform the 'chroot' syscall:
! sudo setcap cap_sys_admin,cap_sys_chroot=ep core
For an example of using chroot, please refer to the 'os/run/chroot.run' script.
Using the configuration concept
###############################

View File

@ -414,14 +414,6 @@ class Init::Child : Genode::Child_policy
}
} _name;
/**
* Platform-specific PD-session arguments
*/
struct Pd_args : Genode::Native_pd_args
{
Pd_args(Genode::Xml_node start_node);
} _pd_args;
struct Read_quota
{
Read_quota(Genode::Xml_node start_node,
@ -482,15 +474,14 @@ class Init::Child : Genode::Child_policy
Resources(Genode::Xml_node start_node, const char *label,
long prio_levels,
Genode::Affinity::Space const &affinity_space,
Genode::Native_pd_args const * pd_args)
Genode::Affinity::Space const &affinity_space)
:
Read_quota(start_node, ram_quota, cpu_quota_pc, constrain_phys),
prio_levels_log2(Genode::log2(prio_levels)),
priority(read_priority(start_node, prio_levels)),
affinity(affinity_space,
read_affinity_location(affinity_space, start_node)),
pd(label, pd_args),
pd(label),
ram(label),
cpu(label,
priority*(Genode::Cpu_session::PRIORITY_LIMIT >> prio_levels_log2),
@ -549,7 +540,6 @@ class Init::Child : Genode::Child_policy
Init::Child_policy_provide_rom_file _config_policy;
Init::Child_policy_provide_rom_file _binary_policy;
Init::Child_policy_redirect_rom_file _configfile_policy;
Init::Child_policy_pd_args _pd_args_policy;
Init::Child_policy_ram_phys _ram_session_policy;
public:
@ -568,9 +558,8 @@ class Init::Child : Genode::Child_policy
_default_route_node(default_route_node),
_name_registry(name_registry),
_name(start_node, name_registry),
_pd_args(start_node),
_resources(start_node, _name.unique, prio_levels,
affinity_space, &_pd_args),
affinity_space),
_entrypoint(cap_session, ENTRYPOINT_STACK_SIZE, _name.unique, false, _resources.affinity.location()),
_binary_rom(_name.file, _name.file),
_binary_rom_ds(_binary_rom.dataspace()),
@ -585,7 +574,6 @@ class Init::Child : Genode::Child_policy
_config_policy("config", _config.dataspace(), &_entrypoint),
_binary_policy("binary", _binary_rom_ds, &_entrypoint),
_configfile_policy("config", _config.filename()),
_pd_args_policy(&_pd_args),
_ram_session_policy(_resources.constrain_phys)
{
using namespace Genode;
@ -743,7 +731,6 @@ class Init::Child : Genode::Child_policy
_labeling_policy. filter_session_args(service, args, args_len);
_priority_policy. filter_session_args(service, args, args_len);
_configfile_policy.filter_session_args(service, args, args_len);
_pd_args_policy. filter_session_args(service, args, args_len);
_ram_session_policy.filter_session_args(service, args, args_len);
}
@ -838,8 +825,6 @@ class Init::Child : Genode::Child_policy
*/
Child_policy::exit(exit_value);
}
Genode::Native_pd_args const *pd_args() const { return &_pd_args; }
};

View File

@ -25,7 +25,6 @@ namespace Init {
class Child_policy_ram_phys;
class Child_policy_enforce_labeling;
class Child_policy_pd_args;
class Child_policy_handle_cpu_priorities;
class Child_policy_provide_rom_file;
class Child_policy_redirect_rom_file;
@ -109,29 +108,6 @@ class Init::Child_policy_enforce_labeling
};
/**
* Policy for handling platform-specific PD-session arguments
*
* This policy is used onthe Linux base platform for prepending the chroot
* path of the child. By applying this policy, the chroot path of the child
* gets supplied to PD session requests.
*/
class Init::Child_policy_pd_args
{
private:
Genode::Native_pd_args const *_pd_args;
public:
Child_policy_pd_args(Genode::Native_pd_args const *pd_args)
: _pd_args(pd_args) { }
void filter_session_args(const char *session, char *args,
Genode::size_t args_len);
};
class Init::Child_policy_handle_cpu_priorities
{
/* priority parameters */

View File

@ -49,9 +49,8 @@ struct Loader::Session_client : Genode::Rpc_client<Session>
void fault_sigh(Signal_context_capability sigh) override {
call<Rpc_fault_sigh>(sigh); }
void start(Name const &binary, Name const &label = "",
Native_pd_args const &pd_args = Native_pd_args()) override {
call<Rpc_start>(binary, label, pd_args); }
void start(Name const &binary, Name const &label = "") override {
call<Rpc_start>(binary, label); }
void view_geometry(Rect rect, Point offset) override {
call<Rpc_view_geometry>(rect, offset); }

View File

@ -31,7 +31,6 @@ namespace Loader {
using Genode::Dataspace_capability;
using Genode::Signal_context_capability;
using Genode::Native_pd_args;
using Genode::Meta::Type_tuple;
struct Session;
@ -144,8 +143,7 @@ struct Loader::Session : Genode::Session
* \throw Rom_module_does_not_exist if the specified binary could
* not obtained as ROM module
*/
virtual void start(Name const &binary, Name const &label = "",
Native_pd_args const &pd_args = Native_pd_args()) = 0;
virtual void start(Name const &binary, Name const &label = "") = 0;
/**
* Set view geometry and buffer offset
@ -174,7 +172,7 @@ struct Loader::Session : Genode::Session
GENODE_RPC(Rpc_fault_sigh, void, fault_sigh, Signal_context_capability);
GENODE_RPC_THROW(Rpc_start, void, start,
GENODE_TYPE_LIST(Rom_module_does_not_exist),
Name const &, Name const &, Native_pd_args const &);
Name const &, Name const &);
GENODE_RPC_THROW(Rpc_view_geometry, void, view_geometry,
GENODE_TYPE_LIST(View_does_not_exist),
Rect, Point);

View File

@ -1,3 +0,0 @@
SRC_CC = pd_args.cc
vpath pd_args.cc $(REP_DIR)/src/init

View File

@ -1,3 +0,0 @@
SRC_CC = pd_args.cc
vpath pd_args.cc $(REP_DIR)/src/init/spec/linux

View File

@ -1,111 +0,0 @@
#
# \brief Test for using chroot on Linux
# \author Norman Feske
# \date 2012-04-18
#
#
if {![have_spec linux]} { puts "Run script requires Linux"; exit 0 }
#
# Build
#
build { core init drivers/timer test/timer }
if {[catch { exec which setcap }]} {
puts stderr "Error: setcap not available, please install the libcap2-bin package"
return 0
}
#
# Clean up remains of a potentially failed previous run
#
proc chroot_path { } { return "/tmp/chroot-test" }
proc chroot_cwd_path { } { return "[chroot_path][pwd]/[run_dir]" }
proc chroot_genode_tmp_path { } { return "[chroot_path]/tmp/genode-[exec id -u]" }
proc cleanup_chroot { } {
umount_and_rmdir [chroot_cwd_path]
umount_and_rmdir [chroot_path]/lib
umount_and_rmdir [chroot_path]/lib64
}
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="test-timer" root="chroot_path">
<resource name="RAM" quantum="1G"/>
</start>
</config>
}
# replace 'chroot_path' marker in config with actual path
regsub "chroot_path" $config [chroot_path] 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 timer test-timer } {
exec cp -H bin/$binary [run_dir] }
#
# Grant chroot permission to core
#
# 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]/core
#
# Setup chroot environment
#
# start with fresh directory
cleanup_chroot
exec mkdir -p [chroot_path]
exec mkdir -p [chroot_path]/lib
# bind mount '/lib' as we need ldso and libc within the chroot environment
exec sudo mount --bind /lib [chroot_path]/lib
#
# Execute test case
#
run_genode_until {.*--- timer test finished ---.*} 60
#
# Remove artifacts created while running the test
#
cleanup_chroot
# vi: set ft=tcl :

View File

@ -1,145 +0,0 @@
#
# \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 drivers/timer 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
}
#
# Clean up remains of a potentially failed previous run
#
proc chroot_path { id } { return "/tmp/chroot-test-$id" }
proc chroot_cwd_path { id } { return "[chroot_path $id][pwd]/[run_dir]" }
proc cleanup_chroot { } {
foreach id { 1 2 } {
umount_and_rmdir [chroot_cwd_path $id]
umount_and_rmdir [chroot_path $id]/lib
umount_and_rmdir [chroot_path $id]/lib64
}
}
cleanup_chroot
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>
}
# 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 timer loader test-chroot_loader test-timer} {
exec cp -H bin/$binary [run_dir] }
#
# Grant chroot permission to 'core'
#
# 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]/core
#
# Setup chroot environment
#
# start with fresh directory
foreach id { 1 2 } {
exec mkdir -p [chroot_path $id]
exec mkdir -p [chroot_path $id]/lib
exec mkdir -p [chroot_path $id]/lib64
# bind mount '/lib' as need libc within the chroot environment
exec sudo mount --bind /lib [chroot_path $id]/lib
catch { exec sudo mount --bind /lib64 [chroot_path $id]/lib64 }
}
#
# 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 -- {init-1 -> test-timer] Done 500 ms period 4 times} $output]} {
puts stderr "Long-running timer test has made too little progress"
exit 3
}
#
# Remove artifacts created while running the test
#
cleanup_chroot
puts "Test succeeded"
# vi: set ft=tcl :

View File

@ -1,23 +0,0 @@
/*
* \brief Extract 'Native_pd_args' from '<start>' node of the init config
* \author Norman Feske
* \date 2012-11.21
*/
/*
* Copyright (C) 2012-2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* init includes */
#include <init/child.h>
Init::Child::Pd_args::Pd_args(Genode::Xml_node start_node) { }
void Init::Child_policy_pd_args::filter_session_args(char const *,
char *, Genode::size_t)
{ }

View File

@ -1,99 +0,0 @@
/*
* \brief Extract 'Native_pd_args' from '<start>' node of the init config
* \author Norman Feske
* \date 2012-11.21
*/
/*
* Copyright (C) 2012-2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* init includes */
#include <init/child.h>
/**
* Read chroot path from XML node
*/
struct Root
{
char path[Genode::Native_pd_args::ROOT_PATH_MAX_LEN];
Root(Genode::Xml_node node)
{
path[0] = 0;
try { node.attribute("root").value(path, sizeof(path)); }
catch (Genode::Xml_node::Nonexistent_attribute) { }
}
};
/**
* Read unsigned ID from XML node
*/
static unsigned id_value(char const *attr, Genode::Xml_node node)
{
unsigned value = 0;
try { node.attribute(attr).value(&value); }
catch (Genode::Xml_node::Nonexistent_attribute) { }
return value;
}
Init::Child::Pd_args::Pd_args(Genode::Xml_node start_node)
:
Genode::Native_pd_args(Root(start_node).path,
id_value("uid", start_node),
id_value("gid", start_node))
{ }
void Init::Child_policy_pd_args::filter_session_args(char const *session,
char *args,
Genode::size_t args_len)
{
/*
* Specify 'Genode' namespace to remove possible ambiguity of
* 'strcmp' when including the header along with libc headers.
*/
if (Genode::strcmp(session, "PD") != 0)
return;
/*
* Apply platform-specific PD-session arguments only if specified.
*/
if (!_pd_args)
return;
using namespace Genode;
/*
* Prepend the '_root' to the 'root' session argument of PD sessions
* initiated through the child (not the child's PD session).
*/
if (_pd_args->root() && _pd_args->root()[0]) {
char path[Parent::Session_args::MAX_SIZE];
Arg_string::find_arg(args, "root").string(path, sizeof(path), "");
char value[Parent::Session_args::MAX_SIZE];
Genode::snprintf(value, sizeof(value),
"\"%s%s\"",
_pd_args->root(), path);
Arg_string::set_arg(args, args_len, "root", value);
}
/*
* Add user ID and group ID to session arguments
*/
if (_pd_args->uid())
Arg_string::set_arg(args, args_len, "uid", _pd_args->uid());
if (_pd_args->gid())
Arg_string::set_arg(args, args_len, "gid", _pd_args->gid());
}

View File

@ -1,3 +1,3 @@
TARGET = init
SRC_CC = main.cc
LIBS = base init_pd_args config
LIBS = base config

View File

@ -38,8 +38,6 @@ namespace Loader {
Label(char const *l) { strncpy(string, l, sizeof(string)); }
} _label;
Native_pd_args _pd_args;
Rpc_entrypoint &_ep;
struct Resources
@ -87,7 +85,6 @@ namespace Loader {
Init::Child_policy_provide_rom_file _binary_policy;
Init::Child_policy_enforce_labeling _labeling_policy;
Init::Child_policy_pd_args _pd_args_policy;
Genode::Child _child;
@ -107,7 +104,6 @@ namespace Loader {
Child(char const *binary_name,
char const *label,
Native_pd_args const &pd_args,
Rpc_entrypoint &ep,
Ram_session_client &ram_session_client,
size_t ram_quota,
@ -119,7 +115,6 @@ namespace Loader {
Signal_context_capability fault_sigh)
:
_label(label),
_pd_args(pd_args),
_ep(ep),
_resources(_label.string, ram_session_client, ram_quota, fault_sigh),
_parent_services(parent_services),
@ -130,7 +125,6 @@ namespace Loader {
_binary_rom_session(_rom_session(binary_name)),
_binary_policy("binary", _binary_rom_session.dataspace(), &_ep),
_labeling_policy(_label.string),
_pd_args_policy(&_pd_args),
_child(_binary_rom_session.dataspace(), _resources.pd.cap(),
_resources.ram.cap(), _resources.cpu.cap(),
_resources.rm.cap(), &_ep, this)
@ -146,13 +140,11 @@ namespace Loader {
** Child-policy interface **
****************************/
char const *name() const { return _label.string; }
Native_pd_args const *pd_args() const { return &_pd_args; }
char const *name() const { return _label.string; }
void filter_session_args(char const *service, char *args, size_t args_len)
{
_labeling_policy.filter_session_args(service, args, args_len);
_pd_args_policy. filter_session_args(service, args, args_len);
}
Service *resolve_session_request(const char *name,

View File

@ -363,8 +363,7 @@ class Loader::Session_component : public Rpc_object<Session>
_fault_sigh = sigh;
}
void start(Name const &binary_name, Name const &label,
Genode::Native_pd_args const &pd_args) override
void start(Name const &binary_name, Name const &label) override
{
if (_child) {
PWRN("cannot start subsystem twice");
@ -378,7 +377,7 @@ class Loader::Session_component : public Rpc_object<Session>
try {
_child = new (&_md_alloc)
Child(binary_name.string(), label.string(),
pd_args, _ep, _ram_session_client,
_ep, _ram_session_client,
ram_quota, _parent_services, _rom_service,
_cpu_service, _rm_service, _nitpicker_service,
_fault_sigh);

View File

@ -1,4 +1,4 @@
TARGET = loader
LIBS = base init_pd_args
LIBS = base
SRC_CC = main.cc
INC_DIR += $(PRG_DIR)

View File

@ -1,171 +0,0 @@
/*
* \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 subsystem configuration.
*/
static char const *subsystem_config()
{
return "<config verbose=\"yes\">\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=\"SIGNAL\"/>\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 const *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;
/*
* Import subsystem's configuration into the subsystem's loader
* session as a ROM module named "config".
*/
_import_rom_module("config", subsystem_config(),
strlen(subsystem_config()) + 1);
/*
* Name of the Genode binary is start as the root of the new
* subsystem.
*/
char const *binary_name = "init";
/*
* 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", binary_name, ++cnt);
/* start execution of new subsystem */
_loader.start(binary_name,
Loader::Session::Name(_label),
Native_pd_args(chroot_path, 0, 0));
}
};
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

@ -1,4 +0,0 @@
TARGET = test-chroot_loader
REQUIRES += linux
SRC_CC = main.cc
LIBS += base config