base: enable executable memory fault handling

Fixes #1723
This commit is contained in:
Alexander Boettcher 2017-10-13 15:26:33 +02:00 committed by Christian Helmuth
parent 03b8e70d3f
commit db329b02b5
11 changed files with 77 additions and 32 deletions

View File

@ -48,11 +48,10 @@ namespace Genode {
*/ */
Mapping(addr_t dst_addr, addr_t src_addr, Mapping(addr_t dst_addr, addr_t src_addr,
Cache_attribute cacheability, bool io_mem, Cache_attribute cacheability, bool io_mem,
unsigned l2size = L4_LOG2_PAGESIZE, unsigned l2size, bool rw, bool executable)
bool rw = true, bool grant = false)
: :
_dst_addr(dst_addr), _dst_addr(dst_addr),
_fpage(Fiasco::l4_fpage(src_addr, l2size, rw, grant)) _fpage(Fiasco::l4_fpage(src_addr, l2size, rw, false))
{ {
if (cacheability == WRITE_COMBINED) if (cacheability == WRITE_COMBINED)
_fpage.fp.cache = Fiasco::L4_FPAGE_BUFFERABLE; _fpage.fp.cache = Fiasco::L4_FPAGE_BUFFERABLE;
@ -163,6 +162,8 @@ namespace Genode {
bool write_fault() const { return (_pf_addr & 2); } bool write_fault() const { return (_pf_addr & 2); }
bool exec_fault() const { return false; }
/** /**
* Return true if last fault was an exception * Return true if last fault was an exception
*/ */

View File

@ -45,7 +45,6 @@ namespace Genode {
bool _iomem; bool _iomem;
unsigned _log2size; unsigned _log2size;
bool _rw; bool _rw;
bool _grant;
public: public:
@ -54,20 +53,20 @@ namespace Genode {
*/ */
Mapping(addr_t dst_addr, addr_t src_addr, Mapping(addr_t dst_addr, addr_t src_addr,
Cache_attribute c, bool io_mem, Cache_attribute c, bool io_mem,
unsigned l2size = L4_LOG2_PAGESIZE, unsigned l2size,
bool rw = true, bool grant = false) bool rw, bool executable)
: _dst_addr(dst_addr), _src_addr(src_addr), : _dst_addr(dst_addr), _src_addr(src_addr),
_cacheability(c), _iomem(io_mem), _log2size(l2size), _cacheability(c), _iomem(io_mem), _log2size(l2size),
_rw(rw), _grant(grant) { } _rw(rw) { }
/** /**
* Construct invalid flexpage * Construct invalid flexpage
*/ */
Mapping() : _dst_addr(0), _src_addr(0), _cacheability(UNCACHED), Mapping() : _dst_addr(0), _src_addr(0), _cacheability(UNCACHED),
_iomem(false), _log2size(0), _rw(false), _grant(false) { } _iomem(false), _log2size(0), _rw(false) { }
Fiasco::l4_umword_t dst_addr() const { return _dst_addr; } Fiasco::l4_umword_t dst_addr() const { return _dst_addr; }
bool grant() const { return _grant; } bool grant() const { return false; }
Fiasco::l4_fpage_t fpage() const Fiasco::l4_fpage_t fpage() const
{ {
@ -176,6 +175,8 @@ namespace Genode {
bool write_fault() const { return (_pf_addr & 2); } bool write_fault() const { return (_pf_addr & 2); }
bool exec_fault() const { return false; }
/** /**
* Return true if last fault was an exception * Return true if last fault was an exception
*/ */

View File

@ -65,7 +65,8 @@ struct Genode::Mapping : Hw::Mapping
Cache_attribute cacheable, Cache_attribute cacheable,
bool io, bool io,
unsigned size_log2, unsigned size_log2,
bool writeable) bool writeable,
bool executable)
: Hw::Mapping(phys, virt, 1 << size_log2, : Hw::Mapping(phys, virt, 1 << size_log2,
{ writeable ? Hw::RW : Hw::RO, Hw::EXEC, Hw::USER, { writeable ? Hw::RW : Hw::RO, Hw::EXEC, Hw::USER,
Hw::NO_GLOBAL, io ? Hw::DEVICE : Hw::RAM, cacheable }) {} Hw::NO_GLOBAL, io ? Hw::DEVICE : Hw::RAM, cacheable }) {}
@ -108,6 +109,11 @@ class Genode::Ipc_pager
*/ */
bool write_fault() const; bool write_fault() const;
/**
* Executable permission fault
*/
bool exec_fault() const { return false; }
/** /**
* Input mapping data as reply to current page fault * Input mapping data as reply to current page fault
*/ */

View File

@ -43,8 +43,8 @@ namespace Genode {
*/ */
Mapping(addr_t dst_addr, addr_t map_addr, Mapping(addr_t dst_addr, addr_t map_addr,
Cache_attribute c, bool io_mem, Cache_attribute c, bool io_mem,
unsigned size_log2 = PAGE_SIZE_LOG2, unsigned size_log2,
bool rw = true) bool rw, bool executable)
: :
_dst_addr(dst_addr), _core_local_addr(map_addr), _dst_addr(dst_addr), _core_local_addr(map_addr),
_attr(c), _size_log2(size_log2), _rw(rw) _attr(c), _size_log2(size_log2), _rw(rw)
@ -125,6 +125,11 @@ namespace Genode {
*/ */
bool write_fault() const { return _fault_type & ERR_W; } bool write_fault() const { return _fault_type & ERR_W; }
/**
* Return true if fault was a non-executable fault
*/
bool exec_fault() const { return false; }
/** /**
* Return true if last fault was an exception * Return true if last fault was an exception
*/ */

View File

@ -41,7 +41,7 @@ namespace Genode {
*/ */
Mapping(addr_t dst_addr, addr_t src_addr, Mapping(addr_t dst_addr, addr_t src_addr,
Cache_attribute cacheability, bool io_mem, Cache_attribute cacheability, bool io_mem,
unsigned l2size = 12, bool rw = true); unsigned l2size, bool rw, bool executable);
/** /**
* Construct invalid mapping * Construct invalid mapping
@ -162,6 +162,11 @@ namespace Genode {
*/ */
bool write_fault() const { return L4_Label(_faulter_tag) & 2; } bool write_fault() const { return L4_Label(_faulter_tag) & 2; }
/**
* Return true if last fault was a executable fault
*/
bool exec_fault() const { return false; }
/** /**
* Return true if last fault was an exception * Return true if last fault was an exception
*/ */

View File

@ -73,7 +73,7 @@ static inline Okl4::L4_ThreadId_t thread_get_my_global_id()
Mapping::Mapping(addr_t dst_addr, addr_t src_addr, Mapping::Mapping(addr_t dst_addr, addr_t src_addr,
Cache_attribute cacheability, bool io_mem, Cache_attribute cacheability, bool io_mem,
unsigned l2size, bool rw) unsigned l2size, bool rw, bool executable)
: :
_fpage(L4_FpageLog2(dst_addr, l2size)), _fpage(L4_FpageLog2(dst_addr, l2size)),
/* /*

View File

@ -46,8 +46,8 @@ namespace Genode {
*/ */
Mapping(addr_t dst_addr, addr_t src_addr, Mapping(addr_t dst_addr, addr_t src_addr,
Cache_attribute, bool io_mem, Cache_attribute, bool io_mem,
unsigned l2size = Pistachio::get_page_size_log2(), unsigned l2size,
bool rw = true, bool grant = false); bool rw, bool executable);
/** /**
* Construct invalid mapping * Construct invalid mapping
@ -169,6 +169,11 @@ namespace Genode {
*/ */
bool write_fault() const { return (_flags & 2); } bool write_fault() const { return (_flags & 2); }
/**
* Return true if last fault was a executable fault
*/
bool exec_fault() const { return false; }
/** /**
* Return true if last fault was an exception * Return true if last fault was an exception
*/ */

View File

@ -41,8 +41,10 @@ using namespace Pistachio;
Mapping::Mapping(addr_t dst_addr, addr_t src_addr, Mapping::Mapping(addr_t dst_addr, addr_t src_addr,
Cache_attribute, bool io_mem, unsigned l2size, Cache_attribute, bool io_mem, unsigned l2size,
bool rw, bool grant) bool rw, bool executable)
{ {
bool const grant = false;
L4_Fpage_t fpage = L4_FpageLog2(src_addr, l2size); L4_Fpage_t fpage = L4_FpageLog2(src_addr, l2size);
fpage += rw ? L4_FullyAccessible : L4_Readable; fpage += rw ? L4_FullyAccessible : L4_Readable;

View File

@ -44,8 +44,7 @@ namespace Genode {
*/ */
Mapping(addr_t dst_addr, addr_t src_addr, Mapping(addr_t dst_addr, addr_t src_addr,
Cache_attribute const cacheability, bool io_mem, Cache_attribute const cacheability, bool io_mem,
unsigned l2size = PAGE_SIZE_LOG2, unsigned l2size, bool rw, bool executable)
bool rw = true)
: :
_from_phys_addr(src_addr), _from_phys_addr(src_addr),
_to_virt_addr(dst_addr), _to_virt_addr(dst_addr),
@ -142,6 +141,11 @@ namespace Genode {
* Return true if page fault was a write fault * Return true if page fault was a write fault
*/ */
bool write_fault() const { return _pf_write; } bool write_fault() const { return _pf_write; }
/**
* Return true if page fault was on non-executable memory
*/
bool exec_fault() const { return false; }
}; };
} }

View File

@ -65,6 +65,7 @@ class Genode::Rm_region : public List<Rm_region>::Element
addr_t _base = 0; addr_t _base = 0;
size_t _size = 0; size_t _size = 0;
bool _write = false; bool _write = false;
bool _exec = false;
Dataspace_component *_dsc = nullptr; Dataspace_component *_dsc = nullptr;
off_t _off = 0; off_t _off = 0;
@ -80,8 +81,8 @@ class Genode::Rm_region : public List<Rm_region>::Element
Rm_region(addr_t base, size_t size, bool write, Rm_region(addr_t base, size_t size, bool write,
Dataspace_component *dsc, off_t offset, Dataspace_component *dsc, off_t offset,
Region_map_component *rm) Region_map_component *rm, bool exec)
: _base(base), _size(size), _write(write), : _base(base), _size(size), _write(write), _exec(exec),
_dsc(dsc), _off(offset), _rm(rm) { } _dsc(dsc), _off(offset), _rm(rm) { }
@ -92,6 +93,7 @@ class Genode::Rm_region : public List<Rm_region>::Element
addr_t base() const { return _base; } addr_t base() const { return _base; }
size_t size() const { return _size; } size_t size() const { return _size; }
bool write() const { return _write; } bool write() const { return _write; }
bool executable() const { return _exec; }
Dataspace_component* dataspace() const { return _dsc; } Dataspace_component* dataspace() const { return _dsc; }
off_t offset() const { return _off; } off_t offset() const { return _off; }
Region_map_component* rm() const { return _rm; } Region_map_component* rm() const { return _rm; }

View File

@ -156,7 +156,8 @@ static void print_page_fault(char const *msg,
Pager_object const &obj) Pager_object const &obj)
{ {
log(msg, " (", log(msg, " (",
pf_type == Region_map::State::WRITE_FAULT ? "WRITE" : "READ", pf_type == Region_map::State::WRITE_FAULT ? "WRITE" :
pf_type == Region_map::State::READ_FAULT ? "READ" : "EXEC",
" pf_addr=", Hex(pf_addr), " pf_ip=", Hex(pf_ip), " from ", obj, ") "); " pf_addr=", Hex(pf_addr), " pf_ip=", Hex(pf_ip), " from ", obj, ") ");
} }
@ -173,6 +174,9 @@ int Rm_client::pager(Ipc_pager &pager)
{ {
Region_map::State::Fault_type pf_type = pager.write_fault() ? Region_map::State::WRITE_FAULT Region_map::State::Fault_type pf_type = pager.write_fault() ? Region_map::State::WRITE_FAULT
: Region_map::State::READ_FAULT; : Region_map::State::READ_FAULT;
if (pager.exec_fault())
pf_type = Region_map::State::EXEC_FAULT;
addr_t pf_addr = pager.fault_addr(); addr_t pf_addr = pager.fault_addr();
addr_t pf_ip = pager.fault_ip(); addr_t pf_ip = pager.fault_ip();
@ -211,7 +215,6 @@ int Rm_client::pager(Ipc_pager &pager)
*/ */
if (pf_type == Region_map::State::WRITE_FAULT && !dsc->writable()) { if (pf_type == Region_map::State::WRITE_FAULT && !dsc->writable()) {
/* attempted there is no attachment return an error condition */
print_page_fault("attempted write at read-only memory", print_page_fault("attempted write at read-only memory",
pf_addr, pf_ip, pf_type, *this); pf_addr, pf_ip, pf_type, *this);
@ -221,6 +224,17 @@ int Rm_client::pager(Ipc_pager &pager)
return 2; return 2;
} }
if (pf_type == Region_map::State::EXEC_FAULT) {
print_page_fault("attempted exec at non-executable memory",
pf_addr, pf_ip, pf_type, *this);
/* register fault at responsible region map */
if (region_map)
region_map->fault(this, pf_addr - region_offset, pf_type);
return 3;
}
Mapping mapping = Region_map_component::create_map_item(region_map, Mapping mapping = Region_map_component::create_map_item(region_map,
region, region,
ds_offset, ds_offset,
@ -323,7 +337,7 @@ Mapping Region_map_component::create_map_item(Region_map_component *region_map,
return Mapping(dst_fault_area.base(), src_fault_area.base(), return Mapping(dst_fault_area.base(), src_fault_area.base(),
dsc->cacheability(), dsc->io_mem(), dsc->cacheability(), dsc->io_mem(),
map_size_log2, dsc->writable()); map_size_log2, dsc->writable(), region->executable());
}; };
@ -414,7 +428,7 @@ Region_map_component::attach(Dataspace_capability ds_cap, size_t size,
/* store attachment info in meta data */ /* store attachment info in meta data */
try { try {
_map.metadata(attach_at, Rm_region((addr_t)attach_at, size, true, _map.metadata(attach_at, Rm_region((addr_t)attach_at, size, true,
dsc, offset, this)); dsc, offset, this, executable));
} catch (Allocator_avl_tpl<Rm_region>::Assign_metadata_failed) { } catch (Allocator_avl_tpl<Rm_region>::Assign_metadata_failed) {