├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── cmake └── Modules │ ├── Findlibelf.cmake │ ├── Findlibudis86.cmake │ ├── gmock.cmake │ └── lcov.cmake ├── examples ├── CMakeLists.txt ├── proxy │ ├── CMakeLists.txt │ └── main.cc └── strace │ ├── CMakeLists.txt │ └── main.cc ├── include ├── CMakeLists.txt └── elkvm │ ├── CMakeLists.txt │ ├── config.h.cmake │ ├── debug.h │ ├── elfloader.h │ ├── elkvm-internal.h │ ├── elkvm-log.h │ ├── elkvm-rlimit.h │ ├── elkvm-udis86.h │ ├── elkvm.h │ ├── environ.h │ ├── gdbstub.h │ ├── gdt.h │ ├── heap.h │ ├── idt.h │ ├── interrupt.h │ ├── kvm.h │ ├── mapping.h │ ├── pager.h │ ├── region.h │ ├── region_manager.h │ ├── regs.h │ ├── stack.h │ ├── syscall.h │ ├── tss.h │ ├── types.h │ └── vcpu.h ├── share ├── CMakeLists.txt ├── entry.S ├── isr.S └── signal.S ├── src ├── CMakeLists.txt ├── debug.cc ├── elfloader.cc ├── environ.cc ├── gdbstub.cc ├── gdt.cc ├── heap.cc ├── idt.cc ├── interrupt.cc ├── kvm.cc ├── mapping.cc ├── pager.cc ├── region.cc ├── region_manager.cc ├── signal.cc ├── stack.cc ├── syscall-stubs.cc ├── syscall.cc ├── syscall_default.cc ├── syscalls-clock.cc ├── syscalls-mprotect.cc ├── syscalls-open.cc ├── syscalls-rlimit.cc ├── syscalls-robust_list.cc ├── syscalls-set_tid_address.cc ├── syscalls-signal.cc ├── syscalls-socket.cc ├── syscalls-statfs.cc ├── tss.cc ├── udis86.cc ├── vcpu.cc ├── vm.cc └── vm_internals.cc └── test ├── CMakeLists.txt ├── integration ├── 001-run.exp ├── 002-proxy.exp ├── 003-attach.exp ├── 004-syscalls.exp ├── hello.attach ├── hello.static ├── run_all.sh ├── syscall_test └── syscalls │ ├── Makefile │ └── syscalls.c ├── test_build.rb ├── test_elfloader.cc ├── test_mapping.cc ├── test_pager.cc ├── test_region.cc ├── test_region_manager.cc └── test_vcpu.cc /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | *.swo 3 | *.o 4 | *.lo 5 | *.a 6 | *.la 7 | *.dirstamp 8 | 9 | include/elkvm/config.h 10 | .ycm* 11 | build/ 12 | CMakeCache.txt 13 | CMakeFiles/ 14 | tags 15 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | PROJECT( libelkvm ) 2 | cmake_minimum_required(VERSION 2.8) 3 | option(libelkvm_build_tests "Build all of libelkvm's unit tests." OFF) 4 | option(libelkvm_generate_coverage "Generate coverage information for libelkvm's unit tests" OFF) 5 | 6 | find_package(Boost 1.54.0 REQUIRED 7 | COMPONENTS log) 8 | 9 | include_directories ("${PROJECT_SOURCE_DIR}/include/elkvm" "${PROJECT_SOURCE_DIR}/src" ) 10 | 11 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11 -DBOOST_LOG_DYN_LINK") 12 | add_definitions(-Wall -Wextra -Weffc++) 13 | add_definitions(-D_PREFIX_="${CMAKE_INSTALL_PREFIX}") 14 | list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/Modules) 15 | 16 | if(libelkvm_build_tests) 17 | enable_testing() 18 | include(gmock) 19 | endif() 20 | 21 | if(libelkvm_generate_coverage) 22 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage") 23 | set(CMAKE_EXE_LINKER_FLAGS="${CMAKE_EXE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage -lgcov") 24 | include(lcov) 25 | endif() 26 | 27 | SET( CMAKE_BUILD_TYPE Debug ) 28 | find_package(libelf REQUIRED) 29 | find_package(libudis86) 30 | if(LIBUDIS86_FOUND) 31 | set(HAVE_LIBUDIS86 ON) 32 | include_directories("${LIBUDIS86_INCLUDE_DIRS}") 33 | endif(LIBUDIS86_FOUND) 34 | 35 | configure_file(${CMAKE_SOURCE_DIR}/include/elkvm/config.h.cmake 36 | ${CMAKE_SOURCE_DIR}/include/elkvm/config.h) 37 | 38 | add_subdirectory( share ) 39 | add_subdirectory( include ) 40 | add_subdirectory( src ) 41 | add_subdirectory( examples ) 42 | 43 | if (libelkvm_build_tests) 44 | add_subdirectory( test ) 45 | endif() 46 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ELKVM 2 | ELKVM is a library that allows execution of an -- 64bit x86 -- ELF binary inside 3 | a virtual machine and forwards all system calls to a handler in the host user 4 | land. This can be used to inspect system calls made by a binary or modify the 5 | results of those system calls. 6 | 7 | A high-level design description can be found in my diploma thesis which is online 8 | at: https://os.inf.tu-dresden.de/papers_ps/pester-diplom.pdf 9 | 10 | Two examples on how the API can be used are found in the examples directory. 11 | 12 | # Install 13 | 14 | You need to install the following additional packages in your distribution: 15 | * check 16 | * cmake 17 | * libudis86 (built with the -fPIC compiler option) 18 | 19 | ELKVM uses cmake as a build system, you can build it in any directory you like to. 20 | In that directory you need to run the following: 21 | 22 | * cmake PATH_TO_ELKVM_TOPLEVEL_DIRECTORY 23 | * make -C include install 24 | * make 25 | * make install 26 | * ldconfig 27 | 28 | This will build the ELKVM library and an example application that just redirects all 29 | system calls to the host Linux kernel. You can find the source code for this 30 | application in the examples/ directory. 31 | 32 | # Using private versions of the tools 33 | 34 | If you have libraries (e.g. libudis86) installed in non-standard locations, 35 | you can tell cmake to search these dirs using the CPATH and LIBRARY_PATH 36 | environment variable. For example: 37 | 38 | ``` 39 | CPATH= LIBRARY_PATH= cmake 40 | ``` 41 | 42 | # Adjusting the Linux kernel 43 | 44 | You also need to add the following patch to your Linux kernel for ELKVM to work: 45 | 46 | ``` 47 | diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c 48 | index 064d0be..501e6a9 100644 49 | --- a/arch/x86/kvm/vmx.c 50 | +++ b/arch/x86/kvm/vmx.c 51 | @@ -5118,9 +5118,10 @@ static int handle_halt(struct kvm_vcpu *vcpu) 52 | 53 | static int handle_vmcall(struct kvm_vcpu *vcpu) 54 | { 55 | - skip_emulated_instruction(vcpu); 56 | - kvm_emulate_hypercall(vcpu); 57 | - return 1; 58 | +// skip_emulated_instruction(vcpu); 59 | +// kvm_emulate_hypercall(vcpu); 60 | + vcpu->run->exit_reason = KVM_EXIT_HYPERCALL; 61 | + return 0; 62 | } 63 | ``` 64 | 65 | # Building and Running the Tests 66 | 67 | ELKVM uses gmock and gtest for unit testing. By default tests are not built. If you 68 | want to build and run the tests you have to enable 69 | 70 | libelkvm_build_tests 71 | 72 | which you can do for example by running 73 | 74 | ccmake PATH_TO_ELKVM_TOPLEVEL_DIRECTORY 75 | 76 | inside your build directory. cmake will download and build gmock for you in order 77 | to run the tests. 78 | 79 | If you have lcov installed, you can generate code coverage data by running 80 | 81 | make coverage 82 | 83 | This will generate some html files, givinig you coverage information in 84 | BUILD_DIRECTORY/cov/index.html 85 | You need to enable the libelkvm_generate_coverage option to enable the generation 86 | of coverage data. Additionally this currently *only works with gcc*. 87 | 88 | # Running the examples 89 | 90 | The examples are automatically built with the normal make process. The proxy example 91 | is a simple monitor, which just forwards each system call to the host Linux kernel 92 | and returns the result to the guest binary. It can be run with: 93 | 94 | ./proxy /PATH/TO/MY/BINARY 95 | 96 | You can use the -d switch to enable debug output, which gives you all system calls made 97 | by the guest binary. The -a option takes the id of a running process and allows you to 98 | move that process into an ELKVM VM. 99 | 100 | 101 | Happy Hacking! :) 102 | -------------------------------------------------------------------------------- /cmake/Modules/Findlibelf.cmake: -------------------------------------------------------------------------------- 1 | # Locate libelf library 2 | # This module defines 3 | # LIBELF_FOUND - System has libelf 4 | # LIBELF_INCLUDE_DIRS - The libelf include directories 5 | # LIBELF_LIBRARIES - The libraries needed to use libelf 6 | 7 | # Note that the expected include convention is 8 | # #include 9 | # and not 10 | # #include 11 | # This is because the libelf includes may live in a location other than 12 | # libelf/ 13 | # 14 | # based on: 15 | # https://github.com/rlsosborne/tool_axe/blob/master/cmake/Modules/FindLibElf.cmake 16 | 17 | find_path(LIBELF_INCLUDE_DIR libelf.h PATH_SUFFIXES libelf) 18 | if("${LIBELF_INCLUDE_DIR}" MATCHES "libelf$") 19 | # If the libelf headers live in a libelf subdirectory then they might 20 | # include each other using the libelf/ prefix. Add the parent 21 | # directory to the list of include directories to make this work. 22 | string(REGEX REPLACE "libelf$" "" LIBELF_INCLUDE_DIRS 23 | "${LIBELF_INCLUDE_DIR}") 24 | set(LIBELF_INCLUDE_DIRS 25 | "${LIBELF_INCLUDE_DIRS}" 26 | "${LIBELF_INCLUDE_DIR}") 27 | else() 28 | set(LIBELF_INCLUDE_DIRS "${LIBELF_INCLUDE_DIR}") 29 | endif() 30 | find_library(LIBELF_LIBRARIES elf) 31 | 32 | include(FindPackageHandleStandardArgs) 33 | # Sets LIBELF_FOUND 34 | find_package_handle_standard_args(LibElf DEFAULT_MSG LIBELF_LIBRARIES LIBELF_INCLUDE_DIRS) 35 | 36 | mark_as_advanced(LIBELF_INCLUDE_DIRS LIBELF_LIBRARIES) 37 | -------------------------------------------------------------------------------- /cmake/Modules/Findlibudis86.cmake: -------------------------------------------------------------------------------- 1 | # - Try to find libudis 2 | # Once done this will define 3 | # 4 | # LIBUDIS86_FOUND - system has libudis86 5 | # LIBUDIS86_INCLUDE_DIRS - the libudis86 include directory 6 | # LIBUDIS86_LIBRARIES - Link these to use libudis86 7 | # LIBUDIS86_DEFINITIONS - Compiler switches required for using libudis86 8 | # 9 | # Based on: 10 | # 11 | # Copyright (c) 2008 Bernhard Walle 12 | # 13 | # Redistribution and use is allowed according to the terms of the New 14 | # BSD license. 15 | # For details see the accompanying COPYING-CMAKE-SCRIPTS file. 16 | # 17 | 18 | 19 | if (LIBUDIS86_LIBRARIES AND LIBUDIS86_INCLUDE_DIRS) 20 | set (LibUDIS86_FIND_QUIETLY TRUE) 21 | endif (LIBUDIS86_LIBRARIES AND LIBUDIS86_INCLUDE_DIRS) 22 | 23 | find_path (LIBUDIS86_INCLUDE_DIRS 24 | NAMES 25 | udis86.h 26 | PATHS 27 | /usr/include 28 | /usr/include/udis86 29 | /usr/local/include 30 | /usr/local/include/udis86 31 | /opt/local/include 32 | /opt/local/include/udis86 33 | ENV CPATH) 34 | 35 | find_library (LIBUDIS86_LIBRARIES 36 | NAMES 37 | udis86 38 | PATHS 39 | /usr/lib 40 | /usr/local/lib 41 | /opt/local/lib 42 | ENV LIBRARY_PATH 43 | ENV LD_LIBRARY_PATH) 44 | 45 | include (FindPackageHandleStandardArgs) 46 | 47 | 48 | # handle the QUIETLY and REQUIRED arguments and set LIBUDIS86_FOUND to TRUE if all listed variables are TRUE 49 | FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibUDIS86 DEFAULT_MSG 50 | LIBUDIS86_LIBRARIES 51 | LIBUDIS86_INCLUDE_DIRS) 52 | 53 | 54 | mark_as_advanced(LIBUDIS86_INCLUDE_DIRS LIBUDIS86_LIBRARIES) 55 | -------------------------------------------------------------------------------- /cmake/Modules/gmock.cmake: -------------------------------------------------------------------------------- 1 | include(ExternalProject) 2 | 3 | ExternalProject_Add(project_gmock 4 | URL https://googlemock.googlecode.com/files/gmock-1.7.0.zip 5 | PREFIX ${CMAKE_CURRENT_BINARY_DIR}/gmock-1.7.0 6 | INSTALL_COMMAND "" 7 | ) 8 | ExternalProject_Get_Property(project_gmock source_dir) 9 | ExternalProject_Get_Property(project_gmock binary_dir) 10 | set(GMOCK_DIR ${source_dir}) 11 | set(GMOCK_INSTALL_DIR ${binary_dir}) 12 | 13 | if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") 14 | # force this option to ON so that Google Test will use /MD instead of /MT 15 | # /MD is now the default for Visual Studio, so it should be our default, too 16 | option(gtest_force_shared_crt 17 | "Use shared (DLL) run-time lib even when Google Test is built as static lib." 18 | ON) 19 | endif() 20 | 21 | add_library(gmock STATIC IMPORTED) 22 | add_library(gmock_main STATIC IMPORTED) 23 | add_library(gtest STATIC IMPORTED) 24 | add_library(gtest_main STATIC IMPORTED) 25 | 26 | set_property(TARGET gmock 27 | PROPERTY IMPORTED_LOCATION ${GMOCK_INSTALL_DIR}/libgmock.a) 28 | set_property(TARGET gmock_main 29 | PROPERTY IMPORTED_LOCATION ${GMOCK_INSTALL_DIR}/libgmock_main.a) 30 | set_property(TARGET gtest 31 | PROPERTY IMPORTED_LOCATION ${GMOCK_INSTALL_DIR}/gtest/libgtest.a) 32 | set_property(TARGET gtest_main 33 | PROPERTY IMPORTED_LOCATION ${GMOCK_INSTALL_DIR}/gtest/libgtest_main.a) 34 | 35 | add_dependencies(gmock project_gmock) 36 | add_dependencies(gmock_main project_gmock) 37 | add_dependencies(gtest project_gtest) 38 | add_dependencies(gtest_main project_gtest) 39 | 40 | set_property(TARGET gtest APPEND_STRING PROPERTY COMPILE_FLAGS " -w") 41 | 42 | include_directories(SYSTEM ${GMOCK_DIR}/gtest/include 43 | ${GMOCK_DIR}/include) 44 | 45 | # 46 | # add_gmock_test( ...) 47 | # 48 | # Adds a Google Mock based test executable, , built from and 49 | # adds the test so that CTest will run it. Both the executable and the test 50 | # will be named . 51 | # 52 | function(add_gmock_test target) 53 | include_directories("${PROJECT_SOURCE_DIR}/include") 54 | add_executable(${target} ${ARGN}) 55 | target_link_libraries(${target} gmock gmock_main) 56 | target_link_libraries(${target} gtest gtest_main) 57 | target_link_libraries(${target} boost_log) 58 | target_link_libraries(${target} pthread) 59 | target_link_libraries(${target} elkvm) 60 | add_test(${target} ${target}) 61 | 62 | add_custom_command(TARGET ${target} 63 | POST_BUILD 64 | COMMAND ${target} 65 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} 66 | COMMENT "Running ${target}" VERBATIM) 67 | 68 | endfunction() 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /cmake/Modules/lcov.cmake: -------------------------------------------------------------------------------- 1 | add_custom_target(coverage) 2 | add_custom_command(TARGET coverage 3 | COMMAND mkdir -p cov 4 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) 5 | add_custom_command(TARGET coverage 6 | COMMAND lcov --directory . --zerocounters 7 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) 8 | add_custom_command(TARGET coverage 9 | COMMAND make test 10 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) 11 | add_custom_command(TARGET coverage 12 | COMMAND lcov --directory . --capture --output-file ./cov/coverage.info 13 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) 14 | add_custom_command(TARGET coverage 15 | COMMAND genhtml -o ./cov ./cov/coverage.info 16 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) 17 | add_dependencies(coverage elkvm) 18 | -------------------------------------------------------------------------------- /examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory( proxy ) 2 | add_subdirectory( strace ) 3 | -------------------------------------------------------------------------------- /examples/proxy/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | find_package(Boost 1.54.0 REQUIRED 2 | COMPONENTS log system) 3 | find_package(Threads REQUIRED) 4 | 5 | set(proxy_SRCS main.cc) 6 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -msse4 -DBOOST_LOG_DYN_LINK") 7 | include_directories("${PROJECT_SOURCE_DIR}/include") 8 | add_executable( proxy ${proxy_SRCS}) 9 | target_link_libraries( proxy elkvm ${Boost_LOG_LIBRARY} 10 | ${Boost_SYSTEM_LIBRARY} 11 | ${CMAKE_THREAD_LIBS_INIT} 12 | ) 13 | -------------------------------------------------------------------------------- /examples/strace/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | find_package(Boost 1.54.0 REQUIRED 2 | COMPONENTS log system) 3 | find_package(Threads REQUIRED) 4 | 5 | set( strace_SRC main.cc ) 6 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DBOOST_LOG_DYN_LINK") 7 | 8 | include_directories("${PROJECT_SOURCE_DIR}/include") 9 | 10 | add_executable( strace ${strace_SRC}) 11 | 12 | target_link_libraries( strace elkvm 13 | ${Boost_LOG_LIBRARY} 14 | ${CMAKE_THREAD_LIBS_INIT} 15 | ${Boost_SYSTEM_LIBRARY} 16 | ) 17 | -------------------------------------------------------------------------------- /examples/strace/main.cc: -------------------------------------------------------------------------------- 1 | // 2 | // libelkvm - A library that allows execution of an ELF binary inside a virtual 3 | // machine without a full-scale operating system 4 | // Copyright (C) 2013-2015 Florian Pester , Björn 5 | // Döbel , economic rights: Technische Universitaet 6 | // Dresden (Germany) 7 | // 8 | // This file is part of libelkvm. 9 | // 10 | // libelkvm is free software: you can redistribute it and/or modify 11 | // it under the terms of the GNU General Public License as published by 12 | // the Free Software Foundation, either version 3 of the License, or 13 | // (at your option) any later version. 14 | // 15 | // libelkvm is distributed in the hope that it will be useful, 16 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | // GNU General Public License for more details. 19 | // 20 | // You should have received a copy of the GNU General Public License 21 | // along with libelkvm. If not, see . 22 | // 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | extern char **environment; 36 | 37 | char const *syscalls[]= { 38 | "read", "write", "open", "close", "stat", "fstat", "lstat", 39 | "poll", "lseek", "mmap", "mprotect", "munmap", "brk", "rt_sigaction", 40 | "rt_sigprocmask", "rt_sigreturn", "ioctl", "pread64", "pwrite64", 41 | "readv", "writev", "access", "pipe", "select", "sched_yield", "mremap", 42 | "msync", "mincore", "madvise", "shmget", "shmat", "shmctl", "dup", "dup2", 43 | "pause", "nanosleep", "getitimer", "alarm", "setitimer", "getpid", "sendfile", 44 | "socket", "connect", "accept", "sendto", "recvfrom", "sendmsg", "recvmsg", 45 | "shutdown", "bind", "listen", "getsockname", "getpeername", "socketpair", 46 | "setsockopt", "getsockopt", "clone", "fork", "vfork", "execve", "exit", 47 | "wait4", "kill", "uname", "semget", "semop", "semctl", "shmdt", "msgget", 48 | "msgsnd", "msgrcv", "msgctl", "fcntl", "flock", "fsync", "fdatasync", 49 | "truncate", "ftruncate", "getdents", "getcwd", "chdir", "fchdir", "rename", 50 | "mkdir", "rmdir", "creat", "link", "unlink", "symlink", "readlink", "chmod", 51 | "fchmod", "chown", "fchown", "lchown", "umask", "gettimeofday", "getrlimit", 52 | "getrusage", "sysinfo", "times", "ptrace", "getuid", "syslog", "getgid", 53 | "setuid", "setgid", "geteuid", "getegid", "setpgid", "getppid", "getpgrp", 54 | "setsid", "setreuid", "setregid", "getgroups", "setgroups", "setresuid", 55 | "getresuid", "setresgid", "getresgid", "getpgid", "setfsuid", "setfsgid", 56 | "getsid", "capget", "capset", "rt_sigpending", "rt_sigtimedwait", 57 | "rt_sigqueueinfo", "rt_sigsuspend", "sigaltstack", "utime", "mknod", 58 | "uselib", "personality", "ustat", "statfs", "fstatfs", "sysfs", "getpriority", 59 | "setpriority", "sched_setparam", "sched_getparam", "sched_setscheduler", 60 | "sched_getscheduler", "sched_get_priority_max", "sched_get_priority_min", 61 | "sched_rr_get_interval", "mlock", "munlock", "mlockall", "munlockall", 62 | "vhangup", "modify_ldt", "pivot_root", "_sysctl", "prctl", "arch_prctl", 63 | "adjtimex", "setrlimit", "chroot", "sync", "acct", "settimeofday", "mount", 64 | "umount2", "swapon", "swapoff", "reboot", "sethostname", "setdomainname", 65 | "iopl", "ioperm", "create_module", "init_module", "delete_module", 66 | "get_kernel_syms", "query_module", "quotactl", "nfsservctl", "getpmsg", 67 | "putpmsg", "afs_syscall", "tuxcall", "security", "gettid", "readahead", 68 | "setxattr", "lsetxattr", "fsetxattr", "getxattr", "lgetxattr", 69 | "fgetxattr", "listxattr", "llistxattr", "flistxattr", "removexattr", 70 | "lremovexattr", "fremovexattr", "tkill", "time", "futex", "sched_setaffinity", 71 | "sched_getaffinity", "set_thread_area", "io_setup", "io_destroy", "io_getevents", 72 | "io_submit", "io_cancel", "get_thread_area", "lookup_dcookie", "epoll_create", 73 | "epoll_ctl_old", "epoll_wait_old", "remap_file_pages", "getdents64", 74 | "set_tid_address", "restart_syscall", "semtimedop", "fadvise64", 75 | "timer_create", "timer_settime", "timer_gettime", "timer_getoverrun", 76 | "timer_delete", "clock_settime", "clock_gettime", "clock_getres", 77 | "clock_nanosleep", "exit_group", "epoll_wait", "epoll_ctl", "tgkill", 78 | "utimes", "vserver", "mbind", "set_mempolicy", "get_mempolicy", 79 | "mq_open", "mq_unlink", "mq_timedsend", "mq_timedreceive", "mq_notify", 80 | "mq_getsetattr", "kexec_load", "waitid", "add_key", "request_key", "keyctl", 81 | "ioprio_set", "ioprio_get", "inotify_init", "inotify_add_watch", 82 | "inotify_rm_watch", "migrate_pages", "openat", "mkdirat", "mknodat", 83 | "fchownat", "futimesat", "newfstatat", "unlinkat", "renameat", "linkat", 84 | "symlinkat", "readlinkat", "fchmodat", "faccessat", "pselect6", "ppoll", 85 | "unshare", "set_robust_list", "get_robust_list", "splice", "tee", "sync_file_range", 86 | "vmsplice", "move_pages", "utimensat", "epoll_pwait", "signalfd", "timerfd_create", 87 | "eventfd", "fallocate", "timerfd_settime", "timerfd_gettime", "accept4", "signalfd4", 88 | "eventfd2", "epoll_create1", "dup3", "pipe2", "inotify_init1", "preadv", "pwritev", 89 | "rt_tgsigqueueinfo", "perf_event_open", "recvmmsg", "fanotify_init", "fanotify_mark", 90 | "prlimit64", "name_to_handle_at", "open_by_handle_at", "clock_adjtime", "syncfs", 91 | "sendmmsg", "setns", "getcpu", "process_vm_readv", "process_vm_writev", "kcmp", 92 | "finit_module", "sched_setattr", "sched_getattr", 93 | }; 94 | 95 | static long 96 | strace_pre_handler(Elkvm::VM* vm __attribute__((unused)), 97 | const std::shared_ptr& vcpu, 98 | int eventtype) 99 | { 100 | if (eventtype != ELKVM_HYPERCALL_SYSCALL) 101 | return 0; 102 | 103 | INFO() << "[ELKVM] System call '" 104 | << syscalls[vcpu->get_reg(Elkvm::Reg_t::rax)] 105 | << "'"; 106 | return 0; 107 | } 108 | 109 | 110 | static long 111 | strace_post_handler(Elkvm::VM* vm __attribute__((unused)), 112 | const std::shared_ptr& vcpu, 113 | int eventtype) 114 | { 115 | if (eventtype != ELKVM_HYPERCALL_SYSCALL) 116 | return 0; 117 | 118 | INFO() << "[ELKVM] = 0x" << std::hex 119 | << vcpu->get_reg(Elkvm::Reg_t::rax); 120 | return 0; 121 | } 122 | 123 | int main(int argc, char *argv[]) 124 | { 125 | if (argc < 2) { 126 | ERROR() << "No program argument given. Need at least a binary name."; 127 | abort(); 128 | } 129 | 130 | INFO() << "[ELKVM] Launching" << std::endl; 131 | 132 | Elkvm::elkvm_opts opts; 133 | int err = elkvm_init(&opts, argc-1, &argv[1], environ); 134 | if (err) { 135 | ERROR() << "ERROR initializing ELKVM: " << strerror(-err); 136 | return 1; 137 | } 138 | 139 | Elkvm::hypercall_handlers strace_handlers = { 140 | .pre_handler = strace_pre_handler, 141 | .post_handler = strace_post_handler 142 | }; 143 | 144 | std::shared_ptr vm = elkvm_vm_create(&opts, argv[1], 1, &strace_handlers); 145 | if (vm == nullptr) { 146 | ERROR() << "ERROR creating VM: " << strerror(errno); 147 | return 1; 148 | } 149 | 150 | err = vm->run(); 151 | if (err) { 152 | ERROR() << "Error running vCPU: " << strerror(-err); 153 | return 1; 154 | } 155 | 156 | err = elkvm_cleanup(&opts); 157 | if (err) { 158 | ERROR() << "Error during cleanup: " << strerror(-err); 159 | return 1; 160 | } 161 | 162 | INFO() "[ELVKM] Terminating successfully."; 163 | 164 | return 0; 165 | } 166 | -------------------------------------------------------------------------------- /include/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory( elkvm ) 2 | -------------------------------------------------------------------------------- /include/elkvm/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | SET( libelkvm_MOC_HEADERS 2 | config.h 3 | debug.h 4 | elfloader.h 5 | elkvm.h 6 | elkvm-internal.h 7 | elkvm-log.h 8 | elkvm-rlimit.h 9 | elkvm-udis86.h 10 | environ.h 11 | gdbstub.h 12 | gdt.h 13 | heap.h 14 | idt.h 15 | interrupt.h 16 | kvm.h 17 | mapping.h 18 | pager.h 19 | region.h 20 | region_manager.h 21 | regs.h 22 | stack.h 23 | syscall.h 24 | tss.h 25 | types.h 26 | vcpu.h 27 | ) 28 | 29 | install (FILES 30 | ${libelkvm_MOC_HEADERS} 31 | DESTINATION include/elkvm) 32 | -------------------------------------------------------------------------------- /include/elkvm/config.h.cmake: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #cmakedefine HAVE_LIBUDIS86 4 | -------------------------------------------------------------------------------- /include/elkvm/debug.h: -------------------------------------------------------------------------------- 1 | /* * libelkvm - A library that allows execution of an ELF binary inside a virtual 2 | * machine without a full-scale operating system 3 | * Copyright (C) 2013-2015 Florian Pester , Björn 4 | * Döbel , economic rights: Technische Universitaet 5 | * Dresden (Germany) 6 | * 7 | * This file is part of libelkvm. 8 | * 9 | * libelkvm is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * libelkvm is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with libelkvm. If not, see . 21 | */ 22 | 23 | #pragma once 24 | 25 | #include 26 | 27 | int elkvm_handle_debug(Elkvm::VM *); 28 | 29 | namespace Elkvm { 30 | std::ostream &print_memory(std::ostream &os, const VM &vm, guestptr_t addr, 31 | size_t sz); 32 | 33 | //namespace Elkvm 34 | } 35 | -------------------------------------------------------------------------------- /include/elkvm/elfloader.h: -------------------------------------------------------------------------------- 1 | /* * libelkvm - A library that allows execution of an ELF binary inside a virtual 2 | * machine without a full-scale operating system 3 | * Copyright (C) 2013-2015 Florian Pester , Björn 4 | * Döbel , economic rights: Technische Universitaet 5 | * Dresden (Germany) 6 | * 7 | * This file is part of libelkvm. 8 | * 9 | * libelkvm is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * libelkvm is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with libelkvm. If not, see . 21 | */ 22 | 23 | #pragma once 24 | 25 | #include 26 | #include 27 | 28 | #include 29 | #include 30 | #include 31 | 32 | #include 33 | 34 | 35 | namespace Elkvm { 36 | 37 | constexpr guestptr_t loader_base_addr = 0x1000000; 38 | struct Elf_auxv { 39 | uint64_t at_phdr; 40 | uint64_t at_phent; 41 | uint64_t at_phnum; 42 | uint64_t at_entry; 43 | uint64_t at_base; 44 | bool valid; 45 | }; 46 | 47 | class elf_file { 48 | private: 49 | int _fd; 50 | 51 | public: 52 | elf_file(std::string pathname); 53 | ~elf_file(); 54 | size_t read(char *buf, size_t bytes, off64_t off = 0) const; 55 | ssize_t read_segment(char *buf, size_t bytes, off64_t off) const; 56 | int fd() const; 57 | }; 58 | 59 | class elf_ptr { 60 | private: 61 | Elf *_ptr; 62 | 63 | public: 64 | elf_ptr(const elf_file &file); 65 | ~elf_ptr(); 66 | 67 | elf_ptr(const elf_ptr &) = delete; 68 | elf_ptr operator=(const elf_ptr &) = delete; 69 | 70 | Elf_Kind get_elf_kind() const; 71 | int get_class() const; 72 | GElf_Ehdr get_ehdr() const; 73 | size_t get_phdrnum() const; 74 | GElf_Phdr get_phdr(unsigned i) const; 75 | }; 76 | 77 | class ElfBinary { 78 | private: 79 | std::unique_ptr _ldr; 80 | std::shared_ptr _rm; 81 | HeapManager &_hm; 82 | 83 | /* this needs to be a size_t because of the decl 84 | * of elf_getphdrnum */ 85 | size_t _num_phdrs; 86 | bool _statically_linked; 87 | bool _shared_object; 88 | bool _is_ldr; 89 | std::string _loader; 90 | guestptr_t _entry_point; 91 | struct Elf_auxv _auxv; 92 | 93 | bool is_valid_elf_kind(const elf_ptr &eptr) const; 94 | bool is_valid_elf_class(const elf_ptr &eptr) const; 95 | void initialize_interpreter(const elf_file &file, GElf_Phdr phdr); 96 | bool check_phdr_for_interpreter(GElf_Phdr phdr) const; 97 | int check_elf(const elf_file &file, const elf_ptr &eptr); 98 | int parse_program(const elf_file &file, const elf_ptr &eptr); 99 | void get_dynamic_loader(const elf_file &file, GElf_Phdr phdr); 100 | void load_phdr(GElf_Phdr phdr, const elf_file &file, const elf_ptr &eptr); 101 | int load_program_header(GElf_Phdr phdr, const Region ®ion, const elf_file &file, 102 | const elf_ptr &eptr); 103 | void pad_begin(GElf_Phdr phdr, const Region ®ion, const elf_file &file, 104 | const elf_ptr &eptr); 105 | void read_segment(GElf_Phdr phdr, const Region ®ion, 106 | const elf_file &file); 107 | void pad_end(GElf_Phdr phdr, const Region ®ion, const elf_file &file, 108 | const elf_ptr &eptr); 109 | void pad_text_begin(const Region ®ion, size_t padsize, const elf_ptr &eptr); 110 | void pad_text_end(void *host_p, size_t padsize, const elf_file &file, 111 | const elf_ptr &eptr); 112 | void pad_data_begin(const Region ®ion, size_t padsize, const elf_file &file, 113 | const elf_ptr &eptr); 114 | void load_dynamic(); 115 | GElf_Phdr text_header; 116 | GElf_Phdr find_header(const elf_ptr &eptr, unsigned flags); 117 | GElf_Phdr find_data_header(const elf_ptr &eptr); 118 | GElf_Phdr find_text_header(const elf_ptr &eptr); 119 | 120 | public: 121 | ElfBinary(std::string pathname, std::shared_ptr rm, 122 | HeapManager &hm, bool is_ldr = false); 123 | 124 | ElfBinary(ElfBinary const&) = delete; 125 | ElfBinary& operator=(ElfBinary const&) = delete; 126 | 127 | int load_binary(std::string pathname); 128 | guestptr_t get_entry_point(); 129 | const struct Elf_auxv &get_auxv() const; 130 | bool is_dynamically_linked() const; 131 | std::string get_loader() const; 132 | }; 133 | 134 | ptopt_t get_pager_opts_from_phdr_flags(int flags); 135 | 136 | //namespace Elkvm 137 | } 138 | 139 | -------------------------------------------------------------------------------- /include/elkvm/elkvm-internal.h: -------------------------------------------------------------------------------- 1 | /* * libelkvm - A library that allows execution of an ELF binary inside a virtual 2 | * machine without a full-scale operating system 3 | * Copyright (C) 2013-2015 Florian Pester , Björn 4 | * Döbel , economic rights: Technische Universitaet 5 | * Dresden (Germany) 6 | * 7 | * This file is part of libelkvm. 8 | * 9 | * libelkvm is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * libelkvm is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with libelkvm. If not, see . 21 | */ 22 | 23 | #pragma once 24 | 25 | #if 1 26 | #include 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | namespace Elkvm { 34 | 35 | bool operator==(const VM &lhs, const VM &rhs); 36 | unsigned get_hypercall_type(const std::shared_ptr&); 37 | 38 | //namespace Elkvm 39 | } 40 | #endif 41 | -------------------------------------------------------------------------------- /include/elkvm/elkvm-log.h: -------------------------------------------------------------------------------- 1 | /* * libelkvm - A library that allows execution of an ELF binary inside a virtual 2 | * machine without a full-scale operating system 3 | * Copyright (C) 2013-2015 Florian Pester , Björn 4 | * Döbel , economic rights: Technische Universitaet 5 | * Dresden (Germany) 6 | * 7 | * This file is part of libelkvm. 8 | * 9 | * libelkvm is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * libelkvm is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with libelkvm. If not, see . 21 | */ 22 | 23 | #pragma once 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #define LOG_RED "\033[31;1m" 34 | #define LOG_GREEN "\033[32m" 35 | #define LOG_YELLOW "\033[33m" 36 | #define LOG_BLUE "\033[34;1m" 37 | #define LOG_MAGENTA "\033[35;1m" 38 | #define LOG_CYAN "\033[36m" 39 | #define LOG_RESET "\033[0m" 40 | 41 | #define LOG_GUEST_HOST(guest, host) (void*)guest << " (" << (void*)host << ")" 42 | #define LOG_DEC_HEX(val) std::dec << val << " (" << std::hex << "0x" << val << ")" 43 | 44 | struct ElkvmLog 45 | { 46 | boost::log::sources::logger_mt logger; 47 | 48 | ElkvmLog() 49 | : logger() 50 | { 51 | auto sink = boost::log::add_console_log(); 52 | boost::log::formatter fm = 53 | boost::log::expressions::stream 54 | << "[" 55 | << boost::log::expressions::format_date_time< boost::posix_time::ptime >("TimeStamp", "%H:%M:%S.%f") 56 | << "] " 57 | << boost::log::expressions::message 58 | << LOG_RESET; 59 | ; 60 | boost::log::add_common_attributes(); 61 | sink->set_formatter(fm); 62 | }; 63 | }; 64 | 65 | extern ElkvmLog globalElkvmLogger; 66 | 67 | #define MY_LOG_PREFIX BOOST_LOG(globalElkvmLogger.logger) << LOG_YELLOW \ 68 | << "(" << std::setw(24) << __func__ << ") " << LOG_RESET 69 | 70 | #define DBG() MY_LOG_PREFIX 71 | #define INFO() MY_LOG_PREFIX 72 | #define ERROR() MY_LOG_PREFIX << LOG_RED 73 | 74 | /* TSC measurement stuff */ 75 | 76 | static __inline__ __attribute__((used)) 77 | unsigned long long rdtsc(void) 78 | { 79 | unsigned hi, lo; 80 | __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi)); 81 | return ( (unsigned long long)lo)|( ((unsigned long long)hi)<<32 ); 82 | } 83 | 84 | 85 | #define TSC_SAMPLE_DATA(sample_size) \ 86 | static const int _tsc_count = (sample_size); /* number of samples */ \ 87 | static uint64_t _tsc[_tsc_count]; /* sample array */ \ 88 | static int _tsc_idx = 0; /* next sample to save */ \ 89 | static int _tsc_counter = 0; /* number of sampling intervals */ \ 90 | uint64_t _tsc1, _tsc2; /* tsc sample for this call */ 91 | 92 | #define TSC_START \ 93 | _tsc1 = rdtsc(); /* entry TSC measure */ 94 | 95 | #define TSC_END do { \ 96 | _tsc2 = rdtsc(); \ 97 | _tsc[_tsc_idx++] = _tsc2 - _tsc1; \ 98 | if (_tsc_idx == _tsc_count) { \ 99 | uint64_t _sum = 0; \ 100 | _tsc_counter += 1; \ 101 | for (unsigned i = 0; i < _tsc_count; ++i) { \ 102 | _sum += _tsc[i]; \ 103 | } \ 104 | INFO() << "[" << _tsc_counter << "] " << _tsc_count \ 105 | << " timestamps: " << std::dec \ 106 | << _sum / _tsc_count << " cycles per call."; \ 107 | _tsc_idx = 0; \ 108 | } \ 109 | } while (0) 110 | -------------------------------------------------------------------------------- /include/elkvm/elkvm-rlimit.h: -------------------------------------------------------------------------------- 1 | /* * libelkvm - A library that allows execution of an ELF binary inside a virtual 2 | * machine without a full-scale operating system 3 | * Copyright (C) 2013-2015 Florian Pester , Björn 4 | * Döbel , economic rights: Technische Universitaet 5 | * Dresden (Germany) 6 | * 7 | * This file is part of libelkvm. 8 | * 9 | * libelkvm is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * libelkvm is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with libelkvm. If not, see . 21 | */ 22 | 23 | #pragma once 24 | 25 | #include 26 | 27 | #include 28 | #include 29 | 30 | namespace Elkvm { 31 | 32 | class rlimit { 33 | private: 34 | std::array _rlimits; 35 | 36 | public: 37 | rlimit(); 38 | const struct ::rlimit *get(int i) const; 39 | void set(int i, const struct ::rlimit *val); 40 | }; 41 | 42 | //namespace Elkvm 43 | } 44 | -------------------------------------------------------------------------------- /include/elkvm/elkvm-udis86.h: -------------------------------------------------------------------------------- 1 | /* * libelkvm - A library that allows execution of an ELF binary inside a virtual 2 | * machine without a full-scale operating system 3 | * Copyright (C) 2013-2015 Florian Pester , Björn 4 | * Döbel , economic rights: Technische Universitaet 5 | * Dresden (Germany) 6 | * 7 | * This file is part of libelkvm. 8 | * 9 | * libelkvm is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * libelkvm is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with libelkvm. If not, see . 21 | */ 22 | 23 | #pragma once 24 | #include 25 | 26 | #include 27 | 28 | #ifdef HAVE_LIBUDIS86 29 | #include 30 | #endif 31 | 32 | #include 33 | 34 | namespace Elkvm { 35 | 36 | class UDis { 37 | private: 38 | const unsigned bits = 64; 39 | const size_t disassembly_size = 40; 40 | 41 | #ifdef HAVE_LIBUDIS86 42 | ud_t ud_obj; 43 | #endif 44 | 45 | public: 46 | UDis(const uint8_t *ptr); 47 | int disassemble(); 48 | std::string next_insn(); 49 | }; 50 | 51 | //namespace Elkvm 52 | } 53 | -------------------------------------------------------------------------------- /include/elkvm/environ.h: -------------------------------------------------------------------------------- 1 | /* * libelkvm - A library that allows execution of an ELF binary inside a virtual 2 | * machine without a full-scale operating system 3 | * Copyright (C) 2013-2015 Florian Pester , Björn 4 | * Döbel , economic rights: Technische Universitaet 5 | * Dresden (Germany) 6 | * 7 | * This file is part of libelkvm. 8 | * 9 | * libelkvm is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * libelkvm is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with libelkvm. If not, see . 21 | */ 22 | 23 | #pragma once 24 | 25 | #include 26 | 27 | #include 28 | 29 | #include 30 | #include 31 | 32 | namespace Elkvm { 33 | class VCPU; 34 | 35 | class EnvRegion { 36 | private: 37 | std::shared_ptr _region; 38 | off64_t _offset; 39 | 40 | public: 41 | EnvRegion(std::shared_ptr r); 42 | guestptr_t write_str(const std::string &str); 43 | }; 44 | 45 | class Environment { 46 | private: 47 | EnvRegion _region; 48 | std::vector _auxv; 49 | std::vector _env; 50 | std::vector _argv; 51 | int _argc; 52 | 53 | const ElfBinary &binary; 54 | 55 | Elf64_auxv_t *calc_auxv(char **env) const; 56 | void fill_argv(char **argv); 57 | void fill_env(char **env); 58 | void fill_auxv(Elf64_auxv_t *auxv); 59 | void fix_auxv_dynamic_values(); 60 | 61 | bool treat_as_int_type(int type) const; 62 | bool ignored_type(int type) const; 63 | void push_str_copy(VCPU& vcpu, const std::string &str); 64 | off64_t copy_and_push_str_arr_p(VCPU& vcpu, off64_t offset, char **str) const; 65 | 66 | void push_auxv_raw(VCPU &vcpu); 67 | 68 | void push_auxv(VCPU& vcpu); 69 | void push_env(VCPU& vcpu); 70 | void push_argv(VCPU& vcpu); 71 | void push_argc(VCPU& vcpu) const; 72 | 73 | public: 74 | Environment(const ElfBinary &bin, std::shared_ptr reg, int argc, 75 | char **argv, char **env); 76 | Environment(Environment const&) = delete; 77 | Environment& operator=(Environment const&) = delete; 78 | int create(VCPU &vcpu); 79 | 80 | }; 81 | 82 | //namespace Elkvm 83 | } 84 | -------------------------------------------------------------------------------- /include/elkvm/gdbstub.h: -------------------------------------------------------------------------------- 1 | /* * libelkvm - A library that allows execution of an ELF binary inside a virtual 2 | * machine without a full-scale operating system 3 | * Copyright (C) 2013-2015 Florian Pester , Björn 4 | * Döbel , economic rights: Technische Universitaet 5 | * Dresden (Germany) 6 | * 7 | * This file is part of libelkvm. 8 | * 9 | * libelkvm is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * libelkvm is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with libelkvm. If not, see . 21 | */ 22 | 23 | #pragma once 24 | 25 | #define GDBSTUB_EXECUTION_BREAKPOINT (0xac1) 26 | #define GDBSTUB_TRACE (0xac2) 27 | #define GDBSTUB_USER_BREAK (0xac3) 28 | 29 | typedef unsigned char Bit8u; 30 | typedef unsigned short Bit16u; 31 | typedef unsigned short bx_bool; 32 | typedef unsigned long Bit32u; 33 | typedef uint64_t Bit64u; 34 | 35 | #define FMT_ADDRX64 "%016lx" 36 | #define GDBSTUB_STOP_NO_REASON -1 37 | 38 | namespace Elkvm { 39 | namespace Debug { 40 | 41 | void hex2mem(char* buf, unsigned char* mem, int count); 42 | char* mem2hex(const Bit8u* mem, char* buf, int count); 43 | 44 | class gdb_session { 45 | private: 46 | const int port = 1234; 47 | const int base = 16; 48 | 49 | int listen_socket_fd; 50 | int socket_fd; 51 | 52 | unsigned char read_cmd_into_buffer(char *buffer); 53 | bool validate_checksum(unsigned char checksum); 54 | void get_command(char* buffer); 55 | 56 | void handle_query(char buffer[255]); 57 | void handle_continue(char buffer[255], VM &vm); 58 | void handle_singlestep(VM &vm); 59 | void handle_memwrite(VM &vm, char buffer[255]); 60 | void handle_memread(VM &vm, char buffer[255]); 61 | void handle_regread(VM &vm); 62 | void handle_qm(); 63 | 64 | void put_reply(const char* buffer); 65 | void put_sigtrap_reply(); 66 | void put_debug_char(char ch); 67 | void flush_debug_buffer(); 68 | char get_debug_char(); 69 | void write_signal(char* buf, int signal); 70 | 71 | void debug_loop(Elkvm::VM &vm); 72 | void wait_for_connection(); 73 | 74 | public: 75 | gdb_session(Elkvm::VM &vm); 76 | }; 77 | 78 | //namespace Debug 79 | } 80 | //namespace Elkvm 81 | } 82 | -------------------------------------------------------------------------------- /include/elkvm/gdt.h: -------------------------------------------------------------------------------- 1 | /* * libelkvm - A library that allows execution of an ELF binary inside a virtual 2 | * machine without a full-scale operating system 3 | * Copyright (C) 2013-2015 Florian Pester , Björn 4 | * Döbel , economic rights: Technische Universitaet 5 | * Dresden (Germany) 6 | * 7 | * This file is part of libelkvm. 8 | * 9 | * libelkvm is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * libelkvm is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with libelkvm. If not, see . 21 | */ 22 | 23 | #pragma once 24 | 25 | #include 26 | 27 | #include 28 | #include 29 | 30 | std::shared_ptr 31 | elkvm_gdt_setup(Elkvm::RegionManager &rm, std::shared_ptr vcpu); 32 | 33 | struct elkvm_gdt_segment_descriptor { 34 | uint16_t limit1; 35 | uint16_t base1; 36 | uint8_t base2; 37 | uint8_t access; 38 | uint8_t limit2_flags; 39 | uint8_t base3; 40 | }; 41 | 42 | #define GDT_SEGMENT_WRITEABLE 2 43 | #define GDT_SEGMENT_READABLE 2 44 | #define GDT_SEGMENT_DIRECTION_BIT 4 45 | #define GDT_SEGMENT_EXECUTABLE 8 46 | #define GDT_SEGMENT_BIT 16 47 | #define GDT_SEGMENT_PRIVILEDGE_USER 96 48 | #define GDT_SEGMENT_PRESENT 128 49 | #define GDT_SEGMENT_LONG 2 50 | #define GDT_SEGMENT_PROTECTED_32 4 51 | #define GDT_SEGMENT_PAGE_GRANULARITY 8 52 | 53 | /* 54 | * we have 2 code segments, 2 stack segments, a data segment and a 55 | * tss segment 56 | * make room for an additional entry, because the entry for 57 | * tss has twice the size in long mode 58 | */ 59 | #define GDT_NUM_ENTRIES 8 60 | 61 | int elkvm_gdt_create_segment_descriptor(struct elkvm_gdt_segment_descriptor *, 62 | uint32_t, uint32_t, uint8_t, uint8_t); 63 | 64 | static inline 65 | uint32_t gdt_base(struct elkvm_gdt_segment_descriptor *entry) { 66 | return entry->base1 | ((uint32_t)entry->base2 << 16) | 67 | ((uint32_t)entry->base3 << 24); 68 | } 69 | 70 | static inline 71 | uint32_t gdt_limit(struct elkvm_gdt_segment_descriptor *entry) { 72 | return entry->limit1 | ((uint32_t)(entry->limit2_flags & 0xF) << 16); 73 | } 74 | 75 | static inline 76 | uint8_t gdt_flags(struct elkvm_gdt_segment_descriptor *entry) { 77 | return entry->limit2_flags >> 4; 78 | } 79 | -------------------------------------------------------------------------------- /include/elkvm/heap.h: -------------------------------------------------------------------------------- 1 | /* * libelkvm - A library that allows execution of an ELF binary inside a virtual 2 | * machine without a full-scale operating system 3 | * Copyright (C) 2013-2015 Florian Pester , Björn 4 | * Döbel , economic rights: Technische Universitaet 5 | * Dresden (Germany) 6 | * 7 | * This file is part of libelkvm. 8 | * 9 | * libelkvm is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * libelkvm is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with libelkvm. If not, see . 21 | */ 22 | 23 | #pragma once 24 | 25 | #include 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | #include 32 | #include 33 | #include 34 | 35 | namespace Elkvm { 36 | class HeapManager { 37 | private: 38 | std::vector mappings_for_brk; 39 | std::vector mappings_for_mmap; 40 | std::shared_ptr _rm; 41 | guestptr_t curbrk; 42 | 43 | int grow(size_t sz); 44 | int shrink(guestptr_t newbrk); 45 | void unmap_to_new_size(Mapping &m, size_t new_size); 46 | guestptr_t create_resized_mapping(Mapping &m, size_t new_size); 47 | 48 | void slice_region(Mapping &m, off_t off, size_t len); 49 | 50 | void free_unused_mappings(guestptr_t brk); 51 | 52 | public: 53 | HeapManager(std::shared_ptr rm) : 54 | mappings_for_brk(), 55 | mappings_for_mmap(), 56 | _rm(rm), 57 | curbrk(0x0) 58 | {} 59 | int init(std::shared_ptr data, size_t sz); 60 | int brk(guestptr_t newbrk); 61 | guestptr_t get_brk() const { return curbrk; }; 62 | bool contains_address(guestptr_t addr) const; 63 | bool brk_contains_address(guestptr_t addr) const 64 | { return (mappings_for_brk.front().guest_address() <= addr) 65 | && (addr < curbrk); } 66 | 67 | Mapping &find_mapping(guestptr_t addr); 68 | Mapping &find_mapping(void *host_p); 69 | bool address_mapped(guestptr_t addr) const; 70 | 71 | Mapping &create_mapping(guestptr_t addr, size_t length, int prot, int flags, 72 | int fd, off_t off, std::shared_ptr r = nullptr); 73 | Mapping &get_mapping(guestptr_t addr, size_t length, int prot, int flags, 74 | int fd, off_t off); 75 | 76 | void free_mapping(Mapping &mapping); 77 | 78 | void dump_mappings() const; 79 | 80 | int map(Mapping &m); 81 | guestptr_t remap(Mapping &m, guestptr_t new_address_p, size_t new_size, int flags); 82 | int unmap(Mapping &m); 83 | int unmap(Mapping &m, guestptr_t unmap_addr, unsigned pages); 84 | 85 | void slice(Mapping &m, guestptr_t slice_base, size_t len); 86 | void slice_begin(Mapping &m, size_t len); 87 | void slice_center(Mapping &m, off_t off, size_t len); 88 | void slice_end(Mapping &m, guestptr_t slice_base); 89 | }; 90 | 91 | //namespace Elkvm 92 | } 93 | -------------------------------------------------------------------------------- /include/elkvm/idt.h: -------------------------------------------------------------------------------- 1 | /* * libelkvm - A library that allows execution of an ELF binary inside a virtual 2 | * machine without a full-scale operating system 3 | * Copyright (C) 2013-2015 Florian Pester , Björn 4 | * Döbel , economic rights: Technische Universitaet 5 | * Dresden (Germany) 6 | * 7 | * This file is part of libelkvm. 8 | * 9 | * libelkvm is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * libelkvm is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with libelkvm. If not, see . 21 | */ 22 | 23 | #pragma once 24 | 25 | #include 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | int elkvm_idt_setup(Elkvm::RegionManager &rm, std::shared_ptr vcpu, 32 | Elkvm::elkvm_flat *); 33 | 34 | struct kvm_idt_entry { 35 | uint16_t offset1; 36 | uint16_t selector; 37 | /* 38 | * in long mode lower three bits of idx are 39 | * used for ist index 40 | */ 41 | uint8_t idx; 42 | uint8_t flags; 43 | uint16_t offset2; 44 | uint32_t offset3; 45 | uint32_t reserved; 46 | }__attribute__((packed)); 47 | 48 | #define IT_CALL_GATE 0xC 49 | #define IT_INTERRUPT_GATE 0xE 50 | #define IT_TRAP_GATE 0xF 51 | 52 | #define IT_LONG_IDT 8 53 | 54 | #define INTERRUPT_ENTRY_PRESENT 128 55 | 56 | static inline 57 | uint64_t idt_entry_offset(struct kvm_idt_entry *entry) { 58 | return entry->offset1 | ((uint64_t)entry->offset2 << 16) | 59 | ((uint64_t)entry->offset3 << 32); 60 | } 61 | 62 | 63 | #define IDT_ENTRY_DE 0x00 64 | #define IDT_ENTRY_DB 0x01 65 | #define IDT_ENTRY_NMI 0x02 66 | #define IDT_ENTRY_BP 0x03 67 | #define IDT_ENTRY_OF 0x04 68 | #define IDT_ENTRY_BR 0x05 69 | #define IDT_ENTRY_UD 0x06 70 | #define IDT_ENTRY_NM 0x07 71 | #define IDT_ENTRY_DF 0x08 72 | #define IDT_ENTRY_CSO 0x09 73 | #define IDT_ENTRY_TS 0x0a 74 | #define IDT_ENTRY_NP 0x0b 75 | #define IDT_ENTRY_SS 0x0c 76 | #define IDT_ENTRY_GP 0x0d 77 | #define IDT_ENTRY_PF 0x0e 78 | //0x0f is reserved 79 | #define IDT_ENTRY_MF 0x10 80 | #define IDT_ENTRY_AC 0x11 81 | #define IDT_ENTRY_MC 0x12 82 | #define IDT_ENTRY_XF 0x13 83 | //0x14 - 0x1d are reserved 84 | #define IDT_ENTRY_SX 0x1e 85 | //0x1f is reserved 86 | -------------------------------------------------------------------------------- /include/elkvm/interrupt.h: -------------------------------------------------------------------------------- 1 | /* * libelkvm - A library that allows execution of an ELF binary inside a virtual 2 | * machine without a full-scale operating system 3 | * Copyright (C) 2013-2015 Florian Pester , Björn 4 | * Döbel , economic rights: Technische Universitaet 5 | * Dresden (Germany) 6 | * 7 | * This file is part of libelkvm. 8 | * 9 | * libelkvm is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * libelkvm is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with libelkvm. If not, see . 21 | */ 22 | 23 | #pragma once 24 | 25 | #include 26 | 27 | #include 28 | #include 29 | 30 | namespace Elkvm { 31 | 32 | namespace Interrupt { 33 | const int success = 0; 34 | const int failure = 1; 35 | namespace Vector { 36 | const int debug_trap = 0x01; 37 | const int stack_segment_fault = 0x0c; 38 | const int general_protection_fault = 0x0d; 39 | const int page_fault = 0x0e; 40 | } 41 | 42 | int handle_stack_segment_fault(uint64_t code); 43 | int handle_general_protection_fault(uint64_t code); 44 | int handle_page_fault(VM &vm, const std::shared_ptr& vcpu, 45 | uint64_t code); 46 | int handle_debug_trap(const std::shared_ptr& vcpu, uint64_t code); 47 | 48 | int handle_segfault(guestptr_t pfla); 49 | } 50 | 51 | //namespace Elkvm 52 | } 53 | 54 | -------------------------------------------------------------------------------- /include/elkvm/kvm.h: -------------------------------------------------------------------------------- 1 | /* * libelkvm - A library that allows execution of an ELF binary inside a virtual 2 | * machine without a full-scale operating system 3 | * Copyright (C) 2013-2015 Florian Pester , Björn 4 | * Döbel , economic rights: Technische Universitaet 5 | * Dresden (Germany) 6 | * 7 | * This file is part of libelkvm. 8 | * 9 | * libelkvm is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * libelkvm is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with libelkvm. If not, see . 21 | */ 22 | 23 | #pragma once 24 | 25 | #include 26 | 27 | #include 28 | #include 29 | 30 | #define KVM_EXPECT_VERSION 12 31 | #define KVM_DEV_PATH "/dev/kvm" 32 | 33 | namespace Elkvm { 34 | class Segment; 35 | 36 | struct elkvm_opts { 37 | int argc; 38 | char **argv; 39 | char **environ; 40 | bool debug; 41 | 42 | /* TODO kvm-specific stuff */ 43 | int fd; 44 | int run_struct_size; 45 | }; 46 | 47 | namespace KVM { 48 | 49 | int init(struct elkvm_opts *opts); 50 | 51 | class VCPU { 52 | private: 53 | int fd; 54 | struct kvm_regs regs; 55 | struct kvm_sregs sregs; 56 | struct kvm_run *run_struct; 57 | 58 | Elkvm::Segment get_reg(const struct kvm_dtable * const ptr) const; 59 | Elkvm::Segment get_reg(const struct kvm_segment * const ptr) const; 60 | void set_reg(struct kvm_dtable *ptr, const Elkvm::Segment &seg); 61 | void set_reg(struct kvm_segment *ptr, const Elkvm::Segment &seg); 62 | 63 | /* internal debugging stuff */ 64 | struct kvm_guest_debug debug; 65 | int set_debug(); 66 | 67 | public: 68 | VCPU(int vmfd, unsigned num); 69 | 70 | CURRENT_ABI::paramtype get_reg(Elkvm::Reg_t reg) const; 71 | void set_reg(Elkvm::Reg_t reg, CURRENT_ABI::paramtype val); 72 | Segment get_reg(Elkvm::Seg_t segtype) const; 73 | void set_reg(Elkvm::Seg_t segtype, const Elkvm::Segment &seg); 74 | 75 | int get_regs(); 76 | int get_sregs(); 77 | int set_regs(); 78 | int set_sregs(); 79 | CURRENT_ABI::paramtype get_interrupt_bitmap(unsigned idx) const; 80 | CURRENT_ABI::paramtype get_msr(uint32_t idx); 81 | void set_msr(uint32_t idx, CURRENT_ABI::paramtype data); 82 | 83 | int run(); 84 | 85 | /* Debugging */ 86 | int enable_debug(); 87 | int singlestep(); 88 | int singlestep_off(); 89 | int enable_software_breakpoints(); 90 | 91 | uint32_t exit_reason(); 92 | uint64_t hardware_exit_reason(); 93 | uint64_t hardware_entry_failure_reason(); 94 | std::ostream &print_mmio(std::ostream &os); 95 | 96 | }; 97 | 98 | //namespace KVM 99 | } 100 | 101 | } // namespace Elkvm 102 | 103 | int elkvm_init(Elkvm::elkvm_opts *, int, char **, char **); 104 | int elkvm_cleanup(Elkvm::elkvm_opts *); 105 | -------------------------------------------------------------------------------- /include/elkvm/mapping.h: -------------------------------------------------------------------------------- 1 | /* * libelkvm - A library that allows execution of an ELF binary inside a virtual 2 | * machine without a full-scale operating system 3 | * Copyright (C) 2013-2015 Florian Pester , Björn 4 | * Döbel , economic rights: Technische Universitaet 5 | * Dresden (Germany) 6 | * 7 | * This file is part of libelkvm. 8 | * 9 | * libelkvm is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * libelkvm is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with libelkvm. If not, see . 21 | */ 22 | 23 | #pragma once 24 | 25 | #include 26 | #include 27 | 28 | #include 29 | 30 | #include 31 | 32 | namespace Elkvm { 33 | class Region; 34 | 35 | class Mapping { 36 | private: 37 | void *host_p; 38 | guestptr_t addr; 39 | size_t length; 40 | unsigned mapped_pages; 41 | int prot; 42 | int flags; 43 | int fd; 44 | off_t offset; 45 | std::shared_ptr region; 46 | 47 | void slice_begin(size_t len); 48 | void slice_center(off_t off, size_t len); 49 | void slice_end(guestptr_t slice_base); 50 | 51 | public: 52 | Mapping(std::shared_ptr r, guestptr_t guest_addr, 53 | size_t l, int pr, int f, int fdes, off_t off); 54 | 55 | Mapping(const Mapping& orig) 56 | : host_p(orig.base_address()), 57 | addr(orig.guest_address()), 58 | length(orig.get_length()), 59 | mapped_pages(orig.get_pages()), 60 | prot(orig.get_prot()), 61 | flags(orig.get_flags()), 62 | fd(orig.get_fd()), 63 | offset(orig.get_offset()), 64 | region(orig.get_region()) 65 | { } 66 | 67 | Mapping& operator=(const Mapping& other) 68 | { 69 | host_p = other.base_address(); 70 | addr = other.guest_address(); 71 | length = other.get_length(); 72 | mapped_pages = other.get_pages(); 73 | prot = other.get_prot(); 74 | flags = other.get_flags(); 75 | fd = other.get_fd(); 76 | offset = other.get_offset(); 77 | region = other.get_region(); 78 | return *this; 79 | } 80 | 81 | bool anonymous() const { return flags & MAP_ANONYMOUS; } 82 | bool contains_address(void *p) const; 83 | bool contains_address(guestptr_t a) const; 84 | bool fits_address(guestptr_t a) const; 85 | 86 | size_t grow(size_t sz); 87 | guestptr_t grow_to_fill(); 88 | 89 | bool readable() const { return prot & PROT_READ; } 90 | bool executable() const { return prot & PROT_EXEC; } 91 | bool writeable() const { return prot & PROT_WRITE; } 92 | 93 | void *base_address() const { return host_p; } 94 | guestptr_t guest_address() const { return addr; } 95 | std::shared_ptr move_guest_address(off64_t off); 96 | int get_fd() const { return fd; } 97 | size_t get_length() const { return length; } 98 | void set_length(size_t len); 99 | off_t get_offset() const { return offset; } 100 | unsigned get_pages() const { return mapped_pages; } 101 | int get_prot() const { return prot; } 102 | int get_flags() const { return flags; } 103 | std::shared_ptr get_region() const { return region; } 104 | 105 | bool all_unmapped() const { return mapped_pages == 0; } 106 | void set_unmapped() { length = mapped_pages = 0; } 107 | void pages_unmapped(unsigned pages) { mapped_pages -= pages; } 108 | 109 | struct region_mapping *c_mapping(); 110 | void sync_back(struct region_mapping *mapping); 111 | int diff(struct region_mapping *mapping) const; 112 | 113 | int fill(); 114 | 115 | void modify(int pr, int fl, int filedes, off_t o); 116 | void mprotect(int pr); 117 | }; 118 | 119 | std::ostream &print(std::ostream &, const Mapping &); 120 | bool operator==(const Mapping &, const Mapping &); 121 | 122 | } 123 | -------------------------------------------------------------------------------- /include/elkvm/pager.h: -------------------------------------------------------------------------------- 1 | /* * libelkvm - A library that allows execution of an ELF binary inside a virtual 2 | * machine without a full-scale operating system 3 | * Copyright (C) 2013-2015 Florian Pester , Björn 4 | * Döbel , economic rights: Technische Universitaet 5 | * Dresden (Germany) 6 | * 7 | * This file is part of libelkvm. 8 | * 9 | * libelkvm is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * libelkvm is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with libelkvm. If not, see . 21 | */ 22 | 23 | #pragma once 24 | 25 | #include 26 | #include 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | #include 35 | 36 | #define ELKVM_PAGER_MEMSIZE 16*1024*1024 37 | #define ELKVM_SYSTEM_MEMSIZE 16*1024*1024 38 | #define ELKVM_SYSTEM_MEMGROW 128*1024*1024 39 | #define KERNEL_SPACE_BOTTOM 0xFFFF800000000000 40 | #define ADDRESS_SPACE_TOP 0xFFFFFFFFFFFFFFFF 41 | 42 | #define PT_BIT_PRESENT 0x1 43 | #define PT_BIT_WRITEABLE 0x2 44 | #define PT_BIT_USER 0x4 45 | #define PT_BIT_WRITE_CACHE 0x8 46 | #define PT_BIT_NO_CACHE 0x16 47 | #define PT_BIT_USED 0x32 48 | #define PT_BIT_LARGEPAGE (1L << 7) 49 | #define PT_BIT_NXE (1L << 63) 50 | 51 | #define HOST_PAGESIZE 0x1000 52 | #define ELKVM_PAGESIZE 0x1000 53 | #define ELKVM_PAGE_MASK (ELKVM_PAGESIZE - 1) 54 | #define ELKVM_PAGESIZE_LARGE 0x200000 55 | #define ELKVM_PAGE_LARGE_MASK (ELKVM_PAGESIZE_LARGE - 1) 56 | #define ELKVM_PAGESIZE_HUGE 0x100000000 57 | #define ELKVM_PAGE_HUGE_MASK (ELKVM_PAGESIZE_HUGE - 1) 58 | /* 59 | * KVM allows only for 32 memory slots in Linux 3.8 60 | * and 128 slots on Linux 3.11 61 | * its down to 125 slots in Linux 3.13 62 | */ 63 | #define KVM_MEMORY_SLOTS 125 64 | 65 | typedef unsigned int ptopt_t; 66 | #define PT_OPT_WRITE 0x1 67 | #define PT_OPT_EXEC 0x2 68 | #define PT_OPT_LARGE 0x4 69 | #define PT_OPT_HUGE 0x8 70 | 71 | typedef uint64_t ptentry_t; 72 | 73 | bool address_in_region(struct kvm_userspace_memory_region *r, void *host_addr); 74 | bool guest_address_in_region(struct kvm_userspace_memory_region *r, 75 | uint64_t guest_physical); 76 | guestptr_t page_begin(guestptr_t addr); 77 | 78 | template 79 | bool page_aligned(T addr); 80 | 81 | guestptr_t next_page(guestptr_t addr); 82 | int pages_from_size(uint64_t size); 83 | int page_remain(guestptr_t addr); 84 | unsigned int offset_in_page(guestptr_t addr); 85 | uint64_t pagesize_align(uint64_t size); 86 | 87 | namespace Elkvm { 88 | 89 | class Region; 90 | 91 | class PagerX86_64 { 92 | private: 93 | const int _vmfd; 94 | std::vector> chunks; 95 | void *host_pml4_p; 96 | void *host_next_free_tbl_p; 97 | guestptr_t guest_next_free; 98 | size_t total_memsz; 99 | std::vector free_slots; 100 | 101 | std::shared_ptr alloc_chunk(void *addr, 102 | size_t chunk_size, int flags); 103 | 104 | void create_entry(ptentry_t *host_entry_p, guestptr_t guest_next, 105 | ptopt_t opts) const; 106 | 107 | int create_page_tables(); 108 | int create_table(ptentry_t *host_entry_p, ptopt_t opts); 109 | 110 | ptentry_t *find_next_table(ptentry_t *tbl_entry_p) const; 111 | 112 | ptentry_t *find_table_entry(ptentry_t *tbl_base_p, 113 | guestptr_t addr, off64_t off_low, off64_t off_high) const; 114 | 115 | ptentry_t *page_table_walk(guestptr_t guest_virtual) const; 116 | ptentry_t *page_table_walk_create(guestptr_t guest_virtual, ptopt_t opts); 117 | 118 | public: 119 | PagerX86_64(int vmfd); 120 | 121 | PagerX86_64(PagerX86_64 const&) = delete; 122 | PagerX86_64& operator=(PagerX86_64 const&) = delete; 123 | 124 | int set_pml4(const std::shared_ptr& r); 125 | 126 | std::vector>::size_type 127 | chunk_count() const { return chunks.size(); } 128 | 129 | int create_mem_chunk(void **host_p, size_t chunk_size); 130 | void dump_page_tables() const; 131 | void dump_table(ptentry_t *host_p, int level) const; 132 | 133 | std::shared_ptr 134 | find_chunk_for_host_p(void *host_mem_p) const; 135 | 136 | int free_page(guestptr_t guest_virtual); 137 | 138 | std::shared_ptr get_chunk( 139 | std::vector>::size_type chunk) 140 | const; 141 | 142 | void *get_host_p(guestptr_t guest_virtual) const ; 143 | guestptr_t host_to_guest_physical(void *host_p) const; 144 | 145 | int map_chunk_to_kvm( 146 | const std::shared_ptr& chunk); 147 | 148 | guestptr_t map_kernel_page(void *host_mem_p, ptopt_t opts); 149 | int map_region(void *start_p, guestptr_t start_addr, 150 | unsigned pages, ptopt_t opts); 151 | int map_user_page(void *host_mem_p, guestptr_t guest_virtual, 152 | ptopt_t opts); 153 | 154 | int unmap_region(guestptr_t start_addr, unsigned pages); 155 | int update_entry(ptentry_t *entry, ptopt_t opts); 156 | }; 157 | 158 | bool contains_address(const std::shared_ptr& chunk, 159 | void *addr); 160 | bool contains_address(const std::shared_ptr& chunk, 161 | guestptr_t addr); 162 | bool contains_phys_address( 163 | const std::shared_ptr& chunk, guestptr_t addr); 164 | 165 | void dump_page_fault_info(guestptr_t pfla, uint32_t err_code, void *host_p); 166 | bool entry_exists(ptentry_t *entry); 167 | 168 | std::ostream &print(std::ostream &os, const struct kvm_userspace_memory_region &r); 169 | //namespace Elkvm 170 | } 171 | -------------------------------------------------------------------------------- /include/elkvm/region.h: -------------------------------------------------------------------------------- 1 | /* * libelkvm - A library that allows execution of an ELF binary inside a virtual 2 | * machine without a full-scale operating system 3 | * Copyright (C) 2013-2015 Florian Pester , Björn 4 | * Döbel , economic rights: Technische Universitaet 5 | * Dresden (Germany) 6 | * 7 | * This file is part of libelkvm. 8 | * 9 | * libelkvm is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * libelkvm is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with libelkvm. If not, see . 21 | */ 22 | 23 | #pragma once 24 | 25 | #include 26 | 27 | #include 28 | 29 | namespace Elkvm { 30 | 31 | class Region { 32 | private: 33 | void *host_p; 34 | guestptr_t addr; 35 | size_t rsize; 36 | bool free; 37 | std::string name; 38 | 39 | public: 40 | Region(void *chunk_p, size_t size, const std::string &title="anon region", 41 | bool f = true) : 42 | host_p(chunk_p), 43 | addr(0), 44 | rsize(size), 45 | free(f), 46 | name(title) 47 | {} 48 | 49 | Region(const Region&) = delete; 50 | Region& operator=(const Region&) = delete; 51 | 52 | void *base_address() const { return host_p; } 53 | struct elkvm_memory_region *c_region() const; 54 | bool contains_address(const void *addr) const; 55 | bool contains_address(guestptr_t addr) const; 56 | off64_t offset_in_region(guestptr_t addr) const; 57 | size_t space_after_address(const void * const) const; 58 | guestptr_t guest_address() const { return addr; } 59 | bool is_free() const { return free; } 60 | void *last_valid_address() const; 61 | guestptr_t last_valid_guest_address() const; 62 | void set_free() { free = true; addr = 0x0; } 63 | void set_guest_addr(guestptr_t a) { addr = a; }; 64 | void set_used() { free = false; } 65 | size_t size() const { return rsize; } 66 | std::shared_ptr slice_begin(const size_t size, 67 | const std::string &purpose="anon region"); 68 | std::pair, std::shared_ptr> 69 | slice_center(off_t off, size_t len); 70 | std::string const& getName() const { return this->name; } 71 | }; 72 | 73 | std::ostream &print(std::ostream &, const Region &); 74 | bool operator==(const Region &, const Region &); 75 | 76 | //namespace Elkvm 77 | } 78 | 79 | -------------------------------------------------------------------------------- /include/elkvm/region_manager.h: -------------------------------------------------------------------------------- 1 | /* * libelkvm - A library that allows execution of an ELF binary inside a virtual 2 | * machine without a full-scale operating system 3 | * Copyright (C) 2013-2015 Florian Pester , Björn 4 | * Döbel , economic rights: Technische Universitaet 5 | * Dresden (Germany) 6 | * 7 | * This file is part of libelkvm. 8 | * 9 | * libelkvm is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * libelkvm is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with libelkvm. If not, see . 21 | */ 22 | 23 | #pragma once 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | #include 30 | #include 31 | 32 | namespace Elkvm { 33 | class RegionManager { 34 | public: 35 | static const unsigned n_freelists = 17; // TODO make configurable constant 36 | private: 37 | std::vector> allocated_regions; 38 | std::array>, n_freelists> freelists; 39 | 40 | PagerX86_64 pager; 41 | 42 | int add_chunk(size_t size, const std::string &purpose); 43 | 44 | public: 45 | RegionManager(int vmfd); 46 | 47 | bool address_valid(const void *host_p) const; 48 | bool host_address_mapped(const void * const) const; 49 | bool same_region(const void *p1, const void *p2) const; 50 | 51 | void add_free_region(std::shared_ptr region); 52 | std::shared_ptr allocate_region(size_t size, 53 | const std::string &purpose="anon region"); 54 | void free_region(std::shared_ptr r); 55 | void free_region(void *host_p, size_t sz); 56 | void use_region(std::shared_ptr r); 57 | 58 | std::shared_ptr find_free_region(size_t size); 59 | std::shared_ptr find_region(const void *host_p) const; 60 | std::shared_ptr find_region(guestptr_t addr) const; 61 | 62 | void dump_regions() const; 63 | void dump_mappings() const; 64 | 65 | /* XXX make this const */ 66 | PagerX86_64 &get_pager() { return pager; } 67 | const PagerX86_64 &get_pager() const { return pager; } 68 | }; 69 | 70 | std::array, RegionManager::n_freelists>::size_type 71 | get_freelist_idx(const size_t size); 72 | 73 | //namespace Elkvm 74 | } 75 | -------------------------------------------------------------------------------- /include/elkvm/regs.h: -------------------------------------------------------------------------------- 1 | /* * libelkvm - A library that allows execution of an ELF binary inside a virtual 2 | * machine without a full-scale operating system 3 | * Copyright (C) 2013-2015 Florian Pester , Björn 4 | * Döbel , economic rights: Technische Universitaet 5 | * Dresden (Germany) 6 | * 7 | * This file is part of libelkvm. 8 | * 9 | * libelkvm is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * libelkvm is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with libelkvm. If not, see . 21 | */ 22 | 23 | #pragma once 24 | 25 | namespace Elkvm { 26 | 27 | enum Reg_t { 28 | rax, rbx, rcx, rdx, 29 | rsi, rdi, rsp, rbp, 30 | r8, r9, r10, r11, 31 | r12, r13, r14, r15, 32 | rip, rflags, 33 | cr0, cr2, cr3, cr4, cr8, 34 | efer, 35 | apic_base 36 | }; 37 | 38 | enum Seg_t { 39 | cs, ds, es, fs, gs, ss, 40 | tr, ldt, 41 | gdt, idt 42 | }; 43 | 44 | //namespace Elkvm 45 | } 46 | -------------------------------------------------------------------------------- /include/elkvm/stack.h: -------------------------------------------------------------------------------- 1 | /* * libelkvm - A library that allows execution of an ELF binary inside a virtual 2 | * machine without a full-scale operating system 3 | * Copyright (C) 2013-2015 Florian Pester , Björn 4 | * Döbel , economic rights: Technische Universitaet 5 | * Dresden (Germany) 6 | * 7 | * This file is part of libelkvm. 8 | * 9 | * libelkvm is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * libelkvm is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with libelkvm. If not, see . 21 | */ 22 | 23 | #pragma once 24 | 25 | #include 26 | #include 27 | 28 | #include 29 | 30 | /* 64bit Linux puts the Stack at 47bits */ 31 | #define LINUX_64_STACK_BASE 0x800000000000 32 | #define ELKVM_STACK_GROW 0x200000 33 | 34 | namespace Elkvm { 35 | 36 | class VM; 37 | class Region; 38 | class RegionManager; 39 | 40 | class Stack { 41 | private: 42 | std::vector> stack_regions; 43 | std::shared_ptr _rm; 44 | std::shared_ptr kernel_stack; 45 | guestptr_t base; 46 | 47 | public: 48 | Stack(std::shared_ptr rm); 49 | void init(std::shared_ptr v, const Environment &e, 50 | std::shared_ptr rm); 51 | int pushq(guestptr_t rsp, uint64_t val); 52 | uint64_t popq(guestptr_t rsp); 53 | bool is_stack_expansion(guestptr_t pfla); 54 | bool grow(guestptr_t pfla); 55 | guestptr_t kernel_base() const { return kernel_stack->guest_address(); } 56 | guestptr_t user_base() const { return base; } 57 | int expand(); 58 | }; 59 | 60 | //namespace Elkvm 61 | } 62 | -------------------------------------------------------------------------------- /include/elkvm/tss.h: -------------------------------------------------------------------------------- 1 | /* * libelkvm - A library that allows execution of an ELF binary inside a virtual 2 | * machine without a full-scale operating system 3 | * Copyright (C) 2013-2015 Florian Pester , Björn 4 | * Döbel , economic rights: Technische Universitaet 5 | * Dresden (Germany) 6 | * 7 | * This file is part of libelkvm. 8 | * 9 | * libelkvm is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * libelkvm is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with libelkvm. If not, see . 21 | */ 22 | 23 | #include 24 | 25 | #include 26 | 27 | #include 28 | 29 | int elkvm_tss_setup64(std::shared_ptr vcpu, 30 | Elkvm::RegionManager &rm, std::shared_ptr r); 31 | 32 | struct elkvm_tss64 { 33 | uint32_t reserved1; 34 | uint64_t rsp0; 35 | uint64_t rsp1; 36 | uint64_t rsp2; 37 | uint64_t reserved2; 38 | uint64_t ist1; 39 | uint64_t ist2; 40 | uint64_t ist3; 41 | uint64_t ist4; 42 | uint64_t ist5; 43 | uint64_t ist6; 44 | uint64_t ist7; 45 | uint64_t reserved3; 46 | uint16_t reserved4; 47 | uint16_t iopb; 48 | }__attribute__((packed)); 49 | 50 | struct elkvm_tss32 { 51 | uint16_t link; 52 | uint16_t reserved1; 53 | uint32_t esp0; 54 | uint16_t ss0; 55 | uint16_t reserved2; 56 | uint32_t esp1; 57 | uint16_t ss1; 58 | uint16_t reserved3; 59 | uint32_t esp2; 60 | uint16_t ss2; 61 | uint16_t reserved4; 62 | uint32_t cr3; 63 | uint32_t eip; 64 | uint32_t eflags; 65 | uint32_t eax; 66 | uint32_t ecx; 67 | uint32_t edx; 68 | uint32_t ebx; 69 | uint32_t esp; 70 | uint32_t ebp; 71 | uint32_t esi; 72 | uint32_t edi; 73 | uint16_t es; 74 | uint16_t reserved5; 75 | uint16_t cs; 76 | uint16_t reserved6; 77 | uint16_t ss; 78 | uint16_t reserved7; 79 | uint16_t ds; 80 | uint16_t reserved8; 81 | uint16_t fs; 82 | uint16_t reserved9; 83 | uint16_t gs; 84 | uint16_t reserved10; 85 | uint16_t ldtr; 86 | uint16_t reserved11; 87 | uint16_t reserved12; 88 | uint16_t iopb; 89 | }__attribute__((packed)); 90 | 91 | int elkvm_tss_setup32(struct elkvm_tss32 *, int); 92 | -------------------------------------------------------------------------------- /include/elkvm/types.h: -------------------------------------------------------------------------------- 1 | /* * libelkvm - A library that allows execution of an ELF binary inside a virtual 2 | * machine without a full-scale operating system 3 | * Copyright (C) 2013-2015 Florian Pester , Björn 4 | * Döbel , economic rights: Technische Universitaet 5 | * Dresden (Germany) 6 | * 7 | * This file is part of libelkvm. 8 | * 9 | * libelkvm is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * libelkvm is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with libelkvm. If not, see . 21 | */ 22 | 23 | #pragma once 24 | 25 | /* 26 | * Basic types used by various ELKVM modules. 27 | */ 28 | 29 | #include 30 | #include 31 | #include 32 | 33 | #include 34 | 35 | /* 36 | * Guest pointer type 37 | */ 38 | typedef uint64_t guestptr_t; 39 | 40 | /* 41 | * TODO: needs doc 42 | */ 43 | struct region_mapping { 44 | void *host_p; 45 | guestptr_t guest_virt; 46 | size_t length; 47 | unsigned mapped_pages; 48 | int prot; 49 | int flags; 50 | int fd; 51 | off_t offset; 52 | }; 53 | 54 | 55 | /* 56 | * TODO: needs doc 57 | */ 58 | struct linux_dirent { 59 | unsigned long d_ino; /* Inode number */ 60 | unsigned long d_off; /* Offset to next linux_dirent */ 61 | unsigned short d_reclen; /* Length of this linux_dirent */ 62 | char d_name[]; /* Filename (null-terminated) */ 63 | /* length is actually (d_reclen - 2 - 64 | offsetof(struct linux_dirent, d_name)) */ 65 | /* 66 | char pad; // Zero padding byte 67 | char d_type; // File type (only since Linux 68 | // 2.6.4); offset is (d_reclen - 1) 69 | */ 70 | }; 71 | 72 | 73 | namespace Elkvm { 74 | class Region; 75 | 76 | 77 | /* 78 | * TODO: needs doc 79 | */ 80 | struct elkvm_flat { 81 | std::shared_ptr region; 82 | uint64_t size; 83 | }; 84 | 85 | 86 | /* 87 | * TODO: needs doc 88 | */ 89 | struct elkvm_signals { 90 | struct sigaction signals[_NSIG]; 91 | }; 92 | } // namespace Elkvm 93 | -------------------------------------------------------------------------------- /include/elkvm/vcpu.h: -------------------------------------------------------------------------------- 1 | /* * libelkvm - A library that allows execution of an ELF binary inside a virtual 2 | * machine without a full-scale operating system 3 | * Copyright (C) 2013-2015 Florian Pester , Björn 4 | * Döbel , economic rights: Technische Universitaet 5 | * Dresden (Germany) 6 | * 7 | * This file is part of libelkvm. 8 | * 9 | * libelkvm is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * libelkvm is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with libelkvm. If not, see . 21 | */ 22 | 23 | #pragma once 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include 32 | 33 | #include 34 | #include 35 | 36 | namespace Elkvm { 37 | 38 | class Segment { 39 | CURRENT_ABI::paramtype _selector; 40 | CURRENT_ABI::paramtype _base; 41 | CURRENT_ABI::paramtype _limit; 42 | CURRENT_ABI::paramtype _type; 43 | CURRENT_ABI::paramtype _present; 44 | CURRENT_ABI::paramtype _dpl; 45 | CURRENT_ABI::paramtype _db; 46 | CURRENT_ABI::paramtype _s; 47 | CURRENT_ABI::paramtype _l; 48 | CURRENT_ABI::paramtype _g; 49 | CURRENT_ABI::paramtype _avl; 50 | 51 | public: 52 | Segment(CURRENT_ABI::paramtype base, 53 | CURRENT_ABI::paramtype limit) : 54 | _selector(0), 55 | _base(base), 56 | _limit(limit), 57 | _type(0), 58 | _present(0), 59 | _dpl(0), 60 | _db(0), 61 | _s(0), 62 | _l(0), 63 | _g(0), 64 | _avl(0) 65 | {} 66 | 67 | Segment(CURRENT_ABI::paramtype selector, 68 | CURRENT_ABI::paramtype base, 69 | CURRENT_ABI::paramtype limit, 70 | CURRENT_ABI::paramtype type, 71 | CURRENT_ABI::paramtype present, 72 | CURRENT_ABI::paramtype dpl, 73 | CURRENT_ABI::paramtype db, 74 | CURRENT_ABI::paramtype s, 75 | CURRENT_ABI::paramtype l, 76 | CURRENT_ABI::paramtype g, 77 | CURRENT_ABI::paramtype avl) : 78 | _selector(selector), 79 | _base(base), 80 | _limit(limit), 81 | _type(type), 82 | _present(present), 83 | _dpl(dpl), 84 | _db(db), 85 | _s(s), 86 | _l(l), 87 | _g(g), 88 | _avl(avl) {} 89 | 90 | CURRENT_ABI::paramtype get_selector() const { return _selector; } 91 | CURRENT_ABI::paramtype get_base() const { return _base; } 92 | CURRENT_ABI::paramtype get_limit() const { return _limit; } 93 | CURRENT_ABI::paramtype get_type() const { return _type; } 94 | CURRENT_ABI::paramtype is_present() const { return _present; } 95 | CURRENT_ABI::paramtype get_dpl() const { return _dpl; } 96 | CURRENT_ABI::paramtype get_db() const { return _db; } 97 | CURRENT_ABI::paramtype get_s() const { return _s; } 98 | CURRENT_ABI::paramtype get_l() const { return _l; } 99 | CURRENT_ABI::paramtype get_g() const { return _g; } 100 | CURRENT_ABI::paramtype get_avl() const { return _avl; } 101 | 102 | void set_base(CURRENT_ABI::paramtype base) { 103 | _base = base; 104 | } 105 | 106 | void set_selector(CURRENT_ABI::paramtype sel) { 107 | _selector = sel; 108 | } 109 | }; 110 | 111 | class VCPU { 112 | private: 113 | bool is_singlestepping; 114 | KVM::VCPU _kvm_vcpu; 115 | Elkvm::Stack stack; 116 | 117 | void initialize_regs(); 118 | 119 | public: 120 | static const int hypercall_exit = 1; 121 | 122 | VCPU(std::shared_ptr rm, int vmfd, unsigned cpu_num); 123 | /* 124 | * Get VCPU registers from hypervisor 125 | */ 126 | int get_regs(); 127 | int get_sregs(); 128 | 129 | /* 130 | * Set VCPU registers with hypervisor 131 | */ 132 | int set_regs(); 133 | int set_sregs(); 134 | 135 | /* 136 | * get and set single registers 137 | */ 138 | CURRENT_ABI::paramtype get_reg(Elkvm::Reg_t reg) const; 139 | Elkvm::Segment get_reg(Elkvm::Seg_t seg) const; 140 | CURRENT_ABI::paramtype get_interrupt_bitmap(unsigned idx) const; 141 | void set_reg(Elkvm::Reg_t reg, CURRENT_ABI::paramtype val); 142 | void set_reg(Elkvm::Seg_t seg, const Elkvm::Segment &s); 143 | void set_entry_point(guestptr_t rip); 144 | 145 | /* MSRs */ 146 | void set_msr(uint32_t idx, CURRENT_ABI::paramtype data); 147 | CURRENT_ABI::paramtype get_msr(uint32_t idx); 148 | 149 | /* RUNNING the VCPU */ 150 | int run(); 151 | bool handle_vm_exit(); 152 | 153 | /* get VCPU hypervisor exit reasons */ 154 | uint32_t exit_reason(); 155 | uint64_t hardware_exit_reason(); 156 | uint64_t hardware_entry_failure_reason(); 157 | 158 | /* Debugging */ 159 | int enable_debug(); 160 | int enable_software_breakpoints(); 161 | bool is_singlestep() { return is_singlestepping; } 162 | int singlestep(); 163 | int singlestep_off(); 164 | std::ostream &print_mmio(std::ostream &os); 165 | 166 | void print_info(const VM &vm); 167 | /* stack handling */ 168 | CURRENT_ABI::paramtype pop(); 169 | void push(CURRENT_ABI::paramtype val); 170 | guestptr_t kernel_stack_base() { return stack.kernel_base(); } 171 | int handle_stack_expansion(uint32_t err, bool debug); 172 | void init_rsp(); 173 | }; 174 | 175 | std::ostream &print(std::ostream &os, const VCPU &vcpu); 176 | std::ostream &print(std::ostream &os, const std::string &name, 177 | const Elkvm::Segment &seg); 178 | std::ostream &print(std::ostream &os, const std::string &name, 179 | struct kvm_dtable dtable); 180 | std::ostream &print_stack(std::ostream &os, const VM &vm, const VCPU &vcpu); 181 | 182 | //namespace Elkvm 183 | } 184 | 185 | #define VCPU_CR0_FLAG_PAGING 0x80000000 186 | #define VCPU_CR0_FLAG_CACHE_DISABLE 0x40000000 187 | #define VCPU_CR0_FLAG_NOT_WRITE_THROUGH 0x20000000 188 | #define VCPU_CR0_FLAG_PROTECTED 0x1 189 | 190 | #define VCPU_CR4_FLAG_OSXSAVE 0x40000 191 | #define VCPU_CR4_FLAG_OSFXSR 0x200 192 | #define VCPU_CR4_FLAG_PAE 0x20 193 | #define VCPU_CR4_FLAG_DE 0x8 194 | 195 | #define VCPU_EFER_FLAG_SCE 0x1 196 | #define VCPU_EFER_FLAG_LME 0x100 197 | #define VCPU_EFER_FLAG_LMA 0x400 198 | #define VCPU_EFER_FLAG_NXE 0x800 199 | #define VMX_INVALID_GUEST_STATE 0x80000021 200 | #define CPUID_EXT_VMX (1 << 5) 201 | 202 | #define VCPU_MSR_STAR 0xC0000081 203 | #define VCPU_MSR_LSTAR 0xC0000082 204 | #define VCPU_MSR_CSTAR 0xC0000083 205 | #define VCPU_MSR_SFMASK 0XC0000084 206 | 207 | void kvm_vcpu_dump_msr(const std::shared_ptr& vcpu, uint32_t); 208 | 209 | /* 210 | * \brief Returns true if the host supports vmx 211 | */ 212 | bool host_supports_vmx(void); 213 | 214 | /* 215 | * \brief Get the host CPUID 216 | */ 217 | void host_cpuid(uint32_t, uint32_t, uint32_t *, uint32_t *, uint32_t *, uint32_t *); 218 | 219 | void print_flags(uint64_t flags); 220 | -------------------------------------------------------------------------------- /share/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_custom_command( 2 | OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/entry 3 | COMMAND 4 | as ${PROJECT_SOURCE_DIR}/share/entry.S -o entry.o && 5 | ld entry.o -Ttext 0x500 -s -r -o entry.tmp && 6 | objcopy -O binary -j .text entry.tmp entry && 7 | rm -f entry.tmp 8 | 9 | ) 10 | add_custom_target(entry ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/entry) 11 | 12 | add_custom_command( 13 | OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/isr 14 | COMMAND 15 | as ${PROJECT_SOURCE_DIR}/share/isr.S -o isr.o && 16 | ld isr.o -Ttext 0x500 -s -r -o isr.tmp && 17 | objcopy -O binary -j .text isr.tmp isr && 18 | rm -f isr.tmp 19 | 20 | ) 21 | add_custom_target(isr ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/isr) 22 | 23 | add_custom_command( 24 | OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/signal 25 | COMMAND 26 | as ${PROJECT_SOURCE_DIR}/share/signal.S -o signal.o && 27 | ld signal.o -Ttext 0x500 -s -r -o signal.tmp && 28 | objcopy -O binary -j .text signal.tmp signal && 29 | rm -f signal.tmp 30 | ) 31 | add_custom_target(signal ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/signal) 32 | 33 | install (FILES ${CMAKE_CURRENT_BINARY_DIR}/entry 34 | ${CMAKE_CURRENT_BINARY_DIR}/isr 35 | ${CMAKE_CURRENT_BINARY_DIR}/signal 36 | DESTINATION share/libelkvm) 37 | -------------------------------------------------------------------------------- /share/entry.S: -------------------------------------------------------------------------------- 1 | _start: 2 | pushq $1 3 | vmcall 4 | sysretq 5 | -------------------------------------------------------------------------------- /share/isr.S: -------------------------------------------------------------------------------- 1 | .macro interrupt_stub iv 2 | .globl _interrupt_stub_\iv 3 | _interrupt_stub_\iv: 4 | pushq $\iv 5 | pushq $2 6 | jmp _isr_common 7 | .endm 8 | 9 | // Exceptions 10 | interrupt_stub 0 11 | interrupt_stub 1 12 | interrupt_stub 2 13 | interrupt_stub 3 14 | interrupt_stub 4 15 | interrupt_stub 5 16 | interrupt_stub 6 17 | interrupt_stub 7 18 | interrupt_stub 8 19 | interrupt_stub 9 20 | interrupt_stub 10 21 | interrupt_stub 11 22 | interrupt_stub 12 23 | interrupt_stub 13 24 | interrupt_stub 14 25 | interrupt_stub 16 26 | interrupt_stub 17 27 | interrupt_stub 18 28 | interrupt_stub 19 29 | 30 | // IRQs (vorausgesetzt diese sind nach 0x20 bis 0x2f gemappt) 31 | interrupt_stub 32 32 | interrupt_stub 33 33 | interrupt_stub 34 34 | interrupt_stub 35 35 | interrupt_stub 36 36 | interrupt_stub 37 37 | interrupt_stub 38 38 | interrupt_stub 39 39 | interrupt_stub 40 40 | interrupt_stub 41 41 | interrupt_stub 42 42 | interrupt_stub 43 43 | interrupt_stub 44 44 | interrupt_stub 45 45 | interrupt_stub 46 46 | interrupt_stub 47 47 | 48 | // Systemaufruf 49 | interrupt_stub 48 50 | 51 | _isr_common: 52 | vmcall 53 | iretq 54 | -------------------------------------------------------------------------------- /share/signal.S: -------------------------------------------------------------------------------- 1 | _start: 2 | popq %rax 3 | retq 4 | 5 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | SET( libelkvm_SRCS 2 | debug.cc 3 | elfloader.cc 4 | environ.cc 5 | gdbstub.cc 6 | gdt.cc 7 | heap.cc 8 | idt.cc 9 | interrupt.cc 10 | kvm.cc 11 | mapping.cc 12 | pager.cc 13 | region.cc 14 | region_manager.cc 15 | signal.cc 16 | stack.cc 17 | syscall.cc 18 | syscalls-clock.cc 19 | syscalls-mprotect.cc 20 | syscalls-open.cc 21 | syscalls-rlimit.cc 22 | syscalls-robust_list.cc 23 | syscalls-set_tid_address.cc 24 | syscalls-signal.cc 25 | syscalls-socket.cc 26 | syscalls-statfs.cc 27 | syscall-stubs.cc 28 | syscall_default.cc 29 | tss.cc 30 | udis86.cc 31 | vcpu.cc 32 | vm.cc 33 | vm_internals.cc 34 | ) 35 | ADD_LIBRARY( elkvm SHARED ${libelkvm_SRCS} ) 36 | 37 | if(LIBUDIS86_FOUND) 38 | # BD: Weird. According to the documentation, passing an absolute library 39 | # path, such as ${LIBUDIS86_LIBRARIES} should instruct CMake to write 40 | # -l. However, in my case it only generated -ludis86 41 | # and forgot about the search path. Therefore, we extract the path here 42 | # separately and pass it as an explicit argument for udis86 dir. 43 | get_filename_component(LIBUDIS86_DIR "${LIBUDIS86_LIBRARIES}" PATH) 44 | target_link_libraries (elkvm -L${LIBUDIS86_DIR} ${LIBUDIS86_LIBRARIES}) 45 | endif(LIBUDIS86_FOUND) 46 | 47 | target_link_libraries (elkvm elf) 48 | add_dependencies(elkvm entry) 49 | add_dependencies(elkvm isr) 50 | add_dependencies(elkvm signal) 51 | 52 | install (TARGETS elkvm DESTINATION lib) 53 | -------------------------------------------------------------------------------- /src/debug.cc: -------------------------------------------------------------------------------- 1 | // 2 | // libelkvm - A library that allows execution of an ELF binary inside a virtual 3 | // machine without a full-scale operating system 4 | // Copyright (C) 2013-2015 Florian Pester , Björn 5 | // Döbel , economic rights: Technische Universitaet 6 | // Dresden (Germany) 7 | // 8 | // This file is part of libelkvm. 9 | // 10 | // libelkvm is free software: you can redistribute it and/or modify 11 | // it under the terms of the GNU General Public License as published by 12 | // the Free Software Foundation, either version 3 of the License, or 13 | // (at your option) any later version. 14 | // 15 | // libelkvm is distributed in the hope that it will be useful, 16 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | // GNU General Public License for more details. 19 | // 20 | // You should have received a copy of the GNU General Public License 21 | // along with libelkvm. If not, see . 22 | // 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | int elkvm_handle_debug(Elkvm::VM *vm) { 36 | int handled = 0; 37 | if(vm->get_handlers()->bp_callback != NULL) { 38 | handled = vm->get_handlers()->bp_callback(vm); 39 | } 40 | 41 | return handled; 42 | } 43 | 44 | namespace Elkvm { 45 | 46 | std::ostream &print_memory(std::ostream &os, const VM &vm, guestptr_t addr, 47 | size_t size) { 48 | assert(addr != 0x0 && "cannot dump address NULL"); 49 | uint64_t *host_p = static_cast( 50 | vm.get_region_manager()->get_pager().get_host_p(addr)); 51 | assert(host_p != nullptr && "cannot dump unmapped memory"); 52 | 53 | os << " Host Address\tGuest Address\t\tValue\t\t\tValue\n"; 54 | for(unsigned i = 0; i < size; i++) { 55 | os << std::hex 56 | << " " << host_p 57 | << " 0x" << addr 58 | << "\t0x" << std::setw(16) << std::setfill('0') << *host_p 59 | << "\t0x" << std::setw(16) << std::setfill('0') << *(host_p + 1) << std::endl; 60 | addr += 0x10; 61 | host_p+=2; 62 | } 63 | 64 | return os; 65 | } 66 | 67 | int VCPU::enable_debug() { 68 | return _kvm_vcpu.enable_debug(); 69 | } 70 | 71 | int VCPU::singlestep() { 72 | is_singlestepping = true; 73 | return _kvm_vcpu.singlestep(); 74 | } 75 | 76 | int VCPU::singlestep_off() { 77 | is_singlestepping = false; 78 | return _kvm_vcpu.singlestep_off(); 79 | } 80 | 81 | int VCPU::enable_software_breakpoints() { 82 | return _kvm_vcpu.enable_software_breakpoints(); 83 | } 84 | 85 | namespace KVM { 86 | 87 | int VCPU::enable_debug() { 88 | debug.control |= KVM_GUESTDBG_ENABLE; 89 | return set_debug(); 90 | } 91 | 92 | int VCPU::singlestep() { 93 | debug.control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_SINGLESTEP; 94 | return set_debug(); 95 | } 96 | 97 | int VCPU::singlestep_off() { 98 | debug.control &= ~KVM_GUESTDBG_SINGLESTEP; 99 | return set_debug(); 100 | } 101 | 102 | int VCPU::set_debug() { 103 | return ioctl(fd, KVM_SET_GUEST_DEBUG, &debug); 104 | } 105 | 106 | int VCPU::enable_software_breakpoints() { 107 | debug.control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP; 108 | return set_debug(); 109 | } 110 | 111 | //namespace KVM 112 | } 113 | //namespace Elkvm 114 | } 115 | -------------------------------------------------------------------------------- /src/environ.cc: -------------------------------------------------------------------------------- 1 | // 2 | // libelkvm - A library that allows execution of an ELF binary inside a virtual 3 | // machine without a full-scale operating system 4 | // Copyright (C) 2013-2015 Florian Pester , Björn 5 | // Döbel , economic rights: Technische Universitaet 6 | // Dresden (Germany) 7 | // 8 | // This file is part of libelkvm. 9 | // 10 | // libelkvm is free software: you can redistribute it and/or modify 11 | // it under the terms of the GNU General Public License as published by 12 | // the Free Software Foundation, either version 3 of the License, or 13 | // (at your option) any later version. 14 | // 15 | // libelkvm is distributed in the hope that it will be useful, 16 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | // GNU General Public License for more details. 19 | // 20 | // You should have received a copy of the GNU General Public License 21 | // along with libelkvm. If not, see . 22 | // 23 | 24 | #include 25 | 26 | #include 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | // the global logger object (see elkvm-log.h) 38 | ElkvmLog globalElkvmLogger; 39 | 40 | namespace Elkvm { 41 | 42 | EnvRegion::EnvRegion(std::shared_ptr r) : 43 | _region(r), 44 | _offset(r->size()) { 45 | _region->set_guest_addr( 46 | reinterpret_cast(_region->base_address())); 47 | } 48 | 49 | guestptr_t EnvRegion::write_str(const std::string &str) { 50 | assert(_offset > (str.length() + 1)); 51 | off64_t noff = _offset - str.length() - 1; 52 | 53 | char *target = static_cast(_region->base_address()) + noff; 54 | assert((target + str.length()) 55 | < (static_cast(_region->base_address()) + _region->size())); 56 | 57 | guestptr_t guest_virtual = _region->guest_address() + noff; 58 | assert((guest_virtual + str.length()) 59 | < (_region->guest_address() + _region->size())); 60 | 61 | str.copy(target, str.length()); 62 | _offset = noff; 63 | return guest_virtual; 64 | } 65 | 66 | Environment::Environment(const ElfBinary &bin, std::shared_ptr reg, 67 | int argc, char **argv, char **env) : 68 | _region(reg), 69 | _auxv(), 70 | _env(), 71 | _argv(), 72 | _argc(argc), 73 | binary(bin) 74 | { 75 | fill_argv(argv), 76 | fill_env(env); 77 | auto auxv = calc_auxv(env); 78 | fill_auxv(auxv); 79 | } 80 | 81 | Elf64_auxv_t *Environment::calc_auxv(char **env) const { 82 | /* XXX this breaks, if we do not get the original envp */ 83 | 84 | /* traverse past the environment */ 85 | char **auxv_p = env; 86 | while(*auxv_p != NULL) { 87 | auxv_p++; 88 | } 89 | auxv_p++; 90 | return reinterpret_cast(auxv_p); 91 | } 92 | 93 | void Environment::fill_argv(char **argv) { 94 | for(int i = 0; i < _argc; i++) { 95 | _argv.emplace_back(argv[i]); 96 | } 97 | } 98 | 99 | void Environment::fill_env(char **env) { 100 | while(*env != nullptr) { 101 | _env.emplace_back(*env); 102 | env++; 103 | } 104 | } 105 | 106 | void Environment::fill_auxv(Elf64_auxv_t *auxv) { 107 | while(auxv->a_type != AT_NULL) { 108 | _auxv.push_back(*auxv); 109 | auxv++; 110 | } 111 | } 112 | 113 | void Environment::fix_auxv_dynamic_values() { 114 | short all_set = 0; 115 | for(auto &a : _auxv) { 116 | /* 117 | * if the binary is dynamically linked, we need to reset these types 118 | * so the dynamic linker loads the correct values 119 | */ 120 | switch(a.a_type) { 121 | 122 | case AT_PHDR: 123 | a.a_un.a_val = binary.get_auxv().at_phdr; 124 | all_set |= 0x1; 125 | break; 126 | case AT_PHENT: 127 | a.a_un.a_val = binary.get_auxv().at_phent; 128 | all_set |= 0x2; 129 | break; 130 | case AT_PHNUM: 131 | a.a_un.a_val = binary.get_auxv().at_phnum; 132 | all_set |= 0x4; 133 | break; 134 | case AT_ENTRY: 135 | a.a_un.a_val = binary.get_auxv().at_entry; 136 | all_set |= 0x8; 137 | break; 138 | case AT_BASE: 139 | a.a_un.a_val = binary.get_auxv().at_base; 140 | all_set |= 0x10; 141 | break; 142 | } 143 | } 144 | assert(all_set == 0x1F && "elf auxv is complete"); 145 | } 146 | 147 | bool Environment::treat_as_int_type(int type) const { 148 | std::vector itypes({ 149 | AT_NULL, 150 | AT_IGNORE, 151 | AT_EXECFD, 152 | AT_PHDR, 153 | AT_PHENT, 154 | AT_PHNUM, 155 | AT_PAGESZ, 156 | AT_FLAGS, 157 | AT_ENTRY, 158 | AT_NOTELF, 159 | AT_UID, 160 | AT_EUID, 161 | AT_GID, 162 | AT_EGID, 163 | AT_HWCAP, 164 | AT_CLKTCK, 165 | AT_SECURE, 166 | AT_BASE, 167 | }); 168 | auto it = std::find(itypes.begin(), itypes.end(), type); 169 | return it != itypes.end(); 170 | } 171 | 172 | bool Environment::ignored_type(int type) const { 173 | std::vector ignored({ 174 | AT_SYSINFO_EHDR 175 | }); 176 | auto it = std::find(std::begin(ignored), std::end(ignored), type); 177 | return it != ignored.end(); 178 | } 179 | 180 | void Environment::push_auxv_raw(VCPU &vcpu) { 181 | for(auto it = _auxv.rbegin(); it != _auxv.rend(); it++) { 182 | const auto &auxv = *it; 183 | if(!ignored_type(auxv.a_type)) { 184 | if(treat_as_int_type(auxv.a_type)) { 185 | vcpu.push(auxv.a_un.a_val); 186 | } else { 187 | push_str_copy(vcpu, std::string(reinterpret_cast(auxv.a_un.a_val))); 188 | } 189 | vcpu.push(auxv.a_type); 190 | } 191 | } 192 | } 193 | 194 | void Environment::push_auxv(VCPU& vcpu) { 195 | if(binary.get_auxv().valid) { 196 | fix_auxv_dynamic_values(); 197 | } 198 | push_auxv_raw(vcpu); 199 | vcpu.push(0); 200 | } 201 | 202 | void Environment::push_env(VCPU& vcpu) { 203 | for(auto it = _env.rbegin(); it != _env.rend(); it++) { 204 | push_str_copy(vcpu, *it); 205 | } 206 | vcpu.push(0); 207 | } 208 | 209 | void Environment::push_argv(VCPU& vcpu) { 210 | for(auto it = _argv.rbegin(); it != _argv.rend(); it++) { 211 | push_str_copy(vcpu, *it); 212 | } 213 | } 214 | 215 | void Environment::push_argc(VCPU &vcpu) const { 216 | vcpu.push(_argc); 217 | } 218 | 219 | void Environment::push_str_copy(VCPU& vcpu, const std::string &str) { 220 | auto guest_virtual = _region.write_str(str); 221 | vcpu.push(guest_virtual); 222 | } 223 | 224 | int Environment::create(VCPU& vcpu) { 225 | int err = vcpu.get_regs(); 226 | assert(err == 0 && "error getting vcpu"); 227 | 228 | push_auxv(vcpu); 229 | push_env(vcpu); 230 | push_argv(vcpu); 231 | push_argc(vcpu); 232 | 233 | /* if the binary is dynamically linked we need to ajdust some stuff */ 234 | //if(binary.is_dynamically_linked()) { 235 | // push_str_copy(*vcpu, bytes, binary.get_loader()); 236 | // opts->argc++; 237 | //} 238 | 239 | err = vcpu.set_regs(); 240 | return err; 241 | } 242 | 243 | //namespace Elkvm 244 | } 245 | -------------------------------------------------------------------------------- /src/gdbstub.cc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUD-OS/libelkvm/959c2e4ed1c2f0e27b196804ce4f10d4bb8231da/src/gdbstub.cc -------------------------------------------------------------------------------- /src/gdt.cc: -------------------------------------------------------------------------------- 1 | // 2 | // libelkvm - A library that allows execution of an ELF binary inside a virtual 3 | // machine without a full-scale operating system 4 | // Copyright (C) 2013-2015 Florian Pester , Björn 5 | // Döbel , economic rights: Technische Universitaet 6 | // Dresden (Germany) 7 | // 8 | // This file is part of libelkvm. 9 | // 10 | // libelkvm is free software: you can redistribute it and/or modify 11 | // it under the terms of the GNU General Public License as published by 12 | // the Free Software Foundation, either version 3 of the License, or 13 | // (at your option) any later version. 14 | // 15 | // libelkvm is distributed in the hope that it will be useful, 16 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | // GNU General Public License for more details. 19 | // 20 | // You should have received a copy of the GNU General Public License 21 | // along with libelkvm. If not, see . 22 | // 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | #include 29 | #include 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | namespace Elkvm { 41 | class VCPU; 42 | } 43 | 44 | std::shared_ptr elkvm_gdt_setup(Elkvm::RegionManager &rm, 45 | std::shared_ptr vcpu) { 46 | std::shared_ptr gdt_region = 47 | rm.allocate_region( 48 | GDT_NUM_ENTRIES * sizeof(struct elkvm_gdt_segment_descriptor), 49 | "ELKVM GDT"); 50 | 51 | guestptr_t guest_virtual = 52 | rm.get_pager().map_kernel_page( 53 | gdt_region->base_address(), 0); 54 | assert(guest_virtual != 0x0 && "could not map gdt"); 55 | gdt_region->set_guest_addr(guest_virtual); 56 | 57 | /* create a null entry, as required by x86 */ 58 | memset(gdt_region->base_address(), 0, 59 | sizeof(struct elkvm_gdt_segment_descriptor)); 60 | 61 | struct elkvm_gdt_segment_descriptor *entry = 62 | reinterpret_cast( 63 | reinterpret_cast(gdt_region->base_address()) 64 | + sizeof(struct elkvm_gdt_segment_descriptor)); 65 | 66 | /* user stack segment */ 67 | elkvm_gdt_create_segment_descriptor(entry, 0x0, 0xFFFFFFFF, 68 | GDT_SEGMENT_PRESENT | GDT_SEGMENT_WRITEABLE | GDT_SEGMENT_BIT | 69 | GDT_SEGMENT_PRIVILEDGE_USER, 70 | GDT_SEGMENT_PAGE_GRANULARITY | GDT_SEGMENT_LONG ); 71 | uint64_t ss_selector = (uint64_t)entry - (uint64_t)gdt_region->base_address(); 72 | entry++; 73 | 74 | /* user code segment */ 75 | elkvm_gdt_create_segment_descriptor(entry, 0x0, 0xFFFFFFFF, 76 | GDT_SEGMENT_READABLE | GDT_SEGMENT_EXECUTABLE | GDT_SEGMENT_BIT | 77 | GDT_SEGMENT_PRESENT | GDT_SEGMENT_PRIVILEDGE_USER | GDT_SEGMENT_DIRECTION_BIT, 78 | GDT_SEGMENT_PAGE_GRANULARITY | GDT_SEGMENT_LONG); 79 | 80 | entry++; 81 | 82 | /* user data segment */ 83 | elkvm_gdt_create_segment_descriptor(entry, 0x0, 0xFFFFFFFF, 84 | GDT_SEGMENT_WRITEABLE | GDT_SEGMENT_BIT | GDT_SEGMENT_PRESENT, 85 | GDT_SEGMENT_PAGE_GRANULARITY | GDT_SEGMENT_LONG ); 86 | 87 | entry++; 88 | 89 | std::shared_ptr tss_region = 90 | rm.allocate_region( 91 | sizeof(struct elkvm_tss64), "ELKVM TSS"); 92 | /* setup the tss, before loading the segment descriptor */ 93 | int err = elkvm_tss_setup64(vcpu, rm, tss_region); 94 | if(err) { 95 | return nullptr; 96 | } 97 | 98 | /* task state segment */ 99 | elkvm_gdt_create_segment_descriptor(entry, 100 | tss_region->guest_address() & 0xFFFFFFFF, 101 | sizeof(struct elkvm_tss64), 102 | 0x9 | GDT_SEGMENT_PRESENT, 103 | GDT_SEGMENT_LONG); 104 | 105 | uint64_t tr_selector = (uint64_t)entry 106 | - (uint64_t)gdt_region->base_address(); 107 | 108 | /* 109 | * tss entry has 128 bits, make a second entry to account for that 110 | * the upper part of base is in the beginning of that second entry 111 | * rest is ignored or must be 0, just set everything to 0 112 | */ 113 | entry++; 114 | uint64_t *upper_tss = (uint64_t *)entry; 115 | *upper_tss = tss_region->guest_address() >> 32; 116 | entry++; 117 | 118 | /* kernel code segment */ 119 | elkvm_gdt_create_segment_descriptor(entry, 0x0, 0xFFFFFFFF, 120 | GDT_SEGMENT_READABLE | GDT_SEGMENT_EXECUTABLE | GDT_SEGMENT_BIT | 121 | GDT_SEGMENT_PRESENT | GDT_SEGMENT_DIRECTION_BIT, 122 | GDT_SEGMENT_PAGE_GRANULARITY | GDT_SEGMENT_LONG); 123 | uint64_t kernel_cs_selector = 124 | (uint64_t)entry - (uint64_t)gdt_region->base_address(); 125 | 126 | entry++; 127 | 128 | /* kernel stack segment */ 129 | elkvm_gdt_create_segment_descriptor(entry, 0x0, 0xFFFFFFFF, 130 | GDT_SEGMENT_WRITEABLE | GDT_SEGMENT_BIT | GDT_SEGMENT_PRESENT, 131 | GDT_SEGMENT_PAGE_GRANULARITY | GDT_SEGMENT_LONG ); 132 | entry++; 133 | 134 | 135 | uint64_t syscall_star = kernel_cs_selector; 136 | uint64_t sysret_star = (ss_selector - 0x8) | 0x3; 137 | uint64_t star = (sysret_star << 48) | (syscall_star << 32); 138 | 139 | vcpu->set_msr(VCPU_MSR_STAR, star); 140 | 141 | err = vcpu->get_sregs(); 142 | if(err) { 143 | return nullptr; 144 | } 145 | 146 | Elkvm::Segment gdt(gdt_region->guest_address(), GDT_NUM_ENTRIES * 8 - 1); 147 | vcpu->set_reg(Elkvm::Seg_t::gdt, gdt); 148 | 149 | Elkvm::Segment tr(tr_selector, 150 | tss_region->guest_address(), 151 | sizeof(struct elkvm_tss64), 152 | 0xb, 153 | 0x1, 154 | 0x0, 155 | 0x0, 156 | 0x0, 157 | 0x1, 158 | 0x0, 159 | 0x0); 160 | vcpu->set_reg(Elkvm::Seg_t::tr, tr); 161 | 162 | err = vcpu->set_sregs(); 163 | if(err) { 164 | return nullptr; 165 | } 166 | 167 | return gdt_region; 168 | } 169 | 170 | int elkvm_gdt_create_segment_descriptor(struct elkvm_gdt_segment_descriptor *entry, 171 | uint32_t base, uint32_t limit, uint8_t access, uint8_t flags) { 172 | 173 | if(base & 0xFFF00000) { 174 | return -EINVAL; 175 | } 176 | 177 | entry->base1 = base & 0xFFFF; 178 | entry->base2 = (base >> 16) & 0xFF; 179 | entry->base3 = (base >> 24); 180 | entry->limit1 = limit & 0xFFFF; 181 | entry->limit2_flags = ((limit >> 16) & 0xF) | ((uint8_t)flags << 4); 182 | entry->access = access; 183 | 184 | return 0; 185 | } 186 | 187 | -------------------------------------------------------------------------------- /src/idt.cc: -------------------------------------------------------------------------------- 1 | // 2 | // libelkvm - A library that allows execution of an ELF binary inside a virtual 3 | // machine without a full-scale operating system 4 | // Copyright (C) 2013-2015 Florian Pester , Björn 5 | // Döbel , economic rights: Technische Universitaet 6 | // Dresden (Germany) 7 | // 8 | // This file is part of libelkvm. 9 | // 10 | // libelkvm is free software: you can redistribute it and/or modify 11 | // it under the terms of the GNU General Public License as published by 12 | // the Free Software Foundation, either version 3 of the License, or 13 | // (at your option) any later version. 14 | // 15 | // libelkvm is distributed in the hope that it will be useful, 16 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | // GNU General Public License for more details. 19 | // 20 | // You should have received a copy of the GNU General Public License 21 | // along with libelkvm. If not, see . 22 | // 23 | 24 | #include 25 | #include 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | int elkvm_idt_setup(Elkvm::RegionManager &rm, 43 | std::shared_ptr vcpu, 44 | Elkvm::elkvm_flat *default_handler) { 45 | std::shared_ptr idt_region = 46 | rm.allocate_region( 47 | 256 * sizeof(struct kvm_idt_entry)); 48 | 49 | /* default handler defines 48 entries, that push the iv to the stack */ 50 | for(int i = 0; i < 48; i++) { 51 | uint64_t offset = default_handler->region->guest_address() + i * 9; 52 | struct kvm_idt_entry *entry = 53 | reinterpret_cast( 54 | reinterpret_cast(idt_region->base_address()) + 55 | i * sizeof(struct kvm_idt_entry)); 56 | 57 | entry->offset1 = offset & 0xFFFF; 58 | entry->offset2 = (offset >> 16) & 0xFFFF; 59 | entry->offset3 = (uint32_t)(offset >> 32); 60 | 61 | entry->selector = 0x0030; 62 | entry->idx = 0x1; 63 | entry->flags = INTERRUPT_ENTRY_PRESENT | IT_TRAP_GATE | IT_LONG_IDT; 64 | entry->reserved = 0x0; 65 | } 66 | 67 | 68 | /* create a page for the idt */ 69 | guestptr_t guest_virtual = 70 | rm.get_pager().map_kernel_page( 71 | idt_region->base_address(), 0); 72 | assert(guest_virtual != 0x0); 73 | idt_region->set_guest_addr(guest_virtual); 74 | 75 | Elkvm::Segment idt(idt_region->guest_address(), 0xFFF); 76 | vcpu->set_reg(Elkvm::Seg_t::idt, idt); 77 | 78 | int err = vcpu->set_sregs(); 79 | 80 | return err; 81 | } 82 | -------------------------------------------------------------------------------- /src/interrupt.cc: -------------------------------------------------------------------------------- 1 | // 2 | // libelkvm - A library that allows execution of an ELF binary inside a virtual 3 | // machine without a full-scale operating system 4 | // Copyright (C) 2013-2015 Florian Pester , Björn 5 | // Döbel , economic rights: Technische Universitaet 6 | // Dresden (Germany) 7 | // 8 | // This file is part of libelkvm. 9 | // 10 | // libelkvm is free software: you can redistribute it and/or modify 11 | // it under the terms of the GNU General Public License as published by 12 | // the Free Software Foundation, either version 3 of the License, or 13 | // (at your option) any later version. 14 | // 15 | // libelkvm is distributed in the hope that it will be useful, 16 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | // GNU General Public License for more details. 19 | // 20 | // You should have received a copy of the GNU General Public License 21 | // along with libelkvm. If not, see . 22 | // 23 | 24 | #include 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | namespace Elkvm { 31 | 32 | int VM::handle_interrupt(const std::shared_ptr& vcpu) { 33 | uint64_t interrupt_vector = vcpu->pop(); 34 | 35 | if(debug_mode()) { 36 | DBG() << " INTERRUPT with vector " << std::hex << "0x" << interrupt_vector 37 | << " detected"; 38 | vcpu->get_sregs(); 39 | print(std::cerr, *vcpu); 40 | print_stack(std::cerr, *this, *vcpu); 41 | 42 | guestptr_t stack_p = vcpu->get_reg(Elkvm::Reg_t::rsp); 43 | guestptr_t *host_p = static_cast( 44 | get_region_manager()->get_pager().get_host_p(stack_p)); 45 | assert(host_p != nullptr); 46 | guestptr_t instr = *(host_p + 1); 47 | print_code(std::cerr, *this, instr); 48 | } 49 | 50 | uint64_t err_code = vcpu->pop(); 51 | switch(interrupt_vector) { 52 | case Interrupt::Vector::debug_trap: 53 | return Elkvm::Interrupt::handle_debug_trap(vcpu, err_code); 54 | case Interrupt::Vector::stack_segment_fault: 55 | return Elkvm::Interrupt::handle_stack_segment_fault(err_code); 56 | case Interrupt::Vector::general_protection_fault: 57 | return Elkvm::Interrupt::handle_general_protection_fault(err_code); 58 | case Interrupt::Vector::page_fault: 59 | return Elkvm::Interrupt::handle_page_fault(*this, vcpu, err_code); 60 | } 61 | 62 | return Interrupt::failure; 63 | } 64 | 65 | namespace Interrupt { 66 | 67 | int handle_stack_segment_fault(uint64_t code) { 68 | ERROR() << "STACK SEGMENT FAULT"; 69 | ERROR() << "Error Code: " << code; 70 | return failure; 71 | } 72 | 73 | int handle_general_protection_fault(uint64_t code) { 74 | ERROR() << "GENERAL PROTECTION FAULT"; 75 | ERROR() << "Error Code:" << code; 76 | return failure; 77 | } 78 | 79 | 80 | int handle_debug_trap(const std::shared_ptr& vcpu, uint64_t code) { 81 | // code is RIP in this case 82 | ERROR() << "Debug trap @ RIP " << (void*)code; 83 | // push RIP back and IRET from handler 84 | vcpu->push(code); 85 | return success; 86 | } 87 | 88 | int handle_page_fault(VM &vm, 89 | const std::shared_ptr& vcpu, 90 | uint64_t code) { 91 | int err = vcpu->get_sregs(); 92 | assert(err == 0 && "error getting vcpu sregs"); 93 | 94 | CURRENT_ABI::paramtype pfla = vcpu->get_reg(Elkvm::Reg_t::cr2); 95 | DBG() << "Page fault @ " << (void*)pfla; 96 | handle_segfault(pfla); 97 | if(vcpu->handle_stack_expansion(code, vm.debug_mode())) { 98 | return success; 99 | } 100 | 101 | void *hp = vm.get_region_manager()->get_pager().get_host_p(pfla); 102 | Elkvm::dump_page_fault_info(pfla, code, hp); 103 | if(hp) { 104 | vm.get_region_manager()->get_pager().dump_page_tables(); 105 | } 106 | 107 | return failure; 108 | } 109 | 110 | int handle_segfault(guestptr_t pfla) { 111 | if(pfla <= 0x1000) { 112 | ERROR() << "\n\nABORT: SEGMENTATION FAULT at 0x" << std::hex << pfla 113 | << std::endl << std::endl; 114 | exit(EXIT_FAILURE); 115 | } 116 | return failure; 117 | } 118 | 119 | //namespace Interrupt 120 | } 121 | 122 | //namespace Elkvm 123 | } 124 | -------------------------------------------------------------------------------- /src/mapping.cc: -------------------------------------------------------------------------------- 1 | // 2 | // libelkvm - A library that allows execution of an ELF binary inside a virtual 3 | // machine without a full-scale operating system 4 | // Copyright (C) 2013-2015 Florian Pester , Björn 5 | // Döbel , economic rights: Technische Universitaet 6 | // Dresden (Germany) 7 | // 8 | // This file is part of libelkvm. 9 | // 10 | // libelkvm is free software: you can redistribute it and/or modify 11 | // it under the terms of the GNU General Public License as published by 12 | // the Free Software Foundation, either version 3 of the License, or 13 | // (at your option) any later version. 14 | // 15 | // libelkvm is distributed in the hope that it will be useful, 16 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | // GNU General Public License for more details. 19 | // 20 | // You should have received a copy of the GNU General Public License 21 | // along with libelkvm. If not, see . 22 | // 23 | 24 | #include 25 | #include 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | namespace Elkvm { 33 | Mapping::Mapping(std::shared_ptr r, 34 | guestptr_t guest_addr, size_t l, int pr, int f, int fdes, off_t off) : 35 | host_p(0), 36 | addr(guest_addr), 37 | length(l), 38 | mapped_pages(~0U), 39 | prot(pr), 40 | flags(f), 41 | fd(fdes), 42 | offset(off), 43 | region(r) 44 | { 45 | assert(region->size() >= length); 46 | 47 | host_p = region->base_address(); 48 | if(addr == 0x0) { 49 | addr = reinterpret_cast(host_p); 50 | } 51 | region->set_guest_addr(addr); 52 | assert(!region->is_free()); 53 | mapped_pages = pages_from_size(length); 54 | } 55 | 56 | guestptr_t Mapping::grow_to_fill() { 57 | addr = region->guest_address(); 58 | length = region->size(); 59 | mapped_pages = pages_from_size(length); 60 | return addr + length; 61 | } 62 | 63 | std::shared_ptr Mapping::move_guest_address(off64_t off) { 64 | assert(off > 0); 65 | assert((unsigned)off < (unsigned)length); 66 | assert(length <= region->size()); 67 | 68 | addr += off; 69 | length -= off; 70 | mapped_pages = pages_from_size(length); 71 | host_p = static_cast(host_p) + off; 72 | 73 | auto r = region->slice_begin(off); 74 | assert(length <= region->size()); 75 | 76 | assert(region != nullptr); 77 | return r; 78 | } 79 | 80 | void Mapping::set_length(size_t len) { 81 | assert(length >= len && "mappings can only shrink this way"); 82 | assert(region != nullptr && "mapping must always have a valid region"); 83 | assert(region->size() >= len && "mappings cannot be larger than their regions"); 84 | 85 | length = len; 86 | mapped_pages = pages_from_size(length); 87 | } 88 | 89 | void Mapping::modify(int pr, int fl, int filedes, off_t o) { 90 | mapped_pages = pages_from_size(length); 91 | 92 | if(pr != prot) { 93 | prot = pr; 94 | } 95 | if(flags != fl) { 96 | if(anonymous() && !(fl & MAP_ANONYMOUS)) { 97 | flags = fl; 98 | fd = filedes; 99 | offset = o; 100 | fill(); 101 | } 102 | flags = fl; 103 | } 104 | if(fd != filedes) { 105 | offset = o; 106 | fd = filedes; 107 | if(!anonymous()) { 108 | fill(); 109 | } 110 | } 111 | if(offset != o) { 112 | offset = o; 113 | if(!anonymous()) { 114 | fill(); 115 | } 116 | } 117 | } 118 | 119 | void Mapping::mprotect(int pr) { 120 | prot = pr; 121 | } 122 | 123 | bool Mapping::contains_address(void *p) const { 124 | return (host_p <= p) && (p < (reinterpret_cast(host_p) + length)); 125 | } 126 | 127 | bool Mapping::contains_address(guestptr_t a) const { 128 | return (addr <= a) && (a < (addr + length)); 129 | } 130 | 131 | bool Mapping::fits_address(guestptr_t a) const { 132 | return (region->guest_address()) <= a 133 | && (a < (region->guest_address() + region->size())); 134 | } 135 | 136 | int Mapping::fill() { 137 | assert(fd > 0 && "cannot fill mapping without file descriptor"); 138 | 139 | off_t pos = lseek(fd, 0, SEEK_CUR); 140 | assert(pos >= 0 && "could not get current file position"); 141 | 142 | int err = lseek(fd, offset, SEEK_SET); 143 | assert(err >= 0 && "seek set in pass_mmap failed"); 144 | 145 | char *buf = reinterpret_cast(host_p); 146 | ssize_t bytes = 0; 147 | size_t total = 0; 148 | errno = 0; 149 | while((total <= length) 150 | && (bytes = read(fd, buf, length - total)) > 0) { 151 | assert(bytes >= 0); 152 | buf += bytes; 153 | total += bytes; 154 | } 155 | 156 | ssize_t rem = length - total; 157 | if(rem > 0) { 158 | // printf("read %zd bytes of %zd bytes\n", total, length); 159 | // printf("\nzeroing out %zd bytes at %p\n", rem, buf); 160 | memset(buf, 0, rem); 161 | } 162 | err = lseek(fd, pos, SEEK_SET); 163 | assert(err >= 0 && "could not restore file position"); 164 | return err; 165 | } 166 | 167 | void Mapping::sync_back(struct region_mapping *mapping) { 168 | host_p = mapping->host_p; 169 | addr = mapping->guest_virt; 170 | region->set_guest_addr(addr); 171 | length = mapping->length; 172 | mapped_pages = pages_from_size(length); 173 | prot = mapping->prot; 174 | 175 | if(flags != mapping->flags || fd != mapping->fd || offset != mapping->offset) { 176 | flags = mapping->flags; 177 | fd = mapping->fd; 178 | offset = mapping->offset; 179 | fill(); 180 | } 181 | } 182 | 183 | int Mapping::diff(struct region_mapping *mapping) const { 184 | assert(host_p == mapping->host_p && "changing the mapping's host address is not yet supported"); 185 | if(host_p != mapping->host_p 186 | || addr != mapping->guest_virt 187 | || length != mapping->length 188 | || prot != mapping->prot) { 189 | return 1; 190 | } 191 | 192 | return 0; 193 | } 194 | 195 | size_t Mapping::grow(size_t sz) { 196 | if(sz <= length) { 197 | return length; 198 | } 199 | 200 | assert(region != nullptr && "no region to grow into"); 201 | if(sz >= region->size()) { 202 | length = region->size(); 203 | } else { 204 | length = sz; 205 | } 206 | mapped_pages = pages_from_size(length); 207 | return length; 208 | } 209 | 210 | std::ostream &print(std::ostream &os, const Mapping &mapping) { 211 | if(mapping.anonymous()) { 212 | os << "ANONYMOUS "; 213 | } else { 214 | os << " "; 215 | } 216 | 217 | os << "MAPPING: 0x" << std::hex << mapping.guest_address() 218 | << " (" << mapping.base_address() << ") length: 0x" << mapping.get_length() 219 | << " last address: " << mapping.guest_address() + mapping.get_length() 220 | << " pages mapped: 0x" << mapping.get_pages(); 221 | if(!mapping.anonymous()) { 222 | os << " fd: " << mapping.get_fd(); 223 | } 224 | os << " protection: "; 225 | if(mapping.readable()) { 226 | os << "R"; 227 | } 228 | if(mapping.writeable()) { 229 | os << "W"; 230 | } 231 | if(mapping.executable()) { 232 | os << "X"; 233 | } 234 | 235 | os << std::endl; 236 | return os; 237 | } 238 | 239 | struct region_mapping *Mapping::c_mapping() { 240 | struct region_mapping *mapping = new(struct region_mapping); 241 | mapping->host_p = host_p; 242 | mapping->guest_virt = addr; 243 | mapping->length = length; 244 | mapping->mapped_pages = mapped_pages; 245 | mapping->prot = prot; 246 | mapping->flags = flags; 247 | mapping->fd = fd; 248 | mapping->offset = offset; 249 | return mapping; 250 | } 251 | 252 | bool operator==(const Mapping &m1, const Mapping &m2) { 253 | return m1.base_address() == m2.base_address() 254 | && m1.guest_address() == m2.guest_address() 255 | && m1.get_length() == m2.get_length() 256 | && m1.get_pages() == m2.get_pages() 257 | && m1.anonymous() == m2.anonymous() 258 | && m1.writeable() == m2.writeable() 259 | && m1.executable() == m2.executable() 260 | && m1.get_fd() == m2.get_fd() 261 | && m1.get_offset() == m2.get_offset(); 262 | } 263 | 264 | //namespace Elkvm 265 | } 266 | -------------------------------------------------------------------------------- /src/region.cc: -------------------------------------------------------------------------------- 1 | // 2 | // libelkvm - A library that allows execution of an ELF binary inside a virtual 3 | // machine without a full-scale operating system 4 | // Copyright (C) 2013-2015 Florian Pester , Björn 5 | // Döbel , economic rights: Technische Universitaet 6 | // Dresden (Germany) 7 | // 8 | // This file is part of libelkvm. 9 | // 10 | // libelkvm is free software: you can redistribute it and/or modify 11 | // it under the terms of the GNU General Public License as published by 12 | // the Free Software Foundation, either version 3 of the License, or 13 | // (at your option) any later version. 14 | // 15 | // libelkvm is distributed in the hope that it will be useful, 16 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | // GNU General Public License for more details. 19 | // 20 | // You should have received a copy of the GNU General Public License 21 | // along with libelkvm. If not, see . 22 | // 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | #include 29 | #include 30 | 31 | #include 32 | #include 33 | #include 34 | 35 | namespace Elkvm { 36 | 37 | std::ostream &print(std::ostream &stream, Region const & r) { 38 | if(r.is_free()) { 39 | stream << "FREE "; 40 | } 41 | stream << std::hex 42 | <<"REGION[" << std::setw(36) << r.getName() << "] guest address: " 43 | << std::setw(19) << (void*)r.guest_address() 44 | << " host_p: " << r.base_address() << " size: 0x" << r.size() 45 | << " last guest address: 0x" << r.guest_address() + r.size() - 1 46 | << std::endl; 47 | return stream; 48 | } 49 | 50 | bool operator==(const Region &r, const void *const p) { 51 | return r.contains_address(p); 52 | } 53 | 54 | bool operator==(const Region &r1, const Region &r2) { 55 | return r1.base_address() == r2.base_address() 56 | && r1.guest_address() == r2.guest_address() 57 | && r1.size() == r2.size() 58 | && r1.is_free() == r2.is_free(); 59 | } 60 | 61 | bool Region::contains_address(const void * const p) const { 62 | return (host_p <= p) && (p < (reinterpret_cast(host_p) + rsize)); 63 | } 64 | 65 | bool Region::contains_address(guestptr_t guest_addr) const { 66 | return (addr <= guest_addr) && (guest_addr < (addr + rsize)); 67 | } 68 | 69 | off64_t Region::offset_in_region(guestptr_t guest_addr) const { 70 | assert(contains_address(addr) && "address must be in region to calc offset"); 71 | return guest_addr - addr; 72 | } 73 | 74 | size_t Region::space_after_address(const void * const p) const { 75 | assert(contains_address(p)); 76 | return reinterpret_cast(host_p) 77 | + rsize - reinterpret_cast(p); 78 | } 79 | 80 | void *Region::last_valid_address() const { 81 | return reinterpret_cast(host_p) + rsize; 82 | } 83 | 84 | guestptr_t Region::last_valid_guest_address() const { 85 | return addr + rsize - 1; 86 | } 87 | 88 | std::shared_ptr Region::slice_begin(const size_t size, 89 | const std::string &purpose) { 90 | //assert(free); 91 | assert(size > 0x0); 92 | assert(rsize > pagesize_align(size)); 93 | 94 | std::shared_ptr r = 95 | std::make_shared(host_p, pagesize_align(size), purpose); 96 | 97 | host_p = reinterpret_cast(host_p) + r->size(); 98 | rsize -= r->size(); 99 | if(addr != 0x0) { 100 | addr += r->size(); 101 | } 102 | assert(rsize > 0x0); 103 | assert(r->size() > 0x0); 104 | return r; 105 | } 106 | 107 | std::pair, std::shared_ptr> 108 | Region::slice_center(off_t off, size_t len) { 109 | 110 | assert(contains_address(reinterpret_cast(host_p) + off + len)); 111 | assert(0 < off); 112 | assert((unsigned)off <= rsize); 113 | 114 | std::shared_ptr r = std::make_shared( 115 | reinterpret_cast(host_p) + off + len, 116 | rsize - off - len); 117 | r->set_guest_addr(addr + off); 118 | 119 | rsize = off; 120 | 121 | std::shared_ptr free_region = std::make_shared( 122 | reinterpret_cast(host_p) + off, len); 123 | 124 | return std::pair, std::shared_ptr>( 125 | r, free_region); 126 | } 127 | 128 | //namespace Elkvm 129 | } 130 | -------------------------------------------------------------------------------- /src/region_manager.cc: -------------------------------------------------------------------------------- 1 | // 2 | // libelkvm - A library that allows execution of an ELF binary inside a virtual 3 | // machine without a full-scale operating system 4 | // Copyright (C) 2013-2015 Florian Pester , Björn 5 | // Döbel , economic rights: Technische Universitaet 6 | // Dresden (Germany) 7 | // 8 | // This file is part of libelkvm. 9 | // 10 | // libelkvm is free software: you can redistribute it and/or modify 11 | // it under the terms of the GNU General Public License as published by 12 | // the Free Software Foundation, either version 3 of the License, or 13 | // (at your option) any later version. 14 | // 15 | // libelkvm is distributed in the hope that it will be useful, 16 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | // GNU General Public License for more details. 19 | // 20 | // You should have received a copy of the GNU General Public License 21 | // along with libelkvm. If not, see . 22 | // 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | namespace Elkvm { 35 | RegionManager::RegionManager(int vmfd) 36 | : allocated_regions(), 37 | freelists(), 38 | pager(vmfd) 39 | { 40 | auto sysregion = allocate_region(ELKVM_PAGER_MEMSIZE, "ELKVM Pager Memory"); 41 | pager.set_pml4(sysregion); 42 | } 43 | 44 | void RegionManager::dump_regions() const { 45 | INFO() << "DUMPING ALL REGIONS:"; 46 | INFO() << "===================="; 47 | for(const auto ® : allocated_regions) { 48 | print(std::cout, *reg); 49 | } 50 | 51 | std::cout << std::endl << std::endl; 52 | } 53 | 54 | std::shared_ptr RegionManager::allocate_region(size_t size, 55 | const std::string &purpose) { 56 | auto r = find_free_region(size); 57 | 58 | if(r == nullptr) { 59 | int err = add_chunk(size, purpose); 60 | assert(err == 0 && "could not allocate memory for new region"); 61 | 62 | r = find_free_region(size); 63 | assert(r != nullptr && "should have free region after allocation"); 64 | } 65 | 66 | if(r->size() > pagesize_align(size)) { 67 | auto new_region = r->slice_begin(size, purpose); 68 | add_free_region(r); 69 | r = new_region; 70 | } 71 | 72 | use_region(r); 73 | 74 | assert(size <= r->size()); 75 | return r; 76 | } 77 | 78 | std::shared_ptr RegionManager::find_free_region(size_t size) { 79 | auto list_idx = get_freelist_idx(size); 80 | 81 | while(list_idx < freelists.size()) { 82 | auto rit = std::find_if(freelists[list_idx].begin(), freelists[list_idx].end(), 83 | [size](const std::shared_ptr& a) 84 | { assert(a != nullptr); return a->size() >= size; }); 85 | if(rit != freelists[list_idx].end()) { 86 | auto r = *rit; 87 | freelists[list_idx].erase(rit); 88 | return r; 89 | } 90 | list_idx++; 91 | } 92 | return nullptr; 93 | } 94 | 95 | std::shared_ptr RegionManager::find_region(const void *host_p) const { 96 | auto r = std::find_if(allocated_regions.begin(), allocated_regions.end(), 97 | [host_p](const std::shared_ptr& a) 98 | { return a->contains_address(host_p); }); 99 | if(r == allocated_regions.end()) { 100 | return nullptr; 101 | } 102 | return *r; 103 | } 104 | 105 | std::shared_ptr RegionManager::find_region(guestptr_t addr) const { 106 | auto r = std::find_if(allocated_regions.begin(), allocated_regions.end(), 107 | [addr](const std::shared_ptr& a) 108 | { return a->contains_address(addr); }); 109 | if(r == allocated_regions.end()) { 110 | return nullptr; 111 | } 112 | return *r; 113 | } 114 | 115 | int RegionManager::add_chunk(const size_t size, const std::string &purpose) { 116 | void *chunk_p; 117 | const size_t grow_size = size > ELKVM_SYSTEM_MEMGROW ? 118 | pagesize_align(size) : ELKVM_SYSTEM_MEMGROW; 119 | 120 | int err = pager.create_mem_chunk(&chunk_p, grow_size); 121 | if(err) { 122 | printf("LIBELKVM: Could not create memory chunk!\n"); 123 | printf("Errno: %i Msg: %s\n", -err, strerror(-err)); 124 | return err; 125 | } 126 | 127 | auto idx = get_freelist_idx(grow_size); 128 | freelists[idx].push_back(std::make_shared(chunk_p, grow_size, purpose)); 129 | return 0; 130 | } 131 | 132 | void RegionManager::add_free_region(std::shared_ptr r) { 133 | auto list_idx = get_freelist_idx(r->size()); 134 | freelists[list_idx].push_back(r); 135 | } 136 | 137 | void RegionManager::free_region(std::shared_ptr r) { 138 | auto rit = std::find(allocated_regions.begin(), allocated_regions.end(), r); 139 | assert(rit != allocated_regions.end()); 140 | allocated_regions.erase(rit); 141 | 142 | r->set_free(); 143 | auto list_idx = get_freelist_idx(r->size()); 144 | freelists[list_idx].push_back(r); 145 | } 146 | 147 | void RegionManager::free_region(void *host_p, const size_t sz) { 148 | auto rit = std::find_if(allocated_regions.begin(), allocated_regions.end(), 149 | [host_p](const std::shared_ptr& a) 150 | { return a->contains_address(host_p); }); 151 | 152 | assert(rit != allocated_regions.end()); 153 | assert((*rit)->contains_address(host_p)); 154 | assert((*rit)->size() == sz); 155 | 156 | auto list_idx = get_freelist_idx(sz); 157 | 158 | (*rit)->set_free(); 159 | freelists[list_idx].push_back(*rit); 160 | allocated_regions.erase(rit); 161 | } 162 | 163 | bool RegionManager::host_address_mapped(const void *const p) const { 164 | for(const auto &r : allocated_regions) { 165 | if(r->contains_address(p)) { 166 | return true; 167 | } 168 | } 169 | return false; 170 | } 171 | 172 | bool RegionManager::same_region(const void *p1, const void *p2) const { 173 | std::shared_ptr r = find_region(p1); 174 | return r->contains_address(p2); 175 | } 176 | 177 | void RegionManager::use_region(std::shared_ptr r) { 178 | assert(r->is_free()); 179 | r->set_used(); 180 | allocated_regions.push_back(r); 181 | } 182 | 183 | std::array, RegionManager::n_freelists>::size_type 184 | get_freelist_idx(const size_t size) { 185 | auto list_idx = 0; 186 | if(size <= 0x1000) { 187 | return list_idx = 0; 188 | } else if(size <= 0x2000) { 189 | return list_idx = 1; 190 | } else if(size <= 0x4000) { 191 | return list_idx = 2; 192 | } else if(size <= 0x8000) { 193 | return list_idx = 3; 194 | } else if(size <= 0x10000) { 195 | return list_idx = 4; 196 | } else if(size <= 0x20000) { 197 | return list_idx = 5; 198 | } else if(size <= 0x40000) { 199 | return list_idx = 6; 200 | } else if(size <= 0x80000) { 201 | return list_idx = 7; 202 | } else if(size <= 0x100000) { 203 | return list_idx = 8; 204 | } else if(size <= 0x200000) { 205 | return list_idx = 9; 206 | } else if(size <= 0x400000) { 207 | return list_idx = 10; 208 | } else if(size <= 0x800000) { 209 | return list_idx = 11; 210 | } else if(size <= 0x1000000) { 211 | return list_idx = 12; 212 | } else if(size <= 0x2000000) { 213 | return list_idx = 13; 214 | } else if(size <= 0x4000000) { 215 | return list_idx = 14; 216 | } else if(size <= 0x8000000) { 217 | return list_idx = 15; 218 | } else { 219 | return list_idx = 16; 220 | } 221 | } 222 | 223 | //namespace Elkvm 224 | } 225 | 226 | 227 | -------------------------------------------------------------------------------- /src/signal.cc: -------------------------------------------------------------------------------- 1 | // 2 | // libelkvm - A library that allows execution of an ELF binary inside a virtual 3 | // machine without a full-scale operating system 4 | // Copyright (C) 2013-2015 Florian Pester , Björn 5 | // Döbel , economic rights: Technische Universitaet 6 | // Dresden (Germany) 7 | // 8 | // This file is part of libelkvm. 9 | // 10 | // libelkvm is free software: you can redistribute it and/or modify 11 | // it under the terms of the GNU General Public License as published by 12 | // the Free Software Foundation, either version 3 of the License, or 13 | // (at your option) any later version. 14 | // 15 | // libelkvm is distributed in the hope that it will be useful, 16 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | // GNU General Public License for more details. 19 | // 20 | // You should have received a copy of the GNU General Public License 21 | // along with libelkvm. If not, see . 22 | // 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | #include 29 | #include 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | static int pending_signals[32]; 37 | static int num_pending_signals = 0; 38 | 39 | void elkvm_signal_handler(int signum) { 40 | 41 | printf("\n============ LIBELKVM ===========\n"); 42 | printf(" CAUGHT SIGNAL %i\n", signum); 43 | printf(" SIGNALS pending: %i\n", num_pending_signals); 44 | printf("=================================\n"); 45 | 46 | pending_signals[num_pending_signals] = signum; 47 | num_pending_signals++; 48 | 49 | } 50 | 51 | int Elkvm::VM::signal_register(int signum, struct sigaction *act, 52 | struct sigaction *oldact) { 53 | assert(signum < _NSIG); 54 | 55 | if(32 <= signum && signum <= 64) { 56 | /* these are real-time signals, we need to adjust the signal number, 57 | * because this is what the libc did, before the ELKVM proxy kernel 58 | * got the syscall, we need to adjust these back 59 | * XXX this is a crude and poorly understood hack! */ 60 | signum = signum % 32; 61 | signum += SIGRTMIN; 62 | } 63 | 64 | if(oldact != nullptr) { 65 | memcpy(oldact, const_cast(get_sig_ptr(signum)), 66 | sizeof(struct sigaction)); 67 | } 68 | 69 | if(act != nullptr) { 70 | memcpy(const_cast(get_sig_ptr(signum)), act, 71 | sizeof(struct sigaction)); 72 | 73 | struct sigaction sa; 74 | sa.sa_handler = elkvm_signal_handler; 75 | int err = sigemptyset(&sa.sa_mask); 76 | assert(err == 0); 77 | sa.sa_flags = 0; 78 | err = sigaction(signum, &sa, NULL); 79 | if(err) { 80 | ERROR() << "Error during sigaction: " << std::dec << err 81 | << " Msg: " << strerror(errno); 82 | } 83 | assert(err == 0); 84 | } 85 | 86 | return 0; 87 | } 88 | 89 | int Elkvm::VM::signal_deliver() { 90 | if(num_pending_signals <= 0) { 91 | return 0; 92 | } 93 | 94 | const auto & vcpu = get_vcpu(0); 95 | assert(vcpu != nullptr); 96 | 97 | num_pending_signals--; 98 | int signum = pending_signals[num_pending_signals]; 99 | 100 | /* push rax onto stack */ 101 | vcpu->push(vcpu->get_reg(Elkvm::Reg_t::rax)); 102 | 103 | /* push signal handler cleanup asm addr onto stack */ 104 | vcpu->push(get_cleanup_flat().region->guest_address()); 105 | 106 | /* setup the signal handler stack frame and pass the signal number as arg */ 107 | vcpu->push((uint64_t) get_sig_ptr(signum)->sa_handler); 108 | vcpu->set_reg(Elkvm::Reg_t::rdi, signum); 109 | 110 | return 0; 111 | } 112 | -------------------------------------------------------------------------------- /src/stack.cc: -------------------------------------------------------------------------------- 1 | // 2 | // libelkvm - A library that allows execution of an ELF binary inside a virtual 3 | // machine without a full-scale operating system 4 | // Copyright (C) 2013-2015 Florian Pester , Björn 5 | // Döbel , economic rights: Technische Universitaet 6 | // Dresden (Germany) 7 | // 8 | // This file is part of libelkvm. 9 | // 10 | // libelkvm is free software: you can redistribute it and/or modify 11 | // it under the terms of the GNU General Public License as published by 12 | // the Free Software Foundation, either version 3 of the License, or 13 | // (at your option) any later version. 14 | // 15 | // libelkvm is distributed in the hope that it will be useful, 16 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | // GNU General Public License for more details. 19 | // 20 | // You should have received a copy of the GNU General Public License 21 | // along with libelkvm. If not, see . 22 | // 23 | 24 | #include 25 | #include 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | namespace Elkvm { 36 | Stack::Stack(std::shared_ptr rm) 37 | : stack_regions(), 38 | _rm(rm), 39 | kernel_stack(nullptr), 40 | base(~0ULL) 41 | { 42 | /* as the stack grows downward we can initialize its address at the base address 43 | * of the env region */ 44 | base = LINUX_64_STACK_BASE; 45 | 46 | /* get memory for the stack, this is expanded as needed */ 47 | int err = expand(); 48 | assert(err == 0 && "stack creation failed"); 49 | 50 | /* get a frame for the kernel (interrupt) stack */ 51 | /* this is only ONE page large */ 52 | kernel_stack = _rm->allocate_region(ELKVM_PAGESIZE, "kernel stack"); 53 | 54 | /* create a mapping for the kernel (interrupt) stack */ 55 | guestptr_t kstack_addr = _rm->get_pager().map_kernel_page(kernel_stack->base_address(), 56 | PT_OPT_WRITE); 57 | assert(kstack_addr != 0x0 && "could not allocate memory for kernel stack"); 58 | 59 | kernel_stack->set_guest_addr(kstack_addr); 60 | } 61 | 62 | int Stack::pushq(guestptr_t rsp, uint64_t val) { 63 | uint64_t *host_p = reinterpret_cast( 64 | _rm->get_pager().get_host_p(rsp)); 65 | if(host_p == nullptr) { 66 | /* current stack is full, we need to expand the stack */ 67 | int err = expand(); 68 | if(err) { 69 | return err; 70 | } 71 | host_p = reinterpret_cast(_rm->get_pager().get_host_p(rsp)); 72 | assert(host_p != NULL); 73 | } 74 | *host_p = val; 75 | return 0; 76 | } 77 | 78 | uint64_t Stack::popq(guestptr_t rsp) { 79 | uint64_t *host_p = reinterpret_cast( 80 | _rm->get_pager().get_host_p(rsp)); 81 | assert(host_p != NULL); 82 | 83 | return *host_p; 84 | } 85 | 86 | int Stack::expand() { 87 | base -= ELKVM_STACK_GROW; 88 | 89 | std::shared_ptr region = _rm->allocate_region(ELKVM_STACK_GROW, "ELKVM stack"); 90 | if(region == nullptr) { 91 | return -ENOMEM; 92 | } 93 | 94 | int err = _rm->get_pager().map_region(region->base_address(), base, 95 | ELKVM_STACK_GROW / ELKVM_PAGESIZE, PT_OPT_WRITE); 96 | if(err) { 97 | return err; 98 | } 99 | 100 | region->set_guest_addr(base); 101 | stack_regions.push_back(region); 102 | 103 | return 0; 104 | } 105 | 106 | bool Stack::is_stack_expansion(guestptr_t pfla) { 107 | guestptr_t stack_top = page_begin(stack_regions.back()->guest_address()); 108 | if(pfla > stack_top) { 109 | return false; 110 | } 111 | 112 | guestptr_t aligned_pfla = page_begin(pfla); 113 | uint64_t pages = pages_from_size(stack_top - aligned_pfla); 114 | 115 | /* TODO right now this is an arbitrary number... */ 116 | return pages < 200; 117 | } 118 | 119 | bool Stack::grow(guestptr_t pfla) { 120 | if(is_stack_expansion(pfla)) { 121 | int err = expand(); 122 | assert(err == 0); 123 | return true; 124 | } 125 | 126 | return false; 127 | } 128 | 129 | //namespace Elkvm 130 | } 131 | -------------------------------------------------------------------------------- /src/syscall_default.cc: -------------------------------------------------------------------------------- 1 | // 2 | // libelkvm - A library that allows execution of an ELF binary inside a virtual 3 | // machine without a full-scale operating system 4 | // Copyright (C) 2013-2015 Florian Pester , Björn 5 | // Döbel , economic rights: Technische Universitaet 6 | // Dresden (Germany) 7 | // 8 | // This file is part of libelkvm. 9 | // 10 | // libelkvm is free software: you can redistribute it and/or modify 11 | // it under the terms of the GNU General Public License as published by 12 | // the Free Software Foundation, either version 3 of the License, or 13 | // (at your option) any later version. 14 | // 15 | // libelkvm is distributed in the hope that it will be useful, 16 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | // GNU General Public License for more details. 19 | // 20 | // You should have received a copy of the GNU General Public License 21 | // along with libelkvm. If not, see . 22 | // 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | #include 44 | #include 45 | 46 | long pass_read(int fd, void *buf, size_t count) { 47 | return read(fd, buf, count); 48 | } 49 | 50 | long pass_write(int fd, void *buf, size_t count) { 51 | return write(fd, buf, count); 52 | } 53 | 54 | long pass_open(const char *pathname, int flags, mode_t mode) { 55 | return open(pathname, flags, mode); 56 | } 57 | 58 | long pass_close(int fd) { 59 | return close(fd); 60 | } 61 | 62 | long pass_stat(const char *path, struct stat *buf) { 63 | return stat(path, buf); 64 | } 65 | 66 | long pass_fstat(int fd, struct stat *buf) { 67 | return fstat(fd, buf); 68 | } 69 | 70 | long pass_lstat(const char *path, struct stat *buf) { 71 | return lstat(path, buf); 72 | } 73 | 74 | long pass_lseek(int fd, off_t offset, int whence) { 75 | return lseek(fd, offset, whence); 76 | } 77 | 78 | long allow_sigaction(int signum __attribute__((unused)), 79 | const struct sigaction *act __attribute__((unused)), 80 | struct sigaction *oldact __attribute__((unused))) { 81 | return 1; 82 | } 83 | 84 | long pass_sigprocmask(int how, const sigset_t *set, sigset_t *old) 85 | { 86 | return sigprocmask(how, set, old); 87 | } 88 | 89 | long pass_ioctl(int fd, unsigned long request, char *argp) { 90 | return ioctl(fd, request, argp); 91 | } 92 | 93 | long pass_munmap(struct region_mapping *mapping) { 94 | return munmap(mapping->host_p, mapping->length); 95 | } 96 | 97 | long pass_readv(int fd, struct iovec *iov, int iovcnt) { 98 | return readv(fd, iov, iovcnt); 99 | } 100 | 101 | long pass_writev(int fd, struct iovec *iov, int iovcnt) { 102 | return writev(fd, iov, iovcnt); 103 | } 104 | 105 | long pass_access(const char *pathname, int mode) { 106 | return access(pathname, mode); 107 | } 108 | 109 | long pass_pipe(int pipefds[2]) { 110 | return pipe(pipefds); 111 | } 112 | 113 | long pass_dup(int oldfd) { 114 | return dup(oldfd); 115 | } 116 | 117 | long pass_nanosleep(const struct timespec* req, struct timespec* rem) 118 | { 119 | return nanosleep(req, rem); 120 | } 121 | 122 | long pass_getpid() { 123 | return getpid(); 124 | } 125 | 126 | long pass_getuid() { 127 | return getuid(); 128 | } 129 | 130 | long pass_getgid() { 131 | return getgid(); 132 | } 133 | 134 | long pass_geteuid() { 135 | return geteuid(); 136 | } 137 | 138 | long pass_getegid() { 139 | return getegid(); 140 | } 141 | 142 | long pass_uname(struct utsname *buf) { 143 | return uname(buf); 144 | } 145 | 146 | long pass_fcntl(int fd, int cmd, ...) { 147 | va_list ap; 148 | long result = 0; 149 | void *parg = NULL; 150 | int iarg = 0; 151 | 152 | va_start(ap, cmd); 153 | switch(cmd) { 154 | case F_GETOWN_EX: 155 | case F_SETOWN_EX: 156 | case F_GETLK: 157 | case F_SETLK: 158 | case F_SETLKW: 159 | parg = va_arg(ap, void *); 160 | result = fcntl(fd, cmd, parg); 161 | break; 162 | default: 163 | iarg = va_arg(ap, int); 164 | result = fcntl(fd, cmd, iarg); 165 | break; 166 | } 167 | 168 | va_end(ap); 169 | return result; 170 | } 171 | 172 | long pass_truncate(const char *path, off_t length) { 173 | return truncate(path, length); 174 | } 175 | 176 | long pass_ftruncate(int fd, off_t length) { 177 | return ftruncate(fd, length); 178 | } 179 | 180 | int pass_getdents(unsigned fd, struct linux_dirent *dirp, unsigned count) { 181 | return syscall(__NR_getdents, fd, dirp, count); 182 | } 183 | 184 | char *pass_getcwd(char *buf, size_t size) { 185 | return getcwd(buf, size); 186 | } 187 | 188 | int pass_chdir(char const *path) { 189 | return chdir(path); 190 | } 191 | 192 | int pass_fchdir(int fd) { 193 | return fchdir(fd); 194 | } 195 | 196 | long pass_mkdir(const char *pathname, mode_t mode) { 197 | return mkdir(pathname, mode); 198 | } 199 | 200 | long pass_unlink(const char *pathname) { 201 | return unlink(pathname); 202 | } 203 | 204 | long pass_readlink(const char *path, char *buf, size_t bufsiz) { 205 | return readlink(path, buf, bufsiz); 206 | } 207 | 208 | long pass_gettimeofday(struct timeval *tv, struct timezone *tz) { 209 | return gettimeofday(tv, tz); 210 | } 211 | 212 | long pass_getrusage(int who, struct rusage *usage) { 213 | return getrusage(who, usage); 214 | } 215 | 216 | long pass_statfs(const char *path, struct statfs *buf) { 217 | return statfs(path, buf); 218 | } 219 | 220 | int pass_fstatfs(int fd, struct statfs *buf) { 221 | return fstatfs(fd, buf); 222 | } 223 | 224 | long pass_setrlimit(int resource, const struct rlimit *rlim) { 225 | return setrlimit(resource, rlim); 226 | } 227 | 228 | long pass_gettid() { 229 | return syscall(__NR_gettid); 230 | } 231 | 232 | long pass_time(time_t *t) { 233 | return time(t); 234 | } 235 | 236 | long pass_futex(int *uaddr, int op, int val, const struct timespec *timeout, 237 | int *uaddr2, int val3) { 238 | return syscall(__NR_futex, uaddr, op, val, timeout, uaddr2, val3); 239 | } 240 | 241 | long pass_clock_gettime(clockid_t clk_id, struct timespec *tp) { 242 | return clock_gettime(clk_id, tp); 243 | } 244 | 245 | int pass_clock_getres(clockid_t clk_id, struct timespec *res) { 246 | return clock_getres(clk_id, res); 247 | } 248 | 249 | void pass_exit_group(int status) { 250 | exit(status); 251 | } 252 | 253 | long pass_tgkill(int tgid, int tid, int sig) { 254 | return syscall(__NR_tgkill, tgid, tid, sig); 255 | } 256 | 257 | int pass_openat(int dirfd, const char *pathname, int flags) { 258 | return openat(dirfd, pathname, flags); 259 | } 260 | 261 | long pass_socket(int domain, int type, int protocol) { 262 | return socket(domain, type, protocol); 263 | } 264 | 265 | long pass_bind(int sock, struct sockaddr const *addr, socklen_t addrlen) { 266 | return bind(sock, addr, addrlen); 267 | } 268 | 269 | long pass_accept(int sock, struct sockaddr* addr, socklen_t *len) { 270 | return accept(sock, addr, len); 271 | } 272 | 273 | long pass_listen(int sock, int backlog) { 274 | return listen(sock, backlog); 275 | } 276 | 277 | long pass_getsockname(int sock, struct sockaddr* addr, socklen_t *addrlen) { 278 | return getsockname(sock, addr, addrlen); 279 | } 280 | 281 | long pass_setsockopt(int sock, int lvl, int optname, const void* optval, 282 | socklen_t optlen) { 283 | return setsockopt(sock, lvl, optname, optval, optlen); 284 | } 285 | 286 | long pass_epoll_create(int size) { 287 | return epoll_create(size); 288 | } 289 | 290 | long pass_set_tid_address(int *tidptr) { 291 | return syscall(__NR_set_tid_address, tidptr); 292 | } 293 | 294 | long pass_epoll_ctl(int epfd, int op, int fd, struct epoll_event* event) { 295 | return epoll_ctl(epfd, op, fd, event); 296 | } 297 | 298 | 299 | long pass_epoll_wait(int epfd, struct epoll_event* events, int max, int timeout) { 300 | return epoll_wait(epfd, events, max, timeout); 301 | } 302 | 303 | long pass_set_robust_list(struct robust_list_head *head, size_t len) { 304 | return syscall(__NR_set_robust_list, head, len); 305 | } 306 | 307 | Elkvm::elkvm_handlers 308 | Elkvm::default_handlers = { 309 | .read = pass_read, 310 | .write = pass_write, 311 | .open = pass_open, 312 | .close = pass_close, 313 | .stat = pass_stat, 314 | .fstat = pass_fstat, 315 | .lstat = pass_lstat, 316 | .poll = NULL, 317 | .lseek = pass_lseek, 318 | .mmap_before = NULL, 319 | .mmap_after = NULL, 320 | .mprotect = NULL, 321 | .munmap = pass_munmap, 322 | /* ... */ 323 | .sigaction = allow_sigaction, 324 | .sigprocmask = pass_sigprocmask, 325 | .ioctl = pass_ioctl, 326 | /* ... */ 327 | .readv = pass_readv, 328 | .writev = pass_writev, 329 | .access = pass_access, 330 | .pipe = pass_pipe, 331 | .dup = pass_dup, 332 | /* ... */ 333 | .nanosleep = pass_nanosleep, 334 | /* ... */ 335 | .getpid = pass_getpid, 336 | /* ... */ 337 | .socket = pass_socket, 338 | .accept = pass_accept, 339 | .bind = pass_bind, 340 | .listen = pass_listen, 341 | .getsockname = pass_getsockname, 342 | /* ... */ 343 | .setsockopt = pass_setsockopt, 344 | /* ... */ 345 | .getuid = pass_getuid, 346 | .getgid = pass_getgid, 347 | .geteuid = pass_geteuid, 348 | .getegid = pass_getegid, 349 | /* ... */ 350 | .uname = pass_uname, 351 | .fcntl = pass_fcntl, 352 | .truncate = pass_truncate, 353 | .ftruncate = pass_ftruncate, 354 | .getdents = pass_getdents, 355 | .getcwd = pass_getcwd, 356 | .chdir = pass_chdir, 357 | .fchdir = pass_fchdir, 358 | .mkdir = pass_mkdir, 359 | .unlink = pass_unlink, 360 | .readlink = pass_readlink, 361 | /* ... */ 362 | .gettimeofday = pass_gettimeofday, 363 | .getrusage = pass_getrusage, 364 | .times = NULL, 365 | /* ... */ 366 | .statfs = pass_statfs, 367 | .fstatfs = pass_fstatfs, 368 | /* ... */ 369 | .setrlimit = pass_setrlimit, 370 | /* ... */ 371 | .gettid = pass_gettid, 372 | .time = pass_time, 373 | .futex = pass_futex, 374 | /* ... */ 375 | .epoll_create = pass_epoll_create, 376 | .set_tid_address = pass_set_tid_address, 377 | .epoll_ctl = pass_epoll_ctl, 378 | .epoll_wait = pass_epoll_wait, 379 | /* ... */ 380 | .clock_gettime = pass_clock_gettime, 381 | .clock_getres = pass_clock_getres, 382 | .exit_group = pass_exit_group, 383 | .tgkill = pass_tgkill, 384 | .openat = pass_openat, 385 | /* ... */ 386 | .set_robust_list = pass_set_robust_list, 387 | 388 | .bp_callback = NULL, 389 | }; 390 | 391 | Elkvm::hypercall_handlers 392 | Elkvm::hypercall_null = { 393 | .pre_handler = NULL, 394 | .post_handler = NULL, 395 | }; 396 | 397 | -------------------------------------------------------------------------------- /src/syscalls-clock.cc: -------------------------------------------------------------------------------- 1 | // 2 | // libelkvm - A library that allows execution of an ELF binary inside a virtual 3 | // machine without a full-scale operating system 4 | // Copyright (C) 2013-2015 Florian Pester , Björn 5 | // Döbel , economic rights: Technische Universitaet 6 | // Dresden (Germany) 7 | // 8 | // This file is part of libelkvm. 9 | // 10 | // libelkvm is free software: you can redistribute it and/or modify 11 | // it under the terms of the GNU General Public License as published by 12 | // the Free Software Foundation, either version 3 of the License, or 13 | // (at your option) any later version. 14 | // 15 | // libelkvm is distributed in the hope that it will be useful, 16 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | // GNU General Public License for more details. 19 | // 20 | // You should have received a copy of the GNU General Public License 21 | // along with libelkvm. If not, see . 22 | // 23 | 24 | #include 25 | #include 26 | 27 | #include 28 | 29 | long elkvm_do_clock_gettime(Elkvm::VM * vm) { 30 | if(vm->get_handlers()->clock_gettime == NULL) { 31 | ERROR() << "CLOCK GETTIME handler not found" << LOG_RESET << "\n"; 32 | return -ENOSYS; 33 | } 34 | 35 | CURRENT_ABI::paramtype clk_id = 0x0; 36 | CURRENT_ABI::paramtype tp_p = 0x0; 37 | struct timespec *tp = nullptr; 38 | 39 | vm->unpack_syscall(&clk_id, &tp_p); 40 | assert(tp_p != 0x0); 41 | 42 | tp = static_cast(vm->host_p(tp_p)); 43 | assert(tp != nullptr); 44 | 45 | long result = vm->get_handlers()->clock_gettime(clk_id, tp); 46 | if(vm->debug_mode()) { 47 | DBG() << "CLOCK GETTIME with clk_id: " << clk_id 48 | << " tp: " << LOG_GUEST_HOST(tp_p, tp); 49 | Elkvm::dbg_log_result(result); 50 | } 51 | return result; 52 | } 53 | 54 | long elkvm_do_clock_getres(Elkvm::VM * vm) { 55 | if(vm->get_handlers()->clock_getres == nullptr) { 56 | return -ENOSYS; 57 | } 58 | 59 | CURRENT_ABI::paramtype clk_id = 0x0; 60 | CURRENT_ABI::paramtype res_p = 0x0; 61 | struct timespec *res = nullptr; 62 | 63 | vm->unpack_syscall(&clk_id, &res_p); 64 | assert(res_p != 0x0); 65 | 66 | res = static_cast(vm->host_p(res_p)); 67 | assert(res != nullptr); 68 | 69 | auto result = vm->get_handlers()->clock_getres(clk_id, res); 70 | if(vm->debug_mode()) { 71 | DBG() << "CLOCK GETRES with clk_id: " << std::dec << clk_id 72 | << " res: " << LOG_GUEST_HOST(res_p, res); 73 | Elkvm::dbg_log_result(result); 74 | } 75 | return result; 76 | } 77 | -------------------------------------------------------------------------------- /src/syscalls-mprotect.cc: -------------------------------------------------------------------------------- 1 | // 2 | // libelkvm - A library that allows execution of an ELF binary inside a virtual 3 | // machine without a full-scale operating system 4 | // Copyright (C) 2013-2015 Florian Pester , Björn 5 | // Döbel , economic rights: Technische Universitaet 6 | // Dresden (Germany) 7 | // 8 | // This file is part of libelkvm. 9 | // 10 | // libelkvm is free software: you can redistribute it and/or modify 11 | // it under the terms of the GNU General Public License as published by 12 | // the Free Software Foundation, either version 3 of the License, or 13 | // (at your option) any later version. 14 | // 15 | // libelkvm is distributed in the hope that it will be useful, 16 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | // GNU General Public License for more details. 19 | // 20 | // You should have received a copy of the GNU General Public License 21 | // along with libelkvm. If not, see . 22 | // 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | namespace Elkvm { 30 | 31 | void slice_and_recreate(VM *vmi, Mapping &mapping, guestptr_t addr, size_t len, int prot) { 32 | auto flags = mapping.get_flags(); 33 | auto fd = mapping.get_fd(); 34 | auto off = mapping.get_offset(); 35 | /* we need to split this mapping */ 36 | vmi->get_heap_manager().slice(mapping, addr, len); 37 | vmi->get_heap_manager().create_mapping(addr, len, prot, flags, fd, off); 38 | } 39 | 40 | //namespace Elkvm 41 | } 42 | 43 | long elkvm_do_mprotect(Elkvm::VM * vmi) { 44 | guestptr_t addr = 0; 45 | CURRENT_ABI::paramtype len = 0; 46 | CURRENT_ABI::paramtype prot = 0; 47 | vmi->unpack_syscall(&addr, &len, &prot); 48 | 49 | assert(page_aligned(addr) && "mprotect address must be page aligned"); 50 | if(!vmi->get_heap_manager().address_mapped(addr)) { 51 | vmi->get_heap_manager().dump_mappings(); 52 | vmi->get_region_manager()->dump_regions(); 53 | INFO() <<"mprotect with invalid address: 0x" << std::hex 54 | << addr << std::endl; 55 | return -EINVAL; 56 | } 57 | 58 | Elkvm::Mapping &mapping = vmi->get_heap_manager().find_mapping(addr); 59 | int err = 0; 60 | 61 | assert(mapping.get_length() >= len); 62 | if(mapping.get_length() != len) { 63 | /* this will invalidate the mapping ref! */ 64 | slice_and_recreate(vmi, mapping, addr, len, prot); 65 | } else { 66 | /* only modify this mapping */ 67 | mapping.mprotect(prot); 68 | err = vmi->get_heap_manager().map(mapping); 69 | } 70 | 71 | if(vmi->debug_mode()) { 72 | DBG() << "MPROTECT requested with address 0x" 73 | << std::hex << addr 74 | << " len: 0x" << len 75 | << " prot: 0x" << prot; 76 | print(std::cout, mapping); 77 | DBG() << "RESULT: " << err; 78 | } 79 | 80 | return err; 81 | } 82 | -------------------------------------------------------------------------------- /src/syscalls-open.cc: -------------------------------------------------------------------------------- 1 | // 2 | // libelkvm - A library that allows execution of an ELF binary inside a virtual 3 | // machine without a full-scale operating system 4 | // Copyright (C) 2013-2015 Florian Pester , Björn 5 | // Döbel , economic rights: Technische Universitaet 6 | // Dresden (Germany) 7 | // 8 | // This file is part of libelkvm. 9 | // 10 | // libelkvm is free software: you can redistribute it and/or modify 11 | // it under the terms of the GNU General Public License as published by 12 | // the Free Software Foundation, either version 3 of the License, or 13 | // (at your option) any later version. 14 | // 15 | // libelkvm is distributed in the hope that it will be useful, 16 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | // GNU General Public License for more details. 19 | // 20 | // You should have received a copy of the GNU General Public License 21 | // along with libelkvm. If not, see . 22 | // 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | #include 29 | #include 30 | 31 | long elkvm_do_open(Elkvm::VM * vm) { 32 | if(vm->get_handlers()->open == nullptr) { 33 | ERROR() << "OPEN handler not found"; 34 | return -ENOSYS; 35 | } 36 | 37 | CURRENT_ABI::paramtype pathname_p = 0x0; 38 | char *pathname = nullptr; 39 | CURRENT_ABI::paramtype flags = 0x0; 40 | CURRENT_ABI::paramtype mode = 0x0; 41 | 42 | vm->unpack_syscall(&pathname_p, &flags, &mode); 43 | assert(pathname_p != 0x0); 44 | 45 | pathname = static_cast(vm->host_p(pathname_p)); 46 | 47 | long result = vm->get_handlers()->open(pathname, 48 | static_cast(flags), static_cast(mode)); 49 | 50 | if(vm->debug_mode()) { 51 | DBG() << "OPEN file " << LOG_GUEST_HOST(pathname_p, pathname) 52 | << " [" << pathname << "]" 53 | << " with flags 0x" << std::hex << flags 54 | << " mode 0x" << mode; 55 | Elkvm::dbg_log_result(result); 56 | } 57 | 58 | return result; 59 | } 60 | 61 | long elkvm_do_openat(Elkvm::VM * vm) { 62 | if(vm->get_handlers()->openat == nullptr) { 63 | ERROR() << "OPENAT handler not found" << LOG_RESET << "\n"; 64 | return -ENOSYS; 65 | } 66 | 67 | CURRENT_ABI::paramtype dirfd = 0; 68 | guestptr_t pathname_p = 0x0; 69 | CURRENT_ABI::paramtype flags = 0; 70 | 71 | vm->unpack_syscall(&dirfd, &pathname_p, &flags); 72 | 73 | char *pathname = nullptr; 74 | if(pathname_p != 0x0) { 75 | pathname = static_cast(vm->host_p(pathname_p)); 76 | } 77 | 78 | int res = vm->get_handlers()->openat(static_cast(dirfd), 79 | pathname, static_cast(flags)); 80 | if(vm->debug_mode()) { 81 | DBG() << "OPENAT with dirfd " << static_cast(dirfd) 82 | << " pathname " << LOG_GUEST_HOST(pathname_p, pathname) 83 | << " [" << std::string(pathname) << "]" 84 | << " flags " << flags; 85 | if(dirfd == AT_FDCWD) { 86 | DBG() << "-> AT_FDCWD"; 87 | } 88 | Elkvm::dbg_log_result(res); 89 | } 90 | 91 | if(res < 0) { 92 | return -errno; 93 | } 94 | 95 | return res; 96 | } 97 | -------------------------------------------------------------------------------- /src/syscalls-rlimit.cc: -------------------------------------------------------------------------------- 1 | // 2 | // libelkvm - A library that allows execution of an ELF binary inside a virtual 3 | // machine without a full-scale operating system 4 | // Copyright (C) 2013-2015 Florian Pester , Björn 5 | // Döbel , economic rights: Technische Universitaet 6 | // Dresden (Germany) 7 | // 8 | // This file is part of libelkvm. 9 | // 10 | // libelkvm is free software: you can redistribute it and/or modify 11 | // it under the terms of the GNU General Public License as published by 12 | // the Free Software Foundation, either version 3 of the License, or 13 | // (at your option) any later version. 14 | // 15 | // libelkvm is distributed in the hope that it will be useful, 16 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | // GNU General Public License for more details. 19 | // 20 | // You should have received a copy of the GNU General Public License 21 | // along with libelkvm. If not, see . 22 | // 23 | 24 | #include 25 | 26 | #include 27 | #include 28 | 29 | long elkvm_do_getrlimit(Elkvm::VM *vm) { 30 | CURRENT_ABI::paramtype resource = 0x0; 31 | CURRENT_ABI::paramtype rlim_p = 0x0; 32 | struct rlimit *rlim = NULL; 33 | 34 | vm->unpack_syscall(&resource, &rlim_p); 35 | 36 | assert(rlim_p != 0x0); 37 | rlim = static_cast(vm->host_p(rlim_p)); 38 | 39 | memcpy(rlim, vm->get_rlimit(resource), sizeof(struct rlimit)); 40 | if(vm->debug_mode()) { 41 | DBG() << "GETRLIMIT with resource: " << std::dec << resource 42 | << " rlim: " << LOG_GUEST_HOST(rlim_p, rlim); 43 | } 44 | 45 | return 0; 46 | } 47 | 48 | long elkvm_do_setrlimit(Elkvm::VM * vm) { 49 | if(vm->get_handlers()->setrlimit == nullptr) { 50 | return -ENOSYS; 51 | } 52 | 53 | CURRENT_ABI::paramtype resource = 0x0; 54 | CURRENT_ABI::paramtype rlim_p = 0x0; 55 | const struct rlimit *rlim = nullptr; 56 | 57 | vm->unpack_syscall(&resource, &rlim_p); 58 | assert(rlim_p != 0x0); 59 | 60 | rlim = static_cast(vm->host_p(rlim_p)); 61 | 62 | int err = vm->get_handlers()->setrlimit(resource, rlim); 63 | if(err == 0) { 64 | vm->set_rlimit(resource, rlim); 65 | } 66 | 67 | if(vm->debug_mode()) { 68 | DBG() << "GETRLIMIT with resource: " << std::dec << resource 69 | << " rlim: " << LOG_GUEST_HOST(rlim_p, rlim); 70 | Elkvm::dbg_log_result(err); 71 | } 72 | return err; 73 | } 74 | -------------------------------------------------------------------------------- /src/syscalls-robust_list.cc: -------------------------------------------------------------------------------- 1 | // 2 | // libelkvm - A library that allows execution of an ELF binary inside a virtual 3 | // machine without a full-scale operating system 4 | // Copyright (C) 2013-2015 Florian Pester , Björn 5 | // Döbel , economic rights: Technische Universitaet 6 | // Dresden (Germany) 7 | // 8 | // This file is part of libelkvm. 9 | // 10 | // libelkvm is free software: you can redistribute it and/or modify 11 | // it under the terms of the GNU General Public License as published by 12 | // the Free Software Foundation, either version 3 of the License, or 13 | // (at your option) any later version. 14 | // 15 | // libelkvm is distributed in the hope that it will be useful, 16 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | // GNU General Public License for more details. 19 | // 20 | // You should have received a copy of the GNU General Public License 21 | // along with libelkvm. If not, see . 22 | // 23 | 24 | #include 25 | #include 26 | 27 | #include 28 | #include 29 | 30 | long elkvm_do_set_robust_list(Elkvm::VM *vm __attribute__((unused))) { 31 | if(vm->get_handlers()->set_robust_list == nullptr) { 32 | return -ENOSYS; 33 | } 34 | 35 | struct robust_list_head *head = nullptr; 36 | size_t len = 0x0; 37 | CURRENT_ABI::paramtype head_p = 0x0; 38 | 39 | vm->unpack_syscall(&head_p, &len); 40 | assert(head_p != 0x0); 41 | 42 | head = static_cast(vm->host_p(head_p)); 43 | long result = vm->get_handlers()->set_robust_list(head, len); 44 | if(vm->debug_mode()) { 45 | DBG() << "SET ROBUST LIST: head: " << LOG_GUEST_HOST(head_p, head) 46 | << " len: " << len; 47 | Elkvm::dbg_log_result(result); 48 | } 49 | return result; 50 | } 51 | 52 | -------------------------------------------------------------------------------- /src/syscalls-set_tid_address.cc: -------------------------------------------------------------------------------- 1 | // 2 | // libelkvm - A library that allows execution of an ELF binary inside a virtual 3 | // machine without a full-scale operating system 4 | // Copyright (C) 2013-2015 Florian Pester , Björn 5 | // Döbel , economic rights: Technische Universitaet 6 | // Dresden (Germany) 7 | // 8 | // This file is part of libelkvm. 9 | // 10 | // libelkvm is free software: you can redistribute it and/or modify 11 | // it under the terms of the GNU General Public License as published by 12 | // the Free Software Foundation, either version 3 of the License, or 13 | // (at your option) any later version. 14 | // 15 | // libelkvm is distributed in the hope that it will be useful, 16 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | // GNU General Public License for more details. 19 | // 20 | // You should have received a copy of the GNU General Public License 21 | // along with libelkvm. If not, see . 22 | // 23 | 24 | #include 25 | #include 26 | 27 | long elkvm_do_set_tid_address(Elkvm::VM * vm) { 28 | if(vm->get_handlers()->set_tid_address == nullptr) { 29 | return -ENOSYS; 30 | } 31 | 32 | int *tidptr = nullptr; 33 | CURRENT_ABI::paramtype tidptr_p = 0x0; 34 | vm->unpack_syscall(&tidptr_p); 35 | assert(tidptr_p != 0x0); 36 | 37 | tidptr = static_cast(vm->host_p(tidptr_p)); 38 | assert(tidptr != nullptr); 39 | long result = vm->get_handlers()->set_tid_address(tidptr); 40 | if(vm->debug_mode()) { 41 | DBG() << "SET TID ADDRESS tidptr at: " << LOG_GUEST_HOST(tidptr_p, tidptr); 42 | Elkvm::dbg_log_result(result); 43 | } 44 | 45 | return result; 46 | } 47 | 48 | -------------------------------------------------------------------------------- /src/syscalls-signal.cc: -------------------------------------------------------------------------------- 1 | // 2 | // libelkvm - A library that allows execution of an ELF binary inside a virtual 3 | // machine without a full-scale operating system 4 | // Copyright (C) 2013-2015 Florian Pester , Björn 5 | // Döbel , economic rights: Technische Universitaet 6 | // Dresden (Germany) 7 | // 8 | // This file is part of libelkvm. 9 | // 10 | // libelkvm is free software: you can redistribute it and/or modify 11 | // it under the terms of the GNU General Public License as published by 12 | // the Free Software Foundation, either version 3 of the License, or 13 | // (at your option) any later version. 14 | // 15 | // libelkvm is distributed in the hope that it will be useful, 16 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | // GNU General Public License for more details. 19 | // 20 | // You should have received a copy of the GNU General Public License 21 | // along with libelkvm. If not, see . 22 | // 23 | 24 | #include 25 | #include 26 | 27 | long elkvm_do_sigaction(Elkvm::VM * vm) { 28 | if(vm->get_handlers()->sigaction == nullptr) { 29 | ERROR() << "SIGACTION handler not found" << LOG_RESET << "\n"; 30 | return -ENOSYS; 31 | } 32 | 33 | CURRENT_ABI::paramtype signum; 34 | CURRENT_ABI::paramtype act_p; 35 | CURRENT_ABI::paramtype oldact_p; 36 | 37 | vm->unpack_syscall(&signum, &act_p, &oldact_p); 38 | 39 | struct sigaction *act = nullptr; 40 | struct sigaction *oldact = nullptr; 41 | if(act_p != 0x0) { 42 | act = static_cast(vm->host_p(act_p)); 43 | } 44 | if(oldact_p != 0x0) { 45 | oldact = static_cast(vm->host_p(oldact_p)); 46 | } 47 | 48 | int err = 0; 49 | if(vm->get_handlers()->sigaction(static_cast(signum), act, oldact)) { 50 | err = vm->signal_register(static_cast(signum), act, oldact); 51 | } 52 | 53 | if(vm->debug_mode()) { 54 | DBG() << "SIGACTION with signum " << signum 55 | << " act " << LOG_GUEST_HOST(act_p, act) 56 | << " oldact " << LOG_GUEST_HOST(oldact_p, oldact); 57 | Elkvm::dbg_log_result(err); 58 | } 59 | 60 | return err; 61 | } 62 | 63 | long elkvm_do_sigprocmask(Elkvm::VM * vm) { 64 | if(vm->get_handlers()->sigprocmask == nullptr) { 65 | ERROR() << "SIGPROCMASK handler not found" << LOG_RESET << "\n"; 66 | return -ENOSYS; 67 | } 68 | 69 | CURRENT_ABI::paramtype how; 70 | CURRENT_ABI::paramtype set_p; 71 | CURRENT_ABI::paramtype oldset_p; 72 | 73 | vm->unpack_syscall(&how, &set_p, &oldset_p); 74 | 75 | sigset_t *set = nullptr; 76 | sigset_t *oldset = nullptr; 77 | if(set_p != 0x0) { 78 | set = static_cast(vm->host_p(set_p)); 79 | } 80 | if(oldset_p != 0x0) { 81 | oldset = static_cast(vm->host_p(oldset_p)); 82 | } 83 | 84 | long result = vm->get_handlers()->sigprocmask(how, set, oldset); 85 | if(vm->debug_mode()) { 86 | DBG() << "RT SIGPROCMASK with how: " << how << " (" << (void*)&how << ") " 87 | << "set: " << (void*)set_p << " (" << (void*)set << ") " 88 | << "oldset: " << (void*)oldset_p << " (" << (void*)oldset; 89 | Elkvm::dbg_log_result(result); 90 | } 91 | return result; 92 | } 93 | -------------------------------------------------------------------------------- /src/syscalls-socket.cc: -------------------------------------------------------------------------------- 1 | // 2 | // libelkvm - A library that allows execution of an ELF binary inside a virtual 3 | // machine without a full-scale operating system 4 | // Copyright (C) 2013-2015 Florian Pester , Björn 5 | // Döbel , economic rights: Technische Universitaet 6 | // Dresden (Germany) 7 | // 8 | // This file is part of libelkvm. 9 | // 10 | // libelkvm is free software: you can redistribute it and/or modify 11 | // it under the terms of the GNU General Public License as published by 12 | // the Free Software Foundation, either version 3 of the License, or 13 | // (at your option) any later version. 14 | // 15 | // libelkvm is distributed in the hope that it will be useful, 16 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | // GNU General Public License for more details. 19 | // 20 | // You should have received a copy of the GNU General Public License 21 | // along with libelkvm. If not, see . 22 | // 23 | 24 | #include 25 | #include 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | long elkvm_do_sendfile(Elkvm::VM * vmi __attribute__((unused))) { 32 | ERROR() << "unimplemented"; exit(1); 33 | return -ENOSYS; 34 | } 35 | 36 | long elkvm_do_socket(Elkvm::VM * vmi __attribute__((unused))) { 37 | CURRENT_ABI::paramtype domain; 38 | CURRENT_ABI::paramtype type; 39 | CURRENT_ABI::paramtype protocol; 40 | 41 | vmi->unpack_syscall(&domain, &type, &protocol); 42 | return vmi->get_handlers()->socket(domain, type, protocol); 43 | } 44 | 45 | long elkvm_do_connect(Elkvm::VM * vmi __attribute__((unused))) { 46 | ERROR() << "unimplemented"; exit(1); 47 | return -ENOSYS; 48 | } 49 | 50 | long elkvm_do_accept(Elkvm::VM * vmi __attribute__((unused))) { 51 | CURRENT_ABI::paramtype sock; 52 | CURRENT_ABI::paramtype addr; 53 | CURRENT_ABI::paramtype len; 54 | struct sockaddr* local_addr = 0; 55 | socklen_t *local_len = 0; 56 | 57 | vmi->unpack_syscall(&sock, &addr, &len); 58 | 59 | if (addr != 0) { 60 | local_addr = reinterpret_cast(vmi->get_region_manager()->get_pager().get_host_p(addr)); 61 | } 62 | if (len != 0) { 63 | local_len = reinterpret_cast(vmi->get_region_manager()->get_pager().get_host_p(len)); 64 | } 65 | 66 | return vmi->get_handlers()->accept(sock, local_addr, local_len); 67 | } 68 | 69 | long elkvm_do_sendto(Elkvm::VM * vmi __attribute__((unused))) { 70 | ERROR() << "unimplemented"; exit(1); 71 | return -ENOSYS; 72 | } 73 | 74 | long elkvm_do_recvfrom(Elkvm::VM * vmi __attribute__((unused))) { 75 | ERROR() << "unimplemented"; exit(1); 76 | return -ENOSYS; 77 | } 78 | 79 | long elkvm_do_sendmsg(Elkvm::VM * vmi __attribute__((unused))) { 80 | ERROR() << "unimplemented"; exit(1); 81 | return -ENOSYS; 82 | } 83 | 84 | long elkvm_do_recvmsg(Elkvm::VM * vmi __attribute__((unused))) { 85 | ERROR() << "unimplemented"; exit(1); 86 | return -ENOSYS; 87 | } 88 | 89 | long elkvm_do_shutdown(Elkvm::VM * vmi __attribute__((unused))) { 90 | ERROR() << "unimplemented"; exit(1); 91 | return -ENOSYS; 92 | } 93 | 94 | long elkvm_do_bind(Elkvm::VM * vmi __attribute__((unused))) { 95 | CURRENT_ABI::paramtype sock; 96 | CURRENT_ABI::paramtype addr; 97 | CURRENT_ABI::paramtype addrlen; 98 | 99 | vmi->unpack_syscall(&sock, &addr, &addrlen); 100 | const struct sockaddr* local_addr = 0; 101 | if (addr) { 102 | local_addr = reinterpret_cast(vmi->get_region_manager()->get_pager().get_host_p(addr)); 103 | } 104 | 105 | return vmi->get_handlers()->bind(sock, local_addr, addrlen); 106 | } 107 | 108 | long elkvm_do_listen(Elkvm::VM * vmi __attribute__((unused))) { 109 | CURRENT_ABI::paramtype sock; 110 | CURRENT_ABI::paramtype backlog; 111 | 112 | vmi->unpack_syscall(&sock, &backlog); 113 | return vmi->get_handlers()->listen(sock, backlog); 114 | } 115 | 116 | long elkvm_do_getsockname(Elkvm::VM * vmi __attribute__((unused))) { 117 | CURRENT_ABI::paramtype sock; 118 | CURRENT_ABI::paramtype addr; 119 | CURRENT_ABI::paramtype len; 120 | struct sockaddr* local_addr = 0; 121 | socklen_t *local_len = 0; 122 | 123 | vmi->unpack_syscall(&sock, &addr, &len); 124 | 125 | if (addr != 0) { 126 | local_addr = reinterpret_cast(vmi->get_region_manager()->get_pager().get_host_p(addr)); 127 | } 128 | if (len != 0) { 129 | local_len = reinterpret_cast(vmi->get_region_manager()->get_pager().get_host_p(len)); 130 | } 131 | return vmi->get_handlers()->getsockname(sock, local_addr, local_len); 132 | } 133 | 134 | long elkvm_do_getpeername(Elkvm::VM * vmi __attribute__((unused))) { 135 | ERROR() << "unimplemented"; exit(1); 136 | return -ENOSYS; 137 | } 138 | 139 | long elkvm_do_socketpair(Elkvm::VM * vmi __attribute__((unused))) { 140 | ERROR() << "unimplemented"; exit(1); 141 | return -ENOSYS; 142 | } 143 | 144 | long elkvm_do_setsockopt(Elkvm::VM * vmi __attribute__((unused))) { 145 | CURRENT_ABI::paramtype sock; 146 | CURRENT_ABI::paramtype lvl; 147 | CURRENT_ABI::paramtype optname; 148 | CURRENT_ABI::paramtype optval; 149 | CURRENT_ABI::paramtype optlen; 150 | 151 | void* local_optval = 0; 152 | 153 | vmi->unpack_syscall(&sock, &lvl, &optname, &optval, &optlen); 154 | 155 | if (optval != 0) { 156 | local_optval = vmi->get_region_manager()->get_pager().get_host_p(optval); 157 | } 158 | 159 | return vmi->get_handlers()->setsockopt(sock, lvl, optname, local_optval, optlen); 160 | } 161 | 162 | long elkvm_do_getsockopt(Elkvm::VM * vmi __attribute__((unused))) { 163 | ERROR() << "unimplemented"; exit(1); 164 | return -ENOSYS; 165 | } 166 | 167 | -------------------------------------------------------------------------------- /src/syscalls-statfs.cc: -------------------------------------------------------------------------------- 1 | // 2 | // libelkvm - A library that allows execution of an ELF binary inside a virtual 3 | // machine without a full-scale operating system 4 | // Copyright (C) 2013-2015 Florian Pester , Björn 5 | // Döbel , economic rights: Technische Universitaet 6 | // Dresden (Germany) 7 | // 8 | // This file is part of libelkvm. 9 | // 10 | // libelkvm is free software: you can redistribute it and/or modify 11 | // it under the terms of the GNU General Public License as published by 12 | // the Free Software Foundation, either version 3 of the License, or 13 | // (at your option) any later version. 14 | // 15 | // libelkvm is distributed in the hope that it will be useful, 16 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | // GNU General Public License for more details. 19 | // 20 | // You should have received a copy of the GNU General Public License 21 | // along with libelkvm. If not, see . 22 | // 23 | 24 | #include 25 | 26 | #include 27 | #include 28 | 29 | long elkvm_do_statfs(Elkvm::VM * vm) { 30 | if(vm->get_handlers()->statfs == nullptr) { 31 | INFO() <<"STATFS handler not found\n"; 32 | return -ENOSYS; 33 | } 34 | 35 | guestptr_t path_p = 0x0; 36 | guestptr_t buf_p = 0x0; 37 | 38 | vm->unpack_syscall(&path_p, &buf_p); 39 | 40 | char *path = nullptr; 41 | struct statfs *buf = nullptr; 42 | if(path_p != 0x0) { 43 | path = static_cast(vm->host_p(path_p)); 44 | } 45 | if(buf_p != 0x0) { 46 | buf = static_cast(vm->host_p(buf_p)); 47 | } 48 | 49 | int res = vm->get_handlers()->statfs(path, buf); 50 | if(vm->debug_mode()) { 51 | DBG() << "STATFS path: " << LOG_GUEST_HOST(path_p, path) 52 | << " [" << std::string(path) << "]" 53 | << " buf: " << LOG_GUEST_HOST(buf_p, buf); 54 | Elkvm::dbg_log_result(res); 55 | } 56 | 57 | if(res == 0) { 58 | return 0; 59 | } 60 | return -errno; 61 | } 62 | 63 | long elkvm_do_fstatfs(Elkvm::VM * vm __attribute__((unused))) { 64 | if(vm->get_handlers()->fstatfs == nullptr) { 65 | return -ENOSYS; 66 | } 67 | 68 | CURRENT_ABI::paramtype fd = 0x0; 69 | CURRENT_ABI::paramtype buf_p = 0x0; 70 | 71 | vm->unpack_syscall(&fd, &buf_p); 72 | 73 | struct statfs *buf = nullptr; 74 | if(buf_p != 0x0) { 75 | buf = static_cast(vm->host_p(buf_p)); 76 | } 77 | 78 | auto result = vm->get_handlers()->fstatfs(fd, buf); 79 | if(vm->debug_mode()) { 80 | DBG() << "FSTATFS fd: " << std::dec << fd 81 | << "buf: " << LOG_GUEST_HOST(buf_p, buf); 82 | Elkvm::dbg_log_result(result); 83 | } 84 | return result; 85 | } 86 | -------------------------------------------------------------------------------- /src/tss.cc: -------------------------------------------------------------------------------- 1 | // 2 | // libelkvm - A library that allows execution of an ELF binary inside a virtual 3 | // machine without a full-scale operating system 4 | // Copyright (C) 2013-2015 Florian Pester , Björn 5 | // Döbel , economic rights: Technische Universitaet 6 | // Dresden (Germany) 7 | // 8 | // This file is part of libelkvm. 9 | // 10 | // libelkvm is free software: you can redistribute it and/or modify 11 | // it under the terms of the GNU General Public License as published by 12 | // the Free Software Foundation, either version 3 of the License, or 13 | // (at your option) any later version. 14 | // 15 | // libelkvm is distributed in the hope that it will be useful, 16 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | // GNU General Public License for more details. 19 | // 20 | // You should have received a copy of the GNU General Public License 21 | // along with libelkvm. If not, see . 22 | // 23 | 24 | #include 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | int elkvm_tss_setup64(std::shared_ptr vcpu, Elkvm::RegionManager &rm, std::shared_ptr r) { 33 | guestptr_t guest_virtual = 34 | rm.get_pager().map_kernel_page( 35 | r->base_address(), 0); 36 | assert(guest_virtual != 0x0 && "could not map tss"); 37 | 38 | r->set_guest_addr(guest_virtual); 39 | struct elkvm_tss64 *tss = (struct elkvm_tss64 *)r->base_address(); 40 | memset(tss, 0, sizeof(struct elkvm_tss64)); 41 | 42 | tss->ist1 = vcpu->kernel_stack_base() + ELKVM_PAGESIZE; 43 | tss->rsp0 = 0xFFFFFFFFFFFFFFFF; 44 | tss->rsp2 = 0x00007FFFFFFFFFFF; 45 | return 0; 46 | } 47 | 48 | int elkvm_tss_setup32(struct elkvm_tss32 *tss, 49 | int kernel_data_selector) { 50 | memset(tss, 0, sizeof(struct elkvm_tss32)); 51 | 52 | tss->ss0 = kernel_data_selector; 53 | tss->esp0 = 0x1042; 54 | //tss->iopb = sizeof(struct elkvm_tss); 55 | 56 | // /* 57 | // It's a quirk in the Intel implementation of hardware virtualization 58 | // extensions. You cannot enter guest mode in vmx with the guest cr0.pe 59 | // cleared (i.e. real mode), so kvm enters the guest in vm86 mode which 60 | // is fairly similar and tries to massage things so it looks to the guest 61 | // as if it is running in real mode. Unfortunately, vm86 mode requires a 62 | // task state segment in the address space, and there is no way for us to 63 | // hide it. kvm doesn't know anything about the guest physical memory map, 64 | // so it has to rely on userspace to supply an unused region. 65 | // */ 66 | // int intel_workaround = ioctl(kvm_fd, KVM_CHECK_EXTENSION, KVM_CAP_SET_TSS_ADDR); 67 | // if(intel_workaround > 0) { 68 | // err = ioctl(vm_fd, KVM_SET_TSS_ADDR, TSS_ADDR); 69 | // if(err < 0) { 70 | // return -errno; 71 | // } 72 | // } 73 | 74 | return 0; 75 | } 76 | -------------------------------------------------------------------------------- /src/udis86.cc: -------------------------------------------------------------------------------- 1 | // 2 | // libelkvm - A library that allows execution of an ELF binary inside a virtual 3 | // machine without a full-scale operating system 4 | // Copyright (C) 2013-2015 Florian Pester , Björn 5 | // Döbel , economic rights: Technische Universitaet 6 | // Dresden (Germany) 7 | // 8 | // This file is part of libelkvm. 9 | // 10 | // libelkvm is free software: you can redistribute it and/or modify 11 | // it under the terms of the GNU General Public License as published by 12 | // the Free Software Foundation, either version 3 of the License, or 13 | // (at your option) any later version. 14 | // 15 | // libelkvm is distributed in the hope that it will be useful, 16 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | // GNU General Public License for more details. 19 | // 20 | // You should have received a copy of the GNU General Public License 21 | // along with libelkvm. If not, see . 22 | // 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include 30 | 31 | #ifdef HAVE_LIBUDIS86 32 | #include 33 | #endif 34 | 35 | namespace Elkvm { 36 | 37 | UDis::UDis(const uint8_t *ptr) : 38 | ud_obj() { 39 | #ifdef HAVE_LIBUDIS86 40 | ud_init(&ud_obj); 41 | ud_set_mode(&ud_obj, bits); 42 | ud_set_syntax(&ud_obj, UD_SYN_INTEL); 43 | ud_set_input_buffer(&ud_obj, ptr, disassembly_size); 44 | #else 45 | (void)ptr; 46 | #endif 47 | } 48 | 49 | int UDis::disassemble() { 50 | #ifdef HAVE_LIBUDIS86 51 | return ud_disassemble(&ud_obj); 52 | #else 53 | return 0; 54 | #endif 55 | } 56 | 57 | std::string UDis::next_insn() { 58 | #ifdef HAVE_LIBUDIS86 59 | return ud_insn_asm(&ud_obj); 60 | #else 61 | return ""; 62 | #endif 63 | } 64 | 65 | std::ostream &print_code(std::ostream &os, const VM &vm, const VCPU &vcpu) { 66 | return print_code(os, vm, vcpu.get_reg(Elkvm::Reg_t::rip)); 67 | } 68 | 69 | std::ostream &print_code(std::ostream &os __attribute__((unused)), 70 | const VM &vm __attribute__((unused)), 71 | guestptr_t addr __attribute__((unused))) { 72 | #ifdef HAVE_LIBUDIS86 73 | 74 | const uint8_t *host_p = static_cast( 75 | vm.get_region_manager()->get_pager().get_host_p(addr)); 76 | assert(host_p != nullptr); 77 | 78 | UDis ud(host_p); 79 | 80 | os << "\n Code (from 0x" << std::hex << addr << "):\n" 81 | << " ------------------------------\n"; 82 | while(ud.disassemble()) { 83 | os << " " << ud.next_insn() << std::endl; 84 | } 85 | os << std::endl; 86 | #else 87 | os << "Printing code needs libudis86\n\n"; 88 | #endif 89 | return os; 90 | } 91 | 92 | //namespace Elkvm 93 | } 94 | -------------------------------------------------------------------------------- /src/vm_internals.cc: -------------------------------------------------------------------------------- 1 | // 2 | // libelkvm - A library that allows execution of an ELF binary inside a virtual 3 | // machine without a full-scale operating system 4 | // Copyright (C) 2013-2015 Florian Pester , Björn 5 | // Döbel , economic rights: Technische Universitaet 6 | // Dresden (Germany) 7 | // 8 | // This file is part of libelkvm. 9 | // 10 | // libelkvm is free software: you can redistribute it and/or modify 11 | // it under the terms of the GNU General Public License as published by 12 | // the Free Software Foundation, either version 3 of the License, or 13 | // (at your option) any later version. 14 | // 15 | // libelkvm is distributed in the hope that it will be useful, 16 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | // GNU General Public License for more details. 19 | // 20 | // You should have received a copy of the GNU General Public License 21 | // along with libelkvm. If not, see . 22 | // 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | namespace Elkvm { 41 | extern std::vector vmi; 42 | 43 | VM::VM(int vmfd, int argc, char ** argv, char **environ, 44 | int run_struct_size, 45 | const Elkvm::hypercall_handlers * const hyp_handlers, 46 | const Elkvm::elkvm_handlers * const handlers, 47 | int debug) : 48 | cpus(), 49 | _debug(debug == 1), 50 | _rm(std::make_shared(vmfd)), 51 | _gdt(nullptr), 52 | hm(_rm), 53 | _vmfd(vmfd), 54 | _argc(argc), 55 | _argv(argv), 56 | _environ(environ), 57 | _run_struct_size(run_struct_size), 58 | _rlimit(), 59 | sigs(), 60 | sighandler_cleanup(), 61 | hypercall_handlers(hyp_handlers), 62 | syscall_handlers(handlers) 63 | {} 64 | 65 | int VM::add_cpu() { 66 | std::shared_ptr vcpu = 67 | std::make_shared(_rm, _vmfd, cpus.size()); 68 | 69 | if(vcpu == NULL) { 70 | return -ENOMEM; 71 | } 72 | 73 | cpus.push_back(vcpu); 74 | 75 | vcpu->set_regs(); 76 | vcpu->set_sregs(); 77 | return 0; 78 | } 79 | 80 | bool VM::address_mapped(guestptr_t addr) const { 81 | return hm.address_mapped(addr); 82 | } 83 | 84 | Mapping &VM::find_mapping(guestptr_t addr) { 85 | if(hm.contains_address(addr)) { 86 | return hm.find_mapping(addr); 87 | } 88 | assert(false && "could not find mapping!"); 89 | } 90 | 91 | 92 | int VM::load_flat(Elkvm::elkvm_flat &flat, const std::string path, 93 | bool kernel) { 94 | int fd = open(path.c_str(), O_RDONLY); 95 | if(fd < 0) { 96 | ERROR() << "Could not find flat binary at: " << path << std::endl; 97 | return -errno; 98 | } 99 | 100 | struct stat stbuf; 101 | int err = fstat(fd, &stbuf); 102 | if(err) { 103 | close(fd); 104 | return -errno; 105 | } 106 | 107 | flat.size = stbuf.st_size; 108 | std::shared_ptr region = _rm->allocate_region(stbuf.st_size,path.c_str()); 109 | 110 | if(kernel) { 111 | guestptr_t addr = _rm->get_pager().map_kernel_page( 112 | region->base_address(), 113 | PT_OPT_EXEC); 114 | if(addr == 0x0) { 115 | close(fd); 116 | return -ENOMEM; 117 | } 118 | region->set_guest_addr(addr); 119 | } else { 120 | /* XXX this will break! */ 121 | region->set_guest_addr(0x1000); 122 | err = _rm->get_pager().map_user_page( 123 | region->base_address(), 124 | region->guest_address(), 125 | PT_OPT_EXEC); 126 | assert(err == 0); 127 | } 128 | 129 | char *buf = reinterpret_cast(region->base_address()); 130 | int bufsize = ELKVM_PAGESIZE; 131 | int bytes = 0; 132 | while((bytes = read(fd, buf, bufsize)) > 0) { 133 | buf += bytes; 134 | } 135 | 136 | close(fd); 137 | flat.region = region; 138 | 139 | return 0; 140 | } 141 | 142 | const std::shared_ptr& VM::get_vcpu(int num) const { 143 | return cpus.at(num); 144 | } 145 | 146 | Elkvm::elkvm_flat &VM::get_cleanup_flat() { 147 | return sighandler_cleanup; 148 | } 149 | 150 | const struct sigaction* VM::get_sig_ptr(unsigned sig) const { 151 | return &sigs.signals[sig]; 152 | } 153 | 154 | // TODO: needed? 155 | bool operator==(const VM &lhs, const VM &rhs) { 156 | return lhs.get_vmfd() == rhs.get_vmfd(); 157 | } 158 | 159 | #if 0 160 | VM &get_vmi(Elkvm::kvm_vm *vm) { 161 | auto it = std::find(vmi.begin(), vmi.end(), *vm); 162 | assert(it != vmi.end()); 163 | return *it; 164 | } 165 | #endif 166 | 167 | /* TODO: Should be a function of the vCPU */ 168 | unsigned get_hypercall_type(const std::shared_ptr& vcpu) 169 | { 170 | return vcpu->pop(); 171 | } 172 | 173 | //namespace Elkvm 174 | } 175 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_gmock_test(libelkvm_vcpu_test test_vcpu.cc) 2 | add_gmock_test(libelkvm_pager_test test_pager.cc) 3 | add_gmock_test(libelkvm_region_test test_region.cc) 4 | add_gmock_test(libelkvm_region_manager_test test_region_manager.cc) 5 | add_gmock_test(libelkvm_elfloader_test test_elfloader.cc) 6 | add_gmock_test(libelkvm_mapping_test test_mapping.cc) 7 | -------------------------------------------------------------------------------- /test/integration/001-run.exp: -------------------------------------------------------------------------------- 1 | #!/usr/bin/expect -f 2 | 3 | set build $env(ELKVM_BUILD) 4 | set timeout 5 5 | log_user 0 6 | #exp_internal 1 7 | 8 | proc failure { msg output } { 9 | send_user "\n========= $msg =========\n"; 10 | send_user "Output was:\n"; 11 | send_user $output; 12 | exit 1; 13 | } 14 | 15 | spawn $build/examples/proxy/proxy ./hello.static & 16 | expect { 17 | "Hello world" { exit 0 } 18 | eof 19 | { 20 | failure "Test terminated prematurely (Expecting 'Hello world')" $expect_out(buffer); 21 | } 22 | timeout 23 | { 24 | failure "Test timed out. This most likely happens because you did not enable the ELKVM kernel patch." $expect_out(buffer); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /test/integration/002-proxy.exp: -------------------------------------------------------------------------------- 1 | #!/usr/bin/expect -f 2 | 3 | set build $env(ELKVM_BUILD) 4 | set timeout 5 5 | log_user 0 6 | #exp_internal 1 7 | 8 | proc failure { msg output } { 9 | send_user "\n========= $msg =========\n"; 10 | send_user "Output was:\n"; 11 | send_user $output; 12 | exit 1; 13 | } 14 | 15 | spawn $build/examples/proxy/proxy -d ./hello.static & 16 | expect { 17 | "EXIT GROUP" { exit 0 } 18 | eof 19 | { 20 | failure "Test terminated prematurely (Expecting 'EXIT GROUP')" $expect_out(buffer); 21 | } 22 | timeout 23 | { 24 | failure "Test timed out. This most likely happens because you did not enable the ELKVM kernel patch." $expect_out(buffer); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /test/integration/003-attach.exp: -------------------------------------------------------------------------------- 1 | #!/usr/bin/expect -f 2 | 3 | set build $env(ELKVM_BUILD) 4 | set timeout 7 5 | log_user 0 6 | exp_internal 0 7 | 8 | proc failure { msg output } { 9 | send_user "\n========= $msg =========\n"; 10 | send_user "Output was:\n"; 11 | send_user $output; 12 | exit 1; 13 | } 14 | 15 | # 1) Launch the process that we want to attach to 16 | spawn ./hello.attach & 17 | # 2) Get the PID that hello.attach prints 18 | expect { 19 | -re "I am PID.*--- (.+) ---.*\r" 20 | { 21 | set attach_id $spawn_id 22 | set pid "$expect_out(1,string)\n"; 23 | #send_user "PID: $pid"; 24 | } 25 | eof 26 | { 27 | failure "Error spawning attach process.\n" $expect_out(buffer) 28 | } 29 | timeout { failure "TIMEOUT" "" } 30 | } 31 | 32 | # 3) Let it run until the 3rd iteration of the print loop 33 | expect { 34 | -i $attach_id 35 | "hello 3" { } 36 | eof { failure "Attach process failed?" $expect_out(buffer) } 37 | timeout { failure "Attach process timed timeout?" ""} 38 | } 39 | 40 | # 4) Launch the proxy and attach to previous PID 41 | spawn $build/examples/proxy/proxy -a $pid 42 | set proxy_id $spawn_id 43 | 44 | # 5) Run the proxy until it prints the 7th loop iteration 45 | expect { 46 | -i $proxy_id 47 | "hello 7" { } 48 | eof { failure "proxy attach failed?" $expect_out(buffer)} 49 | timeout { failure "proxy attach timed timeout?" ""} 50 | } 51 | 52 | -------------------------------------------------------------------------------- /test/integration/004-syscalls.exp: -------------------------------------------------------------------------------- 1 | #!/usr/bin/expect -f 2 | 3 | set build $env(ELKVM_BUILD) 4 | set timeout 5 5 | log_user 0 6 | #exp_internal 1 7 | 8 | proc failure { msg output } { 9 | send_user "\n========= $msg =========\n"; 10 | send_user "Output was:\n"; 11 | send_user $output; 12 | exit 1; 13 | } 14 | 15 | spawn $build/examples/proxy/proxy ./syscall_test & 16 | expect { 17 | "mmap" { exit 0 } 18 | eof 19 | { 20 | failure "Test terminated prematurely (Expecting 'mmap')" $expect_out(buffer); 21 | } 22 | timeout 23 | { 24 | failure "Test timed out. This most likely happens because you did not enable the ELKVM kernel patch." $expect_out(buffer); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /test/integration/hello.attach: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUD-OS/libelkvm/959c2e4ed1c2f0e27b196804ce4f10d4bb8231da/test/integration/hello.attach -------------------------------------------------------------------------------- /test/integration/hello.static: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUD-OS/libelkvm/959c2e4ed1c2f0e27b196804ce4f10d4bb8231da/test/integration/hello.static -------------------------------------------------------------------------------- /test/integration/run_all.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # libelkvm - A library that allows execution of an ELF binary inside a virtual 4 | # machine without a full-scale operating system 5 | # Copyright (C) 2013-2015 Florian Pester , Björn 6 | # Döbel , economic rights: Technische Universitaet 7 | # Dresden (Germany) 8 | # 9 | # This file is part of libelkvm. 10 | # 11 | # libelkvm is free software: you can redistribute it and/or modify 12 | # it under the terms of the GNU General Public License as published by 13 | # the Free Software Foundation, either version 3 of the License, or 14 | # (at your option) any later version. 15 | # 16 | # libelkvm is distributed in the hope that it will be useful, 17 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | # GNU General Public License for more details. 20 | # 21 | # You should have received a copy of the GNU General Public License 22 | # along with libelkvm. If not, see . 23 | # 24 | 25 | export ELKVM_BUILD=../../build 26 | 27 | # Print a banner message 28 | print_msg () { 29 | printf "\033[35m%50s\033[0m " "$1" 30 | } 31 | 32 | # Call this after a test command to validate its result 33 | return_check () { 34 | if [ $? -ne 0 ]; then 35 | echo "\033[31;1mFAILURE\033[0m" 36 | exit $?; 37 | fi 38 | echo "\033[32mOK\033[0m" 39 | } 40 | 41 | # Run expect test and check output 42 | # 43 | # Arguments: 44 | # $1 -- descriptive message 45 | # $2 -- name of expect script to run 46 | run_test () { 47 | message=$1 48 | cmd=$2 49 | print_msg "$1" 50 | expect $2 51 | return_check 52 | } 53 | 54 | print_msg "expect installed?" 55 | which expect >/dev/null 56 | return_check 57 | 58 | if [ -f /proc/sys/kernel/yama/ptrace_scope ]; then 59 | print_msg "/proc/sys/kernel/yama/ptrace_scope set to 0?" 60 | val=`cat /proc/sys/kernel/yama/ptrace_scope` 61 | test "x$val" = "x0" 62 | return_check 63 | fi 64 | 65 | run_test "ELKVM works?" 001-run.exp 66 | run_test "Proxy+debug works?" 002-proxy.exp 67 | run_test "Proxy+attach works?" 003-attach.exp 68 | run_test "System calls work?" 004-syscalls.exp -------------------------------------------------------------------------------- /test/integration/syscall_test: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUD-OS/libelkvm/959c2e4ed1c2f0e27b196804ce4f10d4bb8231da/test/integration/syscall_test -------------------------------------------------------------------------------- /test/integration/syscalls/Makefile: -------------------------------------------------------------------------------- 1 | OBJ = syscalls.o 2 | 3 | CFLAGS += -std=c99 4 | 5 | all : sysbench syscall_test 6 | 7 | sysbench : $(OBJ) 8 | $(CC) -o sysbench $(OBJ) -static 9 | 10 | syscall_test : $(OBJ:.o=.c) 11 | $(CC) -DFAST_BENCH -std=c99 syscalls.c -o syscall_test -static 12 | 13 | 14 | clean : 15 | $(RM) $(OBJ) sysbench syscall_test 16 | -------------------------------------------------------------------------------- /test/integration/syscalls/syscalls.c: -------------------------------------------------------------------------------- 1 | /* * libelkvm - A library that allows execution of an ELF binary inside a virtual 2 | * machine without a full-scale operating system 3 | * Copyright (C) 2013-2015 Florian Pester , Björn 4 | * Döbel , economic rights: Technische Universitaet 5 | * Dresden (Germany) 6 | * 7 | * This file is part of libelkvm. 8 | * 9 | * libelkvm is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * libelkvm is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with libelkvm. If not, see . 21 | */ 22 | 23 | #define _GNU_SOURCE 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include 33 | 34 | #include 35 | #include 36 | 37 | enum { 38 | #ifdef FAST_BENCH 39 | NUM_PID = 1, 40 | NUM_FSTAT = 1, 41 | NUM_MMAP = 1, 42 | NUM_EMPTY = 1, 43 | #else 44 | NUM_PID = 10000000, 45 | NUM_FSTAT = 1000000, 46 | NUM_EMPTY = 100000000, 47 | NUM_MMAP = 100000, 48 | #endif 49 | MMAP_SIZE = 4 * 1024 * 1024, 50 | }; 51 | 52 | 53 | static void print_diff(char const *msg, 54 | int iterations, 55 | struct timeval* start, 56 | struct timeval* stop) 57 | { 58 | long long micro1 = start->tv_sec * 1000000 + start->tv_usec; 59 | long long micro2 = stop->tv_sec * 1000000 + stop->tv_usec; 60 | long long diff = micro2 - micro1; 61 | 62 | printf("\033[32m%30s\033[0m %12lld us = %.4f us / iteration\n", msg, 63 | diff, (float)diff / iterations); 64 | } 65 | 66 | 67 | #define TEST(name, iter, codeblock) \ 68 | static void test_##name(void) { \ 69 | struct timeval a, b; \ 70 | int err = gettimeofday(&a, 0); \ 71 | if (err) { \ 72 | perror("gettimeofday"); \ 73 | exit(err); \ 74 | } \ 75 | for (unsigned i = 0; i < (iter); ++i) { \ 76 | codeblock; \ 77 | } \ 78 | err = gettimeofday(&b, 0); \ 79 | if (err) { \ 80 | perror("gettimeofday"); \ 81 | exit(err); \ 82 | } \ 83 | print_diff(#name, iter, &a, &b); \ 84 | } 85 | 86 | 87 | TEST(empty, NUM_EMPTY, {}); 88 | 89 | TEST(getpid, NUM_PID, 90 | { 91 | long res = syscall(__NR_getpid); 92 | (void)res; 93 | } 94 | ); 95 | 96 | 97 | TEST(fstat, NUM_FSTAT, 98 | { 99 | struct stat statbuf; 100 | int fd = open("/proc/self/exe", O_RDONLY); // XXX /proc does not work... 101 | if (fd < 0) { 102 | perror("open"); 103 | } 104 | int err = fstat(fd, &statbuf); 105 | if (err) { 106 | perror("fstat"); 107 | } 108 | close(fd); 109 | }); 110 | 111 | 112 | TEST(mmap, NUM_MMAP, 113 | { 114 | void *ptr = mmap(0, MMAP_SIZE, PROT_READ | PROT_WRITE, 115 | MAP_ANONYMOUS | MAP_PRIVATE, 116 | 0, 0); 117 | if (!ptr) { 118 | perror("mmap"); 119 | exit(1); 120 | } 121 | munmap(ptr, MMAP_SIZE); 122 | }); 123 | 124 | 125 | int main(int argc, char *argv[]) 126 | { 127 | test_empty(); 128 | test_getpid(); 129 | test_fstat(); 130 | test_mmap(); 131 | return 0; 132 | } 133 | -------------------------------------------------------------------------------- /test/test_build.rb: -------------------------------------------------------------------------------- 1 | # 2 | # libelkvm - A library that allows execution of an ELF binary inside a virtual 3 | # machine without a full-scale operating system 4 | # Copyright (C) 2013-2015 Florian Pester , Björn 5 | # Döbel , economic rights: Technische Universitaet 6 | # Dresden (Germany) 7 | # 8 | # This file is part of libelkvm. 9 | # 10 | # libelkvm is free software: you can redistribute it and/or modify 11 | # it under the terms of the GNU General Public License as published by 12 | # the Free Software Foundation, either version 3 of the License, or 13 | # (at your option) any later version. 14 | # 15 | # libelkvm is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU General Public License 21 | # along with libelkvm. If not, see . 22 | # 23 | 24 | def build(cc, cxx) 25 | `CC=#{cc} CXX=#{cxx} cmake ../.. 2>&1` 26 | `sudo make -C include install 2>&1` 27 | puts "Building with #{cc}" 28 | output = `make -j5 2>&1` 29 | if !$?.success? 30 | puts "Build failed with #{$?}" 31 | puts "Build with #{cc} failed, here is some output:" 32 | puts output 33 | else 34 | puts "Build successfull" 35 | end 36 | $?.success? 37 | end 38 | 39 | build_dir = ".build" 40 | Dir.mkdir(build_dir) 41 | Dir.chdir(build_dir) 42 | 43 | working_build = true 44 | working_build = build("gcc", "g++") 45 | working_build = build("clang", "clang++") if working_build 46 | 47 | Dir.chdir("..") 48 | `rm -rf #{build_dir}` 49 | exit working_build -------------------------------------------------------------------------------- /test/test_elfloader.cc: -------------------------------------------------------------------------------- 1 | // 2 | // libelkvm - A library that allows execution of an ELF binary inside a virtual 3 | // machine without a full-scale operating system 4 | // Copyright (C) 2013-2015 Florian Pester , Björn 5 | // Döbel , economic rights: Technische Universitaet 6 | // Dresden (Germany) 7 | // 8 | // This file is part of libelkvm. 9 | // 10 | // libelkvm is free software: you can redistribute it and/or modify 11 | // it under the terms of the GNU General Public License as published by 12 | // the Free Software Foundation, either version 3 of the License, or 13 | // (at your option) any later version. 14 | // 15 | // libelkvm is distributed in the hope that it will be useful, 16 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | // GNU General Public License for more details. 19 | // 20 | // You should have received a copy of the GNU General Public License 21 | // along with libelkvm. If not, see . 22 | // 23 | 24 | #include 25 | #include 26 | 27 | #include 28 | #include 29 | 30 | namespace testing { 31 | 32 | class AnElfBinary : public Test { 33 | 34 | }; 35 | 36 | TEST(AnElfBinary, SetsWritePagerOption) { 37 | ptopt_t opts = Elkvm::get_pager_opts_from_phdr_flags(PF_W); 38 | ASSERT_THAT(opts, Eq(PT_OPT_WRITE)); 39 | } 40 | 41 | TEST(AnElfBinary, SetsExecutePagerOption) { 42 | ptopt_t opts = Elkvm::get_pager_opts_from_phdr_flags(PF_X); 43 | ASSERT_THAT(opts, Eq(PT_OPT_EXEC)); 44 | } 45 | 46 | //namespace testing 47 | } 48 | -------------------------------------------------------------------------------- /test/test_mapping.cc: -------------------------------------------------------------------------------- 1 | // 2 | // libelkvm - A library that allows execution of an ELF binary inside a virtual 3 | // machine without a full-scale operating system 4 | // Copyright (C) 2013-2015 Florian Pester , Björn 5 | // Döbel , economic rights: Technische Universitaet 6 | // Dresden (Germany) 7 | // 8 | // This file is part of libelkvm. 9 | // 10 | // libelkvm is free software: you can redistribute it and/or modify 11 | // it under the terms of the GNU General Public License as published by 12 | // the Free Software Foundation, either version 3 of the License, or 13 | // (at your option) any later version. 14 | // 15 | // libelkvm is distributed in the hope that it will be useful, 16 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | // GNU General Public License for more details. 19 | // 20 | // You should have received a copy of the GNU General Public License 21 | // along with libelkvm. If not, see . 22 | // 23 | 24 | #include 25 | #include 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | namespace testing { 32 | 33 | class AMapping : public Test { 34 | protected: 35 | std::shared_ptr r; 36 | Elkvm::Mapping mut; 37 | 38 | AMapping() : 39 | r(std::make_shared(nullptr, 0x7000, false)), 40 | mut(r, 0x1000, 0x2000, 0x0, 0x0, 0, 0) 41 | {} 42 | 43 | }; 44 | 45 | TEST_F(AMapping, CannotBeLargerThanTheUnderlyingRegion) { 46 | size_t sz = mut.grow(0x8000); 47 | ASSERT_THAT(sz, Eq(0x7000)); 48 | } 49 | 50 | TEST_F(AMapping, DoesNotAcceptSmallerSizeOnGrow) { 51 | size_t sz = mut.grow(0x1000); 52 | ASSERT_THAT(sz, Eq(0x2000)); 53 | } 54 | 55 | TEST_F(AMapping, GrowsToAnExpectedSize) { 56 | size_t sz = mut.grow(0x4000); 57 | ASSERT_THAT(sz, Eq(0x4000)); 58 | ASSERT_THAT(mut.get_pages(), Eq(4)); 59 | } 60 | 61 | 62 | //namespace testing 63 | } 64 | -------------------------------------------------------------------------------- /test/test_pager.cc: -------------------------------------------------------------------------------- 1 | // 2 | // libelkvm - A library that allows execution of an ELF binary inside a virtual 3 | // machine without a full-scale operating system 4 | // Copyright (C) 2013-2015 Florian Pester , Björn 5 | // Döbel , economic rights: Technische Universitaet 6 | // Dresden (Germany) 7 | // 8 | // This file is part of libelkvm. 9 | // 10 | // libelkvm is free software: you can redistribute it and/or modify 11 | // it under the terms of the GNU General Public License as published by 12 | // the Free Software Foundation, either version 3 of the License, or 13 | // (at your option) any later version. 14 | // 15 | // libelkvm is distributed in the hope that it will be useful, 16 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | // GNU General Public License for more details. 19 | // 20 | // You should have received a copy of the GNU General Public License 21 | // along with libelkvm. If not, see . 22 | // 23 | 24 | #include 25 | #include 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | namespace testing { 32 | 33 | class Pager : public Test { 34 | protected: 35 | Elkvm::PagerX86_64 pager; 36 | 37 | Pager() : pager(5) {} 38 | ~Pager() {} 39 | }; 40 | 41 | TEST_F(Pager, DoesNotCreateAChunkWithUnalignedSize) { 42 | void *x = nullptr; 43 | int err = pager.create_mem_chunk(&x, 0x123); 44 | ASSERT_EQ(err, -EIO); 45 | ASSERT_EQ(x, nullptr); 46 | } 47 | 48 | TEST_F(Pager, DISABLED_CreatesAnEntryWithTheGivenAddress) { 49 | auto ch = pager.get_chunk(0); 50 | void *host_p = reinterpret_cast(0x1042 + ch->userspace_addr); 51 | guestptr_t guest_addr = 0xF042; 52 | 53 | int err = pager.map_user_page(host_p, guest_addr, 0); 54 | ASSERT_EQ(err, 0); 55 | 56 | void *created_addr = pager.get_host_p(guest_addr); 57 | ASSERT_EQ(host_p, created_addr); 58 | } 59 | 60 | TEST_F(Pager, DoesNotCreateAnUnalignedMapping) { 61 | guestptr_t guest_addr = 0x4ee; 62 | void *host_p = reinterpret_cast(0x10000 + ELKVM_SYSTEM_MEMSIZE); 63 | ASSERT_EQ(pager.map_user_page(host_p, guest_addr, 0), -EIO); 64 | } 65 | 66 | 67 | //namespace testing 68 | } 69 | 70 | -------------------------------------------------------------------------------- /test/test_region.cc: -------------------------------------------------------------------------------- 1 | // 2 | // libelkvm - A library that allows execution of an ELF binary inside a virtual 3 | // machine without a full-scale operating system 4 | // Copyright (C) 2013-2015 Florian Pester , Björn 5 | // Döbel , economic rights: Technische Universitaet 6 | // Dresden (Germany) 7 | // 8 | // This file is part of libelkvm. 9 | // 10 | // libelkvm is free software: you can redistribute it and/or modify 11 | // it under the terms of the GNU General Public License as published by 12 | // the Free Software Foundation, either version 3 of the License, or 13 | // (at your option) any later version. 14 | // 15 | // libelkvm is distributed in the hope that it will be useful, 16 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | // GNU General Public License for more details. 19 | // 20 | // You should have received a copy of the GNU General Public License 21 | // along with libelkvm. If not, see . 22 | // 23 | 24 | #include 25 | #include 26 | 27 | #include 28 | 29 | namespace testing { 30 | class MockRegionManager { 31 | MOCK_METHOD1(use_region, void(std::shared_ptr r)); 32 | }; 33 | 34 | class RegionTest : public Test { 35 | protected: 36 | Elkvm::Region r; 37 | 38 | RegionTest() : 39 | r(reinterpret_cast(0xC0F000), 0x12000) {} 40 | ~RegionTest() {} 41 | 42 | virtual void SetUp() {} 43 | virtual void TearDown() {} 44 | }; 45 | 46 | TEST_F(RegionTest, test_contains_address) { 47 | ASSERT_FALSE(r.contains_address(reinterpret_cast(0xc0efff))); 48 | ASSERT_TRUE(r.contains_address(reinterpret_cast(0xc0f000))); 49 | ASSERT_TRUE(r.contains_address(reinterpret_cast(0xc10000))); 50 | ASSERT_TRUE(r.contains_address(reinterpret_cast(0xc20fff))); 51 | ASSERT_FALSE(r.contains_address(reinterpret_cast(0xc21000))); 52 | } 53 | 54 | TEST_F(RegionTest, test_equality) { 55 | 56 | Elkvm::Region r2 = r; 57 | ASSERT_TRUE(r2 == r); 58 | 59 | // XXX RM must be able to find these regions! 60 | // ASSERT_TRUE(Elkvm::same_region(reinterpret_cast(0xC0F000), 61 | // reinterpret_cast(0xC10000))); 62 | // ASSERT_FALSE(Elkvm::same_region(reinterpret_cast(0xC0F000), 63 | // reinterpret_cast(0xC21000))); 64 | } 65 | 66 | TEST_F(RegionTest, test_slice_begin) { 67 | std::shared_ptr r2 = r.slice_begin(0x1000); 68 | ASSERT_FALSE(r.contains_address(reinterpret_cast(0xC0F000))); 69 | ASSERT_TRUE(r.contains_address(reinterpret_cast(0xC10000))); 70 | ASSERT_TRUE(r2->contains_address(reinterpret_cast(0xC0F000))); 71 | ASSERT_TRUE(r2->contains_address(reinterpret_cast(0xC0FFFF))); 72 | ASSERT_FALSE(r2->contains_address(reinterpret_cast(0xC10000))); 73 | ASSERT_TRUE(r.contains_address(reinterpret_cast(0xc20fff))); 74 | } 75 | 76 | TEST_F(RegionTest, test_slice_center) { 77 | r.set_used(); 78 | r.slice_center(0x1000, 0x1000); 79 | ASSERT_EQ(r.base_address(), reinterpret_cast(0xC0F000)); 80 | ASSERT_EQ(r.size(), 0x1000); 81 | ASSERT_FALSE(r.contains_address(reinterpret_cast(0xC10000))); 82 | 83 | // TODO check if 2nd region is correct 84 | // std::shared_ptr r2 = Elkvm::rm.find_region(0xC11000); 85 | // ASSERT_EQ(r2->base_address(), 0xC11000); 86 | // ASSERT_EQ(r2->size(), 0x10000); 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /test/test_region_manager.cc: -------------------------------------------------------------------------------- 1 | // 2 | // libelkvm - A library that allows execution of an ELF binary inside a virtual 3 | // machine without a full-scale operating system 4 | // Copyright (C) 2013-2015 Florian Pester , Björn 5 | // Döbel , economic rights: Technische Universitaet 6 | // Dresden (Germany) 7 | // 8 | // This file is part of libelkvm. 9 | // 10 | // libelkvm is free software: you can redistribute it and/or modify 11 | // it under the terms of the GNU General Public License as published by 12 | // the Free Software Foundation, either version 3 of the License, or 13 | // (at your option) any later version. 14 | // 15 | // libelkvm is distributed in the hope that it will be useful, 16 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | // GNU General Public License for more details. 19 | // 20 | // You should have received a copy of the GNU General Public License 21 | // along with libelkvm. If not, see . 22 | // 23 | 24 | #include 25 | #include 26 | 27 | #include 28 | 29 | namespace testing { 30 | class TheRegionManager : public Test { 31 | protected: 32 | Elkvm::RegionManager rm; 33 | 34 | TheRegionManager() : rm(5) {} 35 | ~TheRegionManager() {} 36 | 37 | virtual void SetUp() {} 38 | virtual void TearDown() {} 39 | }; 40 | 41 | TEST_F(TheRegionManager, DISABLED_ReturnsThatAnUnMappedAddressIsNotMapped) { 42 | ASSERT_FALSE(rm.host_address_mapped(reinterpret_cast(0xC0FFEE))); 43 | } 44 | 45 | TEST_F(TheRegionManager, DISABLED_ReturnsThatAnUnMappedAddressWhichExistsIsNotMapped) { 46 | rm.add_free_region(std::make_shared(reinterpret_cast(0xC0F000), 0x12000)); 47 | ASSERT_FALSE(rm.host_address_mapped(reinterpret_cast(0xC0FFEE))); 48 | } 49 | 50 | TEST_F(TheRegionManager, DISABLED_ReturnsThatAMappedAddressIsMapped) { 51 | rm.allocate_region(0x2000); 52 | ASSERT_TRUE(rm.host_address_mapped(reinterpret_cast(0xC0FFEE))); 53 | } 54 | 55 | TEST_F(TheRegionManager, DISABLED_ServesRequestsForSmallRegions) { 56 | std::shared_ptr r = std::make_shared( 57 | reinterpret_cast(0xC0F000), 0x12000); 58 | rm.add_free_region(r); 59 | 60 | std::shared_ptr r2 = rm.allocate_region(0x2000); 61 | 62 | ASSERT_TRUE(rm.host_address_mapped(reinterpret_cast(0xC0FFEE))); 63 | ASSERT_EQ(0x2000, r2->size()); 64 | ASSERT_FALSE(r2->is_free()); 65 | } 66 | 67 | TEST_F(TheRegionManager, DISABLED_FreesAnAllocatedRegionAndSetsItsGuestAddressToZero) { 68 | std::shared_ptr r = std::make_shared( 69 | reinterpret_cast(0xC0F000), 0x12000); 70 | rm.add_free_region(r); 71 | 72 | std::shared_ptr r2 = rm.allocate_region(0x2000); 73 | 74 | rm.free_region(reinterpret_cast(0xC0F000), 0x2000); 75 | ASSERT_EQ(0x0, r->guest_address()); 76 | } 77 | 78 | TEST_F(TheRegionManager, DISABLED_ReturnsNullWhenNoFreeRegionIsAvailable) { 79 | std::shared_ptr r_res = rm.find_free_region(0x1000); 80 | ASSERT_EQ(r_res, nullptr); 81 | } 82 | 83 | TEST_F(TheRegionManager, DISABLED_FindsFreeRegionsWithMatchingSize) { 84 | std::shared_ptr r = std::make_shared( 85 | reinterpret_cast(0xC0F000), 0x1000); 86 | rm.add_free_region(r); 87 | 88 | auto r_res = rm.find_free_region(0x1000); 89 | 90 | ASSERT_EQ(r, r_res); 91 | } 92 | 93 | TEST_F(TheRegionManager, DISABLED_FindsFreeRegionsWithSmallerSize) { 94 | std::shared_ptr r2 = std::make_shared( 95 | reinterpret_cast(0xD00000), 0x12000); 96 | rm.add_free_region(r2); 97 | 98 | auto r_res = rm.find_free_region(0x1000); 99 | 100 | ASSERT_EQ(r2, r_res); 101 | } 102 | 103 | //namespace testing 104 | } 105 | -------------------------------------------------------------------------------- /test/test_vcpu.cc: -------------------------------------------------------------------------------- 1 | // 2 | // libelkvm - A library that allows execution of an ELF binary inside a virtual 3 | // machine without a full-scale operating system 4 | // Copyright (C) 2013-2015 Florian Pester , Björn 5 | // Döbel , economic rights: Technische Universitaet 6 | // Dresden (Germany) 7 | // 8 | // This file is part of libelkvm. 9 | // 10 | // libelkvm is free software: you can redistribute it and/or modify 11 | // it under the terms of the GNU General Public License as published by 12 | // the Free Software Foundation, either version 3 of the License, or 13 | // (at your option) any later version. 14 | // 15 | // libelkvm is distributed in the hope that it will be useful, 16 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | // GNU General Public License for more details. 19 | // 20 | // You should have received a copy of the GNU General Public License 21 | // along with libelkvm. If not, see . 22 | // 23 | 24 | #include 25 | #include 26 | 27 | #include 28 | 29 | namespace testing { 30 | 31 | class VCPUTest : public Test { 32 | protected: 33 | VCPUTest() : vcpu(nullptr) {} 34 | ~VCPUTest() {} 35 | 36 | virtual void SetUp() {} 37 | virtual void TearDown() {} 38 | 39 | struct kvm_vcpu vcpu; 40 | }; 41 | 42 | TEST_F(VCPUTest, DISABLED_test_had_page_fault) { 43 | vcpu.sregs.cr2 = 0xc0ffee; 44 | int pf = kvm_vcpu_had_page_fault(&vcpu); 45 | ASSERT_EQ(pf, 1); 46 | } 47 | 48 | 49 | //namespace testing 50 | } 51 | --------------------------------------------------------------------------------