server/chroot: remove RPC server

Respond to clients from the "session_requests" ROM dataspace.

Ref #53
This commit is contained in:
Emery Hemingway
2016-12-04 10:59:13 +01:00
committed by Norman Feske
parent 21bf74bbc8
commit c581c5e87b
2 changed files with 314 additions and 90 deletions

129
run/chroot.run Normal file
View File

@@ -0,0 +1,129 @@
#
# \brief Chroot test
# \author Emery Hemingway
# \date 2016-12-03
#
#
# Build
#
build { core init server/vfs server/chroot test/libc }
create_boot_directory
#
# Generate config
#
set config {
<config>
<parent-provides>
<service name="ROM"/>
<service name="RAM"/>
<service name="PD"/>
<service name="RM"/>
<service name="CPU"/>
<service name="LOG"/>
</parent-provides>
<default-route>
<any-service> <parent/> <any-child/> </any-service>
</default-route>
<start name="vfs">
<resource name="RAM" quantum="12M"/>
<provides> <service name="File_system"/> </provides>
<config>
<vfs>
<dir name="test-libc-1">
<log label="chroot-1"/>
</dir>
<dir name="test-libc-2">
<log label="chroot-2"/>
</dir>
<dir name="test-libc-3">
<log label="chroot-3"/>
</dir>
</vfs>
<policy label_prefix="chroot" root="/" writeable="yes"/>
</config>
</start>
<start name="chroot">
<resource name="RAM" quantum="2M"/>
<provides> <service name="File_system"/> </provides>
<route>
<any-service>
<child name="vfs"/> <parent/>
</any-service>
</route>
</start>
<start name="test-libc-1">
<binary name="test-libc"/>
<resource name="RAM" quantum="4M"/>
<config>
<libc stdout="/log">
<vfs> <fs/> </vfs>
</libc>
</config>
<route>
<any-service>
<child name="chroot"/> <parent/>
</any-service>
</route>
</start>
<start name="test-libc-2">
<binary name="test-libc"/>
<resource name="RAM" quantum="4M"/>
<config>
<libc stdout="/log">
<vfs> <fs/> </vfs>
</libc>
</config>
<route>
<any-service>
<child name="chroot"/> <parent/>
</any-service>
</route>
</start>
<start name="test-libc-3">
<binary name="test-libc"/>
<resource name="RAM" quantum="4M"/>
<config>
<libc stdout="/log">
<vfs> <fs/> </vfs>
</libc>
</config>
<route>
<any-service>
<child name="chroot"/> <parent/>
</any-service>
</route>
</start>
</config>
}
install_config $config
#
# Boot modules
#
build_boot_image {
core init vfs chroot
ld.lib.so libc.lib.so libm.lib.so
test-libc
}
#
# Execute test case
#
append qemu_args " -nographic -m 64 "
run_genode_until {child "test-libc-3" exited with exit value 0} 60
# vi: set ft=tcl :

View File

@@ -16,100 +16,132 @@
#include <file_system_session/connection.h>
#include <os/path.h>
#include <os/session_policy.h>
#include <root/root.h>
#include <base/component.h>
#include <base/attached_rom_dataspace.h>
#include <base/rpc_server.h>
#include <parent/parent.h>
#include <base/service.h>
#include <base/allocator_avl.h>
#include <base/heap.h>
using namespace Genode;
namespace Chroot {
using namespace Genode;
struct Main;
template <unsigned MAX_LEN>
static void path_from_label(Path<MAX_LEN> &path, char const *label)
{
char tmp[MAX_LEN];
size_t len = strlen(label);
template <unsigned MAX_LEN>
static void path_from_label(Path<MAX_LEN> &path, char const *label)
{
char tmp[MAX_LEN];
size_t len = strlen(label);
size_t i = 0;
for (size_t j = 1; j < len; ++j) {
if (!strcmp(" -> ", label+j, 4)) {
path.append("/");
size_t i = 0;
for (size_t j = 1; j < len; ++j) {
if (!strcmp(" -> ", label+j, 4)) {
path.append("/");
strncpy(tmp, label+i, (j-i)+1);
/* rewrite any directory seperators */
for (size_t k = 0; k < MAX_LEN; ++k)
if (tmp[k] == '/')
tmp[k] = '_';
path.append(tmp);
strncpy(tmp, label+i, (j-i)+1);
/* rewrite any directory seperators */
for (size_t k = 0; k < MAX_LEN; ++k)
if (tmp[k] == '/')
tmp[k] = '_';
path.append(tmp);
j += 4;
i = j;
j += 4;
i = j;
}
}
path.append("/");
strncpy(tmp, label+i, MAX_LEN);
/* rewrite any directory seperators */
for (size_t k = 0; k < MAX_LEN; ++k)
if (tmp[k] == '/')
tmp[k] = '_';
path.append(tmp);
}
path.append("/");
strncpy(tmp, label+i, MAX_LEN);
/* rewrite any directory seperators */
for (size_t k = 0; k < MAX_LEN; ++k)
if (tmp[k] == '/')
tmp[k] = '_';
path.append(tmp);
}
struct Proxy : Rpc_object<Typed_root<File_system::Session>>
struct Chroot::Main
{
Genode::Attached_rom_dataspace _config_rom;
Parent_service _parent_service;
Heap _heap;
Allocator_avl _fs_tx_block_alloc { &_heap };
File_system::Connection _fs { _fs_tx_block_alloc, 1024 };
enum { PATH_MAX_LEN = 128 };
typedef Genode::Path<PATH_MAX_LEN> Path;
struct Session : Parent::Server
{
Parent::Client parent_client;
Id_space<Parent::Client>::Element client_id;
Id_space<Parent::Server>::Element server_id;
Session(Id_space<Parent::Client> &client_space,
Id_space<Parent::Server> &server_space,
Parent::Server::Id server_id)
:
client_id(parent_client, client_space),
server_id(*this, server_space, server_id) { }
};
Genode::Env &env;
Id_space<Parent::Server> server_id_space;
Heap heap { env.ram(), env.rm() };
Allocator_avl fs_tx_block_alloc { &heap };
File_system::Connection fs { fs_tx_block_alloc, 1 };
Attached_rom_dataspace session_requests { env, "session_requests" };
Attached_rom_dataspace config_rom { env, "config" };
void handle_session_request(Xml_node request);
void handle_session_requests()
{
if (config_sig_rec.pending()) {
do { config_sig_rec.pending_signal(); }
while (config_sig_rec.pending());
config_rom.update();
}
session_requests.update();
Xml_node const requests = session_requests.xml();
requests.for_each_sub_node([&] (Xml_node request) {
handle_session_request(request);
});
}
Signal_handler<Main> session_request_handler {
env.ep(), *this, &Main::handle_session_requests };
Signal_context config_sig_ctx;
Signal_receiver config_sig_rec;
/**
* Constructor
*/
Proxy(Genode::Env &env)
:
_config_rom(env, "config"),
_parent_service("File_system"),
_heap(env.ram(), env.rm())
Main(Genode::Env &env) : env(env)
{
env.parent().announce(env.ep().rpc_ep().manage(this));
config_rom.sigh(config_sig_rec.manage(&config_sig_ctx));
session_requests.sigh(session_request_handler);
}
Session_capability chroot(char const *args, char const *path, Affinity const &affinity)
~Main() {
config_sig_rec.dissolve(&config_sig_ctx); }
Session_capability request_session(Parent::Client::Id const &id,
Session_state::Args const &args)
{
enum { ARGS_MAX_LEN = 256 };
char new_args[ARGS_MAX_LEN];
char tmp[PATH_MAX_LEN];
Path root_path;
strncpy(new_args, args, ARGS_MAX_LEN);
Arg_string::set_arg_string(new_args, ARGS_MAX_LEN, "root", path);
try { return _parent_service.session(new_args, affinity); }
catch (Service::Invalid_args) { throw Root::Invalid_args(); }
catch (Service::Quota_exceeded) { throw Root::Quota_exceeded(); }
catch (...) { }
throw Root::Unavailable();
}
/********************
** Root interface **
********************/
Session_capability session(Root::Session_args const &session_args,
Affinity const &affinity)
{
enum { MAX_LEN = 128 };
char tmp[MAX_LEN];
Path<MAX_LEN> root_path;
Session_label label = label_from_args(session_args.string());
Session_label label = label_from_args(args.string());
char const *label_str = label.string();
/* if policy specifies a merge, use a truncated label */
try {
Session_policy policy(label, _config_rom.xml());
Session_policy policy(label, config_rom.xml());
if (policy.has_attribute("label_prefix")
&& policy.attribute_value("merge", false))
@@ -127,48 +159,111 @@ struct Proxy : Rpc_object<Typed_root<File_system::Session>>
}
} catch (Session_policy::No_policy_defined) { }
/* create a new path from the label */
path_from_label(root_path, label_str);
Arg_string::find_arg(session_args.string(), "root").string(
/* extract and append the orginal root */
Arg_string::find_arg(args.string(), "root").string(
tmp, sizeof(tmp), "/");
root_path.append_element(tmp);
root_path.remove_trailing('/');
char const *args = session_args.string();
char const *new_root = root_path.base();
using namespace File_system;
Dir_handle handle;
char const *errstr;
/* create the new root directory if it is missing */
try { fs.close(ensure_dir(fs, new_root)); }
catch (Node_already_exists) { }
catch (Permission_denied) {
Genode::error(new_root,": permission denied"); throw; }
catch (Name_too_long) {
Genode::error(new_root,": new root too long"); throw; }
catch (No_space) {
Genode::error(new_root,": no space"); throw; }
catch (...) {
Genode::error(new_root,": unknown error"); throw; }
/* rewrite the root session argument */
enum { ARGS_MAX_LEN = 256 };
char new_args[ARGS_MAX_LEN];
strncpy(new_args, args.string(), ARGS_MAX_LEN);
Arg_string::set_arg_string(new_args, ARGS_MAX_LEN, "root", new_root);
Affinity affinity;
return env.session("File_system", id, new_args, affinity);
}
};
void Chroot::Main::handle_session_request(Xml_node request)
{
if (!request.has_attribute("id"))
return;
Parent::Server::Id const server_id { request.attribute_value("id", 0UL) };
if (request.has_type("create")) {
if (!request.has_sub_node("args"))
return;
typedef Session_state::Args Args;
Args const args = request.sub_node("args").decoded_content<Args>();
Session *session = nullptr;
try {
_fs.close(ensure_dir(_fs, new_root));
return chroot(args, new_root, affinity);
session = new (heap)
Session(env.id_space(), server_id_space, server_id);
Session_capability cap = request_session(session->client_id.id(), args);
env.parent().deliver_session_cap(server_id, cap);
}
catch (Node_already_exists) { return chroot(args, new_root, affinity); }
catch (Permission_denied) { errstr = "permission denied"; }
catch (Name_too_long) { errstr = "new root too long"; }
catch (No_space) { errstr = "no space"; }
catch (...) { errstr = "unknown error"; }
Genode::error(new_root, ": ", errstr);
throw Root::Unavailable();
catch (...) {
if (session)
destroy(heap, session);
env.parent().session_response(server_id, Parent::INVALID_ARGS);
}
}
void upgrade(Session_capability cap,
Root::Upgrade_args const &args) override {
_parent_service.upgrade(cap, args.string()); }
if (request.has_type("upgrade")) {
void close(Session_capability cap) override {
_parent_service.close(cap); }
};
server_id_space.apply<Session>(server_id, [&] (Session &session) {
size_t ram_quota = request.attribute_value("ram_quota", 0UL);
char buf[64];
snprintf(buf, sizeof(buf), "ram_quota=%ld", ram_quota);
// XXX handle Root::Invalid_args
env.upgrade(session.client_id.id(), buf);
env.parent().session_response(server_id, Parent::SESSION_OK);
});
}
if (request.has_type("close")) {
server_id_space.apply<Session>(server_id, [&] (Session &session) {
env.close(session.client_id.id());
destroy(heap, &session);
env.parent().session_response(server_id, Parent::SESSION_CLOSED);
});
}
}
/***************
** Component **
***************/
Genode::size_t Component::stack_size() { return 2*1024*sizeof(Genode::addr_t); }
Genode::size_t Component::stack_size() {
return 2*1024*sizeof(Genode::addr_t); }
void Component::construct(Genode::Env &env) { static Proxy inst(env); }
void Component::construct(Genode::Env &env)
{
static Chroot::Main inst(env);
env.parent().announce("File_system");
}