nova: use 16bit for reference count of caps

Bomb and any server may generate references to capabilities exceeding 256 -
use a 16bit counter until the cap handling in Genode gets unified.

Additionally try to print a warning, instead of dying, if we get cap reference
count under or overflow.

Issue #1615
This commit is contained in:
Alexander Boettcher 2015-07-02 20:28:19 +02:00 committed by Christian Helmuth
parent b1dd5fdf1d
commit 4ee8919f29
2 changed files with 38 additions and 23 deletions

View File

@ -39,10 +39,10 @@ namespace Genode {
WORDS = (CAP_RANGE_SIZE - HEADER - sizeof(Avl_node<Cap_range>)) / sizeof(addr_t),
};
uint8_t _cap_array[WORDS * sizeof(addr_t)];
uint16_t _cap_array[WORDS * sizeof(addr_t) / 2];
bool _match(addr_t id) {
return _base <= id && id < _base + sizeof(_cap_array); };
return _base <= id && id < _base + elements(); };
public:
@ -51,12 +51,12 @@ namespace Genode {
static_assert(sizeof(*this) == CAP_RANGE_SIZE,
"Cap_range misconfigured");
for (unsigned i=0; i < sizeof(_cap_array); i++)
for (unsigned i = 0; i < elements(); i++)
_cap_array[i] = 0;
}
addr_t const base() const { return _base; }
unsigned const elements() { return sizeof(_cap_array); }
unsigned const elements() { return sizeof(_cap_array) / sizeof(_cap_array[0]); }
Cap_range *find_by_id(addr_t);

View File

@ -13,13 +13,16 @@
#include <base/cap_map.h>
#include <base/printf.h>
/* base-nova specific include */
#include <nova/syscalls.h>
using namespace Genode;
Capability_map *Genode::cap_map() {
Capability_map *Genode::cap_map()
{
static Genode::Capability_map map;
return &map;
}
@ -39,34 +42,46 @@ Cap_range *Cap_range::find_by_id(addr_t id)
}
void Cap_range::inc(unsigned id, bool inc_if_one) {
void Cap_range::inc(unsigned id, bool inc_if_one)
{
bool failure = false;
{
Lock::Guard guard(_lock);
Lock::Guard guard(_lock);
if (inc_if_one && _cap_array[id] != 1)
return;
if (inc_if_one && _cap_array[id] != 1)
return;
if (_cap_array[id] == 255) {
// PERR("cap overflow - selector %lx - return address %p",
// _base + id, __builtin_return_address(0));
*reinterpret_cast<addr_t *>(0) = 0xdead;
if (_cap_array[id] + 1 == 0)
failure = true;
else
_cap_array[id]++;
}
_cap_array[id]++;
if (failure)
PERR("cap reference counting error - reference overflow of cap=%lx",
_base + id);
}
void Cap_range::dec(unsigned id, bool revoke) {
void Cap_range::dec(unsigned id, bool revoke)
{
bool failure = false;
{
Lock::Guard guard(_lock);
Lock::Guard guard(_lock);
if (_cap_array[id] == 0)
failure = true;
else {
if (revoke && _cap_array[id] == 1)
Nova::revoke(Nova::Obj_crd(_base + id, 0));
if (_cap_array[id] == 0)
*reinterpret_cast<addr_t *>(0) = 0xdead;
_cap_array[id]--;
}
}
if (revoke && _cap_array[id] == 1)
Nova::revoke(Nova::Obj_crd(_base + id, 0));
_cap_array[id]--;
if (failure)
PERR("cap reference counting error - count of cap=%lx is already zero",
_base + id);
}