diff --git a/repos/base-nova/src/core/pd_session_support.cc b/repos/base-nova/src/core/pd_session_support.cc index a7299195ad..204fb09ad0 100644 --- a/repos/base-nova/src/core/pd_session_support.cc +++ b/repos/base-nova/src/core/pd_session_support.cc @@ -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; diff --git a/repos/base/src/core/include/region_map_component.h b/repos/base/src/core/include/region_map_component.h index 6d9e04b4c9..2ded59c6c6 100644 --- a/repos/base/src/core/include/region_map_component.h +++ b/repos/base/src/core/include/region_map_component.h @@ -318,7 +318,8 @@ class Genode::Region_map_component : private Weak_object, Dataspace_capability _ds_cap; template - 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::Return_type { using Functor = Trait::Functor; @@ -327,13 +328,17 @@ class Genode::Region_map_component : private Weak_object, 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, 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, { 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, addr_t ds_offset, addr_t region_offset, Dataspace_component *dsc, - addr_t); + addr_t, addr_t); /************************** ** Region map interface ** diff --git a/repos/base/src/core/region_map_component.cc b/repos/base/src/core/region_map_component.cc index 0d187edf81..f6717cec1c 100644 --- a/repos/base/src/core/region_map_component.cc +++ b/repos/base/src/core/region_map_component.cc @@ -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;