Fiasco.OC: smart-pointer for kernel capabilities.
Implements Native_capability as smart-pointer type referencing Cap_index objects. Whenever capabilities are copied, assigned, constructed, or destructed the reference-counter of the Cap_index is incremented/decremented. When it reaches zero the Cap_index is removed from the process-global cap_map and gets freed. Fix for issue #32.
This commit is contained in:
parent
0d3df86674
commit
ca004658d9
|
@ -53,16 +53,19 @@ namespace Genode
|
||||||
|
|
||||||
enum { INVALID_ID = -1, UNUSED = 0 };
|
enum { INVALID_ID = -1, UNUSED = 0 };
|
||||||
|
|
||||||
uint16_t _id; /* global capability id */
|
uint8_t _ref_cnt; /* reference counter */
|
||||||
|
uint16_t _id; /* global capability id */
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Cap_index() : _id(INVALID_ID) { }
|
Cap_index() : _ref_cnt(0), _id(INVALID_ID) { }
|
||||||
|
|
||||||
bool valid() const { return _id != INVALID_ID; }
|
bool valid() const { return _id != INVALID_ID; }
|
||||||
bool used() const { return _id != UNUSED; }
|
bool used() const { return _id != UNUSED; }
|
||||||
uint16_t id() const { return _id; }
|
uint16_t id() const { return _id; }
|
||||||
void id(uint16_t id) { _id = id; }
|
void id(uint16_t id) { _id = id; }
|
||||||
|
uint8_t inc() { return ++_ref_cnt; }
|
||||||
|
uint8_t dec() { return --_ref_cnt; }
|
||||||
addr_t kcap();
|
addr_t kcap();
|
||||||
|
|
||||||
void* operator new (size_t size, Cap_index* idx) { return idx; }
|
void* operator new (size_t size, Cap_index* idx) { return idx; }
|
||||||
|
|
|
@ -53,7 +53,7 @@ inline void Genode::Ipc_istream::_unmarshal_capability(Genode::Native_capability
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if id is zero an invalid capability was tranfered */
|
/* if id is zero an invalid capability was transfered */
|
||||||
if (!id) {
|
if (!id) {
|
||||||
cap = Native_capability();
|
cap = Native_capability();
|
||||||
return;
|
return;
|
||||||
|
@ -61,26 +61,32 @@ inline void Genode::Ipc_istream::_unmarshal_capability(Genode::Native_capability
|
||||||
|
|
||||||
/* we received a valid, non-local capability, maybe we already own it? */
|
/* we received a valid, non-local capability, maybe we already own it? */
|
||||||
Cap_index *i = cap_map()->find(id);
|
Cap_index *i = cap_map()->find(id);
|
||||||
bool map = false;
|
Genode::addr_t rcv_cap = _rcv_msg->rcv_cap_sel();
|
||||||
if (i) {
|
if (i) {
|
||||||
/**
|
/**
|
||||||
* If we've a dead capability in our database, which is already
|
* If we've a dead capability in our database, which is already
|
||||||
* revoked, its id might be reused.
|
* revoked, its id might be reused.
|
||||||
*/
|
*/
|
||||||
l4_msgtag_t tag = Fiasco::l4_task_cap_valid(L4_BASE_TASK_CAP, i->kcap());
|
l4_msgtag_t tag = l4_task_cap_valid(L4_BASE_TASK_CAP, i->kcap());
|
||||||
if (!tag.label())
|
if (!l4_msgtag_label(tag)) {
|
||||||
map = true;
|
i->inc();
|
||||||
} else {
|
PWRN("leaking capability idx=%p id=%x ref_cnt=%d",i, i->id(), i->dec());
|
||||||
/* insert the new capability in the map */
|
} else {
|
||||||
i = cap_map()->insert(id);
|
/* does somebody tries to fake us? */
|
||||||
map = true;
|
tag = l4_task_cap_equal(L4_BASE_TASK_CAP, i->kcap(), rcv_cap);
|
||||||
|
if (!l4_msgtag_label(tag)) {
|
||||||
|
PWRN("Got fake capability");
|
||||||
|
cap = Native_capability();
|
||||||
|
} else
|
||||||
|
cap = Native_capability(i);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
/* insert the new capability in the map */
|
||||||
/* map the received capability from the receive-buffer if necessary */
|
i = cap_map()->insert(id);
|
||||||
if (map)
|
l4_task_map(L4_BASE_TASK_CAP, L4_BASE_TASK_CAP,
|
||||||
l4_task_map(L4_BASE_TASK_CAP, L4_BASE_TASK_CAP,
|
l4_obj_fpage(rcv_cap, 0, L4_FPAGE_RWX),
|
||||||
l4_obj_fpage(_rcv_msg->rcv_cap_sel(), 0, L4_FPAGE_RWX),
|
i->kcap() | L4_ITEM_MAP | L4_MAP_ITEM_GRANT);
|
||||||
i->kcap() | L4_ITEM_MAP | L4_MAP_ITEM_GRANT);
|
|
||||||
cap = Native_capability(i);
|
cap = Native_capability(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -78,6 +78,19 @@ namespace Genode {
|
||||||
*/
|
*/
|
||||||
Native_capability(void* ptr) : _idx(0), _ptr(ptr) { }
|
Native_capability(void* ptr) : _idx(0), _ptr(ptr) { }
|
||||||
|
|
||||||
|
inline void _inc()
|
||||||
|
{
|
||||||
|
if (_idx)
|
||||||
|
_idx->inc();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void _dec()
|
||||||
|
{
|
||||||
|
if (_idx && !_idx->dec()) {
|
||||||
|
cap_map()->remove(_idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -88,7 +101,16 @@ namespace Genode {
|
||||||
/**
|
/**
|
||||||
* Construct capability manually
|
* Construct capability manually
|
||||||
*/
|
*/
|
||||||
Native_capability(Cap_index* idx) : _idx(idx), _ptr(0) { }
|
Native_capability(Cap_index* idx)
|
||||||
|
: _idx(idx), _ptr(0) { _inc(); }
|
||||||
|
|
||||||
|
Native_capability(const Native_capability &o)
|
||||||
|
: _idx(o._idx), _ptr(o._ptr) { _inc(); }
|
||||||
|
|
||||||
|
~Native_capability()
|
||||||
|
{
|
||||||
|
_dec();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return Cap_index object referenced by this object
|
* Return Cap_index object referenced by this object
|
||||||
|
@ -101,6 +123,16 @@ namespace Genode {
|
||||||
bool operator==(const Native_capability &o) const {
|
bool operator==(const Native_capability &o) const {
|
||||||
return (_ptr) ? _ptr == o._ptr : _idx == o._idx; }
|
return (_ptr) ? _ptr == o._ptr : _idx == o._idx; }
|
||||||
|
|
||||||
|
Native_capability& operator=(const Native_capability &o){
|
||||||
|
if (this == &o)
|
||||||
|
return *this;
|
||||||
|
|
||||||
|
_dec();
|
||||||
|
_ptr = o._ptr;
|
||||||
|
_idx = o._idx;
|
||||||
|
_inc();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
/*******************************************
|
/*******************************************
|
||||||
** Interface provided by all platforms **
|
** Interface provided by all platforms **
|
||||||
|
|
2
base-foc/src/base/env/cap_map.cc
vendored
2
base-foc/src/base/env/cap_map.cc
vendored
|
@ -97,7 +97,7 @@ void Genode::Capability_map::remove(Genode::Cap_index* i)
|
||||||
i = _tree.first()->find_by_id(i->id());
|
i = _tree.first()->find_by_id(i->id());
|
||||||
if (i) {
|
if (i) {
|
||||||
_tree.remove(i);
|
_tree.remove(i);
|
||||||
cap_idx_alloc()->free(i,1);
|
cap_idx_alloc()->free(i, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -151,8 +151,12 @@ Thread_base::Context *Thread_base::_alloc_context(size_t stack_size)
|
||||||
/*
|
/*
|
||||||
* Now the thread context is backed by memory, so it is safe to access its
|
* Now the thread context is backed by memory, so it is safe to access its
|
||||||
* members.
|
* members.
|
||||||
|
*
|
||||||
|
* We need to initalize the context object's memory with zeroes,
|
||||||
|
* otherwise the ds_cap isn't invalid. That would cause trouble
|
||||||
|
* when the assignment operator of Native_capability is used.
|
||||||
*/
|
*/
|
||||||
|
memset(context, 0, sizeof(Context));
|
||||||
context->thread_base = this;
|
context->thread_base = this;
|
||||||
context->stack_base = ds_addr;
|
context->stack_base = ds_addr;
|
||||||
context->ds_cap = ds_cap;
|
context->ds_cap = ds_cap;
|
||||||
|
|
|
@ -57,23 +57,14 @@ void Thread_base::start()
|
||||||
_tid = state.kcap;
|
_tid = state.kcap;
|
||||||
_context->utcb = state.utcb;
|
_context->utcb = state.utcb;
|
||||||
|
|
||||||
/**
|
|
||||||
* If we've a dead capability in our database, which is already
|
|
||||||
* revoked, its id might be reused.
|
|
||||||
*/
|
|
||||||
Cap_index *i = cap_map()->find(state.id);
|
|
||||||
if (i) {
|
|
||||||
l4_msgtag_t tag = l4_task_cap_valid(L4_BASE_TASK_CAP, i->kcap());
|
|
||||||
if (!tag.label())
|
|
||||||
cap_map()->remove(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
l4_utcb_tcr_u(state.utcb)->user[UTCB_TCR_BADGE] = state.id;
|
l4_utcb_tcr_u(state.utcb)->user[UTCB_TCR_BADGE] = state.id;
|
||||||
l4_utcb_tcr_u(state.utcb)->user[UTCB_TCR_THREAD_OBJ] = (addr_t)this;
|
l4_utcb_tcr_u(state.utcb)->user[UTCB_TCR_THREAD_OBJ] = (addr_t)this;
|
||||||
cap_map()->insert(state.id, state.kcap);
|
|
||||||
|
/* we need to manually increase the reference counter here */
|
||||||
|
cap_map()->insert(state.id, state.kcap)->inc();
|
||||||
} catch(Cap_index_allocator::Region_conflict) {
|
} catch(Cap_index_allocator::Region_conflict) {
|
||||||
PERR("could not insert id %lx", state.id);
|
PERR("could not insert id %x", state.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* register initial IP and SP at core */
|
/* register initial IP and SP at core */
|
||||||
|
|
|
@ -50,7 +50,7 @@ Genode::Cap_index_allocator* Genode::cap_idx_alloc()
|
||||||
Core_cap_index* Cap_mapping::_get_cap()
|
Core_cap_index* Cap_mapping::_get_cap()
|
||||||
{
|
{
|
||||||
int id = platform_specific()->cap_id_alloc()->alloc();
|
int id = platform_specific()->cap_id_alloc()->alloc();
|
||||||
return reinterpret_cast<Core_cap_index*>(cap_map()->insert(id));
|
return static_cast<Core_cap_index*>(cap_map()->insert(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -82,17 +82,27 @@ void Cap_mapping::unmap()
|
||||||
|
|
||||||
|
|
||||||
Cap_mapping::Cap_mapping(bool alloc, Native_thread_id r)
|
Cap_mapping::Cap_mapping(bool alloc, Native_thread_id r)
|
||||||
: local(alloc ? _get_cap() : 0), remote(r) { }
|
: local(alloc ? _get_cap() : 0), remote(r)
|
||||||
|
{
|
||||||
|
if (local)
|
||||||
|
local->inc();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Cap_mapping::Cap_mapping(Core_cap_index* i, Native_thread_id r)
|
Cap_mapping::Cap_mapping(Core_cap_index* i, Native_thread_id r)
|
||||||
: local(i), remote(r) { }
|
: local(i), remote(r)
|
||||||
|
{
|
||||||
|
if (local)
|
||||||
|
local->inc();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Cap_mapping::~Cap_mapping()
|
Cap_mapping::~Cap_mapping()
|
||||||
{
|
{
|
||||||
unmap();
|
if (local) {
|
||||||
cap_map()->remove(local);
|
unmap();
|
||||||
|
cap_map()->remove(local);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -113,14 +123,13 @@ Native_capability Cap_session_component::alloc(Cap_session_component *session,
|
||||||
try {
|
try {
|
||||||
using namespace Fiasco;
|
using namespace Fiasco;
|
||||||
|
|
||||||
Core_cap_index* ref = reinterpret_cast<Core_cap_index*>(ep.idx());
|
Core_cap_index* ref = static_cast<Core_cap_index*>(ep.idx());
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Allocate new id, and ipc-gate and set id as gate-label
|
* Allocate new id, and ipc-gate and set id as gate-label
|
||||||
*/
|
*/
|
||||||
unsigned long id = platform_specific()->cap_id_alloc()->alloc();
|
unsigned long id = platform_specific()->cap_id_alloc()->alloc();
|
||||||
Core_cap_index* idx =
|
Core_cap_index* idx = static_cast<Core_cap_index*>(cap_map()->insert(id));
|
||||||
reinterpret_cast<Core_cap_index*>(cap_map()->insert(id));
|
|
||||||
l4_msgtag_t tag = l4_factory_create_gate(L4_BASE_FACTORY_CAP,
|
l4_msgtag_t tag = l4_factory_create_gate(L4_BASE_FACTORY_CAP,
|
||||||
idx->kcap(),
|
idx->kcap(),
|
||||||
ref->pt()->thread().local->kcap(), id);
|
ref->pt()->thread().local->kcap(), id);
|
||||||
|
@ -135,6 +144,7 @@ Native_capability Cap_session_component::alloc(Cap_session_component *session,
|
||||||
|
|
||||||
idx->session(session);
|
idx->session(session);
|
||||||
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 IDs");
|
||||||
|
@ -156,7 +166,7 @@ void Cap_session_component::free(Native_capability cap)
|
||||||
if (!cap.valid())
|
if (!cap.valid())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Core_cap_index* idx = reinterpret_cast<Core_cap_index*>(cap.idx());
|
Core_cap_index* idx = static_cast<Core_cap_index*>(cap.idx());
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* check whether this cap_session has created the capability to delete.
|
* check whether this cap_session has created the capability to delete.
|
||||||
|
|
|
@ -97,8 +97,7 @@ namespace Genode {
|
||||||
** Fiasco-specific Accessors **
|
** Fiasco-specific Accessors **
|
||||||
*******************************/
|
*******************************/
|
||||||
|
|
||||||
Native_capability native_task() const {
|
Core_cap_index* native_task() { return _task.local; }
|
||||||
return Native_capability(_task.local); }
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,4 +19,4 @@
|
||||||
|
|
||||||
|
|
||||||
Genode::Native_capability Genode::Pd_session_component::task_cap() {
|
Genode::Native_capability Genode::Pd_session_component::task_cap() {
|
||||||
return _pd.native_task(); }
|
return Native_capability(_pd.native_task()); }
|
||||||
|
|
|
@ -126,7 +126,7 @@ Platform::Sigma0::Sigma0(Cap_index* i) : Pager_object(0)
|
||||||
* We use the Pager_object here in a slightly different manner,
|
* We use the Pager_object here in a slightly different manner,
|
||||||
* just to tunnel the pager cap to the Platform_thread::start method.
|
* just to tunnel the pager cap to the Platform_thread::start method.
|
||||||
*/
|
*/
|
||||||
cap(reinterpret_cap_cast<Thread_capability>(Native_capability(i)));
|
cap(Native_capability(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -40,13 +40,13 @@ int Platform_thread::start(void *ip, void *sp)
|
||||||
{
|
{
|
||||||
/* map the pager cap */
|
/* map the pager cap */
|
||||||
if (_platform_pd)
|
if (_platform_pd)
|
||||||
_pager.map(_platform_pd->native_task().dst());
|
_pager.map(_platform_pd->native_task()->kcap());
|
||||||
|
|
||||||
/* reserve utcb area and associate thread with this task */
|
/* reserve utcb area and associate thread with this task */
|
||||||
l4_thread_control_start();
|
l4_thread_control_start();
|
||||||
l4_thread_control_pager(_pager.remote);
|
l4_thread_control_pager(_pager.remote);
|
||||||
l4_thread_control_exc_handler(_pager.remote);
|
l4_thread_control_exc_handler(_pager.remote);
|
||||||
l4_thread_control_bind(_utcb, _platform_pd->native_task().dst());
|
l4_thread_control_bind(_utcb, _platform_pd->native_task()->kcap());
|
||||||
l4_msgtag_t tag = l4_thread_control_commit(_thread.local->kcap());
|
l4_msgtag_t tag = l4_thread_control_commit(_thread.local->kcap());
|
||||||
if (l4_msgtag_has_error(tag)) {
|
if (l4_msgtag_has_error(tag)) {
|
||||||
PWRN("l4_thread_control_commit for %lx failed!",
|
PWRN("l4_thread_control_commit for %lx failed!",
|
||||||
|
@ -132,8 +132,8 @@ void Platform_thread::resume()
|
||||||
void Platform_thread::bind(Platform_pd *pd)
|
void Platform_thread::bind(Platform_pd *pd)
|
||||||
{
|
{
|
||||||
_platform_pd = pd;
|
_platform_pd = pd;
|
||||||
_gate.map(pd->native_task().dst());
|
_gate.map(pd->native_task()->kcap());
|
||||||
_irq.map(pd->native_task().dst());
|
_irq.map(pd->native_task()->kcap());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -188,7 +188,7 @@ void Platform_thread::_create_thread()
|
||||||
PERR("cannot create more thread kernel-objects!");
|
PERR("cannot create more thread kernel-objects!");
|
||||||
|
|
||||||
/* create initial gate for thread */
|
/* create initial gate for thread */
|
||||||
_gate.local = reinterpret_cast<Core_cap_index*>(Cap_session_component::alloc(0, _thread.local).idx());
|
_gate.local = static_cast<Core_cap_index*>(Cap_session_component::alloc(0, _thread.local).idx());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,8 @@ namespace Fiasco {
|
||||||
enum { MAIN_THREAD_CAP_ID = 1 };
|
enum { MAIN_THREAD_CAP_ID = 1 };
|
||||||
|
|
||||||
static void main_thread_bootstrap() {
|
static void main_thread_bootstrap() {
|
||||||
|
using namespace Genode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unfortunately ldso calls this function twice. So the second time when
|
* Unfortunately ldso calls this function twice. So the second time when
|
||||||
* inserting the main thread's gate-capability an exception would be raised.
|
* inserting the main thread's gate-capability an exception would be raised.
|
||||||
|
@ -33,11 +35,11 @@ static void main_thread_bootstrap() {
|
||||||
* that's why we first check if the cap is already registered before
|
* that's why we first check if the cap is already registered before
|
||||||
* inserting it.
|
* inserting it.
|
||||||
*/
|
*/
|
||||||
Genode::Cap_index *idx = Genode::cap_map()->find(MAIN_THREAD_CAP_ID);
|
Cap_index *idx = cap_map()->find(MAIN_THREAD_CAP_ID);
|
||||||
if (!idx) {
|
if (!idx) {
|
||||||
Fiasco::l4_utcb_tcr()->user[Fiasco::UTCB_TCR_BADGE] = MAIN_THREAD_CAP_ID;
|
Fiasco::l4_utcb_tcr()->user[Fiasco::UTCB_TCR_BADGE] = MAIN_THREAD_CAP_ID;
|
||||||
Fiasco::l4_utcb_tcr()->user[Fiasco::UTCB_TCR_THREAD_OBJ] = 0;
|
Fiasco::l4_utcb_tcr()->user[Fiasco::UTCB_TCR_THREAD_OBJ] = 0;
|
||||||
Genode::cap_map()->insert(MAIN_THREAD_CAP_ID, Fiasco::MAIN_THREAD_CAP);
|
cap_map()->insert(MAIN_THREAD_CAP_ID, Fiasco::MAIN_THREAD_CAP)->inc();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user