From 5aaf04915c4339512b4461711f74b1dd104386e8 Mon Sep 17 00:00:00 2001 From: Norman Feske Date: Thu, 16 Feb 2012 21:45:37 +0100 Subject: [PATCH] Intercept CPU session of Noux::Child To implement fork semantics, we need to customize the bootstrapping of the newly created process, in particular the startup of the main thread. The CPU session interface provides a suitable hook. By virtualizing the CPU connection of the process to core, we can defer (and parametrize) the startup of the main thread. Furthermore, this enables us to detect illegal attempts by the Noux process to create threads in addition to the main thread. --- ports/src/noux/child.h | 105 ++++++++++++++++++++++++++++++++++++++--- ports/src/noux/main.cc | 10 ++-- 2 files changed, 105 insertions(+), 10 deletions(-) diff --git a/ports/src/noux/child.h b/ports/src/noux/child.h index f25da97a26..6ffe56ef46 100644 --- a/ports/src/noux/child.h +++ b/ports/src/noux/child.h @@ -256,24 +256,108 @@ namespace Noux { }; + /** + * Used to defer the execution of the process' main thread + */ + struct Local_cpu_session : Rpc_object + { + bool forked; + Genode::Cpu_connection cpu; + + Genode::Thread_capability main_thread; + + Local_cpu_session(char const *label, bool forked) + : forked(forked), cpu(label) { } + + Genode::Thread_capability create_thread(Name const &name) + { + /* + * Prevent any attempt to create more than the main + * thread. + */ + if (main_thread.valid()) { + PWRN("Invalid attempt to create a thread besides main"); + return Genode::Thread_capability(); + } + main_thread = cpu.create_thread(name); + + PINF("created main thread"); + return main_thread; + } + + void kill_thread(Genode::Thread_capability thread) { + cpu.kill_thread(thread); } + + Genode::Thread_capability first() { + return cpu.first(); } + + Genode::Thread_capability next(Genode::Thread_capability curr) { + return cpu.next(curr); } + + int set_pager(Genode::Thread_capability thread, + Genode::Pager_capability pager) { + return cpu.set_pager(thread, pager); } + + int start(Genode::Thread_capability thread, Genode::addr_t ip, Genode::addr_t sp) + { + if (forked) { + PINF("defer attempt to start thread at ip 0x%lx", ip); + return 0; + } + return cpu.start(thread, ip, sp); + } + + void pause(Genode::Thread_capability thread) { + cpu.pause(thread); } + + void resume(Genode::Thread_capability thread) { + cpu.resume(thread); } + + void cancel_blocking(Genode::Thread_capability thread) { + cpu.cancel_blocking(thread); } + + int state(Genode::Thread_capability thread, Genode::Thread_state *dst) { + return cpu.state(thread, dst); } + + void exception_handler(Genode::Thread_capability thread, + Genode::Signal_context_capability handler) { + cpu.exception_handler(thread, handler); } + + void single_step(Genode::Thread_capability thread, bool enable) { + cpu.single_step(thread, enable); } + + + /** + * Explicity start main thread, only meaningful when + * 'forked' is true + */ + void start_main_thread(Genode::addr_t ip, Genode::addr_t sp) + { + cpu.start(main_thread, ip, sp); + } + }; + Genode::Rpc_entrypoint ep; + Local_ram_session ram; - Genode::Cpu_connection cpu; + Local_cpu_session cpu; Local_rm_session rm; - Resources(char const *label, Genode::Rpc_entrypoint &ep) + Resources(char const *label, Genode::Rpc_entrypoint &ep, bool forked) : ep(ep), - cpu(label) + cpu(label, forked) { ep.manage(&ram); ep.manage(&rm); + ep.manage(&cpu); } ~Resources() { - ep.dissolve(&rm); ep.dissolve(&ram); + ep.dissolve(&rm); + ep.dissolve(&cpu); } } _resources; @@ -349,6 +433,14 @@ namespace Noux { public: + /** + * Constructor + * + * \param forked false if the child is spawned directly from + * an executable binary (i.e., the init process, + * or children created via execve, or + * true if the child is a fork from another child + */ Child(char const *name, int pid, Genode::Signal_receiver *sig_rec, @@ -357,7 +449,8 @@ namespace Noux { char const *env, Genode::Cap_session *cap_session, Genode::Service_registry *parent_services, - Genode::Rpc_entrypoint &resources_ep) + Genode::Rpc_entrypoint &resources_ep, + bool forked) : _pid(pid), _sig_rec(sig_rec), @@ -367,7 +460,7 @@ namespace Noux { _execve_cleanup_context_cap(sig_rec->manage(&_execve_cleanup_dispatcher)), _cap_session(cap_session), _entrypoint(cap_session, STACK_SIZE, "noux_process", false), - _resources(name, resources_ep), + _resources(name, resources_ep, false), _args(ARGS_DS_SIZE, args), _env(env), _vfs(vfs), diff --git a/ports/src/noux/main.cc b/ports/src/noux/main.cc index 2e5a7c5702..e4daf59840 100644 --- a/ports/src/noux/main.cc +++ b/ports/src/noux/main.cc @@ -148,6 +148,7 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc) } case SYSCALL_IOCTL: + return _lookup_channel(_sysio->ioctl_in.fd)->ioctl(_sysio); case SYSCALL_DIRENT: @@ -171,14 +172,14 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc) env, /* XXX */ _cap_session, _parent_services, - _resources.ep); + _resources.ep, + false); - /* let new chuld inherit our file descriptors */ + /* let new child inherit our file descriptors */ for (int fd = 0; fd < MAX_FILE_DESCRIPTORS; fd++) if (fd_in_use(fd)) child->add_io_channel(io_channel_by_fd(fd), fd); - /* signal main thread to remove ourself */ Genode::Signal_transmitter(_execve_cleanup_context_cap).submit(); @@ -462,7 +463,8 @@ int main(int argc, char **argv) env_string_of_init_process(), &cap, &parent_services, - resources_ep); + resources_ep, + false); static Terminal::Connection terminal;