From 17e2377abf16c3951d7d34521ceade4d7dc31d01 Mon Sep 17 00:00:00 2001 From: pbrook Date: Mon, 9 Jun 2008 13:47:45 +0000 Subject: [PATCH] Prevent guest reusing host memory allocations. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4710 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 2 +- Makefile.target | 4 ++-- cutils.c | 35 --------------------------------- exec.c | 28 ++++++++++++++++++++++++-- linux-user/mmap.c | 46 +++++++++++++++++++++++++++++++++++++++++++ qemu-malloc.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 134 insertions(+), 40 deletions(-) create mode 100644 qemu-malloc.c diff --git a/Makefile b/Makefile index d227f91..fc56a4b 100644 --- a/Makefile +++ b/Makefile @@ -39,7 +39,7 @@ recurse-all: $(SUBDIR_RULES) ####################################################################### # BLOCK_OBJS is code used by both qemu system emulation and qemu-img -BLOCK_OBJS=cutils.o +BLOCK_OBJS=cutils.o qemu-malloc.o BLOCK_OBJS+=block-cow.o block-qcow.o aes.o block-vmdk.o block-cloop.o BLOCK_OBJS+=block-dmg.o block-bochs.o block-vpc.o block-vvfat.o BLOCK_OBJS+=block-qcow2.o block-parallels.o diff --git a/Makefile.target b/Makefile.target index ab60677..50f8c1b 100644 --- a/Makefile.target +++ b/Makefile.target @@ -387,7 +387,7 @@ LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH)el.ld endif endif -OBJS= main.o syscall.o strace.o mmap.o signal.o path.o osdep.o thunk.o \ +OBJS= main.o syscall.o strace.o mmap.o signal.o path.o thunk.o \ elfload.o linuxload.o uaccess.o LIBS+= $(AIOLIBS) ifdef TARGET_HAS_BFLT @@ -444,7 +444,7 @@ LDFLAGS+=-Wl,-segaddr,__STD_PROG_ZONE,0x1000 -image_base 0x0e000000 LIBS+=-lmx -OBJS= main.o commpage.o machload.o mmap.o osdep.o signal.o syscall.o thunk.o +OBJS= main.o commpage.o machload.o mmap.o signal.o syscall.o thunk.o OBJS+= libqemu.a diff --git a/cutils.c b/cutils.c index 738d526..9ef2fa6 100644 --- a/cutils.c +++ b/cutils.c @@ -95,38 +95,3 @@ time_t mktimegm(struct tm *tm) t += 3600 * tm->tm_hour + 60 * tm->tm_min + tm->tm_sec; return t; } - -void *get_mmap_addr(unsigned long size) -{ - return NULL; -} - -void qemu_free(void *ptr) -{ - free(ptr); -} - -void *qemu_malloc(size_t size) -{ - return malloc(size); -} - -void *qemu_mallocz(size_t size) -{ - void *ptr; - ptr = qemu_malloc(size); - if (!ptr) - return NULL; - memset(ptr, 0, size); - return ptr; -} - -char *qemu_strdup(const char *str) -{ - char *ptr; - ptr = qemu_malloc(strlen(str) + 1); - if (!ptr) - return NULL; - strcpy(ptr, str); - return ptr; -} diff --git a/exec.c b/exec.c index 64287e2..18f8f5f 100644 --- a/exec.c +++ b/exec.c @@ -263,13 +263,33 @@ static inline PageDesc *page_find_alloc(target_ulong index) { PageDesc **lp, *p; +#if TARGET_LONG_BITS > 32 + /* Host memory outside guest VM. For 32-bit targets we have already + excluded high addresses. */ + if (index > ((target_ulong)L2_SIZE * L1_SIZE * TARGET_PAGE_SIZE)) + return NULL; +#endif lp = &l1_map[index >> L2_BITS]; p = *lp; if (!p) { /* allocate if not found */ - p = qemu_malloc(sizeof(PageDesc) * L2_SIZE); - memset(p, 0, sizeof(PageDesc) * L2_SIZE); +#if defined(CONFIG_USER_ONLY) + unsigned long addr; + size_t len = sizeof(PageDesc) * L2_SIZE; + /* Don't use qemu_malloc because it may recurse. */ + p = mmap(0, len, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + *lp = p; + addr = h2g(p); + if (addr == (target_ulong)addr) { + page_set_flags(addr & TARGET_PAGE_MASK, + TARGET_PAGE_ALIGN(addr + len), + PAGE_RESERVED); + } +#else + p = qemu_mallocz(sizeof(PageDesc) * L2_SIZE); *lp = p; +#endif } return p + (index & (L2_SIZE - 1)); } @@ -1912,6 +1932,10 @@ void page_set_flags(target_ulong start, target_ulong end, int flags) flags |= PAGE_WRITE_ORG; for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) { p = page_find_alloc(addr >> TARGET_PAGE_BITS); + /* We may be called for host regions that are outside guest + address space. */ + if (!p) + return; /* if the write protection is set, then we invalidate the code inside */ if (!(p->flags & PAGE_WRITE) && diff --git a/linux-user/mmap.c b/linux-user/mmap.c index b4ca107..be1ddb9 100644 --- a/linux-user/mmap.c +++ b/linux-user/mmap.c @@ -73,6 +73,52 @@ void mmap_unlock(void) } #endif +void *qemu_vmalloc(size_t size) +{ + void *p; + unsigned long addr; + mmap_lock(); + /* Use map and mark the pages as used. */ + p = mmap(NULL, size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + + addr = (unsigned long)p; + if (addr == (target_ulong) addr) { + /* Allocated region overlaps guest address space. + This may recurse. */ + page_set_flags(addr & TARGET_PAGE_MASK, TARGET_PAGE_ALIGN(addr + size), + PAGE_RESERVED); + } + + mmap_unlock(); + return p; +} + +void *qemu_malloc(size_t size) +{ + char * p; + size += 16; + p = qemu_vmalloc(size); + *(size_t *)p = size; + return p + 16; +} + +/* We use map, which is always zero initialized. */ +void * qemu_mallocz(size_t size) +{ + return qemu_malloc(size); +} + +void qemu_free(void *ptr) +{ + /* FIXME: We should unmark the reserved pages here. However this gets + complicated when one target page spans multiple host pages, so we + don't bother. */ + size_t *p; + p = (size_t *)((char *)ptr - 16); + munmap(p, *p); +} + /* NOTE: all the constants are the HOST ones, but addresses are target. */ int target_mprotect(abi_ulong start, abi_ulong len, int prot) { diff --git a/qemu-malloc.c b/qemu-malloc.c new file mode 100644 index 0000000..16d3c2e --- /dev/null +++ b/qemu-malloc.c @@ -0,0 +1,59 @@ +/* + * malloc-like functions for system emulation. + * + * Copyright (c) 2006 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "qemu-common.h" + +void *get_mmap_addr(unsigned long size) +{ + return NULL; +} + +void qemu_free(void *ptr) +{ + free(ptr); +} + +void *qemu_malloc(size_t size) +{ + return malloc(size); +} + +void *qemu_mallocz(size_t size) +{ + void *ptr; + ptr = qemu_malloc(size); + if (!ptr) + return NULL; + memset(ptr, 0, size); + return ptr; +} + +char *qemu_strdup(const char *str) +{ + char *ptr; + ptr = qemu_malloc(strlen(str) + 1); + if (!ptr) + return NULL; + strcpy(ptr, str); + return ptr; +} -- 2.7.4