committed by
Norman Feske
parent
58b58f1008
commit
08668bfd1a
33
src/server/chroot/README
Normal file
33
src/server/chroot/README
Normal file
@@ -0,0 +1,33 @@
|
||||
This component intercepts File_system requests and changes
|
||||
the root directory of the request using the session label.
|
||||
|
||||
In this example if cli_monitor had a child named "X", every
|
||||
file system session from "X" would be rooted to the directory
|
||||
"/cli_monitor/X" at "fs_server".
|
||||
|
||||
! <start name="fs_server">
|
||||
! <provides> <service name="File_system"/> </provides>
|
||||
! ...
|
||||
! </start>
|
||||
!
|
||||
! <start name="chroot">
|
||||
! <provides> <service name="File_system"/> </provides>
|
||||
! <config>
|
||||
! <policy label_prefix="cli_monitor ->" merge="yes"/>
|
||||
! </config>
|
||||
! <route>
|
||||
! <any-service>
|
||||
! <child name="fs_server"/> <parent/>
|
||||
! </any-service>
|
||||
! </route>
|
||||
! ...
|
||||
! </start>
|
||||
!
|
||||
! <start name="cli_monitior">
|
||||
! <route>
|
||||
! <any-service>
|
||||
! <child name="chroot"/> <parent/>
|
||||
! </any-service>
|
||||
! </route>
|
||||
! ...
|
||||
! </start>
|
||||
176
src/server/chroot/main.cc
Normal file
176
src/server/chroot/main.cc
Normal file
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
* \brief Change session root server
|
||||
* \author Emery Hemingway
|
||||
* \date 2016-03-10
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2016 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.
|
||||
*/
|
||||
|
||||
/* Genode includes */
|
||||
#include <file_system/util.h>
|
||||
#include <file_system_session/connection.h>
|
||||
#include <cap_session/connection.h>
|
||||
#include <os/path.h>
|
||||
#include <os/session_policy.h>
|
||||
#include <root/root.h>
|
||||
#include <base/rpc_server.h>
|
||||
#include <base/service.h>
|
||||
#include <base/allocator_avl.h>
|
||||
#include <base/sleep.h>
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
|
||||
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("/");
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
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>>
|
||||
{
|
||||
Parent_service _parent_service;
|
||||
Allocator_avl _fs_tx_block_alloc;
|
||||
File_system::Connection _fs;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Proxy()
|
||||
:
|
||||
_parent_service("File_system"),
|
||||
_fs_tx_block_alloc(env()->heap()),
|
||||
_fs(_fs_tx_block_alloc, 1024)
|
||||
{ }
|
||||
|
||||
Session_capability chroot(char const *args, char const *path, Affinity const &affinity)
|
||||
{
|
||||
enum { ARGS_MAX_LEN = 256 };
|
||||
char new_args[ARGS_MAX_LEN];
|
||||
|
||||
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(session_args.string());
|
||||
char const *label_str = label.string();
|
||||
|
||||
try {
|
||||
Session_policy policy(label);
|
||||
|
||||
if (policy.has_attribute("label_prefix")
|
||||
&& policy.attribute_value("merge", false))
|
||||
{
|
||||
/* merge at the next element */
|
||||
size_t offset = policy.attribute("label_prefix").value_size();
|
||||
for (size_t i = offset; i < label.length()-4; ++i) {
|
||||
if (strcmp(label_str+i, " -> ", 4))
|
||||
continue;
|
||||
|
||||
strncpy(tmp, label_str, min(sizeof(tmp), i+1));
|
||||
label_str = tmp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Session_policy::No_policy_defined) { }
|
||||
path_from_label(root_path, label_str);
|
||||
|
||||
Arg_string::find_arg(session_args.string(), "root").string(
|
||||
tmp, sizeof(tmp), "/");
|
||||
root_path.append(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;
|
||||
try {
|
||||
_fs.close(ensure_dir(_fs, new_root));
|
||||
return chroot(args, new_root, affinity);
|
||||
}
|
||||
|
||||
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"; }
|
||||
|
||||
PERR("%s: %s", new_root, errstr);
|
||||
throw Root::Unavailable();
|
||||
}
|
||||
|
||||
void upgrade(Session_capability cap,
|
||||
Root::Upgrade_args const &args) override {
|
||||
_parent_service.upgrade(cap, args.string()); }
|
||||
|
||||
void close(Session_capability cap) override {
|
||||
_parent_service.close(cap); }
|
||||
};
|
||||
|
||||
|
||||
int main(void)
|
||||
{
|
||||
static Cap_connection cap;
|
||||
static Proxy proxy;
|
||||
|
||||
enum { STACK_SIZE = 4096 * 4 };
|
||||
static Rpc_entrypoint ep(&cap, STACK_SIZE, "chroot_ep");
|
||||
|
||||
env()->parent()->announce(ep.manage(&proxy));
|
||||
|
||||
/* let the entrypoint take over */
|
||||
sleep_forever();
|
||||
}
|
||||
3
src/server/chroot/target.mk
Normal file
3
src/server/chroot/target.mk
Normal file
@@ -0,0 +1,3 @@
|
||||
TARGET = chroot
|
||||
SRC_CC = main.cc
|
||||
LIBS = base config
|
||||
Reference in New Issue
Block a user