base: support to attach RAM dataspaces readonly

Fixes #1633
This commit is contained in:
Alexander Boettcher 2018-05-08 11:21:10 +02:00 committed by Christian Helmuth
parent 487e8ea934
commit e6d20aba93
29 changed files with 122 additions and 78 deletions

View File

@ -26,7 +26,7 @@ using namespace Genode;
Region_map::Local_addr
Core_region_map::attach(Dataspace_capability ds_cap, size_t size,
off_t offset, bool use_local_addr,
Region_map::Local_addr, bool)
Region_map::Local_addr, bool, bool writeable)
{
auto lambda = [&] (Dataspace_component *ds) -> Local_addr {
if (!ds)
@ -61,8 +61,9 @@ Core_region_map::attach(Dataspace_capability ds_cap, size_t size,
/* map the dataspace's physical pages to corresponding virtual addresses */
unsigned num_pages = page_rounded_size >> get_page_size_log2();
Page_flags const flags { ds->writable() ? RW : RO, NO_EXEC, KERN,
GLOBAL, ds->io_mem() ? DEVICE : RAM,
Page_flags const flags { (writeable && ds->writable()) ? RW : RO,
NO_EXEC, KERN, GLOBAL,
ds->io_mem() ? DEVICE : RAM,
ds->cacheability() };
if (!map_local(ds->phys_addr(), (addr_t)virt_addr, num_pages, flags))
return nullptr;

View File

@ -94,8 +94,8 @@ void Genode::Cpu::mmu_fault(Context & regs, Kernel::Thread_fault & fault)
};
auto fault_lambda = [] (addr_t err) {
if (!(err & ERR_P)) return Fault::PAGE_MISSING;
if (err & ERR_W) return Fault::WRITE;
if (!(err & ERR_P)) return Fault::PAGE_MISSING;
if (err & ERR_I) return Fault::EXEC;
else return Fault::UNKNOWN;
};

View File

@ -53,7 +53,8 @@ class Genode::Region_map_component : public Rpc_object<Region_map>,
void add_client(Rm_client &) { }
void remove_client(Rm_client &) { }
Local_addr attach(Dataspace_capability, size_t, off_t, bool, Local_addr, bool) {
Local_addr attach(Dataspace_capability, size_t, off_t, bool,
Local_addr, bool, bool) {
return (addr_t)0; }
void detach(Local_addr) { }

View File

@ -43,7 +43,8 @@ class Stack_area_region_map : public Genode::Region_map
* Attach backing store to stack area
*/
Local_addr attach(Genode::Dataspace_capability, Genode::size_t size,
Genode::off_t, bool, Local_addr local_addr, bool)
Genode::off_t, bool, Local_addr local_addr, bool,
bool) override
{
using namespace Genode;
@ -61,17 +62,17 @@ class Stack_area_region_map : public Genode::Region_map
return local_addr;
}
void detach(Local_addr local_addr)
void detach(Local_addr local_addr) override
{
Genode::warning("stack area detach from ", (void*)local_addr,
" - not implemented");
}
void fault_handler(Genode::Signal_context_capability) { }
void fault_handler(Genode::Signal_context_capability) override { }
State state() { return State(); }
State state() override { return State(); }
Genode::Dataspace_capability dataspace() {
Genode::Dataspace_capability dataspace() override {
return Genode::Dataspace_capability(); }
};

View File

@ -77,7 +77,8 @@ class Genode::Region_map_mmap : public Region_map, public Dataspace
bool use_local_addr,
addr_t local_addr,
bool executable,
bool overmap = false);
bool overmap,
bool writeable);
/**
* Determine size of dataspace
@ -115,25 +116,25 @@ class Genode::Region_map_mmap : public Region_map, public Dataspace
** Region map interface **
**************************/
Local_addr attach(Dataspace_capability ds, size_t size,
off_t, bool, Local_addr, bool executable);
Local_addr attach(Dataspace_capability, size_t size, off_t, bool,
Local_addr, bool, bool) override;
void detach(Local_addr local_addr);
void detach(Local_addr) override;
void fault_handler(Signal_context_capability) { }
void fault_handler(Signal_context_capability) override { }
State state() { return State(); }
State state() override { return State(); }
/*************************
** Dataspace interface **
*************************/
size_t size() { return _size; }
size_t size() override { return _size; }
addr_t phys_addr() { return 0; }
addr_t phys_addr() override { return 0; }
bool writable() { return true; }
bool writable() override { return true; }
/**
* Return pseudo dataspace capability of the RM session
@ -142,7 +143,7 @@ class Genode::Region_map_mmap : public Region_map, public Dataspace
* as argument to 'Region_map_mmap::attach'. It is not a
* real capability.
*/
Dataspace_capability dataspace() {
Dataspace_capability dataspace() override {
return Local_capability<Dataspace>::local_cap(this); }
};

View File

@ -39,10 +39,10 @@ Region_map::Local_addr
Region_map_client::attach(Dataspace_capability ds, size_t size,
off_t offset, bool use_local_addr,
Region_map::Local_addr local_addr,
bool executable)
bool executable, bool writeable)
{
return _local(*this)->attach(ds, size, offset, use_local_addr,
local_addr, executable);
local_addr, executable, writeable);
}

View File

@ -123,10 +123,11 @@ void *Region_map_mmap::_map_local(Dataspace_capability ds,
bool use_local_addr,
addr_t local_addr,
bool executable,
bool overmap)
bool overmap,
bool writeable)
{
int const fd = _dataspace_fd(ds);
bool const writable = _dataspace_writable(ds);
bool const writable = _dataspace_writable(ds) && writeable;
int const flags = MAP_SHARED | (overmap ? MAP_FIXED : 0);
int const prot = PROT_READ
@ -172,7 +173,7 @@ Region_map::Local_addr Region_map_mmap::attach(Dataspace_capability ds,
size_t size, off_t offset,
bool use_local_addr,
Region_map::Local_addr local_addr,
bool executable)
bool executable, bool writeable)
{
Lock::Guard lock_guard(lock());
@ -239,7 +240,7 @@ Region_map::Local_addr Region_map_mmap::attach(Dataspace_capability ds,
* argument as the region was reserved by a PROT_NONE mapping.
*/
if (_is_attached())
_map_local(ds, region_size, offset, true, _base + (addr_t)local_addr, executable, true);
_map_local(ds, region_size, offset, true, _base + (addr_t)local_addr, executable, true, writeable);
return (void *)local_addr;
@ -290,7 +291,7 @@ Region_map::Local_addr Region_map_mmap::attach(Dataspace_capability ds,
*/
_map_local(region.dataspace(), region.size(), region.offset(),
true, rm->_base + region.start() + region.offset(),
executable, true);
executable, true, writeable);
}
return rm->_base;
@ -304,7 +305,7 @@ Region_map::Local_addr Region_map_mmap::attach(Dataspace_capability ds,
* Note, we do not overmap.
*/
void *addr = _map_local(ds, region_size, offset, use_local_addr,
local_addr, executable);
local_addr, executable, false, writeable);
_add_to_rmap(Region((addr_t)addr, offset, ds, region_size));

View File

@ -51,7 +51,7 @@ Region_map::Local_addr
Core_region_map::attach(Dataspace_capability ds_cap, size_t,
off_t offset, bool use_local_addr,
Region_map::Local_addr,
bool executable)
bool executable, bool writeable)
{
auto lambda = [&] (Dataspace_component *ds) -> Local_addr {
if (!ds)
@ -76,7 +76,7 @@ Core_region_map::attach(Dataspace_capability ds_cap, size_t,
/* map it */
Nova::Utcb * const utcb = reinterpret_cast<Nova::Utcb *>(Thread::myself()->utcb());
const Nova::Rights rights(true, ds->writable(), executable);
const Nova::Rights rights(true, writeable && ds->writable(), executable);
if (map_local(utcb, ds->phys_addr(), reinterpret_cast<addr_t>(virt_ptr),
page_rounded_size >> get_page_size_log2(), rights, true)) {

View File

@ -66,10 +66,13 @@ void Pd_session_component::map(addr_t virt, addr_t size)
/* one item ever fits on the UTCB */
(void)res;
Nova::Rights const map_rights (true,
region->write() && dsc->writable(),
region->executable());
/* receive window in destination pd */
Nova::Mem_crd crd_mem(mapping.dst_addr() >> 12,
mapping.mem_crd().order(),
Nova::Rights(true, dsc->writable(), region->executable()));
mapping.mem_crd().order(), map_rights);
err = Nova::delegate(pd_core, pd_dst, crd_mem);
} while (err == Nova::NOVA_PD_OOM &&

View File

@ -24,10 +24,10 @@ Region_map_client::Region_map_client(Capability<Region_map> session)
Region_map::Local_addr
Region_map_client::attach(Dataspace_capability ds, size_t size, off_t offset,
bool use_local_addr, Local_addr local_addr,
bool executable)
bool executable, bool writeable)
{
return call<Rpc_attach>(ds, size, offset, use_local_addr, local_addr,
executable);
executable, writeable);
}

View File

@ -22,7 +22,7 @@ using namespace Genode;
Region_map::Local_addr
Core_region_map::attach(Dataspace_capability ds_cap, size_t size,
off_t offset, bool use_local_addr,
Region_map::Local_addr, bool)
Region_map::Local_addr, bool, bool)
{
using namespace Okl4;

View File

@ -24,7 +24,7 @@ using namespace Genode;
Region_map::Local_addr
Core_region_map::attach(Dataspace_capability ds_cap, size_t size, off_t offset,
bool use_local_addr, Region_map::Local_addr, bool)
bool use_local_addr, Region_map::Local_addr, bool, bool)
{
auto lambda = [&] (Dataspace_component *ds) -> Local_addr {
if (!ds)

View File

@ -58,7 +58,7 @@ class Stack_area_region_map : public Region_map
* Allocate and attach on-the-fly backing store to the stack area
*/
Local_addr attach(Dataspace_capability, size_t size, off_t,
bool, Local_addr local_addr, bool) override
bool, Local_addr local_addr, bool, bool) override
{
size = round_page(size);

View File

@ -44,7 +44,8 @@ class Genode::Region_map_client : public Rpc_client<Region_map>
Local_addr attach(Dataspace_capability ds, size_t size = 0,
off_t offset = 0, bool use_local_addr = false,
Local_addr local_addr = (void *)0,
bool executable = false) override;
bool executable = false,
bool writeable = true) override;
void detach(Local_addr) override;
void fault_handler(Signal_context_capability) override;

View File

@ -103,6 +103,7 @@ struct Genode::Region_map : Interface
* the specified 'local_addr'
* \param local_addr local destination address
* \param executable if the mapping should be executable
* \param writeable if the mapping should be writeable
*
* \throw Invalid_dataspace
* \throw Region_conflict
@ -116,7 +117,8 @@ struct Genode::Region_map : Interface
size_t size = 0, off_t offset = 0,
bool use_local_addr = false,
Local_addr local_addr = (void *)0,
bool executable = false) = 0;
bool executable = false,
bool writeable = true) = 0;
/**
* Shortcut for attaching a dataspace at a predefined local address
@ -165,7 +167,8 @@ struct Genode::Region_map : Interface
GENODE_RPC_THROW(Rpc_attach, Local_addr, attach,
GENODE_TYPE_LIST(Invalid_dataspace, Region_conflict,
Out_of_ram, Out_of_caps),
Dataspace_capability, size_t, off_t, bool, Local_addr, bool);
Dataspace_capability, size_t, off_t, bool, Local_addr,
bool, bool);
GENODE_RPC(Rpc_detach, void, detach, Local_addr);
GENODE_RPC(Rpc_fault_handler, void, fault_handler, Signal_context_capability);
GENODE_RPC(Rpc_state, State, state);

View File

@ -162,7 +162,7 @@ _ZN6Genode17Native_capabilityC1Ev T
_ZN6Genode17Native_capabilityC2Ev T
_ZN6Genode17Region_map_client13fault_handlerENS_10CapabilityINS_14Signal_contextEEE T
_ZN6Genode17Region_map_client5stateEv T
_ZN6Genode17Region_map_client6attachENS_10CapabilityINS_9DataspaceEEEmlbNS_10Region_map10Local_addrEb T
_ZN6Genode17Region_map_client6attachENS_10CapabilityINS_9DataspaceEEEmlbNS_10Region_map10Local_addrEbb T
_ZN6Genode17Region_map_client6detachENS_10Region_map10Local_addrE T
_ZN6Genode17Region_map_client9dataspaceEv T
_ZN6Genode17Region_map_clientC1ENS_10CapabilityINS_10Region_mapEEE T

View File

@ -23,7 +23,7 @@ using namespace Genode;
Region_map::Local_addr
Core_region_map::attach(Dataspace_capability ds_cap, size_t, off_t, bool,
Region_map::Local_addr, bool)
Region_map::Local_addr, bool, bool)
{
auto lambda = [] (Dataspace_component *ds) {
if (!ds)

View File

@ -37,7 +37,8 @@ class Genode::Core_region_map : public Region_map
Local_addr attach(Dataspace_capability, size_t size = 0,
off_t offset=0, bool use_local_addr = false,
Local_addr local_addr = 0,
bool executable = false) override;
bool executable = false,
bool writeable = true) override;
void detach(Local_addr);

View File

@ -444,7 +444,8 @@ class Genode::Region_map_component : private Weak_object<Region_map_component>,
** Region map interface **
**************************/
Local_addr attach (Dataspace_capability, size_t, off_t, bool, Local_addr, bool) override;
Local_addr attach (Dataspace_capability, size_t, off_t,
bool, Local_addr, bool, bool) override;
void detach (Local_addr) override;
void fault_handler (Signal_context_capability handler) override;
State state () override;

View File

@ -213,7 +213,8 @@ int Rm_client::pager(Ipc_pager &pager)
/*
* Check if dataspace is compatible with page-fault type
*/
if (pf_type == Region_map::State::WRITE_FAULT && !dsc->writable()) {
if (pf_type == Region_map::State::WRITE_FAULT &&
(!region->write() || !dsc->writable())) {
print_page_fault("attempted write at read-only memory",
pf_addr, pf_ip, pf_type, *this);
@ -337,7 +338,8 @@ Mapping Region_map_component::create_map_item(Region_map_component *,
return Mapping(dst_fault_area.base(), src_fault_area.base(),
dsc->cacheability(), dsc->io_mem(),
map_size_log2, dsc->writable(), region->executable());
map_size_log2, region->write() && dsc->writable(),
region->executable());
};
@ -345,7 +347,7 @@ Region_map::Local_addr
Region_map_component::attach(Dataspace_capability ds_cap, size_t size,
off_t offset, bool use_local_addr,
Region_map::Local_addr local_addr,
bool executable)
bool executable, bool writeable)
{
/* serialize access */
Lock::Guard lock_guard(_lock);
@ -427,7 +429,8 @@ Region_map_component::attach(Dataspace_capability ds_cap, size_t size,
/* store attachment info in meta data */
try {
_map.metadata(attach_at, Rm_region((addr_t)attach_at, size, true,
_map.metadata(attach_at, Rm_region((addr_t)attach_at, size,
dsc->writable() && writeable,
dsc, offset, this, executable));
}
catch (Allocator_avl_tpl<Rm_region>::Assign_metadata_failed) {

View File

@ -67,7 +67,7 @@ class Stack_area_region_map : public Region_map
* Allocate and attach on-the-fly backing store to stack area
*/
Local_addr attach(Dataspace_capability, size_t size, off_t,
bool, Local_addr local_addr, bool) override
bool, Local_addr local_addr, bool, bool) override
{
/* allocate physical memory */
size = round_page(size);

View File

@ -35,7 +35,7 @@ struct Genode::Expanding_region_map_client : Region_map_client
Local_addr attach(Dataspace_capability ds, size_t size, off_t offset,
bool use_local_addr, Local_addr local_addr,
bool executable) override
bool executable, bool writeable) override
{
return retry<Out_of_ram>(
[&] () {
@ -44,7 +44,8 @@ struct Genode::Expanding_region_map_client : Region_map_client
return Region_map_client::attach(ds, size, offset,
use_local_addr,
local_addr,
executable); },
executable,
writeable); },
[&] { _pd_client.upgrade_caps(2); });
},
[&] () { _pd_client.upgrade_ram(8*1024); });

View File

@ -23,10 +23,10 @@ Region_map_client::Region_map_client(Capability<Region_map> cap)
Region_map::Local_addr
Region_map_client::attach(Dataspace_capability ds, size_t size, off_t offset,
bool use_local_addr, Local_addr local_addr,
bool executable)
bool executable, bool writeable)
{
return call<Rpc_attach>(ds, size, offset, use_local_addr, local_addr,
executable);
executable, writeable);
}

View File

@ -301,25 +301,45 @@ struct Main_parent
_address_space.detach((void *)child_virt_addr);
}
void _test_write_fault(addr_t const child_virt_addr)
void _test_write_fault(addr_t const child_virt_addr, unsigned round)
{
if (_child_value() == WRITE_TEST) {
_child_stop() = STOP_TEST;
if (_child_value() != WRITE_TEST) {
Genode::log("test WRITE faults on read-only binary and "
"read-only attached RAM");
Genode::log("got write fault on ROM ", Hex(child_virt_addr));
/* let client continue by providing a dataspace it may write to */
_address_space.detach((void *)child_virt_addr);
_address_space.attach_at(_ds.cap(), child_virt_addr);
_child_value() = WRITE_TEST;
_address_space.attach_at(_binary.dataspace(), child_virt_addr);
return;
}
Genode::log("test WRITE fault on read-only binary");
enum { ROUND_FAULT_ON_ROM_BINARY = 1, ROUND_FAULT_ON_RO_RAM = 2 };
_child_value() = WRITE_TEST;
if (round == ROUND_FAULT_ON_RO_RAM)
_child_stop() = STOP_TEST;
_address_space.attach_at(_binary.dataspace(), child_virt_addr);
Genode::log("got write fault on ", Hex(child_virt_addr),
(round == ROUND_FAULT_ON_ROM_BINARY) ? " ROM (binary)" :
(round == ROUND_FAULT_ON_RO_RAM) ? " read-only attached RAM"
: " unknown");
/* detach region where fault happened */
_address_space.detach((void *)child_virt_addr);
if (round == ROUND_FAULT_ON_ROM_BINARY) {
/* attach a RAM dataspace read-only */
enum {
SIZE = 4096, OFFSET = 0, ATTACH_AT = true, NON_EXEC = false,
READONLY = false
};
_address_space.attach(_ds.cap(), SIZE, OFFSET, ATTACH_AT,
child_virt_addr, NON_EXEC, READONLY);
} else
if (round == ROUND_FAULT_ON_RO_RAM) {
/* let client continue by attaching RAM dataspace writeable */
_address_space.attach_at(_ds.cap(), child_virt_addr);
}
}
void _test_exec_fault(Region_map::State &state)
@ -344,7 +364,7 @@ struct Main_parent
void _handle_fault()
{
enum { FAULT_CNT_READ = 4, FAULT_CNT_WRITE = 5 };
enum { FAULT_CNT_READ = 4, FAULT_CNT_WRITE = 6 };
log("received region-map fault signal, request fault state");
@ -364,7 +384,7 @@ struct Main_parent
_test_read_fault(child_virt_addr);
if (_fault_cnt <= FAULT_CNT_WRITE && _fault_cnt >= FAULT_CNT_READ)
_test_write_fault(child_virt_addr);
_test_write_fault(child_virt_addr, _fault_cnt - FAULT_CNT_READ);
if (!_config.xml().attribute_value("executable_fault_test", true) &&
_fault_cnt >=FAULT_CNT_WRITE)

View File

@ -59,7 +59,8 @@ class Platform::Device_pd
Genode::size_t size = 0, Genode::off_t offset = 0,
bool use_local_addr = false,
Local_addr local_addr = (void *)0,
bool executable = false) override
bool executable = false,
bool writeable = true) override
{
return Genode::retry<Genode::Out_of_ram>(
[&] () {
@ -68,7 +69,8 @@ class Platform::Device_pd
return Region_map_client::attach(ds, size, offset,
use_local_addr,
local_addr,
executable); },
executable,
writeable); },
[&] () {
enum { UPGRADE_CAP_QUOTA = 2 };
Genode::Cap_quota const caps { UPGRADE_CAP_QUOTA };

View File

@ -54,7 +54,7 @@ Region_map::Local_addr
Region_map_component::attach(Dataspace_capability ds_cap, size_t size,
off_t offset, bool use_local_addr,
Region_map::Local_addr local_addr,
bool executable)
bool executable, bool const writeable)
{
size_t ds_size = Dataspace_client(ds_cap).size();
@ -72,7 +72,7 @@ Region_map_component::attach(Dataspace_capability ds_cap, size_t size,
void *addr = _parent_region_map.attach(ds_cap, size, offset,
use_local_addr, local_addr,
executable);
executable, writeable);
Lock::Guard lock_guard(_region_map_lock);
_region_map.insert(new (_alloc) Region(addr, (void*)((addr_t)addr + size - 1), ds_cap, offset));

View File

@ -102,7 +102,8 @@ namespace Gdb_monitor {
**************************************/
Local_addr attach (Dataspace_capability, size_t,
off_t, bool, Local_addr, bool) override;
off_t, bool, Local_addr, bool,
bool) override;
void detach (Local_addr) override;
void fault_handler (Signal_context_capability) override;
State state () override;

View File

@ -232,10 +232,11 @@ class Noux::Region_map_component : public Rpc_object<Region_map>,
**************************/
Local_addr attach(Dataspace_capability ds,
size_t size = 0, off_t offset = 0,
bool use_local_addr = false,
Local_addr local_addr = (addr_t)0,
bool executable = false) override
size_t size, off_t offset,
bool use_local_addr,
Local_addr local_addr,
bool executable,
bool writeable) override
{
/*
* Region map subtracts offset from size if size is 0
@ -245,7 +246,7 @@ class Noux::Region_map_component : public Rpc_object<Region_map>,
for (;;) {
try {
local_addr = _rm.attach(ds, size, offset, use_local_addr,
local_addr, executable);
local_addr, executable, writeable);
break;
}
catch (Out_of_ram) { _pd.upgrade_ram(8*1024); }

View File

@ -47,7 +47,8 @@ class Sub_rm_connection : private Genode::Rm_connection,
Genode::size_t size = 0, Genode::off_t offset = 0,
bool use_local_addr = false,
Local_addr local_addr = (void *)0,
bool executable = false) override
bool executable = false,
bool writeable = true) override
{
Local_addr addr = Genode::retry<Genode::Out_of_ram>(
[&] () {
@ -56,7 +57,8 @@ class Sub_rm_connection : private Genode::Rm_connection,
return Region_map_client::attach(ds, size, offset,
use_local_addr,
local_addr,
executable); },
executable,
writeable); },
[&] () { upgrade_caps(2); });
},
[&] () { upgrade_ram(8192); });