From b90670417be9389f7127034646d8241281663a6c Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Wed, 15 Oct 2014 16:38:22 +0300 Subject: [PATCH] memory: fix off-by-one in to-resize cpu_pages::initialize() established the one-past-the-end page as a sentinel to avoid boundary conditions checks. cpu_pages::do_resize() considers the last page as the sentinel. This discrepancy causes the last page to be considered free by do_resize, which promptly ends up as a use-after-free page. Fix by aligning do_resize() with initialize(). --- core/memory.cc | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/core/memory.cc b/core/memory.cc index f655c54ab3..5a288f1046 100644 --- a/core/memory.cc +++ b/core/memory.cc @@ -465,15 +465,16 @@ void cpu_pages::do_resize(size_t new_size) { } ::madvise(mmap_start, mmap_size, MADV_HUGEPAGE); ::madvise(mmap_start, mmap_size, MADV_HUGEPAGE); - auto new_page_array_pages = align_up(sizeof(page[new_pages]), page_size) / page_size; + // one past last page structure is a sentinel + auto new_page_array_pages = align_up(sizeof(page[new_pages + 1]), page_size) / page_size; auto new_page_array = reinterpret_cast(allocate_large(new_page_array_pages)); std::copy(pages, pages + nr_pages, new_page_array); - // mark new last page as taken to avoid boundary conditions - new_page_array[new_pages - 1].free = false; + // mark new one-past-last page as taken to avoid boundary conditions + new_page_array[new_pages].free = false; auto old_pages = reinterpret_cast(pages); auto old_nr_pages = nr_pages; - auto old_pages_size = align_up(sizeof(page[nr_pages]), page_size); + auto old_pages_size = align_up(sizeof(page[nr_pages + 1]), page_size); pages = new_page_array; nr_pages = new_pages; auto old_pages_start = (old_pages - memory) / page_size; @@ -483,10 +484,7 @@ void cpu_pages::do_resize(size_t new_size) { old_pages_size -= page_size; } free_span(old_pages_start, old_pages_size / page_size); - // keep new last page allocated - free_span(old_nr_pages, new_pages - old_nr_pages - 1); - // free old last page - free_span(old_nr_pages - 1, 1); + free_span(old_nr_pages, new_pages - old_nr_pages); } void cpu_pages::resize(size_t new_size) {