core: restrict mapping size recursively on regions

This commit is contained in:
Alexander Boettcher 2018-05-25 18:57:38 +02:00 committed by Christian Helmuth
parent 5b8a2af979
commit 30c69e73b3
3 changed files with 32 additions and 17 deletions

View File

@ -41,8 +41,9 @@ void Pd_session_component::map(addr_t virt, addr_t size)
auto lambda = [&] (Region_map_component *region_map,
Rm_region *region,
addr_t ds_offset,
addr_t region_offset) -> addr_t
addr_t const ds_offset,
addr_t const region_offset,
addr_t const dst_region_size) -> addr_t
{
Dataspace_component * dsc = region ? region->dataspace() : nullptr;
if (!dsc) {
@ -54,7 +55,8 @@ void Pd_session_component::map(addr_t virt, addr_t size)
region,
ds_offset,
region_offset,
dsc, virt);
dsc, virt,
dst_region_size);
/* asynchronously map memory */
uint8_t err = Nova::NOVA_PD_OOM;

View File

@ -318,7 +318,8 @@ class Genode::Region_map_component : private Weak_object<Region_map_component>,
Dataspace_capability _ds_cap;
template <typename F>
auto _apply_to_dataspace(addr_t addr, F f, addr_t offset, unsigned level)
auto _apply_to_dataspace(addr_t addr, F f, addr_t offset,
unsigned level, addr_t dst_region_size)
-> typename Trait::Functor<decltype(&F::operator())>::Return_type
{
using Functor = Trait::Functor<decltype(&F::operator())>;
@ -327,13 +328,17 @@ class Genode::Region_map_component : private Weak_object<Region_map_component>,
Lock::Guard lock_guard(_lock);
/* skip further lookup when reaching the recursion limit */
if (!level) return f(this, nullptr, 0, 0);
if (!level) return f(this, nullptr, 0, 0, dst_region_size);
/* lookup region and dataspace */
Rm_region *region = _map.metadata((void*)addr);
Dataspace_component *dsc = region ? region->dataspace()
: nullptr;
if (region && dst_region_size > region->size())
dst_region_size = region->size();
/* calculate offset in dataspace */
addr_t ds_offset = region ? (addr - region->base()
+ region->offset()) : 0;
@ -342,15 +347,16 @@ class Genode::Region_map_component : private Weak_object<Region_map_component>,
Native_capability cap = dsc ? dsc->sub_rm()
: Native_capability();
if (!cap.valid()) return f(this, region, ds_offset, offset);
if (!cap.valid()) return f(this, region, ds_offset, offset, dst_region_size);
/* in case of a nested dataspace perform a recursive lookup */
auto lambda = [&] (Region_map_component *rmc) -> Return_type
{
return (!rmc) ? f(nullptr, nullptr, ds_offset, offset)
return (!rmc) ? f(nullptr, nullptr, ds_offset, offset, dst_region_size)
: rmc->_apply_to_dataspace(ds_offset, f,
offset+region->base(),
--level);
--level,
dst_region_size);
};
return _session_ep->apply(cap, lambda);
}
@ -419,7 +425,7 @@ class Genode::Region_map_component : private Weak_object<Region_map_component>,
{
enum { RECURSION_LIMIT = 5 };
return _apply_to_dataspace(addr, f, 0, RECURSION_LIMIT);
return _apply_to_dataspace(addr, f, 0, RECURSION_LIMIT, ~0UL);
}
/**
@ -438,7 +444,7 @@ class Genode::Region_map_component : private Weak_object<Region_map_component>,
addr_t ds_offset,
addr_t region_offset,
Dataspace_component *dsc,
addr_t);
addr_t, addr_t);
/**************************
** Region map interface **

View File

@ -185,8 +185,9 @@ int Rm_client::pager(Ipc_pager &pager)
auto lambda = [&] (Region_map_component *region_map,
Rm_region *region,
addr_t ds_offset,
addr_t region_offset) -> int
addr_t const ds_offset,
addr_t const region_offset,
addr_t const dst_region_size) -> int
{
Dataspace_component * dsc = region ? region->dataspace() : nullptr;
if (!dsc) {
@ -240,7 +241,8 @@ int Rm_client::pager(Ipc_pager &pager)
region,
ds_offset,
region_offset,
dsc, pf_addr);
dsc, pf_addr,
dst_region_size);
/*
* On kernels with a mapping database, the 'dsc' dataspace is a leaf
@ -312,16 +314,17 @@ void Rm_faulter::continue_after_resolved_fault()
Mapping Region_map_component::create_map_item(Region_map_component *,
Rm_region *region,
addr_t ds_offset,
addr_t region_offset,
addr_t const ds_offset,
addr_t const region_offset,
Dataspace_component *dsc,
addr_t page_addr)
addr_t const page_addr,
addr_t const dst_region_size)
{
addr_t ds_base = dsc->map_src_addr();
Fault_area src_fault_area(ds_base + ds_offset);
Fault_area dst_fault_area(page_addr);
src_fault_area.constrain(ds_base, dsc->size());
dst_fault_area.constrain(region_offset + region->base(), region->size());
dst_fault_area.constrain(region_offset + region->base(), dst_region_size);
/*
* Determine mapping size compatible with source and destination,
@ -360,6 +363,10 @@ Region_map_component::attach(Dataspace_capability ds_cap, size_t size,
/* check dataspace validity */
if (!dsc) throw Invalid_dataspace();
size_t const off = offset;
if (off >= dsc->size())
throw Region_conflict();
if (!size)
size = dsc->size() - offset;