From 3fb17998a7e288589614d76a9f39c42b7a4c73b6 Mon Sep 17 00:00:00 2001 From: Michael Lotz Date: Mon, 27 Jun 2011 23:24:17 +0000 Subject: [PATCH] When resizing an area that has individual page protections (set via mprotect), we have to enlarge/shrink the array that holds them and assign a protection value for the additional pages as necessary. Otherwise we'll access invalid memory when looking up page protections for enlarged areas and get random protection values. Experienced with QEMU that sets page protections via mprotect on heap memory. When the heap was later enlarged, write access to the additional memory would result in permission denied errors and crashes. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@42330 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/system/kernel/vm/vm.cpp | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/system/kernel/vm/vm.cpp b/src/system/kernel/vm/vm.cpp index b1e60cedd6..e5879ee84c 100644 --- a/src/system/kernel/vm/vm.cpp +++ b/src/system/kernel/vm/vm.cpp @@ -4765,6 +4765,33 @@ vm_resize_area(area_id areaID, size_t newSize, bool kernel) if (status == B_OK && newSize < oldSize) status = cache->Resize(cache->virtual_base + newSize, priority); + if (status == B_OK) { + // Shrink or grow individual page protections if in use. + if (area->page_protections != NULL) { + uint32 bytes = (newSize / B_PAGE_SIZE + 1) / 2; + uint8* newProtections + = (uint8*)realloc(area->page_protections, bytes); + if (newProtections == NULL) + status = B_NO_MEMORY; + else { + area->page_protections = newProtections; + + if (oldSize < newSize) { + // init the additional page protections to that of the area + uint32 offset = (oldSize / B_PAGE_SIZE + 1) / 2; + uint32 areaProtection = area->protection + & (B_READ_AREA | B_WRITE_AREA | B_EXECUTE_AREA); + memset(area->page_protections + offset, + areaProtection | (areaProtection << 4), bytes - offset); + if ((oldSize / B_PAGE_SIZE) % 2 != 0) { + uint8& entry = area->page_protections[offset - 1]; + entry = (entry & 0x0f) | (areaProtection << 4); + } + } + } + } + } + if (status != B_OK) { // Something failed -- resize the areas back to their original size. // This can fail, too, in which case we're seriously screwed.