From 91f59690c41698c2dd37555cb375138525e72998 Mon Sep 17 00:00:00 2001 From: Norman Feske Date: Mon, 23 Jan 2012 21:04:57 +0100 Subject: [PATCH] Handle corner case in nested RM handling When using an ELF image as returned from the iso9660 server, such an image is represented as a managed dataspace composed of various portions of one RAM dataspace, each portion attached with a different offset. Now, when mapping the text segment of the ELF image (usually starting at 0x1000 within the image), the code mapped at 0x1000 may correspond to any offset within the RAM dataspace used by the iso9660 server. In particular, the src-fault address (the one within the RAM dataspace) may be higher than dst-fault address (somewhere just above 0x1000 where a page-fault occurred). Thereby, 'curr_rm_base' may become negative during the reverse lookup of 'Rm_client::pager'. This corner case used to let the 'Fault_area::constrain' function return an invalid fault area, and thereby let the reverse lookup fail. The improved version explicitly checks for the address overflow condition and tries to constrain the dst fault address to the largest possible log2 page within the positive address range. --- base/src/core/rm_session_component.cc | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/base/src/core/rm_session_component.cc b/base/src/core/rm_session_component.cc index ed6e6eb24..2d72277a7 100644 --- a/base/src/core/rm_session_component.cc +++ b/base/src/core/rm_session_component.cc @@ -596,8 +596,26 @@ bool Rm_session_component::reverse_lookup(addr_t dst_base, if (!*src_dataspace) return false; - /* constrain destination fault area to region */ - dst_fault_area->constrain(dst_base + region->base(), region->size()); + /* + * Constrain destination fault area to region + * + * Handle corner case when the 'dst_base' is negative. In this case, we + * determine the largest flexpage within the positive portion of the + * region. + */ + addr_t region_base = region->base() + dst_base; + size_t region_size = region->size(); + + /* check for overflow condition */ + while ((long)region_base < 0 && (long)(region_base + region_size) > 0) { + + /* increment base address by half of the region size */ + region_base += region_size >> 1; + + /* lower the region size by one log2 step */ + region_size >>= 1; + } + dst_fault_area->constrain(region_base, region_size); /* calculate source fault address relative to 'src_dataspace' */ addr_t src_fault_offset = fault_addr - region->base() + region->offset();