mirror of
https://github.com/genodelabs/genode.git
synced 2025-05-29 05:34:23 +00:00
core: use copy of region metadata in detach
This patch fixes a use-after-free problem raised by the recent ability of the slab allocator to dynamically release empty slab blocks. The Rm_session_component::detach function used to rely on the assumption that the region metadata co-located with the allocator metadata of the '_map' would stay intact even after a 'free' if the region.
This commit is contained in:
parent
329ab80d1d
commit
ed37c2ecff
@ -454,24 +454,30 @@ void Rm_session_component::detach(Local_addr local_addr)
|
|||||||
Lock::Guard lock_guard(_lock);
|
Lock::Guard lock_guard(_lock);
|
||||||
|
|
||||||
/* read meta data for address */
|
/* read meta data for address */
|
||||||
Rm_region *region = _map.metadata(local_addr);
|
Rm_region *region_ptr = _map.metadata(local_addr);
|
||||||
|
|
||||||
if (!region) {
|
if (!region_ptr) {
|
||||||
PDBG("no attachment at %p", (void *)local_addr);
|
PDBG("no attachment at %p", (void *)local_addr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Dataspace_component *dsc = region->dataspace();
|
Dataspace_component *dsc = region_ptr->dataspace();
|
||||||
if (!dsc)
|
if (!dsc)
|
||||||
PWRN("Rm_region of %p may be inconsistent!", this);
|
PWRN("Rm_region of %p may be inconsistent!", this);
|
||||||
|
|
||||||
if (verbose)
|
if (verbose)
|
||||||
PDBG("detach ds %p (a=%lx,s=%zx,o=%lx) at [%lx,%lx)",
|
PDBG("detach ds %p (a=%lx,s=%zx,o=%lx) at [%lx,%lx)",
|
||||||
dsc, dsc->phys_addr(), dsc->size(), region->offset(),
|
dsc, dsc->phys_addr(), dsc->size(), region_ptr->offset(),
|
||||||
region->base(), region->base() + region->size());
|
region_ptr->base(), region_ptr->base() + region_ptr->size());
|
||||||
|
|
||||||
/* inform dataspace about detachment */
|
/* inform dataspace about detachment */
|
||||||
dsc->detached_from(region);
|
dsc->detached_from(region_ptr);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create local copy of region data because the '_map.metadata' of the
|
||||||
|
* region will become unavailable as soon as we call '_map.free' below.
|
||||||
|
*/
|
||||||
|
Rm_region region = *region_ptr;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Deallocate region on platforms that support unmap
|
* Deallocate region on platforms that support unmap
|
||||||
@ -543,20 +549,20 @@ void Rm_session_component::detach(Local_addr local_addr)
|
|||||||
if (prev_rc && prev_rc->has_same_address_space(*rc))
|
if (prev_rc && prev_rc->has_same_address_space(*rc))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
rc->unmap(dsc->core_local_addr() + region->offset(),
|
rc->unmap(dsc->core_local_addr() + region.offset(),
|
||||||
region->base(), region->size());
|
region.base(), region.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If RM session is used as nested dataspace, unmap this
|
* If RM session is used as nested dataspace, unmap this
|
||||||
* dataspace from all RM sessions.
|
* dataspace from all RM sessions.
|
||||||
*/
|
*/
|
||||||
unmap_managed(this, region, 1);
|
unmap_managed(this, ®ion, 1);
|
||||||
|
|
||||||
/* update region list */
|
/* update region list */
|
||||||
Rm_region_ref *p = _regions.first();
|
Rm_region_ref *p = _regions.first();
|
||||||
for (; p; p = p->next())
|
for (; p; p = p->next())
|
||||||
if (p->region() == region) break;
|
if (p->region() == region_ptr) break;
|
||||||
|
|
||||||
if (p) {
|
if (p) {
|
||||||
_regions.remove(p);
|
_regions.remove(p);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user