foc: delete IPC gates on cap session destruction

To correctly delete all IPC gates created via a CAP session, all
capabilities created have to be stored. Otherwise we leak kernel
objects within Fiasco.OC permanently.

Fix #702
This commit is contained in:
Stefan Kalkowski 2014-02-19 10:39:29 +01:00 committed by Christian Helmuth
parent acc46f70b7
commit 28fdc51a76
3 changed files with 54 additions and 29 deletions

View File

@ -84,13 +84,12 @@ Cap_mapping::Cap_mapping(Native_capability cap, Native_thread_id r)
** Cap_session_component ** ** Cap_session_component **
*****************************/ *****************************/
Native_capability Cap_session_component::alloc(Cap_session_component *session, Native_capability Cap_session_component::alloc(Native_capability ep)
Native_capability ep)
{ {
Native_capability cap; Native_capability cap;
if (!ep.valid()) { if (!ep.valid()) {
PWRN("Invalid cap!"); PWRN("Invalid reference capability!");
return cap; return cap;
} }
@ -108,7 +107,7 @@ Native_capability Cap_session_component::alloc(Cap_session_component *session,
Core_cap_index* idx = static_cast<Core_cap_index*>(cap_map()->insert(id)); Core_cap_index* idx = static_cast<Core_cap_index*>(cap_map()->insert(id));
if (!idx) { if (!idx) {
PWRN("Out of capabilities!"); PWRN("Out of capability indices!");
platform_specific()->cap_id_alloc()->free(id); platform_specific()->cap_id_alloc()->free(id);
return cap; return cap;
} }
@ -125,40 +124,51 @@ Native_capability Cap_session_component::alloc(Cap_session_component *session,
/* set debugger-name of ipc-gate to thread's name */ /* set debugger-name of ipc-gate to thread's name */
Fiasco::l4_debugger_set_object_name(idx->kcap(), ref->pt()->name()); Fiasco::l4_debugger_set_object_name(idx->kcap(), ref->pt()->name());
idx->session(session); idx->session(this);
idx->pt(ref->pt()); idx->pt(ref->pt());
idx->inc();
cap = Native_capability(idx); cap = Native_capability(idx);
} catch (Cap_id_allocator::Out_of_ids) { } catch (Cap_id_allocator::Out_of_ids) {
PERR("Out of IDs"); PERR("Out of capability ids");
} }
/*
* insert valid capabilities into the session's object pool to
* be able to destroy them on session destruction.
* For the construction of core's own threads the related cap session
* doesn't have an allocator set. But this session gets never destroyed
* so this is not an issue.
*/
if (cap.valid() && _md_alloc)
_pool.insert(new (_md_alloc) Entry(cap));
return cap; return cap;
} }
Native_capability Cap_session_component::alloc(Native_capability ep)
{
return Cap_session_component::alloc(this, ep);
}
void Cap_session_component::free(Native_capability cap) void Cap_session_component::free(Native_capability cap)
{ {
using namespace Fiasco; using namespace Fiasco;
if (!cap.valid()) if (!cap.valid()) return;
return;
Core_cap_index* idx = static_cast<Core_cap_index*>(cap.idx()); /* proof whether the capability was created by this cap_session */
if (static_cast<Core_cap_index*>(cap.idx())->session() != this) return;
/* _pool.apply(cap, [this] (Entry *e) {
* check whether this cap_session has created the capability to delete. if (e) {
*/ _pool.remove(e);
if (idx->session() != this) destroy(_md_alloc, e);
return; } else
PWRN("Could not find capability to be deleted");
});
}
idx->dec();
Cap_session_component::~Cap_session_component()
{
_pool.remove_all([this] (Entry *e) {
if (!e) return;
destroy(_md_alloc, e);
});
} }
@ -203,7 +213,6 @@ void Genode::Capability_map::remove(Genode::Cap_index* i)
if (i) { if (i) {
Core_cap_index* e = static_cast<Core_cap_index*>(_tree.first() ? _tree.first()->find_by_id(i->id()) : 0); Core_cap_index* e = static_cast<Core_cap_index*>(_tree.first() ? _tree.first()->find_by_id(i->id()) : 0);
if (e == i) { if (e == i) {
l4_msgtag_t tag = l4_task_unmap(L4_BASE_TASK_CAP, l4_msgtag_t tag = l4_task_unmap(L4_BASE_TASK_CAP,
l4_obj_fpage(i->kcap(), 0, L4_FPAGE_RWX), l4_obj_fpage(i->kcap(), 0, L4_FPAGE_RWX),
L4_FP_ALL_SPACES | L4_FP_DELETE_OBJ); L4_FP_ALL_SPACES | L4_FP_DELETE_OBJ);

View File

@ -17,23 +17,34 @@
/* Genode includes */ /* Genode includes */
#include <base/rpc_server.h> #include <base/rpc_server.h>
#include <base/allocator.h> #include <base/allocator.h>
#include <base/object_pool.h>
namespace Genode { namespace Genode {
class Cap_session_component : public Rpc_object<Cap_session> class Cap_session_component : public Rpc_object<Cap_session>
{ {
private:
struct Entry : Object_pool<Entry>::Entry
{
Entry(Native_capability cap) : Object_pool<Entry>::Entry(cap) {}
};
Object_pool<Entry> _pool;
Allocator *_md_alloc;
public: public:
Cap_session_component(Allocator *md_alloc, const char *args) {} Cap_session_component(Allocator *md_alloc, const char *args)
: _md_alloc(md_alloc) {}
~Cap_session_component();
void upgrade_ram_quota(size_t ram_quota) { } void upgrade_ram_quota(size_t ram_quota) { }
Native_capability alloc(Native_capability ep); Native_capability alloc(Native_capability ep);
void free(Native_capability cap); void free(Native_capability cap);
static Native_capability alloc(Cap_session_component *session,
Native_capability ep);
}; };
} }

View File

@ -226,8 +226,13 @@ void Platform_thread::_create_thread()
if (l4_msgtag_has_error(tag)) if (l4_msgtag_has_error(tag))
PERR("cannot create more thread kernel-objects!"); PERR("cannot create more thread kernel-objects!");
/* for core threads we can't use core_env, it is to early */
static Cap_session_component core_thread_cap_session(0,"");
Cap_session &csc = (_core_thread)
? core_thread_cap_session : *core_env()->cap_session();
/* create initial gate for thread */ /* create initial gate for thread */
_gate.local = Cap_session_component::alloc(0, _thread.local); _gate.local = csc.alloc(_thread.local);
} }
@ -311,7 +316,7 @@ Platform_thread::Platform_thread(const char *name)
Platform_thread::~Platform_thread() Platform_thread::~Platform_thread()
{ {
_gate.local.idx()->dec(); core_env()->cap_session()->free(_gate.local);
/* /*
* We inform our protection domain about thread destruction, which will end up in * We inform our protection domain about thread destruction, which will end up in