From a67d24e5095e25f9fca0ddb3adc149ef73a4bc3b Mon Sep 17 00:00:00 2001 From: Emery Hemingway Date: Tue, 26 Sep 2017 10:33:14 -0500 Subject: [PATCH] import chroot from world repository Fix #2529 --- repos/os/recipes/src/chroot/content.mk | 8 + repos/os/recipes/src/chroot/hash | 1 + repos/os/recipes/src/chroot/used_apis | 3 + repos/os/src/server/chroot/README | 33 ++++ repos/os/src/server/chroot/component.cc | 251 ++++++++++++++++++++++++ repos/os/src/server/chroot/target.mk | 3 + 6 files changed, 299 insertions(+) create mode 100644 repos/os/recipes/src/chroot/content.mk create mode 100644 repos/os/recipes/src/chroot/hash create mode 100644 repos/os/recipes/src/chroot/used_apis create mode 100644 repos/os/src/server/chroot/README create mode 100644 repos/os/src/server/chroot/component.cc create mode 100644 repos/os/src/server/chroot/target.mk diff --git a/repos/os/recipes/src/chroot/content.mk b/repos/os/recipes/src/chroot/content.mk new file mode 100644 index 000000000..e533091f1 --- /dev/null +++ b/repos/os/recipes/src/chroot/content.mk @@ -0,0 +1,8 @@ +content: include/file_system + +SRC_DIR = src/server/chroot +include $(GENODE_DIR)/repos/base/recipes/src/content.inc + +include/file_system: + mkdir -p $@ + cp $(GENODE_DIR)/repos/os/include/file_system/* $@ diff --git a/repos/os/recipes/src/chroot/hash b/repos/os/recipes/src/chroot/hash new file mode 100644 index 000000000..128d3c8cb --- /dev/null +++ b/repos/os/recipes/src/chroot/hash @@ -0,0 +1 @@ +2017-09-26 7eba5980fe297d6231ef4c4f9894b88234b897d2 diff --git a/repos/os/recipes/src/chroot/used_apis b/repos/os/recipes/src/chroot/used_apis new file mode 100644 index 000000000..b892d66b5 --- /dev/null +++ b/repos/os/recipes/src/chroot/used_apis @@ -0,0 +1,3 @@ +base +file_system_session +os diff --git a/repos/os/src/server/chroot/README b/repos/os/src/server/chroot/README new file mode 100644 index 000000000..ada05dbfc --- /dev/null +++ b/repos/os/src/server/chroot/README @@ -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". + +! +! +! ... +! +! +! +! +! +! +! +! +! +! +! +! +! ... +! +! +! +! +! +! +! +! +! ... +! diff --git a/repos/os/src/server/chroot/component.cc b/repos/os/src/server/chroot/component.cc new file mode 100644 index 000000000..3e0862728 --- /dev/null +++ b/repos/os/src/server/chroot/component.cc @@ -0,0 +1,251 @@ +/* + * \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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Chroot { + using namespace Genode; + struct Main; +} + + +struct Chroot::Main +{ + enum { PATH_MAX_LEN = 128 }; + typedef Genode::Path Path; + + /** + * Object to bind ids between parent and client space. + */ + struct Session : Parent::Server + { + Parent::Client parent_client; + + Id_space::Element client_id; + Id_space::Element server_id; + + Session(Id_space &client_space, + Id_space &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 server_id_space; + + Heap heap { env.ram(), env.rm() }; + + Allocator_avl fs_tx_block_alloc { &heap }; + + /** + * File-system session for creating new chroot directories + */ + File_system::Connection fs { + env, fs_tx_block_alloc, "", "/", true, 1 }; + + Attached_rom_dataspace session_requests { env, "session_requests" }; + + Attached_rom_dataspace config_rom { env, "config" }; + + void handle_config_update() { config_rom.update(); } + + void handle_session_request(Xml_node request); + + void handle_session_requests() + { + session_requests.update(); + + Xml_node const requests = session_requests.xml(); + + requests.for_each_sub_node([&] (Xml_node request) { + handle_session_request(request); + }); + } + + Signal_handler
config_update_handler { + env.ep(), *this, &Main::handle_config_update }; + + Signal_handler
session_request_handler { + env.ep(), *this, &Main::handle_session_requests }; + + /** + * Constructor + */ + Main(Genode::Env &env) : env(env) + { + config_rom.sigh(config_update_handler); + session_requests.sigh(session_request_handler); + + /* handle requests that have queued before or during construction */ + handle_session_requests(); + } + + Session_capability request_session(Parent::Client::Id const &id, + Session_state::Args const &args) + { + char tmp[PATH_MAX_LEN]; + Path root_path; + + Session_label const label = label_from_args(args.string()); + Session_policy const policy(label, config_rom.xml()); + + /* Use a chroot path from policy */ + if (policy.has_attribute("path")) { + policy.attribute("path").value(tmp, sizeof(tmp)); + root_path.import(tmp); + } + + /* if policy specifies a merge, use a truncated label */ + else 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.string()+i, " -> ", 4)) + continue; + + strncpy(tmp, label.string(), min(sizeof(tmp), i+1)); + break; + } + root_path = path_from_label(tmp); + } + + /* use an implicit chroot path from the label */ + else { + root_path = path_from_label(label.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 *new_root = root_path.base(); + + using namespace File_system; + + /* 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); + + /* sacrifice the label to make space for the root argument */ + Arg_string::remove_arg(new_args, "label"); + + 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(); + + Session *session = nullptr; + try { + 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 (Session_policy::No_policy_defined) { + Genode::error("no policy defined for '", label_from_args(args.string()), "'"); + env.parent().session_response(server_id, Parent::SERVICE_DENIED); + } + + catch (...) { + if (session) + destroy(heap, session); + env.parent().session_response(server_id, Parent::SERVICE_DENIED); + } + } + + if (request.has_type("upgrade")) { + + server_id_space.apply(server_id, [&] (Session &session) { + + size_t ram_quota = request.attribute_value("ram_quota", 0UL); + + String<64> args("ram_quota=", ram_quota); + + env.upgrade(session.client_id.id(), args.string()); + env.parent().session_response(server_id, Parent::SESSION_OK); + }); + } + + if (request.has_type("close")) { + server_id_space.apply(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); } + +void Component::construct(Genode::Env &env) +{ + static Chroot::Main inst(env); + env.parent().announce("File_system"); +} diff --git a/repos/os/src/server/chroot/target.mk b/repos/os/src/server/chroot/target.mk new file mode 100644 index 000000000..7fd2af69e --- /dev/null +++ b/repos/os/src/server/chroot/target.mk @@ -0,0 +1,3 @@ +TARGET = chroot +SRC_CC = component.cc +LIBS = base \ No newline at end of file