Generalize handling of PD-session arguments

On Linux, we want to attach additional attributes to processes, i.e.,
the chroot location, the designated UID, and GID. Instead of polluting
the generic code with such Linux-specific platform details, I introduced
the new 'Native_pd_args' type, which can be customized for each
platform. The platform-dependent policy of init is factored out in the
new 'pd_args' library.

The new 'base-linux/run/lx_pd_args.run' script can be used to validate
the propagation of those attributes into core.

Note that this patch does not add the interpretation of the new UID and
PID attributes by core. This will be subject of a follow-up patch.

Related to #510.
This commit is contained in:
Norman Feske 2012-11-21 15:20:21 +01:00
parent 59eb8bf3a8
commit 959df5d46b
33 changed files with 424 additions and 117 deletions

View File

@ -130,6 +130,8 @@ namespace Genode {
*/
static addr_t context_virtual_size() { return 0x00100000UL; }
};
struct Native_pd_args { };
}

View File

@ -88,6 +88,8 @@ namespace Genode {
*/
static addr_t context_virtual_size() { return 0x00100000UL; }
};
struct Native_pd_args { };
}
#endif /* _INCLUDE__BASE__NATIVE_TYPES_H_ */

View File

@ -161,6 +161,8 @@ namespace Genode {
*/
static addr_t context_virtual_size() { return 0x00100000UL; }
};
struct Native_pd_args { };
}
#endif /* _INCLUDE__BASE__NATIVE_TYPES_H_ */

View File

@ -46,6 +46,8 @@ namespace Genode {
*/
static addr_t context_virtual_size() { return 0x00100000UL; }
};
struct Native_pd_args { };
}
#endif /* _INCLUDE__BASE__NATIVE_TYPES_H_ */

View File

@ -151,6 +151,8 @@ namespace Genode
*/
static addr_t context_virtual_size() { return 0x00100000UL; }
};
struct Native_pd_args { };
}
#endif /* _INCLUDE__BASE__NATIVE_TYPES_H_ */

View File

@ -14,6 +14,7 @@
#ifndef _INCLUDE__BASE__NATIVE_TYPES_H_
#define _INCLUDE__BASE__NATIVE_TYPES_H_
#include <util/string.h>
#include <base/native_capability.h>
#include <base/stdint.h>
@ -149,6 +150,35 @@ namespace Genode {
*/
static addr_t context_virtual_size() { return 0x00100000UL; }
};
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

@ -0,0 +1,100 @@
/*
* \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 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:
/**
* 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=4K, 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

@ -0,0 +1,59 @@
#
# \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

@ -58,9 +58,9 @@ Process::Process(Dataspace_capability elf_data_ds_cap,
Rm_session_capability rm_session_cap,
Parent_capability parent_cap,
char const *name,
char const *root)
Native_pd_args const *pd_args)
:
_pd(name, root),
_pd(name, pd_args),
_cpu_session_client(Cpu_session_capability()),
_rm_session_client(Rm_session_capability())
{

View File

@ -33,6 +33,8 @@ namespace Genode {
unsigned long _pid;
char _label[LABEL_MAX_LEN];
char _root[ROOT_PATH_MAX_LEN];
unsigned _uid;
unsigned _gid;
Parent_capability _parent;
Rpc_entrypoint *_ds_ep;

View File

@ -274,11 +274,32 @@ static const char *get_env(const char *key)
Pd_session_component::Pd_session_component(Rpc_entrypoint *ep, const char *args)
:
_pid(0), _ds_ep(ep)
_pid(0), _uid(0), _gid(0), _ds_ep(ep)
{
Arg_string::find_arg(args, "label").string(_label, sizeof(_label),
"<unlabeled>");
/*
* 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);
/*
* 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", _label);
if (is_chroot) printf(" root: %s\n", _root);
if (_uid) printf(" uid: %u\n", _uid);
if (_gid) printf(" gid: %u\n", _gid);
}

View File

@ -57,10 +57,8 @@ namespace Genode {
*/
static addr_t context_virtual_size() { return 0x00100000UL; }
};
struct Native_pd_args { };
}
#endif /* _INCLUDE__BASE__NATIVE_TYPES_H_ */

View File

@ -230,6 +230,7 @@ namespace Genode {
static addr_t context_virtual_size() { return 0x00100000UL; }
};
struct Native_pd_args { };
}
#endif /* _INCLUDE__BASE__NATIVE_TYPES_H_ */

View File

@ -103,6 +103,8 @@ namespace Genode {
*/
static addr_t context_virtual_size() { return 0x00100000UL; }
};
struct Native_pd_args { };
}
#endif /* _INCLUDE__BASE__NATIVE_TYPES_H_ */

View File

@ -89,6 +89,8 @@ namespace Genode {
*/
static addr_t context_virtual_size() { return 0x00100000UL; }
};
struct Native_pd_args { };
}
#endif /* _INCLUDE__BASE__NATIVE_TYPES_H_ */

View File

@ -95,9 +95,12 @@ namespace Genode {
virtual Ram_session *ref_ram_session() { return env()->ram_session(); }
/**
* Return root path of the child's PD session (only used on Linux)
* Return platform-specific PD-session arguments
*
* This function is used on Linux to supply additional PD-session
* argument to core, i.e., the chroot path, the UID, and the GID.
*/
virtual char const *root() const { return ""; }
virtual Native_pd_args const *pd_args() const { return 0; }
};

View File

@ -57,8 +57,9 @@ namespace Genode {
* \param rm_session RM session for the new protection domain
* \param parent parent of the new protection domain
* \param name name of protection domain (can be used
* in debugging)
* \param root optional chroot path (only on Linux)
* for debugging)
* \param pd_args platform-specific arguments supplied to
* the PD session of the process
*
* The dataspace 'elf_data_ds' can be read-only.
*
@ -71,7 +72,7 @@ namespace Genode {
Rm_session_capability rm_session,
Parent_capability parent,
char const *name,
char const *root = "");
Native_pd_args const *args = 0);
/**
* Destructor

View File

@ -25,15 +25,10 @@ namespace Genode {
* Constructor
*
* \param label session label
* \param root chroot path (only on Linux)
*/
Pd_connection(char const *label = "", char const *root = "")
Pd_connection(char const *label = "", Native_pd_args const *pd_args = 0)
:
Connection<Pd_session>(session("ram_quota=4K, label=\"%s\"%s%s%s",
label,
(root && root[0]) ? ", root=\"" : "",
(root && root[0]) ? root : "",
(root && root[0]) ? "\"" : "")),
Connection<Pd_session>(session("ram_quota=4K, label=\"%s\"", label)),
Pd_session_client(cap())
{ }
};

View File

@ -431,7 +431,7 @@ Child::Child(Dataspace_capability elf_ds,
_parent_cap(_entrypoint->manage(this)),
_policy(policy),
_server(ram),
_process(elf_ds, ram, cpu, rm, _parent_cap, policy->name(), policy->root())
_process(elf_ds, ram, cpu, rm, _parent_cap, policy->name(), policy->pd_args())
{ }

View File

@ -175,7 +175,7 @@ Process::Process(Dataspace_capability elf_ds_cap,
Rm_session_capability rm_session_cap,
Parent_capability parent_cap,
char const *name,
char const *pd_args)
Native_pd_args const *pd_args)
:
_pd(name, pd_args),
_cpu_session_client(cpu_session_cap),

View File

@ -299,29 +299,12 @@ namespace Init {
} _name;
/**
* Path of the child's chroot environment (on Linux)
* Platform-specific PD-session arguments
*/
struct Root
struct Pd_args : Genode::Native_pd_args
{
/*
* XXX dimension ROOT_PATH_LEN depending on the platform
*/
enum { ROOT_PATH_LEN = 256 };
char path[ROOT_PATH_LEN];
/**
* Constructor
*/
Root(Genode::Xml_node start_node)
{
path[0] = 0;
try {
start_node.attribute("root").value(path, sizeof(path)); }
catch (Genode::Xml_node::Nonexistent_attribute) { }
}
} _root;
Pd_args(Genode::Xml_node start_node);
} _pd_args;
/**
* Resources assigned to the child
@ -394,7 +377,7 @@ namespace Init {
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_prepend_chroot_path _chroot_policy;
Init::Child_policy_pd_args _pd_args_policy;
public:
@ -411,7 +394,7 @@ namespace Init {
_default_route_node(default_route_node),
_name_registry(name_registry),
_name(start_node, name_registry),
_root(start_node),
_pd_args(start_node),
_resources(start_node, _name.unique, prio_levels_log2),
_entrypoint(cap_session, ENTRYPOINT_STACK_SIZE, _name.unique, false),
_binary_rom(_name.file, _name.unique),
@ -426,7 +409,7 @@ namespace Init {
_config_policy("config", _config.dataspace(), &_entrypoint),
_binary_policy("binary", _binary_rom.dataspace(), &_entrypoint),
_configfile_policy("config", _config.filename()),
_chroot_policy(_root.path)
_pd_args_policy(&_pd_args)
{
using namespace Genode;
@ -576,7 +559,7 @@ namespace Init {
_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);
_chroot_policy. filter_session_args(service, args, args_len);
_pd_args_policy. filter_session_args(service, args, args_len);
}
bool announce_service(const char *service_name,
@ -599,7 +582,7 @@ namespace Init {
return true;
}
char const *root() const { return _root.path; }
Genode::Native_pd_args const *pd_args() const { return &_pd_args; }
};
}

View File

@ -64,53 +64,25 @@ namespace Init {
/**
* Policy for prepending the chroot path of the child
* Policy for handling platform-specific PD-session arguments
*
* This policy is effective only on the Linux base platform.
*
* By applying this policy, the chroot path of the child gets supplied
* to PD session requests.
* 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 Child_policy_prepend_chroot_path
class Child_policy_pd_args
{
private:
char const *_root_prefix;
Genode::Native_pd_args const *_pd_args;
public:
Child_policy_prepend_chroot_path(const char *root_prefix)
: _root_prefix(root_prefix) { }
Child_policy_pd_args(Genode::Native_pd_args const *pd_args)
: _pd_args(pd_args) { }
/**
* Filter arguments of session request
*
* This function prepends the '_root' to the 'root' session
* argument of PD sessions initiated through the child (not the
* child's PD session).
*/
void filter_session_args(const char *session, char *args,
Genode::size_t args_len)
{
using namespace Genode;
/*
* Specify 'Genode' namespace to remove possible ambiguity of
* 'strcmp' when including the header along with libc headers.
*/
if (Genode::strcmp(session, "PD") != 0)
return;
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\"",
_root_prefix, path);
Arg_string::set_arg(args, args_len, "root", value);
}
Genode::size_t args_len);
};

View File

@ -41,8 +41,9 @@ namespace Loader {
void view_ready_sigh(Signal_context_capability sigh) {
call<Rpc_view_ready_sigh>(sigh); }
void start(Name const &binary, Name const &label = "", Path const &root = "") {
call<Rpc_start>(binary, label, root); }
void start(Name const &binary, Name const &label = "",
Native_pd_args const &pd_args = Native_pd_args()) {
call<Rpc_start>(binary, label, pd_args); }
Nitpicker::View_capability view() {
return call<Rpc_view>(); }

View File

@ -123,7 +123,7 @@ namespace Loader {
* not obtained as ROM module
*/
virtual void start(Name const &binary, Name const &label = "",
Path const &root = "") = 0;
Native_pd_args const &pd_args = Native_pd_args()) = 0;
/**
* Return first nitpicker view created by the loaded subsystem
@ -154,7 +154,7 @@ namespace Loader {
GENODE_RPC(Rpc_view_ready_sigh, void, view_ready_sigh, Signal_context_capability);
GENODE_RPC_THROW(Rpc_start, void, start,
GENODE_TYPE_LIST(Rom_module_does_not_exist),
Name const &, Name const &, Path const &);
Name const &, Name const &, Native_pd_args const &);
GENODE_RPC_THROW(Rpc_view, Nitpicker::View_capability, view,
GENODE_TYPE_LIST(View_does_not_exist));
GENODE_RPC(Rpc_view_geometry, View_geometry, view_geometry);

View File

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

View File

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

View File

@ -0,0 +1,99 @@
/*
* \brief Extract 'Native_pd_args' from '<start>' node of the init config
* \author Norman Feske
* \date 2012-11.21
*/
/*
* Copyright (C) 2012 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());
}

23
os/src/init/pd_args.cc Normal file
View File

@ -0,0 +1,23 @@
/*
* \brief Extract 'Native_pd_args' from '<start>' node of the init config
* \author Norman Feske
* \date 2012-11.21
*/
/*
* Copyright (C) 2012 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,3 +1,3 @@
TARGET = init
SRC_CC = main.cc
LIBS = env cxx server child
LIBS = env cxx server child init_pd_args

View File

@ -36,10 +36,7 @@ namespace Loader {
Label(char const *l) { strncpy(string, l, sizeof(string)); }
} _label;
struct Path {
char string[Session::Path::MAX_SIZE];
Path(char const *l) { strncpy(string, l, sizeof(string)); }
} _root;
Native_pd_args _pd_args;
Rpc_entrypoint &_ep;
@ -75,9 +72,9 @@ namespace Loader {
Rom_session_client _binary_rom_session;
Init::Child_policy_provide_rom_file _binary_policy;
Init::Child_policy_enforce_labeling _labeling_policy;
Init::Child_policy_prepend_chroot_path _chroot_policy;
Init::Child_policy_provide_rom_file _binary_policy;
Init::Child_policy_enforce_labeling _labeling_policy;
Init::Child_policy_pd_args _pd_args_policy;
int _max_width, _max_height;
@ -97,19 +94,20 @@ namespace Loader {
public:
Child(char const *binary_name,
char const *label,
char const *root,
Rpc_entrypoint &ep,
Ram_session_client &ram_session_client,
size_t ram_quota,
Service_registry &parent_services,
Service &local_rom_service,
Service &local_nitpicker_service,
int max_width, int max_height)
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,
Service_registry &parent_services,
Service &local_rom_service,
Service &local_nitpicker_service,
int max_width,
int max_height)
:
_label(label),
_root(root),
_pd_args(pd_args),
_ep(ep),
_resources(_label.string, ram_session_client, ram_quota),
_parent_services(parent_services),
@ -118,7 +116,7 @@ namespace Loader {
_binary_rom_session(_rom_session(binary_name)),
_binary_policy("binary", _binary_rom_session.dataspace(), &_ep),
_labeling_policy(_label.string),
_chroot_policy(_root.string),
_pd_args_policy(&_pd_args),
_max_width(max_width), _max_height(max_height),
_child(_binary_rom_session.dataspace(),
_resources.ram.cap(), _resources.cpu.cap(),
@ -135,13 +133,13 @@ namespace Loader {
** Child-policy interface **
****************************/
const char *name() const { return _label.string; }
char const *root() const { return _root.string; }
char const *name() const { return _label.string; }
Native_pd_args const *pd_args() const { return &_pd_args; }
void filter_session_args(char const *service, char *args, size_t args_len)
{
_labeling_policy.filter_session_args(service, args, args_len);
_chroot_policy. filter_session_args(service, args, args_len);
_pd_args_policy. filter_session_args(service, args, args_len);
if (!strcmp(service, "Nitpicker")) {

View File

@ -244,7 +244,8 @@ namespace Loader {
_nitpicker_service.view_ready_sigh = sigh;
}
void start(Name const &binary_name, Name const &label, Path const &root)
void start(Name const &binary_name, Name const &label,
Genode::Native_pd_args const &pd_args)
{
if (_child) {
PWRN("cannot start subsystem twice");
@ -258,7 +259,7 @@ namespace Loader {
try {
_child = new (&_md_alloc)
Child(binary_name.string(), label.string(),
root.string(), _ep, _ram_session_client,
pd_args, _ep, _ram_session_client,
ram_quota, _parent_services, _rom_service,
_nitpicker_service, _width, _height);
}

View File

@ -1,4 +1,4 @@
TARGET = loader
LIBS = cxx env thread server child signal
SRC_CC = main.cc
TARGET = loader
LIBS = cxx env thread server child signal init_pd_args
SRC_CC = main.cc
INC_DIR += $(PRG_DIR)

View File

@ -135,7 +135,7 @@ class Chroot_subsystem
/* start execution of new subsystem */
_loader.start(binary_name,
Loader::Session::Name(_label),
Loader::Session::Path(chroot_path));
Native_pd_args(chroot_path, 0, 0));
}
};