QEMU escape: Part 1 Environment Set-up

20180302001

Introduction

As a totally newbie in virtualization technology, this post will gives more details in setting up the testing environment for QEMU based on [1].

Environment Setup

In my tesing environment, my host OS is Ubuntu 17.10 and guest OS is Ubuntu 16.04.
Build QEMU
Use the following code to get the desired version of QEMU

$ git clone git://git.qemu-project.org/qemu.git
$ cd qemu
$ git checkout bd80b59
$ mkdir -p bin/debug/native
$ cd bin/debug/native
$ ../../../configure --target-list=x86_64-softmmu --enable-debug \
$                    --disable-werror
$ make -j 4

Before configuring the building environment, follow the steps in [2] to install all necessary libraries. At the same time, make sure the patch files are not merged into the source code.

Create Bootable Drive

Since [1] has skipped this part, so I list the steps here.

qemu-img create -f qcow2 ubuntu.img 60G
qemu-system-x86_64 -enable-kvm -boot d \
-cdrom /path/to/ubuntu-16.04.3-desktop-amd64.iso -m 1024 \
-hda /path/to/ubuntu.img

Then install the Ubuntu in QEMU like virtualbox.

Testing QEMU

Run the following command to boot the virtual machine.

/path/to/qemu-system-x86_64 -enable-kvm -m 2048 -drive \
format=qcow2,file=/path/to/ubuntu.img,if=ide,cache=writeback

To test the mapping translation from guest virtual address to host virtual address.
We first compile the following file in guest machine.

//mmu.c
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <stdlib.h>
#include <fcntl.h>
#include <assert.h>
#include <inttypes.h>

#define PAGE_SHIFT  12
#define PAGE_SIZE   (1 << PAGE_SHIFT)
#define PFN_PRESENT (1ull << 63)
#define PFN_PFN     ((1ull << 55) - 1)

int fd;

uint32_t page_offset(uint32_t addr)
{
    return addr & ((1 << PAGE_SHIFT) - 1);
}

uint64_t gva_to_gfn(void *addr)
{
	uint64_t pme, gfn;
	size_t offset;
	offset = ((uintptr_t)addr >> 9) & ~7;
	lseek(fd, offset, SEEK_SET);
	read(fd, &pme, 8);
	if (!(pme & PFN_PRESENT))
		return -1;
	gfn = pme & PFN_PFN;
	return gfn;
}

uint64_t gva_to_gpa(void *addr)
{
	uint64_t gfn = gva_to_gfn(addr);
	assert(gfn != -1);
	return (gfn << PAGE_SHIFT) | page_offset((uint64_t)addr);
}

int main()
{
	uint8_t *ptr;
	uint64_t ptr_mem;

	fd = open("/proc/self/pagemap", O_RDONLY);
	if (fd < 0) {
		perror("open");
		exit(1);
	}

	ptr = malloc(256);
	strcpy(ptr, "Where am I?");
	printf("%s\n", ptr);
	ptr_mem = gva_to_gpa(ptr);
	printf("Your physical address is at 0x%"PRIx64"\n", ptr_mem);

	return 0;
}

In QEMU, the physical memory of guest machine is a mapped region in Host virtual address space. The code above translates a virtual address in guest machine to a physical address in guest machine. For more details about page map translation please refer to [3].
Then we can use the resolved physical address as offset into the mapped region of virtual address in host machine to locate the address of the string.
The result is given below:
20180302001

The physical address of the string in guest machine is 0x47c00010. Then we attach gdb on host machine to the qemu-system-x86_64 process, dump the process mapping, locate the address of mapped region and view the string at given address.

Conclusion

As a first step, I give detailed steps for setting up the test environment for qemu escape. But running a Ubuntu desktop in QEMU seems quite slow and unnecessary. Later, I may try find alternative ways to run qemu under nographic mode.

Reference

[1] http://www.phrack.org/papers/vm-escape-qemu-case-study.html
[2] https://wiki.qemu.org/Hosts/Linux
[3] https://www.kernel.org/doc/gorman/html/understand/understand006.html
[4] https://github.com/qemu/qemu/commit/39b8e7dcaf04cbdb926b478f825b160d852752b5
[5] https://github.com/qemu/qemu/commit/837f21aacf5a714c23ddaadbbc5212f9b661e3f7

11 thoughts on “QEMU escape: Part 1 Environment Set-up

  1. Thanks for your sharing!!
    This article helps a lot since I am looking for a method to transform the GVA to HVA in QEMU.
    But I have one more question that I am wondering you may know; how to turn the guest physical address into the host virtual address?
    It seems that you find the mapping between GPA and HVA by gdb in your article, but how do you know the base(or the start) of the HVA is 0x7f913c000000?

    Like

    • Hi, eva. You can view the output of gdb. There is a memory area of size 0x80000000 in the memory area of QEMU. As explained in my post, QEMU host will allocate an area in its virtual space as the Physical address of the guest machine. Based on the size of the area, I can decide that’s the memory area allocated for guest physical address space.

      Like

      • Thanks for your reply. I still can not understand why we can know that host virtual address which memory area size is 0x80000000 is the virtual space for the Physical address of the guest machine?
        Does any file describe that QEMU uses 0x80000000 memory area?

        Like

    • I also have another question. How to use gdb on the host to set the break to the application on the guest? In your post, it seems that you set the breakpoint to the guest application of mmu.c to observe the content of host virtual address; however, I can only set the breakpoint to the qemu process from host gdb. Could you give me some suggestion of using gdb on host to set br on the guest applicaion?

      Like

      • Hi, eva.
        For your first question, please take a note in the command line in the bash file:
        qemu-system-x86_64 -enable-kvm -m 2048
        -m 2048 denotes that the memory used for the host machine is 2048MB, which is 2GB or 2^31 =0x80000000 bytes

        For your second question, just put a getchar() to make the program stop at the point. Many methods to do so…

        Like

      • Thanks for your elaborate explain!!! I understand now. One last question, if I emulate ARM Linux through qemu-system-arm, will the converting of GVA to GPA be the same as the converting methods of X86 Linux, which is the method you posted above?

        Like

  2. Thanks for your post. Iam first time qemu. how did you compile your source code in this post ?in gest machine? or Did you compile it in host machine and transfer it to guest VM?

    Like

  3. thank you for your post. your posts are really helpful for me to study qemu.

    I have a qestion. how did you compile and run your source code in this post?
    did you compile in guest vm? or compile it in host machine and transfer it to guest?

    Like

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.