├── .clang-format ├── .github └── workflows │ └── build.yml ├── .gitignore ├── AUTHORS ├── COPYING ├── ChangeLog ├── INSTALL ├── Makefile.am ├── NEWS ├── README ├── README.md ├── bootstrap ├── configure.ac ├── examples ├── Makefile.am └── hookguest.cpp ├── include ├── Makefile.am └── bdvmi │ ├── backendfactory.h │ ├── domainhandler.h │ ├── domainwatcher.h │ ├── driver.h │ ├── eventhandler.h │ ├── eventmanager.h │ ├── logger.h │ ├── pagecache.h │ ├── statscollector.h │ └── version.h ├── libbdvmi.pc.in ├── libbdvmi.spec ├── m4 └── m4_ax_cxx_compile_stdcxx.m4 └── src ├── Makefile.am ├── backendfactory.cpp ├── domainwatcher.cpp ├── driver.cpp ├── dynamiclibfactory.cpp ├── dynamiclibfactory.h ├── eventmanager.cpp ├── kvmdomainwatcher.cpp ├── kvmdomainwatcher.h ├── kvmdriver.cpp ├── kvmdriver.h ├── kvmeventmanager.cpp ├── kvmeventmanager.h ├── logger.cpp ├── pagecache.cpp ├── statscollector.cpp ├── utils.h ├── version.cpp ├── version.ld ├── xcwrapper.cpp ├── xcwrapper.h ├── xenaltp2m.cpp ├── xenaltp2m.h ├── xendomainwatcher.cpp ├── xendomainwatcher.h ├── xendriver.cpp ├── xendriver.h ├── xeneventmanager.cpp ├── xeneventmanager.h ├── xenvmevent_v3.h ├── xenvmevent_v4.h ├── xenvmevent_v5.h ├── xswrapper.cpp └── xswrapper.h /.clang-format: -------------------------------------------------------------------------------- 1 | # clang-format 10.0 2 | 3 | # general 4 | BasedOnStyle: WebKit 5 | Standard: Cpp11 6 | ColumnLimit: 120 7 | SortIncludes: false 8 | AllowShortFunctionsOnASingleLine: None 9 | IndentGotoLabels: false 10 | BreakBeforeBinaryOperators: None 11 | AccessModifierOffset: -8 12 | 13 | # indentation 14 | IndentWidth: 8 15 | TabWidth: 8 16 | UseTab: ForIndentation 17 | IndentCaseLabels: true 18 | 19 | # alignment 20 | AlignConsecutiveAssignments: true 21 | AlignConsecutiveDeclarations: true 22 | AlignConsecutiveMacros: true 23 | PointerAlignment: Right 24 | AlignAfterOpenBracket: Align 25 | 26 | # whitespace management 27 | SpacesInParentheses: true 28 | SpacesInCStyleCastParentheses: true 29 | SpaceBeforeCpp11BracedList: false 30 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | on: [push, pull_request] 2 | jobs: 3 | build: 4 | runs-on: ubuntu-latest 5 | steps: 6 | - uses: actions/checkout@v2 7 | 8 | - name: Checkout libkvmi 9 | uses: actions/checkout@v2 10 | with: 11 | repository: bitdefender/libkvmi 12 | path: libkvmi 13 | 14 | - name: Build and install libkvmi 15 | run: | 16 | cd libkvmi 17 | ./bootstrap 18 | ./configure 19 | make -j$(nproc) 20 | sudo make install 21 | cd .. 22 | 23 | - name: Install other dependencies 24 | run: sudo apt install -y libjsoncpp-dev libboost-dev libxen-dev 25 | 26 | - name: Bootstrap 27 | run: ./bootstrap 28 | 29 | - name: Build for Xen 30 | run: | 31 | ./configure 32 | make -j$(nproc) 33 | 34 | - name: Build for KVM 35 | run: | 36 | ./configure --enable-kvmi --disable-xen 37 | make -j$(nproc) 38 | 39 | - name: Build and install for Xen and KVM 40 | run: | 41 | ./configure --enable-kvmi 42 | make -j$(nproc) 43 | sudo make install 44 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.lo 3 | *.la 4 | autom4te.cache/ 5 | aclocal.m4 6 | compile 7 | config.guess 8 | config.h 9 | config.h.in* 10 | config.log 11 | config.status 12 | config.sub 13 | configure 14 | depcomp 15 | examples/.deps/ 16 | examples/.libs/ 17 | examples/hookguest 18 | install-sh 19 | libtool 20 | ltmain.sh 21 | m4/libtool.m4 22 | m4/lt~obsolete.m4 23 | m4/ltoptions.m4 24 | m4/ltsugar.m4 25 | m4/ltversion.m4 26 | Makefile.in 27 | Makefile 28 | missing 29 | src/.deps/ 30 | src/.libs/ 31 | stamp-h1 32 | 33 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Bitdefender SRL 2 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bitdefender/libbdvmi/51a3de92a3e7ab500115dfc2d09d51ba1397c630/ChangeLog -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | Installation Instructions 2 | ************************* 3 | 4 | Copyright (C) 1994-1996, 1999-2002, 2004-2013 Free Software Foundation, 5 | Inc. 6 | 7 | Copying and distribution of this file, with or without modification, 8 | are permitted in any medium without royalty provided the copyright 9 | notice and this notice are preserved. This file is offered as-is, 10 | without warranty of any kind. 11 | 12 | Basic Installation 13 | ================== 14 | 15 | Briefly, the shell command `./configure && make && make install' 16 | should configure, build, and install this package. The following 17 | more-detailed instructions are generic; see the `README' file for 18 | instructions specific to this package. Some packages provide this 19 | `INSTALL' file but do not implement all of the features documented 20 | below. The lack of an optional feature in a given package is not 21 | necessarily a bug. More recommendations for GNU packages can be found 22 | in *note Makefile Conventions: (standards)Makefile Conventions. 23 | 24 | The `configure' shell script attempts to guess correct values for 25 | various system-dependent variables used during compilation. It uses 26 | those values to create a `Makefile' in each directory of the package. 27 | It may also create one or more `.h' files containing system-dependent 28 | definitions. Finally, it creates a shell script `config.status' that 29 | you can run in the future to recreate the current configuration, and a 30 | file `config.log' containing compiler output (useful mainly for 31 | debugging `configure'). 32 | 33 | It can also use an optional file (typically called `config.cache' 34 | and enabled with `--cache-file=config.cache' or simply `-C') that saves 35 | the results of its tests to speed up reconfiguring. Caching is 36 | disabled by default to prevent problems with accidental use of stale 37 | cache files. 38 | 39 | If you need to do unusual things to compile the package, please try 40 | to figure out how `configure' could check whether to do them, and mail 41 | diffs or instructions to the address given in the `README' so they can 42 | be considered for the next release. If you are using the cache, and at 43 | some point `config.cache' contains results you don't want to keep, you 44 | may remove or edit it. 45 | 46 | The file `configure.ac' (or `configure.in') is used to create 47 | `configure' by a program called `autoconf'. You need `configure.ac' if 48 | you want to change it or regenerate `configure' using a newer version 49 | of `autoconf'. 50 | 51 | The simplest way to compile this package is: 52 | 53 | 1. `cd' to the directory containing the package's source code and type 54 | `./configure' to configure the package for your system. 55 | 56 | Running `configure' might take a while. While running, it prints 57 | some messages telling which features it is checking for. 58 | 59 | 2. Type `make' to compile the package. 60 | 61 | 3. Optionally, type `make check' to run any self-tests that come with 62 | the package, generally using the just-built uninstalled binaries. 63 | 64 | 4. Type `make install' to install the programs and any data files and 65 | documentation. When installing into a prefix owned by root, it is 66 | recommended that the package be configured and built as a regular 67 | user, and only the `make install' phase executed with root 68 | privileges. 69 | 70 | 5. Optionally, type `make installcheck' to repeat any self-tests, but 71 | this time using the binaries in their final installed location. 72 | This target does not install anything. Running this target as a 73 | regular user, particularly if the prior `make install' required 74 | root privileges, verifies that the installation completed 75 | correctly. 76 | 77 | 6. You can remove the program binaries and object files from the 78 | source code directory by typing `make clean'. To also remove the 79 | files that `configure' created (so you can compile the package for 80 | a different kind of computer), type `make distclean'. There is 81 | also a `make maintainer-clean' target, but that is intended mainly 82 | for the package's developers. If you use it, you may have to get 83 | all sorts of other programs in order to regenerate files that came 84 | with the distribution. 85 | 86 | 7. Often, you can also type `make uninstall' to remove the installed 87 | files again. In practice, not all packages have tested that 88 | uninstallation works correctly, even though it is required by the 89 | GNU Coding Standards. 90 | 91 | 8. Some packages, particularly those that use Automake, provide `make 92 | distcheck', which can by used by developers to test that all other 93 | targets like `make install' and `make uninstall' work correctly. 94 | This target is generally not run by end users. 95 | 96 | Compilers and Options 97 | ===================== 98 | 99 | Some systems require unusual options for compilation or linking that 100 | the `configure' script does not know about. Run `./configure --help' 101 | for details on some of the pertinent environment variables. 102 | 103 | You can give `configure' initial values for configuration parameters 104 | by setting variables in the command line or in the environment. Here 105 | is an example: 106 | 107 | ./configure CC=c99 CFLAGS=-g LIBS=-lposix 108 | 109 | *Note Defining Variables::, for more details. 110 | 111 | Compiling For Multiple Architectures 112 | ==================================== 113 | 114 | You can compile the package for more than one kind of computer at the 115 | same time, by placing the object files for each architecture in their 116 | own directory. To do this, you can use GNU `make'. `cd' to the 117 | directory where you want the object files and executables to go and run 118 | the `configure' script. `configure' automatically checks for the 119 | source code in the directory that `configure' is in and in `..'. This 120 | is known as a "VPATH" build. 121 | 122 | With a non-GNU `make', it is safer to compile the package for one 123 | architecture at a time in the source code directory. After you have 124 | installed the package for one architecture, use `make distclean' before 125 | reconfiguring for another architecture. 126 | 127 | On MacOS X 10.5 and later systems, you can create libraries and 128 | executables that work on multiple system types--known as "fat" or 129 | "universal" binaries--by specifying multiple `-arch' options to the 130 | compiler but only a single `-arch' option to the preprocessor. Like 131 | this: 132 | 133 | ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ 134 | CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ 135 | CPP="gcc -E" CXXCPP="g++ -E" 136 | 137 | This is not guaranteed to produce working output in all cases, you 138 | may have to build one architecture at a time and combine the results 139 | using the `lipo' tool if you have problems. 140 | 141 | Installation Names 142 | ================== 143 | 144 | By default, `make install' installs the package's commands under 145 | `/usr/local/bin', include files under `/usr/local/include', etc. You 146 | can specify an installation prefix other than `/usr/local' by giving 147 | `configure' the option `--prefix=PREFIX', where PREFIX must be an 148 | absolute file name. 149 | 150 | You can specify separate installation prefixes for 151 | architecture-specific files and architecture-independent files. If you 152 | pass the option `--exec-prefix=PREFIX' to `configure', the package uses 153 | PREFIX as the prefix for installing programs and libraries. 154 | Documentation and other data files still use the regular prefix. 155 | 156 | In addition, if you use an unusual directory layout you can give 157 | options like `--bindir=DIR' to specify different values for particular 158 | kinds of files. Run `configure --help' for a list of the directories 159 | you can set and what kinds of files go in them. In general, the 160 | default for these options is expressed in terms of `${prefix}', so that 161 | specifying just `--prefix' will affect all of the other directory 162 | specifications that were not explicitly provided. 163 | 164 | The most portable way to affect installation locations is to pass the 165 | correct locations to `configure'; however, many packages provide one or 166 | both of the following shortcuts of passing variable assignments to the 167 | `make install' command line to change installation locations without 168 | having to reconfigure or recompile. 169 | 170 | The first method involves providing an override variable for each 171 | affected directory. For example, `make install 172 | prefix=/alternate/directory' will choose an alternate location for all 173 | directory configuration variables that were expressed in terms of 174 | `${prefix}'. Any directories that were specified during `configure', 175 | but not in terms of `${prefix}', must each be overridden at install 176 | time for the entire installation to be relocated. The approach of 177 | makefile variable overrides for each directory variable is required by 178 | the GNU Coding Standards, and ideally causes no recompilation. 179 | However, some platforms have known limitations with the semantics of 180 | shared libraries that end up requiring recompilation when using this 181 | method, particularly noticeable in packages that use GNU Libtool. 182 | 183 | The second method involves providing the `DESTDIR' variable. For 184 | example, `make install DESTDIR=/alternate/directory' will prepend 185 | `/alternate/directory' before all installation names. The approach of 186 | `DESTDIR' overrides is not required by the GNU Coding Standards, and 187 | does not work on platforms that have drive letters. On the other hand, 188 | it does better at avoiding recompilation issues, and works well even 189 | when some directory options were not specified in terms of `${prefix}' 190 | at `configure' time. 191 | 192 | Optional Features 193 | ================= 194 | 195 | If the package supports it, you can cause programs to be installed 196 | with an extra prefix or suffix on their names by giving `configure' the 197 | option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. 198 | 199 | Some packages pay attention to `--enable-FEATURE' options to 200 | `configure', where FEATURE indicates an optional part of the package. 201 | They may also pay attention to `--with-PACKAGE' options, where PACKAGE 202 | is something like `gnu-as' or `x' (for the X Window System). The 203 | `README' should mention any `--enable-' and `--with-' options that the 204 | package recognizes. 205 | 206 | For packages that use the X Window System, `configure' can usually 207 | find the X include and library files automatically, but if it doesn't, 208 | you can use the `configure' options `--x-includes=DIR' and 209 | `--x-libraries=DIR' to specify their locations. 210 | 211 | Some packages offer the ability to configure how verbose the 212 | execution of `make' will be. For these packages, running `./configure 213 | --enable-silent-rules' sets the default to minimal output, which can be 214 | overridden with `make V=1'; while running `./configure 215 | --disable-silent-rules' sets the default to verbose, which can be 216 | overridden with `make V=0'. 217 | 218 | Particular systems 219 | ================== 220 | 221 | On HP-UX, the default C compiler is not ANSI C compatible. If GNU 222 | CC is not installed, it is recommended to use the following options in 223 | order to use an ANSI C compiler: 224 | 225 | ./configure CC="cc -Ae -D_XOPEN_SOURCE=500" 226 | 227 | and if that doesn't work, install pre-built binaries of GCC for HP-UX. 228 | 229 | HP-UX `make' updates targets which have the same time stamps as 230 | their prerequisites, which makes it generally unusable when shipped 231 | generated files such as `configure' are involved. Use GNU `make' 232 | instead. 233 | 234 | On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot 235 | parse its `' header file. The option `-nodtk' can be used as 236 | a workaround. If GNU CC is not installed, it is therefore recommended 237 | to try 238 | 239 | ./configure CC="cc" 240 | 241 | and if that doesn't work, try 242 | 243 | ./configure CC="cc -nodtk" 244 | 245 | On Solaris, don't put `/usr/ucb' early in your `PATH'. This 246 | directory contains several dysfunctional programs; working variants of 247 | these programs are available in `/usr/bin'. So, if you need `/usr/ucb' 248 | in your `PATH', put it _after_ `/usr/bin'. 249 | 250 | On Haiku, software installed for all users goes in `/boot/common', 251 | not `/usr/local'. It is recommended to use the following options: 252 | 253 | ./configure --prefix=/boot/common 254 | 255 | Specifying the System Type 256 | ========================== 257 | 258 | There may be some features `configure' cannot figure out 259 | automatically, but needs to determine by the type of machine the package 260 | will run on. Usually, assuming the package is built to be run on the 261 | _same_ architectures, `configure' can figure that out, but if it prints 262 | a message saying it cannot guess the machine type, give it the 263 | `--build=TYPE' option. TYPE can either be a short name for the system 264 | type, such as `sun4', or a canonical name which has the form: 265 | 266 | CPU-COMPANY-SYSTEM 267 | 268 | where SYSTEM can have one of these forms: 269 | 270 | OS 271 | KERNEL-OS 272 | 273 | See the file `config.sub' for the possible values of each field. If 274 | `config.sub' isn't included in this package, then this package doesn't 275 | need to know the machine type. 276 | 277 | If you are _building_ compiler tools for cross-compiling, you should 278 | use the option `--target=TYPE' to select the type of system they will 279 | produce code for. 280 | 281 | If you want to _use_ a cross compiler, that generates code for a 282 | platform different from the build platform, you should specify the 283 | "host" platform (i.e., that on which the generated programs will 284 | eventually be run) with `--host=TYPE'. 285 | 286 | Sharing Defaults 287 | ================ 288 | 289 | If you want to set default values for `configure' scripts to share, 290 | you can create a site shell script called `config.site' that gives 291 | default values for variables like `CC', `cache_file', and `prefix'. 292 | `configure' looks for `PREFIX/share/config.site' if it exists, then 293 | `PREFIX/etc/config.site' if it exists. Or, you can set the 294 | `CONFIG_SITE' environment variable to the location of the site script. 295 | A warning: not all `configure' scripts look for a site script. 296 | 297 | Defining Variables 298 | ================== 299 | 300 | Variables not defined in a site shell script can be set in the 301 | environment passed to `configure'. However, some packages may run 302 | configure again during the build, and the customized values of these 303 | variables may be lost. In order to avoid this problem, you should set 304 | them in the `configure' command line, using `VAR=value'. For example: 305 | 306 | ./configure CC=/usr/local2/bin/gcc 307 | 308 | causes the specified `gcc' to be used as the C compiler (unless it is 309 | overridden in the site shell script). 310 | 311 | Unfortunately, this technique does not work for `CONFIG_SHELL' due to 312 | an Autoconf limitation. Until the limitation is lifted, you can use 313 | this workaround: 314 | 315 | CONFIG_SHELL=/bin/bash ./configure CONFIG_SHELL=/bin/bash 316 | 317 | `configure' Invocation 318 | ====================== 319 | 320 | `configure' recognizes the following options to control how it 321 | operates. 322 | 323 | `--help' 324 | `-h' 325 | Print a summary of all of the options to `configure', and exit. 326 | 327 | `--help=short' 328 | `--help=recursive' 329 | Print a summary of the options unique to this package's 330 | `configure', and exit. The `short' variant lists options used 331 | only in the top level, while the `recursive' variant lists options 332 | also present in any nested packages. 333 | 334 | `--version' 335 | `-V' 336 | Print the version of Autoconf used to generate the `configure' 337 | script, and exit. 338 | 339 | `--cache-file=FILE' 340 | Enable the cache: use and save the results of the tests in FILE, 341 | traditionally `config.cache'. FILE defaults to `/dev/null' to 342 | disable caching. 343 | 344 | `--config-cache' 345 | `-C' 346 | Alias for `--cache-file=config.cache'. 347 | 348 | `--quiet' 349 | `--silent' 350 | `-q' 351 | Do not print messages saying which checks are being made. To 352 | suppress all normal output, redirect it to `/dev/null' (any error 353 | messages will still be shown). 354 | 355 | `--srcdir=DIR' 356 | Look for the package's source code in directory DIR. Usually 357 | `configure' can determine that directory automatically. 358 | 359 | `--prefix=DIR' 360 | Use DIR as the installation prefix. *note Installation Names:: 361 | for more details, including other options available for fine-tuning 362 | the installation locations. 363 | 364 | `--no-create' 365 | `-n' 366 | Run the configure checks, but stop before creating any output 367 | files. 368 | 369 | `configure' also accepts some other, not widely useful, options. Run 370 | `configure --help' for more details. 371 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = src include examples 2 | EXTRA_DIST = bootstrap 3 | ACLOCAL_AMFLAGS = -I m4 4 | 5 | pkgconfigdir = ${libdir}/pkgconfig 6 | pkgconfig_DATA = libbdvmi.pc 7 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bitdefender/libbdvmi/51a3de92a3e7ab500115dfc2d09d51ba1397c630/NEWS -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bitdefender/libbdvmi/51a3de92a3e7ab500115dfc2d09d51ba1397c630/README -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Libbdvmi 2 | 3 | (c) 2015-2021 Bitdefender SRL 4 | 5 | ## Usage 6 | 7 | Please use Xen 4.6 or newer. To test the library, issue: 8 | ``` 9 | $ ./bootstrap 10 | $ ./configure 11 | $ make 12 | ``` 13 | This will build the library and the test under examples/. 14 | 15 | To build the library with KVM support (if libkvmi is installed), issue: 16 | ``` 17 | $ ./configure --enable-kvmi 18 | ``` 19 | 20 | To see the test in action, run (as root): 21 | ``` 22 | # ./hookguest 23 | ``` 24 | in the `examples/` subdirectory, then simply start a Xen domain up. 25 | 26 | The application can be shut down at any time via `^C`. 27 | -------------------------------------------------------------------------------- /bootstrap: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | autoreconf --install 4 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_INIT([libbdvmi], [1.0]) 2 | 3 | LT_INIT 4 | 5 | AC_CONFIG_SRCDIR(src/xendriver.cpp) 6 | AC_CONFIG_MACRO_DIR([m4]) 7 | AC_CONFIG_HEADERS(config.h) 8 | 9 | CXXFLAGS="$CXXFLAGS -W -Wall -DXC_WANT_COMPAT_MAP_FOREIGN_API -DXC_WANT_COMPAT_EVTCHN_API -DXC_WANT_COMPAT_DEVICEMODEL_API" 10 | XENDIR="" 11 | 12 | AC_ARG_ENABLE(debug, 13 | [ --enable-debug compile with gdb debug information], 14 | CXXFLAGS="$CXXFLAGS -g") 15 | 16 | AC_ARG_ENABLE(optimize, 17 | [ --enable-optimize optimize compiled code (-O2)], 18 | CXXFLAGS="$CXXFLAGS -O2") 19 | 20 | AC_ARG_ENABLE(xen, 21 | [ --disable-xen disable XEN support], [], [enable_xen=yes]) 22 | 23 | AC_ARG_WITH(xen, 24 | [ --with-xen specify Xen includes and libraries parent directory], 25 | XENDIR="$withval") 26 | 27 | AC_ARG_ENABLE(kvmi, 28 | [ --enable-kvmi enable KVMI support], 29 | CPPFLAGS="$CPPFLAGS -DUSE_KVMI",[enable_kvmi=no]) 30 | 31 | if test -n $XENDIR && test "x$enable_xen" = "xyes"; then 32 | CFLAGS="-I$/XENDIR/include $CFLAGS" 33 | CXXFLAGS="-I$XENDIR/include $CXXFLAGS" 34 | LDFLAGS="-L$XENDIR/lib -Wl,-rpath,$XENDIR/lib $LDFLAGS" 35 | fi 36 | 37 | AM_INIT_AUTOMAKE 38 | AC_PROG_CXX 39 | AC_PROG_INSTALL 40 | AC_PROG_LIBTOOL 41 | AC_LANG(C++) 42 | 43 | AX_CXX_COMPILE_STDCXX([14], [ext]) 44 | 45 | AC_CHECK_HEADERS([boost/container/flat_map.hpp], [], [AC_MSG_ERROR(bailing out)]) 46 | 47 | AS_IF([test "x$enable_xen" = "xyes"], [ 48 | AC_CHECK_LIB(xenctrl, xc_interface_open, , AC_MSG_ERROR([Could not find libxenctrl!])) 49 | AC_CHECK_LIB(xenstore, xs_open, , AC_MSG_ERROR([Could not find libxenstore!])) 50 | ]) 51 | 52 | if test "x$enable_kvmi" = "xyes" ; then 53 | PKG_CHECK_MODULES(KVMI, [libkvmi]) 54 | PKG_CHECK_MODULES(UUID, [uuid]) 55 | PKG_CHECK_MODULES(CRYPTO, [libcrypto]) 56 | fi 57 | 58 | AC_CHECK_TYPE(int32_t, int) 59 | AC_CHECK_TYPE(int16_t, short) 60 | AC_CHECK_TYPE(uint16_t, unsigned short) 61 | AC_CHECK_TYPE(uint32_t, unsigned int) 62 | AC_CHECK_TYPE(uint64_t, unsigned long long) 63 | 64 | echo "=== 65 | XEN: $enable_xen 66 | KVM: $enable_kvmi 67 | ===" 68 | AS_IF([test "x$enable_xen" != "xyes" -a "x$enable_kvmi" != "xyes"], [ 69 | AC_MSG_ERROR([At least one backend (Xen, KVM) must be enabled]) 70 | ]) 71 | 72 | AM_CONDITIONAL([KVMI], [test "x$enable_kvmi" = "xyes"]) 73 | AM_CONDITIONAL([XEN], [test "x$enable_xen" = "xyes"]) 74 | 75 | AC_OUTPUT(Makefile src/Makefile include/Makefile examples/Makefile libbdvmi.pc) 76 | -------------------------------------------------------------------------------- /examples/Makefile.am: -------------------------------------------------------------------------------- 1 | AM_CPPFLAGS = -I$(top_srcdir)/include 2 | 3 | bin_PROGRAMS = hookguest 4 | 5 | hookguest_SOURCES = hookguest.cpp 6 | hookguest_LDADD = $(top_builddir)/src/libbdvmi.la -ldl 7 | -------------------------------------------------------------------------------- /examples/hookguest.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-2017 Bitdefender SRL, All rights reserved. 2 | // 3 | // This library is free software; you can redistribute it and/or 4 | // modify it under the terms of the GNU Lesser General Public 5 | // License as published by the Free Software Foundation; either 6 | // version 3.0 of the License, or (at your option) any later version. 7 | // 8 | // This library is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 | // Lesser General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU Lesser General Public 14 | // License along with this library. 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | using namespace std; 29 | 30 | namespace { // Anonymous namespace 31 | 32 | sig_atomic_t stop; 33 | 34 | void stop_handler( int /* signo */ ) 35 | { 36 | stop = 1; 37 | } 38 | } 39 | 40 | class DemoEventHandler : public bdvmi::EventHandler { 41 | 42 | public: 43 | // Callback for CR write events 44 | void handleCR( unsigned short /* vcpu */, unsigned short crNumber, const bdvmi::Registers & /* regs */, 45 | uint64_t /* oldValue */, uint64_t newValue, bdvmi::HVAction & /* hvAction */ ) override 46 | { 47 | cout << "CR" << crNumber << " event, newValue: 0x" << hex << newValue << endl; 48 | } 49 | 50 | // Callback for writes in MSR addresses 51 | void handleMSR( unsigned short /* vcpu */, uint32_t msr, uint64_t /* oldValue */, uint64_t newValue, 52 | bdvmi::HVAction & /* hvAction */ ) override 53 | { 54 | cout << "MSR " << msr << " event, newValue: 0x" << hex << newValue << endl; 55 | } 56 | 57 | // Callback for page faults 58 | void handlePageFault( unsigned short vcpu, const bdvmi::Registers & /* regs */, uint64_t /* physAddress */, 59 | uint64_t /* virtAddress */, bool /* read */, bool /* write */, bool /* execute */, 60 | bool /* inGpt */, bdvmi::HVAction & /* action */, 61 | bdvmi::EmulatorContext & /* emulatorCtx */, 62 | unsigned short & /* instructionLength */ ) override 63 | { 64 | cout << "Page fault event on VCPU: " << vcpu << endl; 65 | } 66 | 67 | void handleVMCALL( unsigned short vcpu, const bdvmi::Registers ®s ) override 68 | { 69 | cout << "VMCALL event on VCPU " << vcpu << ", EAX: 0x" << hex << regs.rax << endl; 70 | } 71 | 72 | void handleXSETBV( unsigned short vcpu ) override 73 | { 74 | cout << "XSETBV event on VCPU " << vcpu << endl; 75 | } 76 | 77 | // Reserved (currently not in use) 78 | bool handleBreakpoint( unsigned short vcpu, const bdvmi::Registers & /* regs */, uint64_t gpa ) override 79 | { 80 | cout << "INT3 (breakpoint) event on VCPU " << vcpu << ", gpa: " << hex << showbase << gpa << endl; 81 | 82 | // Did not do anything about the breakpoint, so reinject it. 83 | return false; 84 | } 85 | 86 | void handleInterrupt( unsigned short vcpu, const bdvmi::Registers & /* regs */, uint32_t /* vector */, 87 | uint64_t /* errorCode */, uint64_t /* cr2 */ ) override 88 | { 89 | cout << "Interrupt event on VCPU " << vcpu << endl; 90 | } 91 | 92 | void handleDescriptorAccess( unsigned short vcpu, const bdvmi::Registers & /* regs */, unsigned int /* flags */, 93 | unsigned short & /* instructionLength */, bdvmi::HVAction & /* action */ ) override 94 | { 95 | cout << "Descriptor access on VCPU " << vcpu << endl; 96 | } 97 | 98 | void handleSessionOver( bdvmi::GuestState /* state */ ) override 99 | { 100 | cout << "Session over." << endl; 101 | } 102 | 103 | // This callback will run before each event (helper) 104 | void runPreEvent() override 105 | { 106 | cout << "Prepare for event ..." << endl; 107 | } 108 | 109 | void handleFatalError() override 110 | { 111 | throw std::runtime_error( "A fatal error occurred, cannot continue" ); 112 | } 113 | 114 | void runPostEvent() override 115 | { 116 | cout << "Event handled ..." << endl; 117 | } 118 | }; 119 | 120 | class DemoDomainHandler : public bdvmi::DomainHandler { 121 | 122 | public: 123 | DemoDomainHandler( bdvmi::BackendFactory &bf ) 124 | : bf_{ bf } 125 | { 126 | } 127 | 128 | public: 129 | // Found a domain 130 | void handleDomainFound( const string &uuid, const string &name ) override 131 | { 132 | cout << "A new domain started running: " << name << ", UUID: " << uuid << endl; 133 | hookDomain( uuid ); 134 | } 135 | 136 | // The domain is no longer running 137 | void handleDomainFinished( const string &uuid ) override 138 | { 139 | cout << "Domain finished: " << uuid << endl; 140 | } 141 | 142 | void cleanup( bool /* suspendIntrospectorDomain */ ) override 143 | { 144 | cout << "Done waiting for domains to start." << endl; 145 | } 146 | 147 | private: 148 | void hookDomain( const string &uuid ) 149 | { 150 | auto pd = bf_.driver( uuid, false ); 151 | auto em = bf_.eventManager( *pd, stop ); 152 | 153 | DemoEventHandler deh; 154 | 155 | em->handler( &deh ); 156 | 157 | em->enableCrEvents( 0 ); 158 | em->enableCrEvents( 3 ); 159 | 160 | em->waitForEvents(); 161 | } 162 | 163 | private: 164 | bdvmi::BackendFactory &bf_; 165 | }; 166 | 167 | int main() 168 | { 169 | try { 170 | signal( SIGINT, stop_handler ); 171 | signal( SIGHUP, stop_handler ); 172 | signal( SIGTERM, stop_handler ); 173 | 174 | bdvmi::logger.info( []( const std::string &s ) { cout << "[INFO] " << s << endl; } ); 175 | bdvmi::logger.debug( []( const std::string &s ) { cout << "[DEBUG] " << s << endl; } ); 176 | bdvmi::logger.warning( []( const std::string &s ) { cout << "[WARNING] " << s << endl; } ); 177 | bdvmi::logger.error( []( const std::string &s ) { cerr << "[ERROR] " << s << "\n"; } ); 178 | 179 | bdvmi::BackendFactory bf( bdvmi::BackendFactory::BACKEND_XEN ); 180 | DemoDomainHandler ddh( bf ); 181 | 182 | auto pdw = bf.domainWatcher( stop ); 183 | 184 | cout << "Registering handler ... " << endl; 185 | 186 | pdw->handler( &ddh ); 187 | 188 | cout << "Waiting for domains ..." << endl; 189 | pdw->waitForDomains(); 190 | 191 | cout << "\nDone." << endl; 192 | } catch ( const exception &e ) { 193 | cerr << "Error: caught exception: " << e.what() << endl; 194 | return -1; 195 | } 196 | 197 | return 0; 198 | } 199 | -------------------------------------------------------------------------------- /include/Makefile.am: -------------------------------------------------------------------------------- 1 | nobase_include_HEADERS = bdvmi/domainhandler.h bdvmi/driver.h bdvmi/eventmanager.h \ 2 | bdvmi/backendfactory.h bdvmi/domainwatcher.h bdvmi/eventhandler.h \ 3 | bdvmi/statscollector.h bdvmi/pagecache.h bdvmi/version.h bdvmi/logger.h 4 | -------------------------------------------------------------------------------- /include/bdvmi/backendfactory.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-2019 Bitdefender SRL, All rights reserved. 2 | // 3 | // This library is free software; you can redistribute it and/or 4 | // modify it under the terms of the GNU Lesser General Public 5 | // License as published by the Free Software Foundation; either 6 | // version 3.0 of the License, or (at your option) any later version. 7 | // 8 | // This library is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 | // Lesser General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU Lesser General Public 14 | // License along with this library. 15 | 16 | #ifndef __BDVMIBACKENDFACTORY_H_INCLUDED__ 17 | #define __BDVMIBACKENDFACTORY_H_INCLUDED__ 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | namespace bdvmi { 24 | 25 | class DomainWatcher; 26 | class Driver; 27 | class EventManager; 28 | 29 | class BackendFactory { 30 | 31 | public: 32 | enum BackendType { BACKEND_XEN, BACKEND_KVM }; 33 | 34 | public: 35 | explicit BackendFactory( BackendType type ); 36 | 37 | public: 38 | std::unique_ptr domainWatcher( sig_atomic_t &sigStop ); 39 | 40 | std::unique_ptr driver( const std::string &domain, bool altp2m, bool hvmOnly = true ); 41 | 42 | std::unique_ptr eventManager( Driver &driver, sig_atomic_t &sigStop ); 43 | 44 | public: 45 | BackendFactory( const BackendFactory & ) = delete; 46 | BackendFactory &operator=( const BackendFactory & ) = delete; 47 | 48 | private: 49 | BackendType type_; 50 | }; 51 | 52 | } // namespace bdvmi 53 | 54 | #endif // __BDVMIBACKENDFACTORY_H_INCLUDED__ 55 | -------------------------------------------------------------------------------- /include/bdvmi/domainhandler.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-2019 Bitdefender SRL, All rights reserved. 2 | // 3 | // This library is free software; you can redistribute it and/or 4 | // modify it under the terms of the GNU Lesser General Public 5 | // License as published by the Free Software Foundation; either 6 | // version 3.0 of the License, or (at your option) any later version. 7 | // 8 | // This library is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 | // Lesser General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU Lesser General Public 14 | // License along with this library. 15 | 16 | #ifndef __BDVMIDOMAINHANDLER_H_INCLUDED__ 17 | #define __BDVMIDOMAINHANDLER_H_INCLUDED__ 18 | 19 | #include 20 | 21 | namespace bdvmi { 22 | 23 | class DomainHandler { 24 | 25 | public: 26 | // base class, so virtual destructor 27 | virtual ~DomainHandler() = default; 28 | 29 | public: 30 | virtual void handleDomainFound( const std::string &uuid, const std::string &name ) = 0; 31 | 32 | virtual void handleDomainFinished( const std::string &uuid ) = 0; 33 | 34 | // For those backends capable of figuring this out, if introspection is stopped as a 35 | // consequence of suspending the domain in which introspection is running then 36 | // suspendIntrospectorDomain will be true. 37 | virtual void cleanup( bool suspendIntrospectorDomain = false ) = 0; 38 | }; 39 | 40 | } // namespace bdvmi 41 | 42 | #endif // __BDVMIDOMAINHANDLER_H_INCLUDED__ 43 | -------------------------------------------------------------------------------- /include/bdvmi/domainwatcher.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-2019 Bitdefender SRL, All rights reserved. 2 | // 3 | // This library is free software; you can redistribute it and/or 4 | // modify it under the terms of the GNU Lesser General Public 5 | // License as published by the Free Software Foundation; either 6 | // version 3.0 of the License, or (at your option) any later version. 7 | // 8 | // This library is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 | // Lesser General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU Lesser General Public 14 | // License along with this library. 15 | 16 | #ifndef __BDVMIDOMAINWATCHER_H_INCLUDED__ 17 | #define __BDVMIDOMAINWATCHER_H_INCLUDED__ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | namespace bdvmi { 25 | 26 | // Forward declaration, minimize compile-time header dependencies 27 | class DomainHandler; 28 | 29 | class DomainWatcher { 30 | 31 | protected: 32 | struct DomainInfo { 33 | enum State { STATE_NEW, STATE_FINISHED }; 34 | 35 | DomainInfo( const std::string &u, State s = STATE_NEW, const std::string &n = "unknown" ) 36 | : uuid( u ) 37 | , state( s ) 38 | , name( n ) 39 | { 40 | } 41 | 42 | std::string uuid; 43 | State state; 44 | std::string name; 45 | }; 46 | 47 | public: 48 | DomainWatcher( sig_atomic_t &sigStop ); 49 | 50 | // Base class, so virtual destructor 51 | virtual ~DomainWatcher() = default; 52 | 53 | public: 54 | // Return true if the guest running the application can do introspection 55 | virtual bool accessGranted() = 0; 56 | 57 | // Called before a dedicated child process is fork()ed to handle the domain 58 | virtual void forkingHandler( const std::string & /* uuid */ ) 59 | { 60 | } 61 | 62 | // Called if (and when) a dedicated child process has fork()ed to handle the domain 63 | virtual void forkedHandler( const std::string & /* uuid */, bool /* parent */ = true ) 64 | { 65 | } 66 | 67 | // Called when a dedicated child process has ended 68 | virtual void diedHandler( const std::string & /* uuid */ ) 69 | { 70 | } 71 | 72 | void handler( DomainHandler *h ) 73 | { 74 | handler_ = h; 75 | } 76 | 77 | void stop() 78 | { 79 | stop_ = true; 80 | } 81 | 82 | // "Template" pattern - calls waitForDomainOrTimeout() 83 | void waitForDomains(); 84 | 85 | virtual void setAuthCookie( const std::string & /* authCookie */ ) 86 | { 87 | } 88 | 89 | virtual bool ownUuid( std::string &uuid ) const = 0; 90 | 91 | protected: 92 | // Return true if a new domain is up, false for timeout 93 | virtual bool waitForDomainsOrTimeout( std::list &domains, int ms ) = 0; 94 | 95 | protected: 96 | sig_atomic_t &sigStop_; 97 | bool suspendIntrospectorDomain_{ false }; 98 | 99 | private: 100 | bool stop_{ false }; 101 | DomainHandler *handler_{ nullptr }; 102 | }; 103 | 104 | } // namespace bdvmi 105 | 106 | #endif // __BDVMIDOMAINWATCHER_H_INCLUDED__ 107 | -------------------------------------------------------------------------------- /include/bdvmi/driver.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-2019 Bitdefender SRL, All rights reserved. 2 | // 3 | // This library is free software; you can redistribute it and/or 4 | // modify it under the terms of the GNU Lesser General Public 5 | // License as published by the Free Software Foundation; either 6 | // version 3.0 of the License, or (at your option) any later version. 7 | // 8 | // This library is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 | // Lesser General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU Lesser General Public 14 | // License along with this library. 15 | 16 | #ifndef __BDVMIDRIVER_H_INCLUDED__ 17 | #define __BDVMIDRIVER_H_INCLUDED__ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #define PAGE_SHIFT 12 27 | #define PAGE_SIZE ( 1UL << PAGE_SHIFT ) 28 | #define PAGE_MASK ( ~( PAGE_SIZE - 1 ) ) 29 | 30 | #define gpa_to_gfn( pa ) ( ( unsigned long )( ( pa ) >> PAGE_SHIFT ) ) 31 | #define gfn_to_gpa( fn ) ( ( unsigned long )( ( fn ) << PAGE_SHIFT ) ) 32 | 33 | /* From xen/include/asm-x86/msr-index.h */ 34 | #define MSR_IA32_SYSENTER_CS 0x00000174 35 | #define MSR_IA32_SYSENTER_ESP 0x00000175 36 | #define MSR_IA32_SYSENTER_EIP 0x00000176 37 | #define MSR_IA32_CR_PAT 0x00000277 38 | #define MSR_IA32_MISC_ENABLE 0x000001a0 39 | #define MSR_IA32_MC0_CTL 0x00000400 40 | 41 | #define MSR_EFER 0xc0000080 /* extended feature register */ 42 | #define MSR_STAR 0xc0000081 /* legacy mode SYSCALL target */ 43 | #define MSR_LSTAR 0xc0000082 /* long mode SYSCALL target */ 44 | #define MSR_CSTAR 0xc0000083 /* compat mode SYSCALL target */ 45 | #define MSR_FS_BASE 0xc0000100 /* 64bit FS base */ 46 | #define MSR_GS_BASE 0xc0000101 /* 64bit GS base */ 47 | #define MSR_SHADOW_GS_BASE 0xc0000102 /* SwapGS GS shadow */ 48 | 49 | // mapPhysMemToHost() flags 50 | #define PHYSMAP_NO_CACHE 0x00000001 51 | 52 | namespace bdvmi { 53 | 54 | class PageCache; 55 | 56 | struct Registers { 57 | 58 | enum GuestX86Mode { ERROR, CS_TYPE_16, CS_TYPE_32, CS_TYPE_64 }; 59 | 60 | uint64_t sysenter_cs{}; 61 | uint64_t sysenter_esp{}; 62 | uint64_t sysenter_eip{}; 63 | uint64_t msr_efer{}; 64 | uint64_t msr_star{}; 65 | uint64_t msr_lstar{}; 66 | uint64_t msr_pat{}; 67 | uint64_t msr_cstar{}; 68 | 69 | uint64_t cs_base{}; 70 | uint64_t cs_limit{}; 71 | uint64_t cs_sel{}; 72 | uint64_t ss_base{}; 73 | uint64_t ss_limit{}; 74 | uint64_t ss_sel{}; 75 | uint64_t ss_arbytes{}; 76 | uint64_t ds_base{}; 77 | uint64_t ds_limit{}; 78 | uint64_t ds_sel{}; 79 | uint64_t ds_arbytes{}; 80 | uint64_t es_base{}; 81 | uint64_t es_limit{}; 82 | uint64_t es_sel{}; 83 | uint64_t es_arbytes{}; 84 | uint64_t fs_limit{}; 85 | uint64_t fs_sel{}; 86 | uint64_t fs_arbytes{}; 87 | uint64_t gs_limit{}; 88 | uint64_t gs_sel{}; 89 | uint64_t gs_arbytes{}; 90 | uint64_t shadow_gs{}; 91 | 92 | uint64_t fs_base{}; 93 | uint64_t gs_base{}; 94 | uint64_t idtr_base{}; 95 | uint64_t idtr_limit{}; 96 | uint64_t gdtr_base{}; 97 | uint64_t gdtr_limit{}; 98 | 99 | uint64_t rax{}; 100 | uint64_t rcx{}; 101 | uint64_t rdx{}; 102 | uint64_t rbx{}; 103 | uint64_t rsp{}; 104 | uint64_t rbp{}; 105 | uint64_t rsi{}; 106 | uint64_t rdi{}; 107 | uint64_t r8{}; 108 | uint64_t r9{}; 109 | uint64_t r10{}; 110 | uint64_t r11{}; 111 | uint64_t r12{}; 112 | uint64_t r13{}; 113 | uint64_t r14{}; 114 | uint64_t r15{}; 115 | uint64_t rflags{}; 116 | uint64_t rip{}; 117 | uint64_t cr0{}; 118 | uint64_t cr2{}; 119 | uint64_t cr3{}; 120 | uint64_t cr4{}; 121 | 122 | uint32_t cs_arbytes{}; 123 | 124 | GuestX86Mode guest_x86_mode{ ERROR }; 125 | }; 126 | 127 | struct EmulatorContext { 128 | void reset() 129 | { 130 | address_ = 0; 131 | size_ = 0; 132 | memset( data_, 0, sizeof( data_ ) ); 133 | } 134 | 135 | uint64_t address_{}; 136 | uint32_t size_{}; 137 | uint8_t data_[164]{}; 138 | }; 139 | 140 | enum MapReturnCode { MAP_SUCCESS, MAP_FAILED_GENERIC, MAP_PAGE_NOT_PRESENT, MAP_INVALID_PARAMETER }; 141 | 142 | class EventHandler; 143 | 144 | class Driver { 145 | 146 | public: 147 | enum PageRestriction { PAGE_READ = 1 << 0, PAGE_WRITE = 1 << 1, PAGE_EXECUTE = 1 << 2 }; 148 | 149 | using ConvertibleMap = boost::container::flat_map; 150 | using ViewConvertibleMap = boost::container::flat_map; 151 | using MemAccessMap = boost::container::flat_map; 152 | using ViewMemAccessMap = boost::container::flat_map; 153 | 154 | public: 155 | Driver( EventHandler *handler = nullptr ) 156 | : handler_{ handler } 157 | { 158 | } 159 | 160 | // base class => virtual destructor 161 | virtual ~Driver() = default; 162 | 163 | public: 164 | void handler( EventHandler *h ) 165 | { 166 | handler_ = h; 167 | } 168 | 169 | EventHandler *handler() const 170 | { 171 | return handler_; 172 | } 173 | 174 | public: 175 | // Get VCPU count 176 | virtual bool cpuCount( unsigned int &count ) const = 0; 177 | 178 | // Get TSC speed 179 | virtual bool tscSpeed( unsigned long long &speed ) const = 0; 180 | 181 | // Get MTRR type for guestAddress 182 | virtual bool mtrrType( unsigned long long guestAddress, uint8_t &type ) const = 0; 183 | 184 | // Set guest page protection (_NOT_ virtual) 185 | bool setPageProtection( unsigned long long guestAddress, bool read, bool write, bool execute, 186 | unsigned short view = 0 ); 187 | 188 | // Get guest page protection (_NOT_ virtual) 189 | bool getPageProtection( unsigned long long guestAddress, bool &read, bool &write, bool &execute, 190 | unsigned short view = 0 ); 191 | 192 | // Flush page protections (_NOT_ virtual) 193 | void flushPageProtections(); 194 | 195 | // Get registers 196 | virtual bool registers( unsigned short vcpu, Registers ®s ) const = 0; 197 | 198 | // Set registers 199 | virtual bool setRegisters( unsigned short vcpu, const Registers ®s, bool setEip, bool delay ) = 0; 200 | 201 | virtual MapReturnCode mapPhysMemToHost( unsigned long long address, size_t length, uint32_t flags, 202 | void *&pointer ) = 0; 203 | 204 | virtual bool unmapPhysMem( void *hostPtr ) = 0; 205 | 206 | virtual bool injectTrap( unsigned short vcpu, uint8_t trapNumber, uint32_t errorCode, uint64_t cr2 ) = 0; 207 | 208 | virtual bool setRepOptimizations( bool enable ) = 0; 209 | 210 | virtual bool shutdown() = 0; 211 | 212 | virtual bool pause() = 0; 213 | 214 | virtual bool unpause() = 0; 215 | 216 | virtual size_t setPageCacheLimit( size_t limit ) = 0; 217 | 218 | virtual bool getXSAVESize( unsigned short vcpu, size_t &size ) = 0; 219 | 220 | virtual bool getXSAVEArea( unsigned short vcpu, void *buffer, size_t bufSize ) = 0; 221 | 222 | // Get the maximum accessible guest frame number (_NOT_ virtual) 223 | bool maxGPFN( unsigned long long &gfn ); 224 | 225 | virtual bool getEPTPageConvertible( unsigned short index, unsigned long long guestAddress, 226 | bool &convertible ) = 0; 227 | 228 | bool setEPTPageConvertible( unsigned short index, unsigned long long guestAddress, bool convertible ); 229 | 230 | virtual bool createEPT( unsigned short &index ) = 0; 231 | 232 | virtual bool destroyEPT( unsigned short index ) = 0; 233 | 234 | virtual bool switchEPT( unsigned short index ) = 0; 235 | 236 | virtual bool setVEInfoPage( unsigned short vcpu, unsigned long long gpa ) = 0; 237 | 238 | virtual bool disableVE( unsigned short vcpu ) = 0; 239 | 240 | virtual unsigned short eptpIndex( unsigned short vcpu ) const = 0; 241 | 242 | virtual bool update() = 0; 243 | 244 | virtual std::string uuid() const = 0; 245 | 246 | virtual unsigned int id() const = 0; 247 | 248 | virtual void enableCache( unsigned short vcpu ) = 0; 249 | 250 | virtual void disableCache() = 0; 251 | 252 | virtual uint32_t startTime() = 0; 253 | 254 | virtual bool isMsrCached( uint64_t msr ) const = 0; 255 | 256 | // Does this driver support altp2m #VE? 257 | virtual bool veSupported() const = 0; 258 | 259 | // Does this driver support altp2m VMFUNC? 260 | virtual bool vmfuncSupported() const = 0; 261 | 262 | // Does this driver support Intel SPP? 263 | virtual bool sppSupported() const = 0; 264 | 265 | // Does this driver support DTR events? 266 | virtual bool dtrEventsSupported() const = 0; 267 | 268 | virtual bool getXCR0( unsigned short vcpu, uint64_t &xcr0 ) const = 0; 269 | 270 | private: 271 | virtual void *mapGuestPageImpl( unsigned long long gfn ) = 0; 272 | 273 | virtual void unmapGuestPageImpl( void *hostPtr, unsigned long long gfn ) = 0; 274 | 275 | virtual bool setPageProtectionImpl( const MemAccessMap &accessMap, unsigned short view ) = 0; 276 | 277 | virtual bool setPageConvertibleImpl( const ConvertibleMap &convMap, unsigned short view ) = 0; 278 | 279 | // Get guest page protection 280 | virtual bool getPageProtectionImpl( unsigned long long guestAddress, bool &read, bool &write, bool &execute, 281 | unsigned short view ) = 0; 282 | 283 | virtual bool maxGPFNImpl( unsigned long long &gfn, bool &trustworthy ) = 0; 284 | 285 | private: 286 | EventHandler * handler_{ nullptr }; 287 | ViewMemAccessMap memAccessCache_; 288 | ViewMemAccessMap delayedMemAccessWrite_; 289 | ViewConvertibleMap delayedConvertibleWrite_; 290 | std::mutex memAccessCacheMutex_; 291 | std::mutex convertibleCacheMutex_; 292 | std::mutex maxGPFNMutex_; 293 | unsigned long long maxGPFN_{ 0 }; 294 | 295 | friend class PageCache; 296 | }; 297 | 298 | } // namespace bdvmi 299 | 300 | #endif // __BDVMIDRIVER_H_INCLUDED__ 301 | -------------------------------------------------------------------------------- /include/bdvmi/eventhandler.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-2019 Bitdefender SRL, All rights reserved. 2 | // 3 | // This library is free software; you can redistribute it and/or 4 | // modify it under the terms of the GNU Lesser General Public 5 | // License as published by the Free Software Foundation; either 6 | // version 3.0 of the License, or (at your option) any later version. 7 | // 8 | // This library is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 | // Lesser General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU Lesser General Public 14 | // License along with this library. 15 | 16 | #ifndef __BDVMIEVENTHANDLER_H_INCLUDED__ 17 | #define __BDVMIEVENTHANDLER_H_INCLUDED__ 18 | 19 | #include 20 | 21 | namespace bdvmi { 22 | 23 | // Forward declaration 24 | struct Registers; 25 | struct EmulatorContext; 26 | 27 | enum HVAction { NONE, EMULATE_NOWRITE, SKIP_INSTRUCTION, ALLOW_VIRTUAL, EMULATE_SET_CTXT }; 28 | 29 | enum GuestState { RUNNING, POST_SHUTDOWN, SHUTDOWN_IN_PROGRESS }; 30 | 31 | #define BDVMI_DESC_ACCESS_IDTR 0x01 32 | #define BDVMI_DESC_ACCESS_GDTR 0x02 33 | #define BDVMI_DESC_ACCESS_TR 0x04 34 | #define BDVMI_DESC_ACCESS_LDTR 0x08 35 | #define BDVMI_DESC_ACCESS_READ 0x10 36 | #define BDVMI_DESC_ACCESS_WRITE 0x20 37 | 38 | class EventHandler { 39 | 40 | public: 41 | // Base class, so virtual destructor. 42 | virtual ~EventHandler() = default; 43 | 44 | public: 45 | // Callback for CR{0,3,4} write events. 46 | virtual void handleCR( unsigned short vcpu, unsigned short crNumber, const bdvmi::Registers ®s, 47 | uint64_t oldValue, uint64_t newValue, HVAction &action ) = 0; 48 | 49 | // Callback for writes in MSR addresses. 50 | virtual void handleMSR( unsigned short vcpu, uint32_t msr, uint64_t oldValue, uint64_t newValue, 51 | HVAction &action ) = 0; 52 | 53 | // Callback for page faults. 54 | virtual void handlePageFault( unsigned short vcpu, const Registers ®s, uint64_t physAddress, 55 | uint64_t virtAddress, bool read, bool write, bool execute, bool inGpt, 56 | HVAction &action, EmulatorContext &emulatorCtx, 57 | unsigned short &instructionSize ) = 0; 58 | 59 | // Callback for VMCALL events. 60 | virtual void handleVMCALL( unsigned short vcpu, const Registers ®s ) = 0; 61 | 62 | virtual void handleXSETBV( unsigned short vcpu ) = 0; 63 | 64 | // Return false if you want to reinject 65 | virtual bool handleBreakpoint( unsigned short vcpu, const Registers ®s, uint64_t gpa ) = 0; 66 | 67 | virtual void handleInterrupt( unsigned short vcpu, const Registers ®s, uint32_t vector, uint64_t errorCode, 68 | uint64_t cr2 ) = 0; 69 | 70 | virtual void handleDescriptorAccess( unsigned short vcpu, const Registers ®s, unsigned int flags, 71 | unsigned short &instructionLength, HVAction &action ) = 0; 72 | 73 | // Notice that the connection to the guest has been terminated (if guestStillRunning is true 74 | // then this has _not_ happened because the guest shut down or has been forcefully terminated). 75 | virtual void handleSessionOver( GuestState state ) = 0; 76 | 77 | virtual void handleFatalError() = 0; 78 | 79 | // Useful for reloading configuration, checking state, etc. 80 | virtual void runPreEvent() = 0; 81 | 82 | virtual void runPostEvent() = 0; 83 | }; 84 | 85 | } // namespace bdvmi 86 | 87 | #endif // __BDVMIEVENTHANDLER_H_INCLUDED__ 88 | -------------------------------------------------------------------------------- /include/bdvmi/eventmanager.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-2019 Bitdefender SRL, All rights reserved. 2 | // 3 | // This library is free software; you can redistribute it and/or 4 | // modify it under the terms of the GNU Lesser General Public 5 | // License as published by the Free Software Foundation; either 6 | // version 3.0 of the License, or (at your option) any later version. 7 | // 8 | // This library is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 | // Lesser General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU Lesser General Public 14 | // License along with this library. 15 | 16 | #ifndef __BDVMIEVENTMANAGER_H_INCLUDED__ 17 | #define __BDVMIEVENTMANAGER_H_INCLUDED__ 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | namespace bdvmi { 24 | 25 | // forward declaration, minimize compile-time file dependencies 26 | class EventHandler; 27 | 28 | class EventManager { 29 | 30 | public: 31 | EventManager( sig_atomic_t &sigStop ); 32 | 33 | // base class, so virtual destructor 34 | virtual ~EventManager() = default; 35 | 36 | public: 37 | // Set the handler 38 | void handler( EventHandler *handler ) 39 | { 40 | handler_ = handler; 41 | } 42 | 43 | // Get the handler 44 | EventHandler *handler() const 45 | { 46 | return handler_; 47 | } 48 | 49 | bool enableMsrEvents( unsigned int msr, bool &oldValue ); 50 | 51 | bool disableMsrEvents( unsigned int msr, bool &oldValue ); 52 | 53 | bool enableCrEvents( unsigned int cr ); 54 | 55 | bool disableCrEvents( unsigned int cr ); 56 | 57 | bool enableXSETBVEvents(); 58 | 59 | bool disableXSETBVEvents(); 60 | 61 | bool enableBreakpointEvents(); 62 | 63 | bool disableBreakpointEvents(); 64 | 65 | bool enableVMCALLEvents(); 66 | 67 | bool disableVMCALLEvents(); 68 | 69 | bool enableDescriptorEvents(); 70 | 71 | bool disableDescriptorEvents(); 72 | 73 | // Loop waiting for events 74 | virtual void waitForEvents() = 0; 75 | 76 | // Stop the event loop 77 | virtual void stop() = 0; 78 | 79 | // Get the domain UUID 80 | virtual std::string uuid() = 0; 81 | 82 | private: 83 | virtual bool enableMsrEventsImpl( unsigned int msr ) = 0; 84 | 85 | virtual bool disableMsrEventsImpl( unsigned int msr ) = 0; 86 | 87 | virtual bool enableCrEventsImpl( unsigned int cr ) = 0; 88 | 89 | virtual bool disableCrEventsImpl( unsigned int cr ) = 0; 90 | 91 | virtual bool enableXSETBVEventsImpl() = 0; 92 | 93 | virtual bool disableXSETBVEventsImpl() = 0; 94 | 95 | virtual bool enableBreakpointEventsImpl() = 0; 96 | 97 | virtual bool disableBreakpointEventsImpl() = 0; 98 | 99 | virtual bool enableVMCALLEventsImpl() = 0; 100 | 101 | virtual bool disableVMCALLEventsImpl() = 0; 102 | 103 | virtual bool enableDescriptorEventsImpl() 104 | { 105 | return false; 106 | } 107 | 108 | virtual bool disableDescriptorEventsImpl() 109 | { 110 | return false; 111 | } 112 | 113 | protected: 114 | sig_atomic_t & sigStop_; 115 | std::set enabledCrs_; 116 | std::set enabledMsrs_; 117 | 118 | private: 119 | EventHandler *handler_{ nullptr }; 120 | bool breakpointEnabled_{ false }; 121 | bool xsetbvEnabled_{ false }; 122 | bool vmcallEnabled_{ false }; 123 | bool descriptorEnabled_{ false }; 124 | }; 125 | } // namespace bdvmi 126 | 127 | #endif // __BDVMIEVENTMANAGER_H_INCLUDED__ 128 | -------------------------------------------------------------------------------- /include/bdvmi/logger.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-2019 Bitdefender SRL, All rights reserved. 2 | // 3 | // This library is free software; you can redistribute it and/or 4 | // modify it under the terms of the GNU Lesser General Public 5 | // License as published by the Free Software Foundation; either 6 | // version 3.0 of the License, or (at your option) any later version. 7 | // 8 | // This library is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 | // Lesser General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU Lesser General Public 14 | // License along with this library. 15 | 16 | #ifndef __LOGGER_H_INCLUDED__ 17 | #define __LOGGER_H_INCLUDED__ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #define HEXLOG( v ) std::hex << std::showbase << v << std::dec 28 | 29 | namespace bdvmi { 30 | 31 | std::ostream &DEBUG( std::ostream &os ); 32 | std::ostream &ERROR( std::ostream &os ); 33 | std::ostream &INFO( std::ostream &os ); 34 | std::ostream &WARNING( std::ostream &os ); 35 | std::ostream &TRACE( std::ostream &os ); 36 | 37 | class LogStream; 38 | 39 | using LogHelperFunction = std::function; 40 | 41 | class LogStreambuf : public std::streambuf { 42 | 43 | public: 44 | enum LogLevel { DEBUG, INFO, WARNING, ERROR, TRACE }; 45 | 46 | private: 47 | struct Buffer { 48 | std::string contents_; 49 | LogLevel level_{ DEBUG }; 50 | }; 51 | 52 | public: 53 | LogStreambuf(); 54 | ~LogStreambuf(); 55 | 56 | public: 57 | void level( LogLevel level ); 58 | 59 | private: 60 | int_type overflow( int_type c ) override; 61 | std::streamsize xsputn( const char_type *s, std::streamsize n ) override; 62 | int_type sync() override; 63 | 64 | private: 65 | thread_local static std::unordered_map buffers_; 66 | static std::atomic_long indexGenerator_; 67 | long index_{ 0 }; 68 | LogHelperFunction debug_; 69 | LogHelperFunction error_; 70 | LogHelperFunction info_; 71 | LogHelperFunction warning_; 72 | std::atomic_bool trace_{ false }; 73 | std::string prefix_; 74 | 75 | friend class LogStream; 76 | }; 77 | 78 | class LogStream : public std::ostream { 79 | 80 | public: 81 | LogStream() 82 | : std::ostream{ &lsb_ } 83 | { 84 | } 85 | 86 | void debug( LogHelperFunction fn ) 87 | { 88 | lsb_.debug_ = std::move( fn ); 89 | } 90 | 91 | void error( LogHelperFunction fn ) 92 | { 93 | lsb_.error_ = std::move( fn ); 94 | } 95 | 96 | void info( LogHelperFunction fn ) 97 | { 98 | lsb_.info_ = std::move( fn ); 99 | } 100 | 101 | void warning( LogHelperFunction fn ) 102 | { 103 | lsb_.warning_ = std::move( fn ); 104 | } 105 | 106 | bool trace() const 107 | { 108 | return lsb_.trace_; 109 | } 110 | 111 | void trace( bool value ) 112 | { 113 | lsb_.trace_ = value; 114 | } 115 | 116 | void prefix( const std::string &prefix ) 117 | { 118 | lsb_.prefix_ = prefix; 119 | } 120 | 121 | private: 122 | LogStreambuf lsb_; 123 | }; 124 | 125 | extern LogStream logger; 126 | 127 | } // namespace bdvmi 128 | 129 | #endif // __LOGGER_H_INCLUDED__ 130 | -------------------------------------------------------------------------------- /include/bdvmi/pagecache.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-2019 Bitdefender SRL, All rights reserved. 2 | // 3 | // This library is free software; you can redistribute it and/or 4 | // modify it under the terms of the GNU Lesser General Public 5 | // License as published by the Free Software Foundation; either 6 | // version 3.0 of the License, or (at your option) any later version. 7 | // 8 | // This library is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 | // Lesser General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU Lesser General Public 14 | // License along with this library. 15 | 16 | #ifndef __BDVMIPAGECACHE_H_INCLUDED__ 17 | #define __BDVMIPAGECACHE_H_INCLUDED__ 18 | 19 | #include "driver.h" 20 | #include 21 | 22 | namespace bdvmi { 23 | 24 | class PageCache { 25 | 26 | public: 27 | static constexpr size_t MAX_CACHE_SIZE_DEFAULT = 1536; // pages 28 | 29 | private: 30 | struct CacheInfo { 31 | unsigned long accessed{ 0 }; 32 | void * pointer{ nullptr }; 33 | short inUse{ 1 }; 34 | }; 35 | 36 | using CacheMap = std::unordered_map; 37 | using ReverseCacheMap = std::unordered_map; 38 | 39 | public: 40 | PageCache( Driver *driver ); 41 | ~PageCache(); 42 | 43 | public: 44 | size_t setLimit( size_t limit ); 45 | 46 | void reset(); 47 | void driver( Driver *driver ) 48 | { 49 | driver_ = driver; 50 | } 51 | MapReturnCode update( unsigned long gfn, void *&pointer ); 52 | bool release( void *pointer ); 53 | 54 | private: 55 | MapReturnCode insertNew( unsigned long gfn, void *&pointer ); 56 | void cleanup(); 57 | unsigned long generateIndex() const; 58 | bool checkPages( void *addr, size_t size ) const; 59 | 60 | public: // no copying around 61 | PageCache( const PageCache & ) = delete; 62 | PageCache &operator=( const PageCache & ) = delete; 63 | 64 | private: 65 | Driver * driver_; 66 | CacheMap cache_; 67 | ReverseCacheMap reverseCache_; 68 | size_t cacheLimit_{ MAX_CACHE_SIZE_DEFAULT }; 69 | int linuxMajVersion_{ -1 }; 70 | }; 71 | 72 | } // namespace bdvmi 73 | 74 | #endif // __BDVMIPAGECACHE_H_INCLUDED__ 75 | -------------------------------------------------------------------------------- /include/bdvmi/statscollector.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-2019 Bitdefender SRL, All rights reserved. 2 | // 3 | // This library is free software; you can redistribute it and/or 4 | // modify it under the terms of the GNU Lesser General Public 5 | // License as published by the Free Software Foundation; either 6 | // version 3.0 of the License, or (at your option) any later version. 7 | // 8 | // This library is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 | // Lesser General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU Lesser General Public 14 | // License along with this library. 15 | 16 | #ifndef __BDVMISTATSCOLLECTOR_H_INCLUDED__ 17 | #define __BDVMISTATSCOLLECTOR_H_INCLUDED__ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | namespace bdvmi { 26 | 27 | class StatsCollector { 28 | 29 | private: 30 | StatsCollector() = default; 31 | 32 | public: 33 | StatsCollector( const StatsCollector & ) = delete; 34 | StatsCollector &operator=( const StatsCollector & ) = delete; 35 | 36 | public: 37 | static StatsCollector &instance(); 38 | 39 | public: 40 | void enable( bool value ); 41 | 42 | void count( const std::string & st, 43 | const std::chrono::duration &duration = std::chrono::duration::zero() ); 44 | 45 | void dump() const; 46 | 47 | bool enabled() const 48 | { 49 | return enable_; 50 | } 51 | 52 | private: 53 | std::atomic_bool enable_{ false }; 54 | std::unordered_map>> stats_; 55 | mutable std::mutex statsMutex_; 56 | }; 57 | 58 | #ifndef BDVMI_DISABLE_STATS 59 | 60 | class StatsCounter { 61 | 62 | public: 63 | explicit StatsCounter( std::string st ) 64 | : name_{ std::move( st ) } 65 | { 66 | if ( !StatsCollector::instance().enabled() ) 67 | return; 68 | 69 | start_ = std::chrono::high_resolution_clock::now(); 70 | } 71 | 72 | ~StatsCounter() 73 | { 74 | if ( !StatsCollector::instance().enabled() ) 75 | return; 76 | 77 | StatsCollector::instance().count( name_, std::chrono::high_resolution_clock::now() - start_ ); 78 | } 79 | 80 | private: 81 | std::string name_; 82 | std::chrono::time_point start_; 83 | }; 84 | 85 | #else 86 | 87 | struct StatsCounter { 88 | StatsCounter( ... ) 89 | { 90 | } 91 | }; 92 | 93 | #endif // BDVMI_DISABLE_STATS 94 | 95 | } // namespace bdvmi 96 | 97 | #endif // __BDVMISTATSCOLLECTOR_H_INCLUDED__ 98 | -------------------------------------------------------------------------------- /include/bdvmi/version.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2019 Bitdefender SRL, All rights reserved. 2 | // 3 | // This library is free software; you can redistribute it and/or 4 | // modify it under the terms of the GNU Lesser General Public 5 | // License as published by the Free Software Foundation; either 6 | // version 3.0 of the License, or (at your option) any later version. 7 | // 8 | // This library is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 | // Lesser General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU Lesser General Public 14 | // License along with this library. 15 | 16 | #ifndef __BDVMIVERSION_H_INCLUDED__ 17 | #define __BDVMIVERSION_H_INCLUDED__ 18 | 19 | #include 20 | 21 | namespace bdvmi { 22 | 23 | class Version { 24 | public: 25 | Version( int verMajor = 0, int verMinor = 0, const std::string &verExtra = "" ); 26 | 27 | int getMajor() const; 28 | int getMinor() const; 29 | std::string getExtra() const; 30 | 31 | friend std::ostream &operator<<( std::ostream &, const Version & ); 32 | friend int cmp( const Version &l, const Version &r ); 33 | 34 | private: 35 | int verMajor_; 36 | int verMinor_; 37 | std::string verExtra_; 38 | }; 39 | 40 | inline bool operator==( const Version &l, const Version &r ) 41 | { 42 | return cmp( l, r ) == 0; 43 | } 44 | 45 | inline bool operator!=( const Version &l, const Version &r ) 46 | { 47 | return cmp( l, r ) != 0; 48 | } 49 | 50 | inline bool operator<( const Version &l, const Version &r ) 51 | { 52 | return cmp( l, r ) < 0; 53 | } 54 | 55 | inline bool operator>( const Version &l, const Version &r ) 56 | { 57 | return cmp( l, r ) > 0; 58 | } 59 | 60 | inline bool operator<=( const Version &l, const Version &r ) 61 | { 62 | return cmp( l, r ) <= 0; 63 | } 64 | 65 | inline bool operator>=( const Version &l, const Version &r ) 66 | { 67 | return cmp( l, r ) >= 0; 68 | } 69 | 70 | } // namespace bdvmi 71 | 72 | #endif // __BDVMIVERSION_H_INCLUDED__ 73 | -------------------------------------------------------------------------------- /libbdvmi.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@prefix@ 2 | exec_prefix=@exec_prefix@ 3 | libdir=@libdir@ 4 | includedir=@includedir@ 5 | 6 | Name: @PACKAGE_NAME@ 7 | Description: A C++ library for virtual machine introspection 8 | Version: @PACKAGE_VERSION@ 9 | Libs: -L${libdir} -lbdvmi 10 | Cflags: -I${includedir} 11 | -------------------------------------------------------------------------------- /libbdvmi.spec: -------------------------------------------------------------------------------- 1 | Name: libbdvmi 2 | Summary: A C++ virtual machine introspection library 3 | License: LGPLv3+ 4 | URL: https://github.com/bitdefender/libbdvmi 5 | Version: 1.0.0 6 | Release: 0 7 | Group: System/Libraries 8 | BuildRequires: autoconf automake libtool glibc-devel gcc-c++ kernel-headers make libkvmi-devel 9 | Source0: https://github.com/bitdefender/libbdvmi/archive/v1.0.0.tar.gz 10 | 11 | %description 12 | This package contains a fairly basic VMI library written in C++ and which supports Xen and KVM (via libkvmi) 13 | 14 | %package devel 15 | Summary: A C++ virtual machine introspection library development package 16 | Requires: libbdvmi = %{version} 17 | Group: Development/Libraries 18 | 19 | %description devel 20 | This package contains the headers and static library necessary for building 21 | applications that use libbdvmi 22 | 23 | %prep 24 | %setup 25 | ./bootstrap 26 | 27 | %build 28 | %configure --enable-optimize --enable-kvmi 29 | make 30 | 31 | %install 32 | %make_install 33 | 34 | %files 35 | %{_bindir}/hookguest 36 | %{_libdir}/libbdvmi.so 37 | %{_libdir}/libbdvmi.so.1 38 | %{_libdir}/libbdvmi.so.1.0.0 39 | 40 | %files devel 41 | %{_includedir}/bdvmi/ 42 | %{_libdir}/libbdvmi.a 43 | %{_libdir}/libbdvmi.la 44 | %{_libdir}/pkgconfig/libbdvmi.pc 45 | -------------------------------------------------------------------------------- /src/Makefile.am: -------------------------------------------------------------------------------- 1 | AM_CPPFLAGS = -I$(top_srcdir)/include 2 | 3 | lib_LTLIBRARIES = libbdvmi.la 4 | 5 | noinst_HEADERS = dynamiclibfactory.h utils.h \ 6 | xcwrapper.h xenaltp2m.h \ 7 | xendomainwatcher.h xendriver.h \ 8 | xeneventmanager.h xswrapper.h \ 9 | xenvmevent_v3.h xenvmevent_v4.h \ 10 | xenvmevent_v5.h kvmdomainwatcher.h \ 11 | kvmdriver.h kvmeventmanager.h 12 | 13 | libbdvmi_la_SOURCES = backendfactory.cpp domainwatcher.cpp \ 14 | statscollector.cpp \ 15 | driver.cpp dynamiclibfactory.cpp \ 16 | eventmanager.cpp pagecache.cpp \ 17 | version.cpp logger.cpp 18 | 19 | if XEN 20 | libbdvmi_la_SOURCES += xendomainwatcher.cpp xendriver.cpp \ 21 | xeneventmanager.cpp xcwrapper.cpp \ 22 | xenaltp2m.cpp xswrapper.cpp 23 | endif 24 | 25 | if KVMI 26 | libbdvmi_la_SOURCES += kvmdomainwatcher.cpp kvmdriver.cpp \ 27 | kvmeventmanager.cpp 28 | libbdvmi_la_CXXFLAGS = $(KVMI_CFLAGS) $(UUID_CFLAGS) $(CRYPTO_CFLAGS) 29 | libbdvmi_la_LIBADD = $(KVMI_LIBS) $(UUID_LIBS) $(CRYPTO_LIBS) 30 | endif 31 | 32 | libbdvmi_la_LDFLAGS = -version-number 1:0 \ 33 | -Wl,--version-script,$(srcdir)/version.ld 34 | -------------------------------------------------------------------------------- /src/backendfactory.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-2019 Bitdefender SRL, All rights reserved. 2 | // 3 | // This library is free software; you can redistribute it and/or 4 | // modify it under the terms of the GNU Lesser General Public 5 | // License as published by the Free Software Foundation; either 6 | // version 3.0 of the License, or (at your option) any later version. 7 | // 8 | // This library is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 | // Lesser General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU Lesser General Public 14 | // License along with this library. 15 | 16 | #include "bdvmi/backendfactory.h" 17 | #ifdef USE_XEN 18 | #include "xendriver.h" 19 | #include "xendomainwatcher.h" 20 | #include "xeneventmanager.h" 21 | #endif 22 | #ifdef USE_KVMI 23 | #include "kvmdriver.h" 24 | #include "kvmdomainwatcher.h" 25 | #include "kvmeventmanager.h" 26 | #endif 27 | #include 28 | 29 | namespace bdvmi { 30 | 31 | BackendFactory::BackendFactory( BackendType type ) 32 | : type_{ type } 33 | { 34 | if ( type_ != BACKEND_XEN && type_ != BACKEND_KVM ) 35 | throw std::runtime_error( "Xen and KVM are the only supported backends for now" ); 36 | } 37 | 38 | std::unique_ptr BackendFactory::domainWatcher( sig_atomic_t &sigStop ) 39 | { 40 | switch ( type_ ) { 41 | #ifdef USE_XEN 42 | case BACKEND_XEN: 43 | return std::make_unique( sigStop ); 44 | #endif 45 | #ifdef USE_KVMI 46 | case BACKEND_KVM: 47 | return std::make_unique( sigStop ); 48 | #endif 49 | default: 50 | throw std::runtime_error( "Xen and KVM are the only supported backends for now" ); 51 | } 52 | } 53 | 54 | std::unique_ptr BackendFactory::driver( const std::string &domain, bool altp2m, bool hvmOnly ) 55 | { 56 | switch ( type_ ) { 57 | #ifdef USE_XEN 58 | case BACKEND_XEN: 59 | return std::make_unique( domain, altp2m, hvmOnly ); 60 | #endif 61 | #ifdef USE_KVMI 62 | case BACKEND_KVM: 63 | return std::make_unique( domain, altp2m ); 64 | #endif 65 | default: 66 | throw std::runtime_error( "Xen and KVM are the only supported backends for now" ); 67 | } 68 | } 69 | 70 | std::unique_ptr BackendFactory::eventManager( Driver &driver, sig_atomic_t &sigStop ) 71 | { 72 | switch ( type_ ) { 73 | #ifdef USE_XEN 74 | case BACKEND_XEN: 75 | return std::make_unique( dynamic_cast( driver ), sigStop ); 76 | #endif 77 | #ifdef USE_KVMI 78 | case BACKEND_KVM: 79 | return std::make_unique( dynamic_cast( driver ), sigStop ); 80 | #endif 81 | default: 82 | throw std::runtime_error( "Xen and KVM are the only supported backends for now" ); 83 | } 84 | } 85 | 86 | } // namespace bdvmi 87 | -------------------------------------------------------------------------------- /src/domainwatcher.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-2019 Bitdefender SRL, All rights reserved. 2 | // 3 | // This library is free software; you can redistribute it and/or 4 | // modify it under the terms of the GNU Lesser General Public 5 | // License as published by the Free Software Foundation; either 6 | // version 3.0 of the License, or (at your option) any later version. 7 | // 8 | // This library is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 | // Lesser General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU Lesser General Public 14 | // License along with this library. 15 | 16 | #include "bdvmi/domainwatcher.h" 17 | #include "bdvmi/domainhandler.h" 18 | 19 | namespace bdvmi { 20 | 21 | DomainWatcher::DomainWatcher( sig_atomic_t &sigStop ) 22 | : sigStop_{ sigStop } 23 | { 24 | } 25 | 26 | void DomainWatcher::waitForDomains() 27 | { 28 | int ms = 100; 29 | 30 | for ( ;; ) { 31 | 32 | if ( sigStop_ || stop_ ) { 33 | if ( handler_ ) 34 | handler_->cleanup( suspendIntrospectorDomain_ ); 35 | return; 36 | } 37 | 38 | try { 39 | std::list domains; 40 | 41 | if ( waitForDomainsOrTimeout( domains, ms ) ) { 42 | 43 | for ( auto &&domain : domains ) { 44 | if ( handler_ ) { 45 | switch ( domain.state ) { 46 | case DomainInfo::STATE_NEW: 47 | handler_->handleDomainFound( domain.uuid, domain.name ); 48 | break; 49 | case DomainInfo::STATE_FINISHED: 50 | handler_->handleDomainFinished( domain.uuid ); 51 | break; 52 | } 53 | } 54 | } 55 | } 56 | 57 | ms = 100; 58 | 59 | } catch ( ... ) { // try again on exceptions, but later 60 | ms = 2000; // make it 2 seconds 61 | } 62 | } 63 | } 64 | 65 | } // namespace bdvmi 66 | -------------------------------------------------------------------------------- /src/driver.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-2021 Bitdefender SRL, All rights reserved. 2 | // 3 | // This library is free software; you can redistribute it and/or 4 | // modify it under the terms of the GNU Lesser General Public 5 | // License as published by the Free Software Foundation; either 6 | // version 3.0 of the License, or (at your option) any later version. 7 | // 8 | // This library is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 | // Lesser General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU Lesser General Public 14 | // License along with this library. 15 | 16 | #include "bdvmi/driver.h" 17 | #include "bdvmi/logger.h" 18 | #include 19 | 20 | namespace bdvmi { 21 | 22 | bool Driver::setPageProtection( unsigned long long guestAddress, bool read, bool write, bool execute, 23 | unsigned short view ) 24 | { 25 | /* 26 | * The Intel SDM says: 27 | * 28 | * AN EPT misconfiguration occurs if any of the following is identified while translating 29 | * a guest-physical address: 30 | * 31 | * * The value of bits 2:0 of an EPT paging-structure entry is either 010b (write-only) 32 | * or 110b (write/execute). 33 | * 34 | */ 35 | if ( write && !read ) { 36 | logger << ERROR << "Attempted to set GPA " << std::hex << std::showbase << guestAddress << " " 37 | << ( read ? "r" : "-" ) << ( write ? "w" : "-" ) << ( execute ? "x" : "-" ) << std::flush; 38 | return false; 39 | } 40 | 41 | uint64_t gfn = gpa_to_gfn( guestAddress ); 42 | uint8_t memaccess = ( read ? PAGE_READ : 0 ) | ( write ? PAGE_WRITE : 0 ) | ( execute ? PAGE_EXECUTE : 0 ); 43 | 44 | std::lock_guard guard( memAccessCacheMutex_ ); 45 | 46 | auto &&accessMap = memAccessCache_[view]; 47 | auto it = accessMap.find( gfn ); 48 | 49 | if ( it == accessMap.end() && read && write && execute ) 50 | return true; 51 | 52 | if ( it != accessMap.end() && it->second == memaccess ) 53 | return true; 54 | 55 | memAccessCache_[view][gfn] = memaccess; 56 | delayedMemAccessWrite_[view][gfn] = memaccess; 57 | 58 | return true; 59 | } 60 | 61 | bool Driver::setEPTPageConvertible( unsigned short view, unsigned long long guestAddress, bool convertible ) 62 | { 63 | uint64_t gfn = gpa_to_gfn( guestAddress ); 64 | 65 | std::lock_guard guard( convertibleCacheMutex_ ); 66 | 67 | delayedConvertibleWrite_[view][gfn] = convertible; 68 | 69 | // TODO: if we can't think of any input validation criteria, this function should become void 70 | return true; 71 | } 72 | 73 | bool Driver::getPageProtection( unsigned long long guestAddress, bool &read, bool &write, bool &execute, 74 | unsigned short view ) 75 | { 76 | uint64_t gfn = gpa_to_gfn( guestAddress ); 77 | uint8_t memaccess = 0; 78 | 79 | { 80 | std::lock_guard guard( memAccessCacheMutex_ ); 81 | 82 | auto &&accessMap = memAccessCache_[view]; 83 | auto it = accessMap.find( gfn ); 84 | 85 | if ( it != accessMap.end() ) { 86 | memaccess = it->second; 87 | 88 | read = !!( memaccess & PAGE_READ ); 89 | write = !!( memaccess & PAGE_WRITE ); 90 | execute = !!( memaccess & PAGE_EXECUTE ); 91 | 92 | return true; 93 | } 94 | } 95 | 96 | if ( !getPageProtectionImpl( guestAddress, read, write, execute, view ) ) 97 | return false; 98 | 99 | memaccess = ( read ? PAGE_READ : 0 ) | ( write ? PAGE_WRITE : 0 ) | ( execute ? PAGE_EXECUTE : 0 ); 100 | 101 | std::lock_guard guard( memAccessCacheMutex_ ); 102 | memAccessCache_[view][gfn] = memaccess; 103 | 104 | return true; 105 | } 106 | 107 | void Driver::flushPageProtections() 108 | { 109 | { 110 | std::lock_guard guard( memAccessCacheMutex_ ); 111 | 112 | for ( auto &&item : delayedMemAccessWrite_ ) { 113 | if ( item.second.empty() ) 114 | continue; 115 | 116 | setPageProtectionImpl( item.second, item.first ); 117 | 118 | // item.second.clear(); 119 | decltype( item.second ) notUsingMemory; 120 | std::swap( item.second, notUsingMemory ); 121 | } 122 | } 123 | 124 | std::lock_guard guard( convertibleCacheMutex_ ); 125 | 126 | for ( auto &&item : delayedConvertibleWrite_ ) { 127 | if ( item.second.empty() ) 128 | continue; 129 | 130 | setPageConvertibleImpl( item.second, item.first ); 131 | 132 | // item.second.clear(); 133 | decltype( item.second ) notUsingMemory; 134 | std::swap( item.second, notUsingMemory ); 135 | } 136 | } 137 | 138 | bool Driver::maxGPFN( unsigned long long &gfn ) 139 | { 140 | std::lock_guard guard( maxGPFNMutex_ ); 141 | 142 | // Integrators call this method before becoming multi-threaded relying on the fact 143 | // that the result gets cached and the algorithm below never gets to run again 144 | if ( maxGPFN_ ) { 145 | gfn = maxGPFN_; 146 | return true; 147 | } 148 | 149 | unsigned long long maxGpfn = 0; 150 | bool trustworthy = false; 151 | 152 | if ( !maxGPFNImpl( maxGpfn, trustworthy ) ) 153 | return false; 154 | 155 | if ( trustworthy ) { 156 | gfn = maxGPFN_ = maxGpfn; 157 | return true; 158 | } 159 | 160 | // 161 | // The code below resided in the introspection engine (introcore), but it was decided that 162 | // it should be pushed down to the glue layer. While in its initial location the following 163 | // explanation existed for it: 164 | // 165 | // although there is a GLUE_IFACE.QueryGuestInfo information class that returns this 166 | // information, #IG_QUERY_INFO_CLASS_MAX_GPFN, in practice is has been observed to not 167 | // always be accurate. Especially on XEN, for example, for guests with 1G of memory it 168 | // would usually report back 4G of memory available, or for guests with more memory, the 169 | // value would be slightly below the last page the guest could actually access. Since 170 | // having this information is vital for some subsystems (such as the \#VE one), we try to 171 | // figure it out ourselves. The algorithm is simple enough. Start with the page returned 172 | // by #IG_QUERY_INFO_CLASS_MAX_GPFN query, and try to see if there is any memory available 173 | // about it. If a physical page is mappable, we consider that it is available to the guest, 174 | // since introcore should not be able to access memory that is not available to the guest. 175 | // We do this search until a hole of 256 consecutive invalid pages is found. If during this 176 | // search a valid page is found above the one returned by the hypervisor, we consider it to 177 | // be the last physical page which the guest can access. If no page is found about the hint 178 | // value, we may be in the case in which the hypervisor reported more than the guest has 179 | // access to. While this is not as critical as the case in which the value is lower, it may 180 | // still lead to unnecessary memory consumption. In this case we go below the page returned 181 | // by the hypervisor until we find a page that we can map. The first page that can be 182 | // mapped is treated as the last physical page the guest can access. Since this value will 183 | // not change while introcore is running, it is cached inside the #gGuest variable and 184 | // subsequent calls to this function will return the cached value, in order to avoid long 185 | // pauses every time the query is done. 186 | // 187 | 188 | #define MAX_GPA_SEARCH_COUNT 256 189 | 190 | bool atLeastOneValid = false; 191 | 192 | // A frame number is returned, so shift it to make it a GPA again. 193 | unsigned long long lastOkGpa = maxGpfn << 12; 194 | unsigned long long testGpa = lastOkGpa + PAGE_SIZE; 195 | 196 | // Sometimes max GPFN does not actually tell us what is the last GPA that the guest can 197 | // access, so we try to find it by mapping some pages above it and see where we are 198 | // forced to stop. We've observed that for some VMs, GPFNs above max GPFN are sometimes 199 | // used by a guest (for PTs, for example). 200 | unsigned int invalidCount = 0; 201 | while ( invalidCount < MAX_GPA_SEARCH_COUNT ) { 202 | void *dummy = nullptr; 203 | 204 | if ( mapPhysMemToHost( testGpa, PAGE_SIZE, PHYSMAP_NO_CACHE, dummy ) == MAP_SUCCESS ) { 205 | lastOkGpa = testGpa; 206 | unmapPhysMem( dummy ); 207 | invalidCount = 0; 208 | atLeastOneValid = true; 209 | } else 210 | invalidCount++; 211 | 212 | testGpa += PAGE_SIZE; 213 | } 214 | 215 | if ( !atLeastOneValid ) { 216 | testGpa = lastOkGpa; 217 | 218 | while ( true ) { 219 | void *dummy = nullptr; 220 | 221 | if ( mapPhysMemToHost( testGpa, PAGE_SIZE, PHYSMAP_NO_CACHE, dummy ) == MAP_SUCCESS ) { 222 | lastOkGpa = testGpa; 223 | unmapPhysMem( dummy ); 224 | break; 225 | } 226 | 227 | testGpa -= PAGE_SIZE; 228 | 229 | if ( !testGpa ) { 230 | logger << ERROR << "No valid GPA was found" << std::flush; 231 | return false; 232 | } 233 | } 234 | } 235 | 236 | #undef MAX_GPA_SEARCH_COUNT 237 | 238 | maxGPFN_ = gfn = lastOkGpa >> 12; 239 | 240 | logger << DEBUG << "MaxGPFN: " << std::hex << std::showbase << maxGPFN_ << std::flush; 241 | 242 | return true; 243 | } 244 | 245 | } // namespace bdvmi 246 | -------------------------------------------------------------------------------- /src/dynamiclibfactory.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2019 Bitdefender SRL, All rights reserved. 2 | // 3 | // This library is free software; you can redistribute it and/or 4 | // modify it under the terms of the GNU Lesser General Public 5 | // License as published by the Free Software Foundation; either 6 | // version 3.0 of the License, or (at your option) any later version. 7 | // 8 | // This library is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 | // Lesser General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU Lesser General Public 14 | // License along with this library. 15 | 16 | #include "dynamiclibfactory.h" 17 | 18 | namespace bdvmi { 19 | 20 | DynamicLibFactory::DynamicLibFactory( const std::string &libPath ) 21 | { 22 | libHandle_ = dlopen( libPath.c_str(), RTLD_NOW | RTLD_GLOBAL ); 23 | 24 | if ( !libHandle_ ) 25 | throw std::runtime_error( "Failed to open the \"" + libPath + "\" library: " + dlerror() ); 26 | } 27 | 28 | DynamicLibFactory::~DynamicLibFactory() 29 | { 30 | dlclose( libHandle_ ); 31 | } 32 | 33 | bool DynamicLibFactory::contains( const std::string &name ) const 34 | { 35 | dlerror(); 36 | ::dlsym( libHandle_, name.c_str() ); 37 | 38 | return ( dlerror() == nullptr ); 39 | } 40 | 41 | } // namespace bdvmi 42 | -------------------------------------------------------------------------------- /src/dynamiclibfactory.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-2019 Bitdefender SRL, All rights reserved. 2 | // 3 | // This library is free software; you can redistribute it and/or 4 | // modify it under the terms of the GNU Lesser General Public 5 | // License as published by the Free Software Foundation; either 6 | // version 3.0 of the License, or (at your option) any later version. 7 | // 8 | // This library is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 | // Lesser General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU Lesser General Public 14 | // License along with this library. 15 | 16 | #ifndef __BDVMIDYNAMICLIBFACTORY_H_INCLUDED__ 17 | #define __BDVMIDYNAMICLIBFACTORY_H_INCLUDED__ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | namespace bdvmi { 25 | 26 | class DynamicLibFactory { 27 | public: 28 | explicit DynamicLibFactory( const std::string &libPath ); 29 | ~DynamicLibFactory(); 30 | 31 | DynamicLibFactory( const DynamicLibFactory & ) = delete; 32 | DynamicLibFactory &operator=( const DynamicLibFactory & ) = delete; 33 | 34 | template T *lookup( bool required = true ) const 35 | { 36 | char *error; 37 | 38 | dlerror(); 39 | T *func = reinterpret_cast(::dlsym( libHandle_, name ) ); 40 | error = dlerror(); 41 | 42 | if ( required && error ) 43 | throw std::runtime_error( std::string( "Failed to get the \"" ) + name + "\" function" ); 44 | return func; 45 | } 46 | 47 | bool contains( const std::string &name ) const; 48 | 49 | private: 50 | void *libHandle_; 51 | }; 52 | 53 | } // namespace bdvmi 54 | 55 | #endif // __BDVMIDYNAMICLIBFACTORY_H_INCLUDED__ 56 | -------------------------------------------------------------------------------- /src/eventmanager.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-2019 Bitdefender SRL, All rights reserved. 2 | // 3 | // This library is free software; you can redistribute it and/or 4 | // modify it under the terms of the GNU Lesser General Public 5 | // License as published by the Free Software Foundation; either 6 | // version 3.0 of the License, or (at your option) any later version. 7 | // 8 | // This library is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 | // Lesser General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU Lesser General Public 14 | // License along with this library. 15 | 16 | #include "bdvmi/eventmanager.h" 17 | 18 | namespace bdvmi { 19 | 20 | EventManager::EventManager( sig_atomic_t &sigStop ) 21 | : sigStop_{ sigStop } 22 | { 23 | } 24 | 25 | bool EventManager::enableMsrEvents( unsigned int msr, bool &oldValue ) 26 | { 27 | oldValue = ( enabledMsrs_.find( msr ) != enabledMsrs_.end() ); 28 | 29 | if ( oldValue ) 30 | return true; // Already enabled 31 | 32 | if ( !enableMsrEventsImpl( msr ) ) 33 | return false; 34 | 35 | enabledMsrs_.insert( msr ); 36 | 37 | return true; 38 | } 39 | 40 | bool EventManager::disableMsrEvents( unsigned int msr, bool &oldValue ) 41 | { 42 | oldValue = ( enabledMsrs_.find( msr ) != enabledMsrs_.end() ); 43 | 44 | if ( !oldValue ) 45 | return true; // Already disabled 46 | 47 | if ( !disableMsrEventsImpl( msr ) ) 48 | return false; 49 | 50 | enabledMsrs_.erase( msr ); 51 | 52 | return true; 53 | } 54 | 55 | bool EventManager::enableCrEvents( unsigned int cr ) 56 | { 57 | if ( enabledCrs_.find( cr ) != enabledCrs_.end() ) 58 | return true; // Already enabled 59 | 60 | if ( !enableCrEventsImpl( cr ) ) 61 | return false; 62 | 63 | enabledCrs_.insert( cr ); 64 | 65 | return true; 66 | } 67 | 68 | bool EventManager::disableCrEvents( unsigned int cr ) 69 | { 70 | if ( enabledCrs_.find( cr ) == enabledCrs_.end() ) 71 | return true; // Already disabled 72 | 73 | if ( !disableCrEventsImpl( cr ) ) 74 | return false; 75 | 76 | enabledCrs_.erase( cr ); 77 | 78 | return true; 79 | } 80 | 81 | bool EventManager::enableXSETBVEvents() 82 | { 83 | if ( xsetbvEnabled_ ) 84 | return true; 85 | 86 | xsetbvEnabled_ = enableXSETBVEventsImpl(); 87 | 88 | return xsetbvEnabled_; 89 | } 90 | 91 | bool EventManager::disableXSETBVEvents() 92 | { 93 | if ( !xsetbvEnabled_ ) 94 | return true; 95 | 96 | xsetbvEnabled_ = !disableXSETBVEventsImpl(); 97 | 98 | return !xsetbvEnabled_; 99 | } 100 | 101 | bool EventManager::enableBreakpointEvents() 102 | { 103 | if ( breakpointEnabled_ ) 104 | return true; 105 | 106 | breakpointEnabled_ = enableBreakpointEventsImpl(); 107 | 108 | return breakpointEnabled_; 109 | } 110 | 111 | bool EventManager::disableBreakpointEvents() 112 | { 113 | if ( !breakpointEnabled_ ) 114 | return true; 115 | 116 | breakpointEnabled_ = !disableBreakpointEventsImpl(); 117 | 118 | return !breakpointEnabled_; 119 | } 120 | 121 | bool EventManager::enableVMCALLEvents() 122 | { 123 | if ( vmcallEnabled_ ) 124 | return true; 125 | 126 | vmcallEnabled_ = enableVMCALLEventsImpl(); 127 | 128 | return vmcallEnabled_; 129 | } 130 | 131 | bool EventManager::disableVMCALLEvents() 132 | { 133 | if ( !vmcallEnabled_ ) 134 | return true; 135 | 136 | vmcallEnabled_ = !disableVMCALLEventsImpl(); 137 | 138 | return !vmcallEnabled_; 139 | } 140 | 141 | bool EventManager::enableDescriptorEvents() 142 | { 143 | if ( descriptorEnabled_ ) 144 | return true; 145 | 146 | descriptorEnabled_ = enableDescriptorEventsImpl(); 147 | 148 | return descriptorEnabled_; 149 | } 150 | 151 | bool EventManager::disableDescriptorEvents() 152 | { 153 | if ( !descriptorEnabled_ ) 154 | return true; 155 | 156 | descriptorEnabled_ = !disableDescriptorEventsImpl(); 157 | 158 | return !descriptorEnabled_; 159 | } 160 | 161 | } // namespace bdvmi 162 | -------------------------------------------------------------------------------- /src/kvmdomainwatcher.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-2019 Bitdefender SRL, All rights reserved. 2 | // 3 | // This library is free software; you can redistribute it and/or 4 | // modify it under the terms of the GNU Lesser General Public 5 | // License as published by the Free Software Foundation; either 6 | // version 3.0 of the License, or (at your option) any later version. 7 | // 8 | // This library is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 | // Lesser General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU Lesser General Public 14 | // License along with this library. 15 | 16 | #include "kvmdomainwatcher.h" 17 | #include "kvmdriver.h" 18 | #include "utils.h" 19 | #include "bdvmi/logger.h" 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | namespace { 29 | 30 | constexpr char UUID_PROVIDER[] = "/sys/devices/virtual/dmi/id/product_uuid"; 31 | 32 | bool getSvaUuid( std::string &uuid ) 33 | { 34 | std::ifstream in( UUID_PROVIDER ); 35 | 36 | if ( in ) { 37 | in >> uuid; 38 | 39 | std::transform( std::begin( uuid ), std::end( uuid ), std::begin( uuid ), ::tolower ); 40 | } 41 | 42 | return !!in; 43 | } 44 | 45 | } // namespace 46 | 47 | namespace bdvmi { 48 | 49 | KvmDomainWatcher::name2dom_t KvmDomainWatcher::knownDomains_; 50 | 51 | std::string UuidToString( const unsigned char ( *uuid )[16] ) 52 | { 53 | char str[37] = {}; 54 | 55 | uuid_unparse( *uuid, str ); 56 | 57 | return str; 58 | } 59 | 60 | void KvmDomainWatcher::LogCallback( kvmi_log_level level, const char *s, void * /* ctx */ ) 61 | { 62 | // NOTE: (for alazar) - ctx is now unused, unless you want to reserve it for 63 | // something in the future it should probably be removed altogether now. 64 | 65 | switch ( level ) { 66 | case KVMI_LOG_LEVEL_DEBUG: 67 | logger << DEBUG << "KVMI: " << s << std::flush; 68 | break; 69 | case KVMI_LOG_LEVEL_INFO: 70 | logger << INFO << "KVMI: " << s << std::flush; 71 | break; 72 | case KVMI_LOG_LEVEL_WARNING: 73 | logger << WARNING << "KVMI: " << s << std::flush; 74 | break; 75 | case KVMI_LOG_LEVEL_ERROR: 76 | logger << ERROR << "KVMI: " << s << std::flush; 77 | break; 78 | default: 79 | logger << ERROR << "KVMI: UNKNOWN LEVEL: " << s << std::flush; 80 | break; 81 | } 82 | } 83 | 84 | bool KvmDomainWatcher::loadLibkvmiOnce() 85 | { 86 | if ( kvmi_ ) 87 | return true; 88 | 89 | kvmi_ = kvmi_init_vsock( 1234, newConnection, reinterpret_cast( newHandshake ), this ); 90 | 91 | return !!kvmi_; 92 | } 93 | 94 | KvmDomainWatcher::KvmDomainWatcher( sig_atomic_t &sigStop ) 95 | : DomainWatcher{ sigStop } 96 | { 97 | if ( !getSvaUuid( ownUuid_ ) ) 98 | logger << ERROR << "Can't get our own UUID!" << std::flush; 99 | 100 | kvmi_set_log_cb( LogCallback, nullptr ); 101 | 102 | if ( !loadLibkvmiOnce() ) { 103 | logger << WARNING << "kvmi_init failed: " << strerror( errno ) << std::flush; 104 | logger << INFO << "Waiting for libvirt credentials to enable vsock support" << std::flush; 105 | } 106 | } 107 | 108 | bool KvmDomainWatcher::accessGranted() 109 | { 110 | return loadLibkvmiOnce(); 111 | } 112 | 113 | KvmDomainWatcher::~KvmDomainWatcher() 114 | { 115 | kvmi_uninit( kvmi_ ); 116 | 117 | kvmi_set_log_cb( nullptr, nullptr ); 118 | } 119 | 120 | // This is a callback invoked by libkvmi 121 | int KvmDomainWatcher::newConnection( void *dom, unsigned char ( *uuid )[16], void *ctx ) 122 | { 123 | KvmDomainWatcher *kdw = static_cast( ctx ); 124 | const std::string clientUuid = UuidToString( uuid ); 125 | 126 | if ( !kdw->queueConnection( clientUuid, dom ) ) 127 | return -1; 128 | 129 | kdw->signalNewConnection(); 130 | 131 | return 0; 132 | } 133 | 134 | // This is a callback invoked by libkvmi 135 | int KvmDomainWatcher::newHandshake( const void *_qemu, void *_intro, void *ctx ) 136 | { 137 | KvmDomainWatcher *kdw = static_cast( ctx ); 138 | 139 | const kvmi_qemu2introspector *qemu = static_cast( _qemu ); 140 | const std::string uuid = UuidToString( &qemu->uuid ); 141 | 142 | if ( kdw->sigStop_ ) { 143 | logger << WARNING << "[" << uuid << "] New handshake refused" << std::flush; 144 | return -1; 145 | } 146 | 147 | std::string cookie; 148 | 149 | kdw->getAuthCookie( cookie ); 150 | logger << DEBUG << "[" << uuid << "] Handshake authCookie: '" << cookie << "'" << std::flush; 151 | 152 | kvmi_introspector2qemu *intro = static_cast( _intro ); 153 | 154 | SHA_CTX sha; 155 | SHA1_Init( &sha ); 156 | SHA1_Update( &sha, cookie.c_str(), cookie.size() ); 157 | SHA1_Final( intro->cookie_hash, &sha ); 158 | 159 | return 0; 160 | } 161 | 162 | void KvmDomainWatcher::signalNewConnection() 163 | { 164 | ringQueue_.notify_one(); 165 | } 166 | 167 | bool KvmDomainWatcher::queueConnection( const std::string &name, void *domCtx ) 168 | { 169 | std::unique_lock lock( mutexQueue_ ); 170 | 171 | auto found = knownDomains_.find( name ); 172 | 173 | KvmDomainWatcher::KvmDomain *dom; 174 | 175 | if ( found != knownDomains_.end() ) { 176 | dom = &found->second; 177 | if ( !dom->resetSafely() ) { 178 | logger << WARNING << "[" << name 179 | << "] Drop the connection. The child didn't finish the old one." << std::flush; 180 | lock.unlock(); 181 | // Allow diedHandler() to park() the domain 182 | sleep( 1 ); // :D 183 | return false; 184 | } 185 | } else { 186 | auto res = knownDomains_.emplace( name, KvmDomain() ); 187 | dom = &res.first->second; 188 | } 189 | 190 | dom->connect( domCtx ); 191 | 192 | return true; 193 | } 194 | 195 | void KvmDomainWatcher::handleDomainEvent( const struct kvmi_dom_event *ev, const std::string &uuid ) const 196 | { 197 | uint32_t eventID = ev->event.common.event; 198 | 199 | if ( eventID != KVMI_EVENT_UNHOOK ) 200 | logger << ERROR << "[" << uuid << "] We've got an unexpected event " << eventID << std::flush; 201 | } 202 | 203 | // 204 | // We have 4 parties using/watching the socket and only a read() would detect 205 | // if the other site closed the socket (both users from the other site 206 | // closed the fd) or one of 4 called shutdown(socket,RW). 207 | // 208 | // QEMU ------------------> hanshake <------------- bdmid/parent (KvmDomainWatcher) 209 | // \ | 210 | // v v 211 | // Kernel (shutdown) ----> introspection <-------- bdmid/child 212 | // 213 | // bdmid/parent holds the socket/connection and announce the new domain on every 214 | // reconnection (the guest might have been restarted). Following the announcement, 215 | // the child will be started and it will read from socket. Once the child dies 216 | // (with the introspection disabled or crashed), the parent will read the socket 217 | // and get either: 218 | // a) 0 bytes - the socket has been closed by kernel/QEMU 219 | // (the child doesn't call shutdown()) 220 | // b) unexpected event => the parent will shutdown the socket 221 | // in order to catch this case before we pin release/1.0 222 | // (the child must ensure that the kernel won't send events 223 | // once the introspection is disabled) 224 | // The child could: 225 | // a) crash while not hooked, hooking, hooked or unhooking 226 | // b) unhook and exit nicely (guest not supported, policy, signal 227 | // or Introcore detected the shutdown (future development)) 228 | // 229 | // KvmDomainWatcher behaves like XenDomainWatcher: 230 | // a) every connection/reconnection means guest PowerOn/Resume or "bd start" 231 | // KvmDomain::FRESH/RESURRECTED, DomainInfo::STATE_NEW 232 | // b) every disconnect means guest PowerOff/Reboot/Suspend 233 | // following KvmDomain::PARKED (child died) 234 | // KvmDomain::FRESH, DomainInfo::STATE_FINISHED 235 | // b1) bugs in child/unhook 236 | // KvmDomain::FRESH, DomainInfo::STATE_FINISHED 237 | // the guest should be restarted 238 | // 239 | // TODO: 240 | // a) KvmDomainWatcher should watch PowerOn/Off events through libvirt 241 | // b) KvmDriver should start the accepting thread (kvmi_init()) 242 | // (currenly, any connect()/handshake blocks the hooking of other guests). 243 | // c) Use the connection time as "Guest start time" 244 | // and drop kvmi_qemu2introspector.start_time 245 | // 246 | bool KvmDomainWatcher::waitForDomainsOrTimeout( std::list &domains, int ms ) 247 | { 248 | // First function used by the callers is this one or accessGranted(). 249 | // The exception below has been moved here from constructor 250 | // in order to allow the callers to wait/loop until accessGranted() returns true. 251 | if ( !kvmi_ ) 252 | throw std::runtime_error( "kvmi_init() has failed" ); 253 | 254 | domains.clear(); 255 | 256 | std::unique_lock lock( mutexQueue_ ); 257 | 258 | for ( auto &&known : knownDomains_ ) { 259 | const std::string &uuid = known.first; 260 | KvmDomain & dom = known.second; 261 | 262 | if ( ( dom.isNew() || dom.isResurrected() ) && uuid == ownUuid_ ) { 263 | dom.park(); 264 | } else if ( dom.isNew() ) { 265 | domains.emplace_back( uuid, DomainInfo::STATE_NEW, dom.name() ); 266 | 267 | dom.park(); 268 | } else if ( dom.isResurrected() ) { 269 | domains.emplace_back( uuid, DomainInfo::STATE_FINISHED ); 270 | domains.emplace_back( uuid, DomainInfo::STATE_NEW, dom.name() ); 271 | 272 | dom.park(); 273 | } else if ( dom.isParked() ) { 274 | CUniquePtr evPtr; 275 | kvmi_dom_event * ev = nullptr; 276 | bool gotEvent = dom.getEvent( &ev ); 277 | int err = errno; 278 | 279 | evPtr.reset( ev ); 280 | 281 | if ( gotEvent && uuid == ownUuid_ ) { 282 | logger << WARNING << "Detected pause, suspend, shutdown or migrate." << std::flush; 283 | handleDomainEvent( ev, uuid ); 284 | suspendIntrospectorDomain_ = true; 285 | stop(); 286 | return false; 287 | } else if ( gotEvent ) { 288 | handleDomainEvent( ev, uuid ); 289 | 290 | domains.emplace_back( uuid, DomainInfo::STATE_FINISHED ); 291 | 292 | dom.forgetWithShutdown(); 293 | } else if ( err && uuid == ownUuid_ ) { 294 | logger << WARNING << "[" << uuid << "] Mother ship connection lost: (" << err << ") " 295 | << strerror( err ) << std::flush; 296 | 297 | dom.forgetWithShutdown(); 298 | } else if ( err ) { 299 | logger << WARNING << "[" << uuid << "] Connection closed (" << err << ") " 300 | << strerror( err ) << std::flush; 301 | domains.emplace_back( uuid, DomainInfo::STATE_FINISHED ); 302 | 303 | dom.forgetWithShutdown(); 304 | } 305 | } 306 | } 307 | 308 | if ( !domains.empty() ) 309 | return true; 310 | 311 | std::cv_status rc = ringQueue_.wait_for( lock, std::chrono::milliseconds( ms ) ); 312 | 313 | return rc != std::cv_status::timeout; 314 | } 315 | 316 | void KvmDomainWatcher::forkingHandler( const std::string &uuid ) 317 | { 318 | std::unique_lock lock( mutexQueue_ ); 319 | 320 | auto found = knownDomains_.find( uuid ); 321 | 322 | if ( found == knownDomains_.end() ) 323 | logger << WARNING << "[" << uuid << "] Unknown domain." << std::flush; 324 | else 325 | found->second.fork(); 326 | } 327 | 328 | void KvmDomainWatcher::forkedHandler( const std::string &name, bool parent ) 329 | { 330 | if ( !parent ) { 331 | auto dom = knownDomains_.begin(); 332 | 333 | // 334 | // This is the child bdmid. Remove from the list of known domains 335 | // all but that which represents us. This frees up some memory while 336 | // also making sure we have no reference to the sockets corresponding 337 | // to other domains 338 | // 339 | while ( dom != knownDomains_.end() ) { 340 | if ( dom->first != name ) { 341 | dom->second.forget(); 342 | knownDomains_.erase( dom ); 343 | dom = knownDomains_.begin(); 344 | } else 345 | ++dom; 346 | } 347 | 348 | kvmi_close( kvmi_ ); 349 | 350 | return; 351 | } 352 | } 353 | 354 | // This is invoked by child::KvmDriver (this is why knowDomains_ is static) 355 | void *KvmDomainWatcher::domainContext( const std::string &name ) 356 | { 357 | const auto dom = knownDomains_.find( name ); 358 | 359 | if ( dom == knownDomains_.end() ) 360 | return nullptr; 361 | 362 | return dom->second.context(); 363 | } 364 | 365 | void KvmDomainWatcher::setAuthCookie( const std::string &authCookie ) 366 | { 367 | std::lock_guard guard( authCookieMutex_ ); 368 | 369 | authCookie_ = authCookie; 370 | } 371 | 372 | void KvmDomainWatcher::diedHandler( const std::string &uuid ) 373 | { 374 | std::lock_guard lock( mutexQueue_ ); 375 | 376 | auto dom = knownDomains_.find( uuid ); 377 | 378 | if ( dom != knownDomains_.end() ) { 379 | dom->second.park(); 380 | logger << DEBUG << "[" << uuid << "] Parked" << std::flush; 381 | } 382 | } 383 | 384 | } // namespace bdvmi 385 | -------------------------------------------------------------------------------- /src/kvmdomainwatcher.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-2019 Bitdefender SRL, All rights reserved. 2 | // 3 | // This library is free software; you can redistribute it and/or 4 | // modify it under the terms of the GNU Lesser General Public 5 | // License as published by the Free Software Foundation; either 6 | // version 3.0 of the License, or (at your option) any later version. 7 | // 8 | // This library is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 | // Lesser General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU Lesser General Public 14 | // License along with this library. 15 | 16 | #ifndef __BDVMIKVMDOMAINWATCHER_H_INCLUDED__ 17 | #define __BDVMIKVMDOMAINWATCHER_H_INCLUDED__ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include "bdvmi/domainwatcher.h" 25 | 26 | namespace bdvmi { 27 | 28 | class KvmDomainWatcher : public DomainWatcher { 29 | class KvmDomain { 30 | private: 31 | void *ctx_{ nullptr }; 32 | 33 | enum { NEW, 34 | FORKED, 35 | PARKED, 36 | RESURRECTED, 37 | } state_ = { NEW }; 38 | 39 | void close( bool shutdown ) 40 | { 41 | if ( ctx_ ) { 42 | kvmi_domain_close( ctx_, shutdown ); 43 | ctx_ = nullptr; 44 | state_ = NEW; 45 | } 46 | } 47 | 48 | public: 49 | void forgetWithShutdown() 50 | { 51 | close( true ); 52 | } 53 | void forget() 54 | { 55 | close( false ); 56 | } 57 | ~KvmDomain() 58 | { 59 | // Called from parent (state_ != FORKED) and child ( state_ == FORKED ) 60 | if ( state_ != FORKED ) 61 | forgetWithShutdown(); 62 | } 63 | std::string name() const 64 | { 65 | // libkvmi puts zero terminated string 66 | char buf[64] = {}; 67 | 68 | kvmi_domain_name( ctx_, buf, sizeof( buf ) ); 69 | return buf; 70 | } 71 | void *context() const 72 | { 73 | return ctx_; 74 | } 75 | void connect( void *ctx ) 76 | { 77 | // guest time 78 | kvmi_control_vm_events( ctx, KVMI_EVENT_UNHOOK, true ); 79 | ctx_ = ctx; 80 | } 81 | void fork() 82 | { 83 | state_ = FORKED; 84 | } 85 | void park() 86 | { 87 | state_ = PARKED; 88 | } 89 | bool resetSafely() 90 | { 91 | if ( !ctx_ ) 92 | return true; 93 | 94 | if ( state_ == FORKED ) 95 | return false; 96 | 97 | forgetWithShutdown(); 98 | state_ = RESURRECTED; 99 | return true; 100 | } 101 | bool isNew() const 102 | { 103 | return ctx_ && state_ == NEW; 104 | } 105 | bool isResurrected() const 106 | { 107 | return ctx_ && state_ == RESURRECTED; 108 | } 109 | bool isParked() const 110 | { 111 | return ctx_ && state_ == PARKED; 112 | } 113 | bool getEvent( kvmi_dom_event **event ) 114 | { 115 | if ( kvmi_wait_event( ctx_, KVMI_NOWAIT ) ) { 116 | if ( errno == ETIMEDOUT ) 117 | errno = 0; 118 | return false; 119 | } 120 | 121 | return kvmi_pop_event( ctx_, event ) == 0; 122 | } 123 | }; 124 | 125 | public: 126 | explicit KvmDomainWatcher( sig_atomic_t &sigStop ); 127 | 128 | virtual ~KvmDomainWatcher(); 129 | 130 | public: 131 | bool accessGranted() override; 132 | 133 | static void *domainContext( const std::string &name ); 134 | 135 | void setAuthCookie( const std::string &authCookie ) override; 136 | 137 | // Merge with Xen 138 | bool ownUuid( std::string &uuid ) const override 139 | { 140 | uuid = ownUuid_; 141 | return true; 142 | } 143 | 144 | private: 145 | bool waitForDomainsOrTimeout( std::list &domains, int ms ) override; 146 | 147 | void forkingHandler( const std::string &uuid ) override; 148 | 149 | void forkedHandler( const std::string &uuid, bool parent = true ) override; 150 | 151 | void diedHandler( const std::string &uuid ) override; 152 | 153 | KvmDomainWatcher( const KvmDomainWatcher & ); 154 | 155 | KvmDomainWatcher &operator=( const KvmDomainWatcher & ); 156 | 157 | bool queueConnection( const std::string &name, void *dom ); 158 | 159 | void signalNewConnection(); 160 | 161 | void handleDomainEvent( const struct kvmi_dom_event *ev, const std::string &uuid ) const; 162 | 163 | void getAuthCookie( std::string &authCookie ) const 164 | { 165 | std::lock_guard guard( authCookieMutex_ ); 166 | 167 | authCookie = authCookie_; 168 | } 169 | 170 | bool loadLibkvmiOnce(); 171 | 172 | static void LogCallback( kvmi_log_level level, const char *s, void *ctx ); 173 | 174 | protected: 175 | static int newConnection( void *dom, unsigned char ( *uuid )[16], void *ctx ); 176 | 177 | static int newHandshake( const void *qemu, void *intro, void *ctx ); 178 | 179 | private: 180 | using name2dom_t = std::unordered_map; 181 | 182 | void *kvmi_{ nullptr }; 183 | 184 | std::mutex mutexQueue_; 185 | std::condition_variable ringQueue_; 186 | 187 | static name2dom_t knownDomains_; 188 | 189 | mutable std::mutex authCookieMutex_; 190 | std::string authCookie_; 191 | 192 | std::string ownUuid_; 193 | }; 194 | } // namespace bdvmi 195 | 196 | #endif // __BDVMIKVMDOMAINWATCHER_H_INCLUDED__ 197 | -------------------------------------------------------------------------------- /src/kvmdriver.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-2021 Bitdefender SRL, All rights reserved. 2 | // 3 | // This library is free software; you can redistribute it and/or 4 | // modify it under the terms of the GNU Lesser General Public 5 | // License as published by the Free Software Foundation; either 6 | // version 3.0 of the License, or (at your option) any later version. 7 | // 8 | // This library is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 | // Lesser General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU Lesser General Public 14 | // License along with this library. 15 | 16 | #ifndef __BDVMIKVMDRIVER_H_INCLUDED__ 17 | #define __BDVMIKVMDRIVER_H_INCLUDED__ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include "bdvmi/driver.h" 30 | #include "bdvmi/pagecache.h" 31 | 32 | namespace bdvmi { 33 | 34 | #define KVMI_SHUTDOWN_GUEST_FLAG ( 1 << 0 ) 35 | #define KVMI_REP_OPTIMIZATIONS_FLAG ( 1 << 1 ) 36 | #define KVMI_MAX_EPT_VIEWS 10 37 | 38 | class KvmDriver : public Driver { 39 | using EventBitset = std::bitset; 40 | 41 | public: 42 | struct RegsCache { 43 | Registers registers_; 44 | int vcpu_{ -1 }; 45 | bool valid_{ false }; 46 | bool dirty_{ false }; 47 | uint16_t view_{ 0 }; 48 | std::mutex mutex_; 49 | bool valid( unsigned short vcpu ) 50 | { 51 | return valid_ && vcpu_ == static_cast( vcpu ); 52 | } 53 | }; 54 | 55 | struct PendingVcpusCache { 56 | std::set pendingVcpus_; 57 | std::mutex mutex_; 58 | }; 59 | 60 | struct EventReply { 61 | explicit EventReply( const struct kvmi_dom_event *msg ) 62 | { 63 | memset( &reply_, 0, sizeof( reply_ ) ); 64 | reply_.vcpu_.vcpu = msg->event.common.vcpu; 65 | reply_.common_.event = msg->event.common.event; 66 | reply_.common_.action = KVMI_EVENT_ACTION_CONTINUE; 67 | seq_ = msg->seq; 68 | size_ = sizeof( reply_.vcpu_ ) + sizeof( reply_.common_ ); 69 | switch ( reply_.common_.event ) { 70 | case KVMI_EVENT_CR: 71 | size_ += sizeof( reply_.event_.cr ); 72 | break; 73 | case KVMI_EVENT_MSR: 74 | size_ += sizeof( reply_.event_.msr ); 75 | break; 76 | case KVMI_EVENT_PF: 77 | size_ += sizeof( reply_.event_.pf ); 78 | break; 79 | } 80 | } 81 | struct { 82 | struct kvmi_vcpu_hdr vcpu_; 83 | struct kvmi_event_reply common_; 84 | union { 85 | struct kvmi_event_cr_reply cr; 86 | struct kvmi_event_msr_reply msr; 87 | struct kvmi_event_pf_reply pf; 88 | } event_; 89 | } reply_; 90 | unsigned int seq_; 91 | unsigned int size_; 92 | }; 93 | 94 | KvmDriver( const std::string &domain, bool altp2m ); 95 | 96 | virtual ~KvmDriver(); 97 | 98 | private: 99 | class BatchMessages { 100 | public: 101 | BatchMessages( void *dom, KvmDriver *driver ); 102 | ~BatchMessages(); 103 | bool commit(); 104 | bool addRegisters() const; 105 | bool addEventReply( EventReply &reply ) const; 106 | bool addPageAccess( unsigned long long int &gpa, unsigned char &access, unsigned short count, 107 | unsigned short view ) const; 108 | bool addPauseVcpu( unsigned short vcpu ) const; 109 | 110 | private: 111 | void * grp_{ nullptr }; 112 | KvmDriver *driver_; 113 | }; 114 | 115 | friend class BatchMessages; 116 | 117 | public: 118 | bool cpuCount( unsigned int &count ) const override; 119 | 120 | bool tscSpeed( unsigned long long &speed ) const override; 121 | 122 | bool mtrrType( unsigned long long guestAddress, uint8_t &type ) const override; 123 | 124 | bool registers( unsigned short vcpu, Registers ®s ) const override; 125 | 126 | bool setRegisters( unsigned short vcpu, const Registers ®s, bool setEip, bool delay ) override; 127 | 128 | MapReturnCode mapPhysMemToHost( unsigned long long address, size_t length, uint32_t flags, 129 | void *&pointer ) override; 130 | 131 | bool unmapPhysMem( void *hostPtr ) override; 132 | 133 | bool injectTrap( unsigned short vcpu, uint8_t trapNumber, uint32_t errorCode, uint64_t cr2 ) override; 134 | 135 | bool setRepOptimizations( bool enable ) override; 136 | 137 | bool getRepOptimizations() const; 138 | 139 | bool shutdown() override; 140 | 141 | bool testShutdown(); 142 | 143 | bool pause() override; 144 | 145 | bool unpause() override; 146 | 147 | bool pauseAllVcpus(); 148 | 149 | bool kickAllVcpus(); 150 | 151 | size_t setPageCacheLimit( size_t limit ) override; 152 | 153 | unsigned short eptpIndex( unsigned short vcpu ) const override; 154 | 155 | bool getEPTPageConvertible( unsigned short index, unsigned long long address, bool &convertible ) override; 156 | 157 | bool initialViewSetup( unsigned short vcpu ); 158 | 159 | bool controlEPTview( unsigned short vcpu, unsigned short view, bool visible); 160 | 161 | bool getNextAvailableView( unsigned short &index ); 162 | 163 | bool createEPT( unsigned short &index ) override; 164 | 165 | bool destroyEPT( unsigned short index ) override; 166 | 167 | bool vcpuSwitchView( unsigned short vcpu, unsigned short index ); 168 | 169 | bool switchEPT( unsigned short index ) override; 170 | 171 | bool setVEInfoPage( unsigned short vcpu, unsigned long long gpa ) override; 172 | 173 | bool disableVE( unsigned short vcpu ) override; 174 | 175 | bool getXSAVESize( unsigned short vcpu, size_t &size ) override; 176 | 177 | bool getXSAVEArea( unsigned short vcpu, void *buffer, size_t bufSize ) override; 178 | 179 | bool update() override; 180 | 181 | std::string uuid() const override; 182 | 183 | unsigned int id() const override; 184 | 185 | void enableCache( unsigned short /* vcpu */ ) override 186 | { 187 | // useless 188 | } 189 | 190 | void disableCache() override; 191 | 192 | bool registerVMEvent( unsigned int id, bool enable ) const; 193 | 194 | bool registerEvent( unsigned short vcpu, unsigned int id, bool enable ) const; 195 | 196 | bool registerMSREvents( unsigned short vcpu, unsigned int msr, bool enable ) const; 197 | 198 | bool registerCREvents( unsigned short vcpu, unsigned int cr, bool enable ) const; 199 | 200 | bool flushCtrlEvents( unsigned short vcpu, const std::set &enabledCrs, 201 | const std::set &enabledMsrs ); 202 | 203 | bool flushEvents( unsigned short vcpu ); 204 | 205 | bool flushCREvents( unsigned short vcpu, const std::set &enabledCrs ); 206 | 207 | bool flushMSREvents( unsigned short vcpu, const std::set &enabledMsrs ); 208 | 209 | uint32_t startTime() override; 210 | 211 | bool isMsrCached( uint64_t msr ) const override; 212 | 213 | // Does this driver support altp2m #VE? 214 | bool veSupported() const override 215 | { 216 | return veSupported_; 217 | } 218 | 219 | // Does this driver support altp2m VMFUNC? 220 | bool vmfuncSupported() const override 221 | { 222 | return eptpSupported_; 223 | } 224 | 225 | // Does this driver support Intel SPP? 226 | bool sppSupported() const override 227 | { 228 | return false; 229 | } 230 | 231 | // Does this driver support DTR events? 232 | bool dtrEventsSupported() const override 233 | { 234 | return true; 235 | } 236 | 237 | void skipInstruction( const short instructionSize ); 238 | 239 | void loadRegisters( Registers ®s, const struct kvmi_event &event ) const; 240 | 241 | unsigned long long getNextRip() const; 242 | 243 | bool getEventMsg( struct kvmi_dom_event *&event, int ms, bool &abort ); 244 | 245 | void pauseEventReceived(); 246 | 247 | size_t pendingPauseEvents() const 248 | { 249 | return pendingPauseEvents_; 250 | } 251 | 252 | void waitForUnpause() 253 | { 254 | std::lock_guard lock( eventProcessingMutex_ ); 255 | } 256 | 257 | bool isConnected(); 258 | 259 | void suspending( bool value ); 260 | 261 | bool suspending() const; 262 | 263 | void beginEvent( Registers ®s, const struct kvmi_event &event ); 264 | 265 | bool replyEvent( EventReply &reply ); 266 | 267 | void setVcpuEventsDirty(); 268 | 269 | void setVcpuVectorSize(); 270 | 271 | bool updateVcpuCount(); 272 | 273 | bool setVcpuEvents( unsigned int id ); 274 | 275 | void setVcpuEventsLater( unsigned int id ); 276 | 277 | bool clearVcpuEvents( unsigned int id ); 278 | 279 | bool clearVcpuEvents(); 280 | 281 | void enablePendingVcpusCache(); 282 | 283 | bool getXCR0( unsigned short /* vcpu */, uint64_t & /* xcr0 */ ) const override 284 | { 285 | return false; 286 | } 287 | 288 | private: 289 | void *mapGuestPageImpl( unsigned long long gfn ) override; 290 | 291 | void unmapGuestPageImpl( void *hostPtr, unsigned long long gfn ) override; 292 | 293 | bool setPageProtectionImpl( const MemAccessMap &accessMap, unsigned short view ) override; 294 | 295 | bool getPageProtectionImpl( unsigned long long guestAddress, bool &read, bool &write, bool &execute, 296 | unsigned short view ) override; 297 | 298 | bool setPageConvertibleImpl( const ConvertibleMap &convMap, unsigned short view ) override; 299 | 300 | bool isViewCacheEnabled( unsigned short vcpu, unsigned short &view ) const; 301 | 302 | void enableVcpuCache( unsigned short vcpu, unsigned short view, const Registers ®s ); 303 | 304 | void updateVcpuCache( unsigned short view ); 305 | 306 | bool isPendingVcpusCacheEnabled( unsigned short vcpu ) const; 307 | 308 | void disablePendingVcpusCache( unsigned short vcpu ); 309 | 310 | bool maxGPFNImpl( unsigned long long &gfn, bool &trustworthy ) override; 311 | 312 | private: 313 | KvmDriver( const KvmDriver & ); 314 | 315 | KvmDriver &operator=( const KvmDriver & ); 316 | 317 | private: 318 | struct vcpuEvents { 319 | bool dirty_{ true }; 320 | EventBitset enabled_; 321 | std::set enabledCrs_; 322 | std::set enabledMsrs_; 323 | }; 324 | 325 | int flags_{ KVMI_REP_OPTIMIZATIONS_FLAG }; 326 | void * domCtx_; 327 | std::string domain_; 328 | int64_t startTime_{ -1 }; 329 | mutable RegsCache regsCache_; 330 | PageCache pageCache_; 331 | bool suspending_{ false }; 332 | size_t pauseCount_{ 0 }; 333 | std::mutex pauseMutex_; 334 | size_t pendingPauseEvents_{ 0 }; 335 | std::mutex eventProcessingMutex_; 336 | mutable std::atomic vcpuCount_{ 0 }; 337 | std::vector vcpuEvents_; 338 | EventBitset enabledEvents_; 339 | std::unique_ptr batch_; 340 | bool eptpSupported_{ false }; 341 | bool veSupported_{ false }; 342 | unsigned short untrustedView_{ 0 }; 343 | mutable PendingVcpusCache pendingCache_; 344 | unsigned short vcpuPendingSwitchCount_{ 0 }; 345 | 346 | /* EPT views available for VMFUNC */ 347 | std::array guestVisibleEPTviews_{ }; 348 | }; 349 | } // namespace bdvmi 350 | 351 | #endif // __BDVMIKVMDRIVER_H_INCLUDED__ 352 | -------------------------------------------------------------------------------- /src/kvmeventmanager.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-2019 Bitdefender SRL, All rights reserved. 2 | // 3 | // This library is free software; you can redistribute it and/or 4 | // modify it under the terms of the GNU Lesser General Public 5 | // License as published by the Free Software Foundation; either 6 | // version 3.0 of the License, or (at your option) any later version. 7 | // 8 | // This library is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 | // Lesser General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU Lesser General Public 14 | // License along with this library. 15 | 16 | #ifndef __BDVMIKVMEVENTMANAGER_H_INCLUDED__ 17 | #define __BDVMIKVMEVENTMANAGER_H_INCLUDED__ 18 | 19 | #include 20 | #include 21 | #include 22 | #include "bdvmi/eventmanager.h" 23 | 24 | namespace bdvmi { 25 | 26 | class KvmDriver; 27 | 28 | class KvmEventManager : public EventManager { 29 | public: 30 | KvmEventManager( KvmDriver &driver, sig_atomic_t &sigStop ); 31 | 32 | virtual ~KvmEventManager(); 33 | 34 | public: 35 | void waitForEvents() override; 36 | 37 | void stop() override; 38 | 39 | std::string uuid() override; 40 | 41 | private: 42 | bool enableMsrEventsImpl( unsigned int msr ) override; 43 | 44 | bool disableMsrEventsImpl( unsigned int msr ) override; 45 | 46 | bool enableCrEventsImpl( unsigned int cr ) override; 47 | 48 | bool disableCrEventsImpl( unsigned int cr ) override; 49 | 50 | bool enableXSETBVEventsImpl() override; 51 | 52 | bool disableXSETBVEventsImpl() override; 53 | 54 | bool enableBreakpointEventsImpl() override; 55 | 56 | bool disableBreakpointEventsImpl() override; 57 | 58 | bool enableVMCALLEventsImpl() override; 59 | 60 | bool disableVMCALLEventsImpl() override; 61 | 62 | bool enableDescriptorEventsImpl() override; 63 | 64 | bool disableDescriptorEventsImpl() override; 65 | 66 | void flushEventQueue(); 67 | 68 | private: 69 | KvmEventManager( const KvmEventManager & ); 70 | 71 | KvmEventManager &operator=( const KvmEventManager & ); 72 | 73 | bool initVMEvents(); 74 | 75 | bool initVcpuEvents(); 76 | 77 | void traceEventMessage( const struct kvmi_dom_event &msg ); 78 | 79 | void traceEventReply( const struct kvmi_dom_event &msg, const struct KvmDriver::EventReply &rpl ); 80 | 81 | private: 82 | KvmDriver &driver_; 83 | bool stop_{ false }; 84 | bool disconnected_{ false }; 85 | }; 86 | } // namespace bdvmi 87 | 88 | #endif // __BDVMIKVMEVENTMANAGER_H_INCLUDED__ 89 | -------------------------------------------------------------------------------- /src/logger.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-2019 Bitdefender SRL, All rights reserved. 2 | // 3 | // This library is free software; you can redistribute it and/or 4 | // modify it under the terms of the GNU Lesser General Public 5 | // License as published by the Free Software Foundation; either 6 | // version 3.0 of the License, or (at your option) any later version. 7 | // 8 | // This library is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 | // Lesser General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU Lesser General Public 14 | // License along with this library. 15 | 16 | #include 17 | 18 | namespace { 19 | 20 | std::ostream &setLevel( std::ostream &os, bdvmi::LogStreambuf::LogLevel level ) 21 | { 22 | bdvmi::LogStreambuf *lsb = dynamic_cast( os.rdbuf() ); 23 | 24 | if ( lsb ) 25 | lsb->level( level ); 26 | 27 | return os; 28 | } 29 | } // anonymous namespace 30 | 31 | namespace bdvmi { 32 | 33 | thread_local std::unordered_map LogStreambuf::buffers_; 34 | std::atomic_long LogStreambuf::indexGenerator_{ 0 }; 35 | 36 | LogStreambuf::LogStreambuf() 37 | { 38 | index_ = ++indexGenerator_; 39 | } 40 | 41 | LogStreambuf::~LogStreambuf() 42 | { 43 | sync(); 44 | 45 | // You'd think we'd buffers_.erase( index_ ) here, but a logger is often a global 46 | // object, and there are legitimate cases where that means that buffers_ is destroyed 47 | // _before_ it (especially with all the thread_local magic). 48 | // This means that the application will end up with a buffer per logger instance until 49 | // the end. It shouldn't be a big deal - how many different loggers could one 50 | // application be interested in? 51 | } 52 | 53 | void LogStreambuf::level( LogLevel level ) 54 | { 55 | sync(); 56 | buffers_[index_].level_ = level; 57 | } 58 | 59 | LogStreambuf::int_type LogStreambuf::overflow( int_type c ) 60 | { 61 | if ( c != EOF ) 62 | buffers_[index_].contents_ += static_cast( c ); 63 | 64 | return c; 65 | } 66 | 67 | std::streamsize LogStreambuf::xsputn( const char_type *s, std::streamsize n ) 68 | { 69 | buffers_[index_].contents_.append( s, n ); 70 | 71 | return n; 72 | } 73 | 74 | LogStreambuf::int_type LogStreambuf::sync() 75 | { 76 | if ( buffers_[index_].contents_.empty() ) 77 | return 0; 78 | 79 | auto &buffer = buffers_[index_]; 80 | 81 | if ( !prefix_.empty() ) 82 | buffer.contents_ = prefix_ + buffer.contents_; 83 | 84 | switch ( buffer.level_ ) { 85 | case DEBUG: 86 | if ( debug_ ) 87 | debug_( buffer.contents_ ); 88 | break; 89 | case TRACE: // TRACE is a special case of DEBUG 90 | if ( debug_ && trace_ ) 91 | debug_( buffer.contents_ ); 92 | break; 93 | case ERROR: 94 | if ( error_ ) 95 | error_( buffer.contents_ ); 96 | break; 97 | case INFO: 98 | if ( info_ ) 99 | info_( buffer.contents_ ); 100 | break; 101 | case WARNING: 102 | if ( warning_ ) 103 | warning_( buffer.contents_ ); 104 | break; 105 | default: 106 | buffer.contents_.clear(); 107 | return -1; 108 | } 109 | 110 | buffer.contents_.clear(); 111 | return 0; 112 | } 113 | 114 | // Singleton, but not enforced (there's no harm in several instances) 115 | LogStream logger; 116 | 117 | std::ostream &DEBUG( std::ostream &os ) 118 | { 119 | return setLevel( os, LogStreambuf::DEBUG ); 120 | } 121 | 122 | std::ostream &ERROR( std::ostream &os ) 123 | { 124 | return setLevel( os, LogStreambuf::ERROR ); 125 | } 126 | 127 | std::ostream &INFO( std::ostream &os ) 128 | { 129 | return setLevel( os, LogStreambuf::INFO ); 130 | } 131 | 132 | std::ostream &WARNING( std::ostream &os ) 133 | { 134 | return setLevel( os, LogStreambuf::WARNING ); 135 | } 136 | 137 | std::ostream &TRACE( std::ostream &os ) 138 | { 139 | return setLevel( os, LogStreambuf::TRACE ); 140 | } 141 | 142 | } // namespace bdvmi 143 | -------------------------------------------------------------------------------- /src/pagecache.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-2019 Bitdefender SRL, All rights reserved. 2 | // 3 | // This library is free software; you can redistribute it and/or 4 | // modify it under the terms of the GNU Lesser General Public 5 | // License as published by the Free Software Foundation; either 6 | // version 3.0 of the License, or (at your option) any later version. 7 | // 8 | // This library is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 | // Lesser General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU Lesser General Public 14 | // License along with this library. 15 | 16 | #include 17 | #include "bdvmi/logger.h" 18 | #include "bdvmi/pagecache.h" 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | namespace bdvmi { 27 | 28 | PageCache::PageCache( Driver *driver ) 29 | : driver_{ driver } 30 | { 31 | std::ifstream in( "/proc/sys/kernel/osrelease" ); 32 | 33 | if ( in ) 34 | in >> linuxMajVersion_; 35 | else 36 | logger << WARNING << "Cannot access /proc/sys/kernel/osrelease" << std::flush; 37 | } 38 | 39 | bool PageCache::checkPages( void *addr, size_t size ) const 40 | { 41 | unsigned char vec[1] = {}; 42 | 43 | // The page is not present or otherwise unavailable 44 | if ( linuxMajVersion_ < 4 && ( mincore( addr, size, vec ) < 0 || !( vec[0] & 0x01 ) ) ) 45 | return false; 46 | 47 | return true; 48 | } 49 | 50 | size_t PageCache::setLimit( size_t limit ) 51 | { 52 | if ( limit >= 50 ) // magic number! 53 | cacheLimit_ = limit; 54 | 55 | return cacheLimit_; 56 | } 57 | 58 | void PageCache::reset() 59 | { 60 | if ( driver_ ) { 61 | for ( auto &&item : cache_ ) { 62 | if ( item.second.inUse ) 63 | logger << TRACE << "Address " << item.second.pointer << " (gfn " << std::hex 64 | << reverseCache_[item.second.pointer] << std::dec << ") is still mapped (" 65 | << item.second.inUse << ") ?!" << std::flush; 66 | 67 | driver_->unmapGuestPageImpl( item.second.pointer, item.first ); 68 | } 69 | } 70 | 71 | cache_.clear(); 72 | } 73 | 74 | PageCache::~PageCache() 75 | { 76 | reset(); 77 | } 78 | 79 | MapReturnCode PageCache::update( unsigned long gfn, void *&pointer ) 80 | { 81 | auto i = cache_.find( gfn ); 82 | 83 | if ( i == cache_.end() ) // not found 84 | return insertNew( gfn, pointer ); 85 | 86 | i->second.accessed = generateIndex(); 87 | ++i->second.inUse; 88 | 89 | pointer = i->second.pointer; 90 | return MAP_SUCCESS; 91 | } 92 | 93 | bool PageCache::release( void *pointer ) 94 | { 95 | auto ri = reverseCache_.find( pointer ); 96 | 97 | if ( ri == reverseCache_.end() ) 98 | return false; // nothing to do, not in cache 99 | 100 | auto ci = cache_.find( ri->second ); 101 | 102 | if ( ci == cache_.end() ) 103 | return false; 104 | 105 | --ci->second.inUse; // decrease refcount 106 | 107 | return true; 108 | } 109 | 110 | MapReturnCode PageCache::insertNew( unsigned long gfn, void *&pointer ) 111 | { 112 | if ( !driver_ ) { 113 | pointer = nullptr; 114 | return MAP_FAILED_GENERIC; 115 | } 116 | 117 | if ( cache_.size() >= cacheLimit_ ) 118 | cleanup(); 119 | 120 | CacheInfo ci; 121 | 122 | ci.accessed = generateIndex(); 123 | ci.inUse = 1; 124 | ci.pointer = driver_->mapGuestPageImpl( gfn ); 125 | 126 | if ( !ci.pointer ) { 127 | /* 128 | logger << ERROR << "xc_map_foreign_range(0x" << std::setfill( '0' ) << std::setw( 16 ) 129 | << std::hex << gfn << ") failed: " << strerror( errno ) << std::flush; 130 | */ 131 | 132 | pointer = nullptr; 133 | return MAP_FAILED_GENERIC; 134 | } 135 | 136 | if ( !checkPages( ci.pointer, PAGE_SIZE ) ) { 137 | logger << ERROR << "check_pages(0x" << std::setfill( '0' ) << std::setw( 16 ) << std::hex << gfn 138 | << ") failed: " << strerror( errno ) << std::flush; 139 | 140 | driver_->unmapGuestPageImpl( ci.pointer, gfn ); 141 | 142 | pointer = nullptr; 143 | return MAP_PAGE_NOT_PRESENT; 144 | } 145 | 146 | cache_[gfn] = ci; 147 | reverseCache_[ci.pointer] = gfn; 148 | 149 | pointer = ci.pointer; 150 | return MAP_SUCCESS; 151 | } 152 | 153 | void PageCache::cleanup() 154 | { 155 | std::vector> timeOrderedGFNs; 156 | 157 | for ( auto &&item : cache_ ) 158 | if ( item.second.inUse < 1 ) 159 | timeOrderedGFNs.push_back( 160 | std::pair( item.second.accessed, item.first ) ); 161 | 162 | if ( timeOrderedGFNs.empty() ) // All mapped pages are in use. 163 | return; 164 | 165 | std::sort( timeOrderedGFNs.begin(), timeOrderedGFNs.end(), 166 | []( const auto &lhs, const auto &rhs ) { return lhs.first < rhs.first; } ); 167 | 168 | size_t count = 0; 169 | 170 | for ( auto &&item : timeOrderedGFNs ) { 171 | if ( count++ >= cacheLimit_ / 2 ) 172 | break; 173 | 174 | auto ci = cache_.find( item.second ); 175 | 176 | if ( ci == cache_.end() ) 177 | continue; 178 | 179 | driver_->unmapGuestPageImpl( ci->second.pointer, ci->first ); 180 | reverseCache_.erase( ci->second.pointer ); 181 | cache_.erase( ci ); 182 | } 183 | } 184 | 185 | unsigned long PageCache::generateIndex() const 186 | { 187 | static unsigned long index = 0; 188 | return index++; 189 | } 190 | 191 | } // namespace bdvmi 192 | -------------------------------------------------------------------------------- /src/statscollector.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-2019 Bitdefender SRL, All rights reserved. 2 | // 3 | // This library is free software; you can redistribute it and/or 4 | // modify it under the terms of the GNU Lesser General Public 5 | // License as published by the Free Software Foundation; either 6 | // version 3.0 of the License, or (at your option) any later version. 7 | // 8 | // This library is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 | // Lesser General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU Lesser General Public 14 | // License along with this library. 15 | 16 | #include "bdvmi/statscollector.h" 17 | #include "bdvmi/logger.h" 18 | 19 | namespace bdvmi { 20 | 21 | StatsCollector &StatsCollector::instance() 22 | { 23 | static StatsCollector theInstance; 24 | return theInstance; 25 | } 26 | 27 | void StatsCollector::enable( bool value ) 28 | { 29 | enable_ = value; 30 | 31 | std::lock_guard lock( statsMutex_ ); 32 | stats_.clear(); 33 | } 34 | 35 | void StatsCollector::count( const std::string &st, const std::chrono::duration &duration ) 36 | { 37 | if ( !enable_ ) 38 | return; 39 | 40 | std::lock_guard lock( statsMutex_ ); 41 | 42 | auto &value = stats_[st]; 43 | 44 | value.first++; 45 | value.second += duration; 46 | } 47 | 48 | void StatsCollector::dump() const 49 | { 50 | std::lock_guard lock( statsMutex_ ); 51 | 52 | logger << DEBUG; 53 | 54 | for ( auto &&s : stats_ ) 55 | logger << s.first << ": " << s.second.first << "; "; 56 | 57 | logger << std::flush; 58 | 59 | logger << DEBUG; 60 | 61 | for ( auto &&s : stats_ ) 62 | logger << s.first << ": " << s.second.second.count() << " s; "; 63 | 64 | logger << std::flush; 65 | } 66 | 67 | } // namespace bdvmi 68 | -------------------------------------------------------------------------------- /src/utils.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-2019 Bitdefender SRL, All rights reserved. 2 | // 3 | // This library is free software; you can redistribute it and/or 4 | // modify it under the terms of the GNU Lesser General Public 5 | // License as published by the Free Software Foundation; either 6 | // version 3.0 of the License, or (at your option) any later version. 7 | // 8 | // This library is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 | // Lesser General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU Lesser General Public 14 | // License along with this library. 15 | 16 | #ifndef __BDVMIUTILS_H_INCLUDED__ 17 | #define __BDVMIUTILS_H_INCLUDED__ 18 | 19 | #include 20 | #include 21 | 22 | namespace bdvmi { 23 | 24 | class NonCopyable { 25 | protected: 26 | NonCopyable() = default; 27 | 28 | public: 29 | NonCopyable( const NonCopyable & ) = delete; 30 | NonCopyable &operator=( const NonCopyable & ) = delete; 31 | }; 32 | 33 | template class NCFunction; 34 | 35 | template 36 | class NCFunction : private NonCopyable, public std::function { 37 | public: 38 | NCFunction() = default; 39 | 40 | explicit NCFunction( const std::function &&f ) : std::function( f ) 41 | { 42 | } 43 | 44 | NCFunction &operator=( std::function &&f ) 45 | { 46 | std::function::operator=( std::move( f ) ); 47 | return *this; 48 | } 49 | }; 50 | 51 | template struct PrependArg; 52 | 53 | template struct PrependArg { 54 | using type = R( A, Args... ); 55 | }; 56 | 57 | using CDeleterType = void ( * )( void * ); 58 | template using CUniquePtrType = std::unique_ptr; 59 | 60 | template class CUniquePtr : public CUniquePtrType { 61 | public: 62 | CUniquePtr( void *ptr = nullptr ) 63 | : CUniquePtrType( static_cast( ptr ), []( void *ptr ) { ::free( ptr ); } ) 64 | { 65 | } 66 | }; 67 | 68 | } // namespace bdvmi 69 | #endif /* __BDVMIUTILS_H_INCLUDED__ */ 70 | -------------------------------------------------------------------------------- /src/version.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-2019 Bitdefender SRL, All rights reserved. 2 | // 3 | // This library is free software; you can redistribute it and/or 4 | // modify it under the terms of the GNU Lesser General Public 5 | // License as published by the Free Software Foundation; either 6 | // version 3.0 of the License, or (at your option) any later version. 7 | // 8 | // This library is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 | // Lesser General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU Lesser General Public 14 | // License along with this library. 15 | 16 | #include "bdvmi/version.h" 17 | 18 | namespace bdvmi { 19 | 20 | Version::Version( int verMajor, int verMinor, const std::string &verExtra ) 21 | : verMajor_{ verMajor } 22 | , verMinor_{ verMinor } 23 | , verExtra_{ verExtra } 24 | { 25 | } 26 | 27 | int Version::getMajor() const 28 | { 29 | return verMajor_; 30 | } 31 | 32 | int Version::getMinor() const 33 | { 34 | return verMinor_; 35 | } 36 | 37 | std::string Version::getExtra() const 38 | { 39 | return verExtra_; 40 | } 41 | 42 | int cmp( const Version &l, const Version &r ) 43 | { 44 | int majorDiff = l.verMajor_ - r.verMajor_; 45 | return ( majorDiff ) ? majorDiff : ( l.verMinor_ - r.verMinor_ ); 46 | } 47 | 48 | std::ostream &operator<<( std::ostream &str, const Version &obj ) 49 | { 50 | str << std::dec << obj.verMajor_ << "." << obj.verMinor_ << obj.verExtra_; 51 | return str; 52 | } 53 | 54 | } // namespace bdvmi 55 | -------------------------------------------------------------------------------- /src/version.ld: -------------------------------------------------------------------------------- 1 | BDVMI_1.0 { 2 | extern "C++" { 3 | bdvmi::*; 4 | "typeinfo for std::runtime_error"; 5 | "typeinfo for std::exception"; 6 | }; 7 | }; 8 | 9 | # this is where private symbols go 10 | BDVMI_priv { 11 | local: 12 | *; 13 | }; 14 | -------------------------------------------------------------------------------- /src/xcwrapper.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-2019 Bitdefender SRL, All rights reserved. 2 | // 3 | // This library is free software; you can redistribute it and/or 4 | // modify it under the terms of the GNU Lesser General Public 5 | // License as published by the Free Software Foundation; either 6 | // version 3.0 of the License, or (at your option) any later version. 7 | // 8 | // This library is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 | // Lesser General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU Lesser General Public 14 | // License along with this library. 15 | 16 | #ifndef __BDVMIXCWRAPPER_H_INCLUDED__ 17 | #define __BDVMIXCWRAPPER_H_INCLUDED__ 18 | 19 | #ifndef __XEN_TOOLS__ 20 | #define __XEN_TOOLS__ 1 21 | #endif 22 | 23 | #include 24 | #include 25 | 26 | extern "C" { 27 | #include 28 | #include 29 | #include 30 | } 31 | 32 | #include "bdvmi/driver.h" 33 | #include "bdvmi/version.h" 34 | #include "utils.h" 35 | 36 | /* 37 | * DEFINITIONS FOR CPU BARRIERS 38 | */ 39 | #ifndef xen_barrier 40 | #define xen_barrier() asm volatile( "" : : : "memory" ) 41 | 42 | #if defined( __i386__ ) 43 | #define xen_mb() asm volatile( "lock; addl $0,0(%%esp)" : : : "memory" ) 44 | #define xen_rmb() xen_barrier() 45 | #define xen_wmb() xen_barrier() 46 | #elif defined( __x86_64__ ) 47 | #define xen_mb() asm volatile( "mfence" : : : "memory" ) 48 | #define xen_rmb() xen_barrier() 49 | #define xen_wmb() xen_barrier() 50 | #else 51 | #error "Define barriers" 52 | #endif 53 | #endif // xen_barrier 54 | 55 | struct xc_interface_core; 56 | using xc_interface = struct xc_interface_core; 57 | 58 | #if __XEN_LATEST_INTERFACE_VERSION__ == 0x00040600 59 | using xc_evtchn = struct xc_interface_core; 60 | #else 61 | struct xenevtchn_handle; 62 | using xc_evtchn = struct xenevtchn_handle; 63 | #endif 64 | 65 | namespace bdvmi { 66 | 67 | struct XenDomainInfo { 68 | uint32_t domid{ 0 }; 69 | bool hvm{ false }; 70 | bool dying{ false }; 71 | bool shutdown{ false }; 72 | unsigned int max_vcpu_id{ 0 }; 73 | unsigned long max_memkb{ 0 }; 74 | }; 75 | 76 | struct XenDomctlInfo { 77 | bool pvh{ false }; 78 | }; 79 | 80 | struct Registers; 81 | 82 | // 83 | // The simplest way to add a new dynamically-loaded function to libbdvmi: 84 | // 85 | // Say the libxc function's name is int xc_do_stuff(xc_interface *, uint32_t ), then: 86 | // 87 | // 1. DECLARE_BDVMI_FUNCTION( do_stuff, int( uint32_t ) ) below. 88 | // _Don't_ add the xc_interface * param. 89 | // 90 | // 2. Add a member in class XC: 91 | // NCFunction doStuff; // NC stands for non-copyable 92 | // 93 | // 3. Add a member in class XCFactory: 94 | // std::function doStuff; 95 | // 96 | // 4. Add: 97 | // doStuff = LOOKUP_XC_FUNCTION_REQUIRED( do_stuff ); 98 | // to XCFactory::XCFactory()'s body (follow the other similar code). 99 | // If it's OK to _not_ find the function in the library, say LOOKUP_XC_FUNCTION_OPTIONAL() instead. 100 | // For required functions, not finding them results in an exception being thrown. 101 | // 102 | // 5. Add doStuff( std::bind( XCFactory::instance().doStuff, xci_.get(), _1 ) ) to class XC's constructor's 103 | // initializer list. This will bind the internal libxc handle to the first parameter, and _1 is a 104 | // placeholder for the uint32_t parameter. If you have several parameters in the original function after 105 | // xc_interface *, they become _1, _2, _3, and so on here. 106 | // 107 | 108 | #define DECLARE_BDVMI_FUNCTION( NAME, TYPE ) \ 109 | using bdvmi_##NAME##_fn_t = TYPE; \ 110 | using xc_##NAME##_fn_t = PrependArg::type; \ 111 | constexpr char xc_##NAME##_fn_name[] = "xc_" #NAME; 112 | 113 | DECLARE_BDVMI_FUNCTION( domain_pause, int( uint32_t ) ) 114 | DECLARE_BDVMI_FUNCTION( domain_unpause, int( uint32_t ) ) 115 | DECLARE_BDVMI_FUNCTION( domain_shutdown, int( uint32_t, int ) ) 116 | DECLARE_BDVMI_FUNCTION( domain_getinfo, int( uint32_t, XenDomainInfo & ) ) 117 | DECLARE_BDVMI_FUNCTION( domain_getinfolist, int( uint32_t, XenDomctlInfo & ) ) 118 | DECLARE_BDVMI_FUNCTION( domain_maximum_gpfn, int( uint32_t, xen_pfn_t * ) ) 119 | DECLARE_BDVMI_FUNCTION( domain_debug_control, int( uint32_t, uint32_t, uint32_t ) ) 120 | DECLARE_BDVMI_FUNCTION( domain_get_tsc_info, int( uint32_t, uint32_t *, uint64_t *, uint32_t *, uint32_t * ) ) 121 | DECLARE_BDVMI_FUNCTION( domain_set_access_required, int( uint32_t, unsigned int ) ) 122 | DECLARE_BDVMI_FUNCTION( domain_hvm_getcontext, int( uint32_t, uint8_t *, uint32_t ) ) 123 | DECLARE_BDVMI_FUNCTION( domain_hvm_getcontext_partial, int( uint32_t, uint16_t, uint16_t, void *, uint32_t ) ) 124 | DECLARE_BDVMI_FUNCTION( set_mem_access, int( uint32_t, const Driver::MemAccessMap & ) ) 125 | DECLARE_BDVMI_FUNCTION( altp2m_get_mem_access, int( uint32_t, uint16_t, xen_pfn_t, xenmem_access_t * ) ) 126 | DECLARE_BDVMI_FUNCTION( domain_set_cores_per_socket, int( uint32_t, uint32_t ) ) 127 | DECLARE_BDVMI_FUNCTION( altp2m_set_mem_access, int( uint32_t, uint16_t, const Driver::MemAccessMap & ) ) 128 | DECLARE_BDVMI_FUNCTION( altp2m_set_domain_state, int( uint32_t, bool ) ) 129 | DECLARE_BDVMI_FUNCTION( altp2m_create_view, int( uint32_t, xenmem_access_t, uint16_t * ) ) 130 | DECLARE_BDVMI_FUNCTION( altp2m_destroy_view, int( uint32_t, uint16_t ) ) 131 | DECLARE_BDVMI_FUNCTION( altp2m_switch_to_view, int( uint32_t, uint16_t ) ) 132 | DECLARE_BDVMI_FUNCTION( altp2m_set_suppress_ve, int( uint32_t, uint16_t, xen_pfn_t, bool ) ) 133 | DECLARE_BDVMI_FUNCTION( altp2m_get_suppress_ve, int( uint32_t, uint16_t, xen_pfn_t, bool * ) ) 134 | DECLARE_BDVMI_FUNCTION( altp2m_set_vcpu_enable_notify, int( uint32_t, uint32_t, xen_pfn_t ) ) 135 | DECLARE_BDVMI_FUNCTION( altp2m_set_vcpu_disable_notify, int( uint32_t, uint32_t ) ) 136 | DECLARE_BDVMI_FUNCTION( altp2m_get_vcpu_p2m_idx, int( uint32_t, uint32_t, uint16_t * ) ) 137 | DECLARE_BDVMI_FUNCTION( map_foreign_range, void *( uint32_t, int, int, unsigned long )) 138 | DECLARE_BDVMI_FUNCTION( get_mem_access, int( uint32_t, uint64_t, xenmem_access_t * ) ) 139 | DECLARE_BDVMI_FUNCTION( hvm_inject_trap, int( uint32_t, int, uint8_t, uint8_t, uint32_t, uint8_t, uint64_t ) ) 140 | DECLARE_BDVMI_FUNCTION( vcpu_set_registers, int( uint32_t, unsigned short, const Registers &, bool ) ) 141 | DECLARE_BDVMI_FUNCTION( monitor_enable, void *( uint32_t, uint32_t * )) 142 | DECLARE_BDVMI_FUNCTION( monitor_disable, int( uint32_t ) ) 143 | DECLARE_BDVMI_FUNCTION( monitor_singlestep, int( uint32_t, bool ) ) 144 | DECLARE_BDVMI_FUNCTION( monitor_software_breakpoint, int( uint32_t, bool ) ) 145 | DECLARE_BDVMI_FUNCTION( monitor_emulate_each_rep, int( uint32_t, bool ) ) 146 | DECLARE_BDVMI_FUNCTION( monitor_mov_to_msr, int( uint32_t, uint32_t, bool, bool ) ) 147 | DECLARE_BDVMI_FUNCTION( monitor_guest_request, int( uint32_t, bool, bool, bool ) ) 148 | DECLARE_BDVMI_FUNCTION( monitor_write_ctrlreg, int( uint32_t, uint16_t, bool, bool, uint64_t, bool ) ) 149 | DECLARE_BDVMI_FUNCTION( monitor_descriptor_access, int( uint32_t /* domain */, bool /* enable */ ) ) 150 | DECLARE_BDVMI_FUNCTION( monitor_inguest_pagefault, int( uint32_t /* domain */, bool /* disable */ ) ) 151 | DECLARE_BDVMI_FUNCTION( monitor_emul_unimplemented, int( uint32_t, bool ) ) 152 | DECLARE_BDVMI_FUNCTION( vm_event_get_version, int() ) 153 | 154 | using bdvmi_evtchn_open_fn_t = xc_evtchn *( void ); 155 | using bdvmi_evtchn_close_fn_t = int( xc_evtchn * ); 156 | using bdvmi_evtchn_fd_fn_t = int( xc_evtchn * ); 157 | using bdvmi_evtchn_pending_fn_t = int( xc_evtchn * ); 158 | using bdvmi_evtchn_bind_interdomain_fn_t = int( xc_evtchn *, uint32_t, uint32_t ); 159 | using bdvmi_evtchn_unbind_fn_t = int( xc_evtchn *, uint32_t ); 160 | using bdvmi_evtchn_unmask_fn_t = int( xc_evtchn *, uint32_t ); 161 | using bdvmi_evtchn_notify_fn_t = int( xc_evtchn *, uint32_t ); 162 | 163 | class XC { 164 | public: 165 | XC(); 166 | 167 | static const unsigned long pageSize; 168 | static const unsigned long pageShift; 169 | static const unsigned long pageMask; 170 | static const unsigned long invalidMfn; 171 | static const uint8_t shutdownPoweroff; 172 | 173 | static xenmem_access_t xenMemAccess( uint8_t bdvmiBitmask ); 174 | 175 | private: 176 | std::unique_ptr xci_; 177 | 178 | public: 179 | const Version version; 180 | const bool isXenServer{ false }; 181 | const std::string caps; 182 | const std::string uuid; 183 | 184 | // Domain Management functions 185 | NCFunction domainPause; 186 | NCFunction domainUnpause; 187 | NCFunction domainShutdown; 188 | NCFunction domainGetInfo; 189 | NCFunction domainGetInfoList; 190 | NCFunction domainMaximumGpfn; 191 | NCFunction domainDebugControl; 192 | NCFunction domainGetTscInfo; 193 | NCFunction domainSetAccessRequired; 194 | NCFunction domainHvmGetContext; 195 | NCFunction domainHvmGetContextPartial; 196 | NCFunction setMemAccess; 197 | 198 | // ALTP2M support 199 | NCFunction altp2mGetMemAccess; 200 | NCFunction altp2mSetMemAccess; 201 | NCFunction altp2mSetDomainState; 202 | NCFunction altp2mCreateView; 203 | NCFunction altp2mDestroyView; 204 | NCFunction altp2mSwitchToView; 205 | NCFunction altp2mSetSuppressVE; 206 | NCFunction altp2mGetSuppressVE; 207 | NCFunction altp2mSetVcpuEnableNotify; 208 | NCFunction altp2mSetVcpuDisableNotify; 209 | NCFunction altp2mGetVcpuP2mIdx; 210 | 211 | NCFunction mapForeignRange; 212 | NCFunction getMemAccess; 213 | NCFunction hvmInjectTrap; 214 | NCFunction vcpuSetRegisters; 215 | 216 | // Monitor functions 217 | NCFunction monitorEnable; 218 | NCFunction monitorDisable; 219 | NCFunction monitorSinglestep; 220 | NCFunction monitorSoftwareBreakpoint; 221 | NCFunction monitorEmulateEachRep; 222 | NCFunction monitorMovToMsr; 223 | NCFunction monitorGuestRequest; 224 | NCFunction monitorWriteCtrlreg; 225 | NCFunction monitorDescriptorAccess; 226 | NCFunction monitorInguestPagefault; 227 | NCFunction monitorEmulUnimplemented; 228 | 229 | // XenServer-specific functions 230 | NCFunction domainSetCoresPerSocket; 231 | 232 | // General query functions 233 | NCFunction vmEventGetVersion; 234 | 235 | /* 236 | * Event Channel functions 237 | */ 238 | std::function evtchnOpen; 239 | std::function evtchnClose; 240 | std::function evtchnFd; 241 | std::function evtchnPending; 242 | std::function evtchnBindInterdomain; 243 | std::function evtchnUnbind; 244 | std::function evtchnUnmask; 245 | std::function evtchnNotify; 246 | }; 247 | 248 | } // namespace bdvmi 249 | 250 | #endif // __BDVMIXCWRAPPER_H_INCLUDED__ 251 | -------------------------------------------------------------------------------- /src/xenaltp2m.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-2019 Bitdefender SRL, All rights reserved. 2 | // 3 | // This library is free software; you can redistribute it and/or 4 | // modify it under the terms of the GNU Lesser General Public 5 | // License as published by the Free Software Foundation; either 6 | // version 3.0 of the License, or (at your option) any later version. 7 | // 8 | // This library is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 | // Lesser General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU Lesser General Public 14 | // License along with this library. 15 | 16 | // #define BDVMI_DISABLE_STATS 17 | 18 | #include "bdvmi/driver.h" 19 | #include "bdvmi/logger.h" 20 | #include "bdvmi/statscollector.h" 21 | #include "xenaltp2m.h" 22 | #include "xcwrapper.h" 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | namespace bdvmi { 29 | 30 | XenAltp2mDomainState::XenAltp2mDomainState( XC &xc, uint32_t domain, bool enable ) 31 | : xc_{ xc } 32 | , domain_{ domain } 33 | { 34 | if ( !enable ) 35 | return; 36 | 37 | if ( !xc_.altp2mSetVcpuDisableNotify ) { 38 | logger << WARNING << "[ALTP2M] no disable_notify() function present" << std::flush; 39 | return; 40 | } 41 | 42 | if ( !xc_.altp2mSetSuppressVE || !xc_.altp2mGetSuppressVE ) { 43 | logger << WARNING << "[ALTP2M] no #VE suppress bit handlers available" << std::flush; 44 | return; 45 | } 46 | 47 | if ( xc_.altp2mSetDomainState( domain, true ) < 0 ) { 48 | logger << WARNING << "[ALTP2M] could not enable altp2m on domain: " << strerror( errno ) << std::flush; 49 | return; 50 | } 51 | 52 | if ( !xc_.altp2mGetVcpuP2mIdx ) 53 | logger << WARNING << "[ALTP2M] no p2m_idx() function present" << std::flush; 54 | 55 | enabled_ = true; 56 | } 57 | 58 | XenAltp2mDomainState::~XenAltp2mDomainState() 59 | { 60 | if ( !enabled_ ) 61 | return; 62 | 63 | switchToView( 0 ); 64 | 65 | for ( auto &&view : views_ ) 66 | xc_.altp2mDestroyView( domain_, view ); 67 | 68 | xc_.altp2mSetDomainState( domain_, false ); 69 | } 70 | 71 | int XenAltp2mDomainState::createView( xenmem_access_t defaultAccess, uint16_t &id ) 72 | { 73 | if ( !enabled_ ) 74 | return -ENOTSUP; 75 | 76 | int rc; 77 | if ( ( rc = xc_.altp2mCreateView( domain_, defaultAccess, &id ) ) >= 0 ) { 78 | // Driver::MemAccessMap ma; 79 | // ma[~0ull] = Driver::PAGE_READ | Driver::PAGE_WRITE; 80 | // xc_.altp2mSetMemAccess( domain_, id, ma ); 81 | 82 | views_.insert( id ); 83 | } 84 | 85 | return rc; 86 | } 87 | 88 | int XenAltp2mDomainState::destroyView( uint16_t view ) 89 | { 90 | if ( !enabled_ ) 91 | return -ENOTSUP; 92 | 93 | int rc = xc_.altp2mDestroyView( domain_, view ); 94 | 95 | if ( rc >= 0 ) 96 | views_.erase( view ); 97 | 98 | return rc; 99 | } 100 | 101 | int XenAltp2mDomainState::switchToView( uint16_t view ) 102 | { 103 | if ( !enabled_ ) 104 | return -ENOTSUP; 105 | 106 | uint16_t currentView; 107 | 108 | int rc = getCurrentView( 0, currentView ); 109 | if ( rc < 0 ) 110 | return rc; 111 | 112 | if ( view == currentView ) 113 | return 0; 114 | 115 | if ( view && views_.find( view ) == views_.end() ) 116 | return -EINVAL; 117 | 118 | if ( ( rc = xc_.altp2mSwitchToView( domain_, view ) ) >= 0 ) { 119 | currentView_ = view; 120 | } 121 | 122 | return rc; 123 | } 124 | 125 | int XenAltp2mDomainState::getCurrentView( uint32_t vcpu, uint16_t &view ) const 126 | { 127 | if ( !enabled_ ) { 128 | view = 0; 129 | return 0; 130 | } 131 | 132 | if ( isCacheEnabled( vcpu, view ) ) 133 | return 0; 134 | 135 | if ( !xc_.altp2mGetVcpuP2mIdx ) { 136 | view = currentView_; 137 | return 0; 138 | } 139 | 140 | StatsCounter counter( "altp2mGetVcpuP2mIdx" ); 141 | return xc_.altp2mGetVcpuP2mIdx( domain_, vcpu, &view ); 142 | } 143 | 144 | int XenAltp2mDomainState::setVEInfoPage( uint32_t vcpu, xen_pfn_t gpa ) 145 | { 146 | if ( !enabled_ ) 147 | return -ENOTSUP; 148 | 149 | return xc_.altp2mSetVcpuEnableNotify( domain_, vcpu, gpa ); 150 | } 151 | 152 | int XenAltp2mDomainState::disableVE( uint32_t vcpu ) 153 | { 154 | if ( !enabled_ || !xc_.altp2mSetVcpuDisableNotify ) 155 | return -ENOTSUP; 156 | 157 | return xc_.altp2mSetVcpuDisableNotify( domain_, vcpu ); 158 | } 159 | 160 | int XenAltp2mDomainState::setSuppressVE( uint16_t view, xen_pfn_t gfn, bool sve ) 161 | { 162 | if ( !enabled_ ) 163 | return -ENOTSUP; 164 | 165 | if ( view && views_.find( view ) == views_.end() ) 166 | return -EINVAL; 167 | 168 | return xc_.altp2mSetSuppressVE( domain_, view, gfn, sve ); 169 | } 170 | 171 | int XenAltp2mDomainState::getSuppressVE( uint16_t view, xen_pfn_t gfn, bool &sve ) 172 | { 173 | if ( !enabled_ ) 174 | return -ENOTSUP; 175 | 176 | if ( view && views_.find( view ) == views_.end() ) 177 | return -EINVAL; 178 | 179 | return xc_.altp2mGetSuppressVE( domain_, view, gfn, &sve ); 180 | } 181 | 182 | void XenAltp2mDomainState::enableCache( uint32_t vcpu, uint16_t idx ) 183 | { 184 | if ( !enabled_ ) 185 | return; 186 | 187 | std::lock_guard lock( viewCache_.mutex_ ); 188 | viewCache_.views_[vcpu] = idx; 189 | } 190 | 191 | void XenAltp2mDomainState::disableCache( uint32_t vcpu ) 192 | { 193 | if ( !enabled_ ) 194 | return; 195 | 196 | std::lock_guard lock( viewCache_.mutex_ ); 197 | viewCache_.views_.erase( vcpu ); 198 | } 199 | 200 | bool XenAltp2mDomainState::isCacheEnabled( uint32_t vcpu, uint16_t &view ) const 201 | { 202 | std::lock_guard lock( viewCache_.mutex_ ); 203 | auto it = viewCache_.views_.find( vcpu ); 204 | 205 | if ( it == viewCache_.views_.end() ) 206 | return false; 207 | 208 | view = it->second; 209 | 210 | return true; 211 | } 212 | 213 | } // namespace bdvmi 214 | -------------------------------------------------------------------------------- /src/xenaltp2m.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-2019 Bitdefender SRL, All rights reserved. 2 | // 3 | // This library is free software; you can redistribute it and/or 4 | // modify it under the terms of the GNU Lesser General Public 5 | // License as published by the Free Software Foundation; either 6 | // version 3.0 of the License, or (at your option) any later version. 7 | // 8 | // This library is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 | // Lesser General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU Lesser General Public 14 | // License along with this library. 15 | 16 | #ifndef __BDVMIXENALTP2M_H_INCLUDED__ 17 | #define __BDVMIXENALTP2M_H_INCLUDED__ 18 | 19 | #ifndef __XEN_TOOLS__ 20 | #define __XEN_TOOLS__ 1 21 | #endif 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include "xcwrapper.h" 29 | 30 | extern "C" { 31 | #include 32 | } 33 | 34 | namespace bdvmi { 35 | 36 | class XenAltp2mDomainState { 37 | 38 | struct ViewCache { 39 | std::unordered_map< uint32_t, uint16_t > views_; 40 | std::mutex mutex_; 41 | }; 42 | 43 | public: 44 | XenAltp2mDomainState( XC &xc, uint32_t domain, bool enable = true ); 45 | ~XenAltp2mDomainState(); 46 | 47 | int createView( xenmem_access_t defaultAccess, uint16_t &id ); 48 | 49 | int switchToView( uint16_t view ); 50 | 51 | int destroyView( uint16_t view ); 52 | 53 | int getCurrentView( uint32_t vcpu, uint16_t &view ) const; 54 | 55 | int setVEInfoPage( uint32_t vcpu, xen_pfn_t gpa ); 56 | 57 | int disableVE( uint32_t vcpu ); 58 | 59 | int setSuppressVE( uint16_t view, xen_pfn_t gfn, bool sve ); 60 | 61 | int getSuppressVE( uint16_t view, xen_pfn_t gfn, bool &sve ); 62 | 63 | explicit operator bool() const 64 | { 65 | return enabled_; 66 | } 67 | 68 | void enableCache( uint32_t vcpu, uint16_t view ); 69 | 70 | void disableCache( uint32_t vcpu ); 71 | 72 | private: 73 | bool isCacheEnabled( uint32_t vcpu, uint16_t &view ) const; 74 | 75 | private: 76 | XC & xc_; 77 | uint32_t domain_; 78 | uint16_t currentView_{ 0 }; 79 | std::set views_; 80 | bool enabled_{ false }; 81 | mutable ViewCache viewCache_; 82 | }; 83 | 84 | } // namespace bdvmi 85 | #endif //__BDVMIXENALTP2M_H_INCLUDED__ 86 | -------------------------------------------------------------------------------- /src/xendomainwatcher.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-2019 Bitdefender SRL, All rights reserved. 2 | // 3 | // This library is free software; you can redistribute it and/or 4 | // modify it under the terms of the GNU Lesser General Public 5 | // License as published by the Free Software Foundation; either 6 | // version 3.0 of the License, or (at your option) any later version. 7 | // 8 | // This library is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 | // Lesser General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU Lesser General Public 14 | // License along with this library. 15 | 16 | #include "bdvmi/logger.h" 17 | #include "xcwrapper.h" 18 | #include "xendomainwatcher.h" 19 | #include "utils.h" 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | namespace bdvmi { 27 | 28 | constexpr char XenDomainWatcher::TEMPORARY_UUID_SUFFIX[]; 29 | constexpr size_t XenDomainWatcher::PREFIX_SIZE; 30 | 31 | XenDomainWatcher::XenDomainWatcher( sig_atomic_t &sigStop ) 32 | : DomainWatcher{ sigStop } 33 | , ownUuid_{ xc_.uuid } 34 | { 35 | if ( !xs_.watch( "@introduceDomain", introduceToken_ ) ) 36 | throw std::runtime_error( "xs_watch() failed" ); 37 | 38 | if ( !xs_.watch( "@releaseDomain", releaseToken_ ) ) { 39 | xs_.unwatch( "@introduceDomain", introduceToken_ ); 40 | throw std::runtime_error( "xs_watch() failed" ); 41 | } 42 | 43 | // Retrieving the UUID can also be achieved under Linux by simply reading 44 | // /sys/hypervisor/uuid. 45 | logger << INFO << "SVA UUID: " << ownUuid_ << std::flush; 46 | } 47 | 48 | XenDomainWatcher::~XenDomainWatcher() 49 | { 50 | xs_.unwatch( "@introduceDomain", introduceToken_ ); 51 | xs_.unwatch( "@releaseDomain", releaseToken_ ); 52 | 53 | if ( !controlXenStorePath_.empty() ) { 54 | xs_.unwatch( controlXenStorePath_, controlToken_ ); 55 | xs_.rm( XS::xbtNull, controlXenStorePath_ ); 56 | } 57 | } 58 | 59 | bool XenDomainWatcher::getNewDomains( std::list &domains ) 60 | { 61 | int domid = 1; 62 | XenDomainInfo dominfo; 63 | int err = -1; 64 | bool ret = false; 65 | 66 | while ( ( err = xc_.domainGetInfo( domid, dominfo ) ) == 1 ) { 67 | 68 | domid = dominfo.domid + 1; 69 | 70 | std::string key = "/local/domain/" + std::to_string( dominfo.domid ) + "/vm-data/pre-resume"; 71 | 72 | CUniquePtr dummy( xs_.readTimeout( XS::xbtNull, key, nullptr, 1 ) ); 73 | 74 | // Key exists, so the domain is pre-resuming. Wait until post-resume to 75 | // hook the domain, don't hook it immediately. 76 | if ( dummy ) { 77 | if ( preResumeDomains_.find( dominfo.domid ) == preResumeDomains_.end() ) { 78 | xs_.watch( key, postResumeToken_ ); 79 | preResumeDomains_.insert( dominfo.domid ); 80 | } 81 | 82 | continue; 83 | } else { 84 | if ( preResumeDomains_.find( dominfo.domid ) != preResumeDomains_.end() ) { 85 | xs_.unwatch( key, postResumeToken_ ); 86 | preResumeDomains_.erase( dominfo.domid ); 87 | } 88 | } 89 | 90 | if ( xs_.isDomainIntroduced( dominfo.domid ) ) { 91 | // New domain 92 | if ( domIds_.find( dominfo.domid ) == domIds_.end() ) { 93 | std::string path = "/local/domain/" + std::to_string( dominfo.domid ) + "/name"; 94 | bool self = isSelf( dominfo.domid ); 95 | 96 | errno = 0; 97 | 98 | if ( self ) 99 | initControlKey( dominfo.domid ); 100 | 101 | CUniquePtr name( xs_.readTimeout( XS::xbtNull, path, nullptr, 1 ) ); 102 | 103 | if ( name ) { // domain running or new domain w name set 104 | if ( !self ) { 105 | std::string guestUuid = uuid( dominfo.domid ); 106 | 107 | // Temporary UUID set for localhost migration purposes (XenServer/XAPI). 108 | // The guest is not really ready until the real UUID is set, so 109 | // wait for that. 110 | if ( guestUuid.length() > 24 && 111 | guestUuid.substr( 24 ) == TEMPORARY_UUID_SUFFIX ) { 112 | path = 113 | "/local/domain/" + std::to_string( dominfo.domid ) + "/vm"; 114 | xs_.watch( path, "uuid" + std::to_string( dominfo.domid ) ); 115 | } else { 116 | processNewDomain( domains, dominfo.domid, guestUuid, 117 | name.get() ); 118 | ret = true; 119 | } 120 | } 121 | } else // new domain, name not yet set 122 | xs_.watch( path, "dom" + std::to_string( dominfo.domid ) ); 123 | } 124 | } 125 | } 126 | 127 | if ( err == -1 && ( errno == EACCES || errno == EPERM ) ) { 128 | std::runtime_error e( "access denied for xc_domain_getinfo()" ); 129 | logger << ERROR << e.what() << std::flush; 130 | throw e; 131 | } 132 | 133 | return ret; 134 | } 135 | 136 | bool XenDomainWatcher::accessGranted() 137 | { 138 | XenDomainInfo dominfo; 139 | 140 | if ( xc_.domainGetInfo( 1, dominfo ) == -1 && ( errno == EACCES || errno == EPERM ) ) 141 | return false; 142 | 143 | return true; 144 | } 145 | 146 | bool XenDomainWatcher::waitForDomainsOrTimeout( std::list &domains, int ms ) 147 | { 148 | struct pollfd fd; 149 | bool ret = false; 150 | 151 | fd.revents = 0; 152 | fd.fd = xs_.fileno(); 153 | fd.events = POLLIN | POLLERR; 154 | 155 | int rc = poll( &fd, 1, ms ); 156 | 157 | domains.clear(); 158 | 159 | if ( rc == 0 ) 160 | return false; // timeout 161 | 162 | if ( fd.revents & POLLIN ) { 163 | std::vector vec; 164 | 165 | if ( !xs_.readWatch( vec ) ) 166 | return false; 167 | 168 | if ( introduceToken_ == vec[XS::watchToken] ) 169 | ret = getNewDomains( domains ); 170 | 171 | if ( releaseToken_ == vec[XS::watchToken] ) { 172 | auto i = domIds_.begin(); 173 | decltype( i ) j; 174 | 175 | while ( i != domIds_.end() ) { 176 | j = i; 177 | ++i; 178 | 179 | if ( !xs_.isDomainIntroduced( j->first ) ) { 180 | domains.emplace_back( j->second, DomainInfo::STATE_FINISHED ); 181 | 182 | preResumeDomains_.erase( j->first ); 183 | domIds_.erase( j ); 184 | 185 | ret = true; 186 | } 187 | } 188 | } 189 | 190 | if ( controlToken_ == vec[XS::watchToken] ) { 191 | if ( firstControlCommand_ ) // ignore first event, it's just how XenStore works 192 | firstControlCommand_ = false; 193 | else { 194 | CUniquePtr value( 195 | xs_.readTimeout( XS::xbtNull, vec[XS::watchPath], nullptr, 1 ) ); 196 | 197 | if ( value ) { 198 | std::string tmp = value.get(); 199 | 200 | logger << INFO << "Received control command: " << tmp << std::flush; 201 | 202 | if ( tmp == "shutdown" ) 203 | stop(); 204 | else if ( tmp == "scandomains" ) 205 | ret = getNewDomains( domains ); 206 | } 207 | } 208 | } 209 | 210 | if ( postResumeToken_ == vec[XS::watchToken] ) 211 | ret = getNewDomains( domains ); 212 | 213 | if ( !vec[XS::watchToken].compare( 0, 3, "dom" ) ) { 214 | int domid = 1; 215 | 216 | if ( sscanf( vec[XS::watchToken].c_str(), "dom%d", &domid ) == 1 ) { 217 | CUniquePtr name( xs_.readTimeout( XS::xbtNull, vec[XS::watchPath], nullptr, 1 ) ); 218 | 219 | if ( name ) { 220 | if ( !isSelf( domid ) ) { 221 | processNewDomain( domains, domid, uuid( domid ), name.get() ); 222 | ret = true; 223 | } 224 | 225 | xs_.unwatch( vec[XS::watchPath], vec[XS::watchToken] ); 226 | } 227 | } 228 | } 229 | 230 | if ( !vec[XS::watchToken].compare( 0, 4, "uuid" ) ) { 231 | int domid = 1; 232 | 233 | if ( sscanf( vec[XS::watchToken].c_str(), "uuid%d", &domid ) == 1 ) { 234 | unsigned int size = 0; 235 | std::string uuid; 236 | 237 | CUniquePtr val( xs_.readTimeout( XS::xbtNull, vec[XS::watchPath], &size, 1 ) ); 238 | 239 | if ( val ) { 240 | if ( size > PREFIX_SIZE ) 241 | uuid = val.get() + PREFIX_SIZE; 242 | 243 | if ( !isSelf( domid ) ) { 244 | if ( uuid.length() > 24 && 245 | uuid.substr( 24 ) != TEMPORARY_UUID_SUFFIX ) { 246 | std::string path = 247 | "/local/domain/" + std::to_string( domid ) + "/vm"; 248 | 249 | xs_.unwatch( path, "uuid" + std::to_string( domid ) ); 250 | 251 | path = "/local/domain/" + std::to_string( domid ) + "/name"; 252 | 253 | CUniquePtr name( 254 | xs_.readTimeout( XS::xbtNull, path, nullptr, 1 ) ); 255 | 256 | if ( name ) { 257 | processNewDomain( domains, domid, uuid, name.get() ); 258 | ret = true; 259 | } else 260 | xs_.watch( "/local/domain/" + std::to_string( domid ) + 261 | "/name", 262 | "dom" + std::to_string( domid ) ); 263 | } 264 | } 265 | } 266 | } 267 | } 268 | } 269 | 270 | return ret; 271 | } 272 | 273 | std::string XenDomainWatcher::uuid( domid_t domain ) const 274 | { 275 | std::string strUuid; 276 | unsigned int size = 0; 277 | std::string key = "/local/domain/" + std::to_string( domain ) + "/vm"; 278 | 279 | CUniquePtr path( xs_.readTimeout( XS::xbtNull, key, &size, 1 ) ); 280 | 281 | if ( path && size > PREFIX_SIZE ) 282 | strUuid = path.get() + PREFIX_SIZE; // Get rid of "/vm/" 283 | 284 | return strUuid; 285 | } 286 | 287 | bool XenDomainWatcher::isSelf( domid_t domain ) const 288 | { 289 | return ownUuid_ == uuid( domain ); 290 | } 291 | 292 | void XenDomainWatcher::initControlKey( domid_t domain ) 293 | { 294 | if ( !keyCreated_ ) { // One-time only 295 | keyCreated_ = true; 296 | controlXenStorePath_ = "/local/domain/" + std::to_string( domain ) + "/vm-data/introspection-control"; 297 | const std::string value = "started"; 298 | 299 | if ( !xs_.write( XS::xbtNull, controlXenStorePath_, value.c_str(), value.length() ) ) 300 | logger << ERROR << "Could not write XenStore key " << controlXenStorePath_ << std::flush; 301 | 302 | xs_.watch( controlXenStorePath_, controlToken_ ); 303 | } 304 | } 305 | 306 | void XenDomainWatcher::processNewDomain( std::list &domains, domid_t domid, const std::string &uuid, 307 | const std::string &name ) 308 | { 309 | domains.emplace_back( uuid, DomainInfo::STATE_NEW, name ); 310 | domIds_[domid] = uuid; 311 | } 312 | 313 | } // namespace bdvmi 314 | -------------------------------------------------------------------------------- /src/xendomainwatcher.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-2019 Bitdefender SRL, All rights reserved. 2 | // 3 | // This library is free software; you can redistribute it and/or 4 | // modify it under the terms of the GNU Lesser General Public 5 | // License as published by the Free Software Foundation; either 6 | // version 3.0 of the License, or (at your option) any later version. 7 | // 8 | // This library is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 | // Lesser General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU Lesser General Public 14 | // License along with this library. 15 | 16 | #ifndef __BDVMIXENDOMAINWATCHER_H_INCLUDED__ 17 | #define __BDVMIXENDOMAINWATCHER_H_INCLUDED__ 18 | 19 | #include "bdvmi/domainwatcher.h" 20 | #include "xcwrapper.h" 21 | #include "xswrapper.h" 22 | #include 23 | 24 | namespace bdvmi { 25 | 26 | class XenDomainWatcher : public DomainWatcher { 27 | 28 | public: 29 | explicit XenDomainWatcher( sig_atomic_t &sigStop ); 30 | 31 | virtual ~XenDomainWatcher(); 32 | 33 | public: 34 | bool accessGranted() override; 35 | 36 | bool ownUuid( std::string &uuid ) const override 37 | { 38 | uuid = ownUuid_; 39 | return true; 40 | } 41 | 42 | public: 43 | // No copying allowed 44 | XenDomainWatcher( const XenDomainWatcher & ) = delete; 45 | 46 | // No copying allowed 47 | XenDomainWatcher &operator=( const XenDomainWatcher & ) = delete; 48 | 49 | private: 50 | bool waitForDomainsOrTimeout( std::list &domains, int ms ) override; 51 | 52 | bool isSelf( domid_t domain ) const; 53 | 54 | void initControlKey( domid_t domain ); 55 | 56 | bool getNewDomains( std::list &domains ); 57 | 58 | std::string uuid( domid_t domain ) const; 59 | 60 | void processNewDomain( std::list &domains, domid_t domid, const std::string &uuid, 61 | const std::string &name ); 62 | 63 | private: 64 | mutable XS xs_; 65 | mutable XC xc_; 66 | std::string ownUuid_; 67 | std::string controlXenStorePath_; 68 | const std::string introduceToken_{ "introduce" }; 69 | const std::string releaseToken_{ "release" }; 70 | const std::string controlToken_{ "control" }; 71 | const std::string postResumeToken_{ "post-resume" }; 72 | std::unordered_map domIds_; 73 | bool firstControlCommand_{ true }; 74 | bool keyCreated_{ false }; 75 | std::set preResumeDomains_; 76 | constexpr static char TEMPORARY_UUID_SUFFIX[]{ "000000000001" }; 77 | constexpr static size_t PREFIX_SIZE{ 4 }; 78 | }; 79 | 80 | } // namespace bdvmi 81 | 82 | #endif // __BDVMIXENDOMAINWATCHER_H_INCLUDED__ 83 | -------------------------------------------------------------------------------- /src/xendriver.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-2021 Bitdefender SRL, All rights reserved. 2 | // 3 | // This library is free software; you can redistribute it and/or 4 | // modify it under the terms of the GNU Lesser General Public 5 | // License as published by the Free Software Foundation; either 6 | // version 3.0 of the License, or (at your option) any later version. 7 | // 8 | // This library is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 | // Lesser General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU Lesser General Public 14 | // License along with this library. 15 | 16 | #ifndef __BDVMIXENDRIVER_H_INCLUDED__ 17 | #define __BDVMIXENDRIVER_H_INCLUDED__ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include "bdvmi/driver.h" 26 | #include "bdvmi/pagecache.h" 27 | 28 | #include "xcwrapper.h" 29 | #include "xenaltp2m.h" 30 | #include "xswrapper.h" 31 | 32 | namespace bdvmi { 33 | 34 | class XenDriver : public Driver { 35 | 36 | struct RegsCache { 37 | Registers registers_; 38 | int vcpu_{ -1 }; 39 | bool valid_{ false }; 40 | std::mutex mutex_; 41 | }; 42 | 43 | public: 44 | struct DelayedWrite { 45 | Registers registers_; 46 | bool pending_{ false }; 47 | }; 48 | 49 | public: 50 | // Create a XenDriver object with the domain name 51 | XenDriver( const std::string &uuid, bool altp2m, bool hvmOnly = true ); 52 | 53 | // Create a XenDriver object with the domain ID (# xl list) 54 | XenDriver( domid_t domain, bool altp2m, bool hvmOnly = true ); 55 | 56 | ~XenDriver(); 57 | 58 | public: 59 | bool cpuCount( unsigned int &count ) const override; 60 | 61 | bool tscSpeed( unsigned long long &speed ) const override; 62 | 63 | bool mtrrType( unsigned long long guestAddress, uint8_t &type ) const override; 64 | 65 | bool registers( unsigned short vcpu, Registers ®s ) const override; 66 | 67 | bool setRegisters( unsigned short vcpu, const Registers ®s, bool setEip, bool delay ) override; 68 | 69 | MapReturnCode mapPhysMemToHost( unsigned long long address, size_t length, uint32_t flags, 70 | void *&pointer ) override; 71 | 72 | bool unmapPhysMem( void *hostPtr ) override; 73 | 74 | bool injectTrap( unsigned short vcpu, uint8_t trapNumber, uint32_t errorCode, uint64_t cr2 ) override; 75 | 76 | bool setRepOptimizations( bool enable ) override; 77 | 78 | bool shutdown() override; 79 | 80 | bool pause() override; 81 | 82 | bool unpause() override; 83 | 84 | size_t setPageCacheLimit( size_t limit ) override; 85 | 86 | bool getXSAVESize( unsigned short vcpu, size_t &size ) override; 87 | 88 | bool getXSAVEArea( unsigned short vcpu, void *buffer, size_t bufSize ) override; 89 | 90 | bool getEPTPageConvertible( unsigned short index, unsigned long long address, bool &convertible ) override; 91 | 92 | bool createEPT( unsigned short &index ) override; 93 | 94 | bool destroyEPT( unsigned short index ) override; 95 | 96 | bool switchEPT( unsigned short index ) override; 97 | 98 | bool setVEInfoPage( unsigned short vcpu, unsigned long long gpa ) override; 99 | 100 | bool disableVE( unsigned short vcpu ) override; 101 | 102 | unsigned short eptpIndex( unsigned short vcpu ) const override; 103 | 104 | bool update() override; 105 | 106 | std::string uuid() const override 107 | { 108 | return uuid_; 109 | } 110 | 111 | unsigned int id() const override 112 | { 113 | return domain_; 114 | } 115 | 116 | void enableCache( unsigned short vcpu ) override; 117 | 118 | void disableCache() override; 119 | 120 | void enableP2mIdxCache( unsigned short vcpu, unsigned short idx ); 121 | 122 | void disableP2mIdxCache( unsigned short vcpu ); 123 | 124 | uint32_t startTime() override; 125 | 126 | bool isMsrCached( uint64_t msr ) const override; 127 | 128 | // Does this driver support altp2m #VE? 129 | bool veSupported() const override 130 | { 131 | return !!altp2mState_; 132 | } 133 | 134 | // Does this driver support altp2m VMFUNC? 135 | bool vmfuncSupported() const override 136 | { 137 | return !!altp2mState_; 138 | } 139 | 140 | // Does this driver support Intel SPP? 141 | bool sppSupported() const override 142 | { 143 | return false; 144 | } 145 | 146 | bool dtrEventsSupported() const override 147 | { 148 | return !!xc_.monitorDescriptorAccess && xc_.version >= Version( 4, 11 ); 149 | } 150 | 151 | bool getXCR0( unsigned short vcpu, uint64_t &xcr0 ) const override; 152 | 153 | private: 154 | void *mapGuestPageImpl( unsigned long long gfn ) override; 155 | 156 | void unmapGuestPageImpl( void *hostPtr, unsigned long long gfn ) override; 157 | 158 | bool setPageProtectionImpl( const MemAccessMap &accessMap, unsigned short view ) override; 159 | 160 | bool getPageProtectionImpl( unsigned long long guestAddress, bool &read, bool &write, bool &execute, 161 | unsigned short view ) override; 162 | 163 | bool setPageConvertibleImpl( const ConvertibleMap &convMap, unsigned short view ) override; 164 | 165 | public: // Xen specific-stuff 166 | XC &nativeHandle() const 167 | { 168 | return xc_; 169 | } 170 | 171 | public: 172 | static int32_t guestX86Mode( const Registers ®s ); 173 | 174 | DelayedWrite &delayedWrite() 175 | { 176 | return delayedWrite_; 177 | } 178 | 179 | bool pendingInjection( unsigned short vcpu ) const; 180 | 181 | void clearInjection( unsigned short vcpu ); 182 | 183 | bool altp2mEnabled() const 184 | { 185 | return !!altp2mState_; 186 | } 187 | 188 | public: 189 | // Don't allow copying for these objects (class has xci_) 190 | XenDriver( const XenDriver & ) = delete; 191 | 192 | // Don't allow copying for these objects (class has xci_) 193 | XenDriver &operator=( const XenDriver & ) = delete; 194 | 195 | private: 196 | void init( domid_t domain, bool hvmOnly ); 197 | 198 | static domid_t getDomainId( const std::string &domainName ); 199 | 200 | bool getXSAVEInfo( unsigned short vcpu, struct hvm_hw_cpu_xsave &xsaveInfo ) const; 201 | 202 | bool getPAT( unsigned short vcpu, uint64_t &pat ) const; 203 | 204 | bool isVarMtrrOverlapped( const struct hvm_hw_mtrr &hwMtrr ) const; 205 | 206 | void getMtrrRange( uint64_t base_msr, uint64_t mask_msr, uint64_t &base, uint64_t &end ) const; 207 | 208 | unsigned int cpuid_eax( unsigned int op ) const; 209 | 210 | static std::string queryUuid( XS &xs, const std::string &domain ); 211 | 212 | bool maxGPFNImpl( unsigned long long &gfn, bool &trustworthy ) override; 213 | 214 | private: 215 | mutable XS xs_; 216 | mutable XC xc_; 217 | domid_t domain_; 218 | PageCache pageCache_; 219 | std::string uuid_; 220 | mutable RegsCache regsCache_; 221 | bool update_{ false }; 222 | DelayedWrite delayedWrite_; 223 | std::unordered_map pendingInjections_; 224 | uint32_t startTime_{ static_cast( -1 ) }; 225 | mutable bool patInitialized_{ false }; 226 | mutable uint64_t msrPat_{ 0 }; 227 | unsigned long long maxGPFN_{ 0 }; 228 | XenAltp2mDomainState altp2mState_; 229 | std::function setMemAccess_; 230 | std::function getMemAccess_; 231 | unsigned int physAddr_{ 0 }; 232 | }; 233 | 234 | } // namespace bdvmi 235 | 236 | #endif // __BDVMIXENDRIVER_H_INCLUDED__ 237 | -------------------------------------------------------------------------------- /src/xeneventmanager.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-2019 Bitdefender SRL, All rights reserved. 2 | // 3 | // This library is free software; you can redistribute it and/or 4 | // modify it under the terms of the GNU Lesser General Public 5 | // License as published by the Free Software Foundation; either 6 | // version 3.0 of the License, or (at your option) any later version. 7 | // 8 | // This library is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 | // Lesser General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU Lesser General Public 14 | // License along with this library. 15 | 16 | #ifndef __BDVMIXENEVENTMANAGER_H_INCLUDED__ 17 | #define __BDVMIXENEVENTMANAGER_H_INCLUDED__ 18 | 19 | #include "bdvmi/eventhandler.h" 20 | #include "bdvmi/eventmanager.h" 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | extern "C" { 27 | #define private rprivate /* private is a C++ keyword */ 28 | #include 29 | #undef private 30 | } 31 | 32 | #include "xcwrapper.h" 33 | #include "xswrapper.h" 34 | 35 | namespace bdvmi { 36 | 37 | class XenDriver; 38 | 39 | class XenEventManager : public EventManager { 40 | 41 | public: 42 | XenEventManager( XenDriver &driver, sig_atomic_t &sigStop ); 43 | 44 | virtual ~XenEventManager(); 45 | 46 | public: 47 | // Loop waiting for events 48 | void waitForEvents() override; 49 | 50 | // Stop the event loop 51 | void stop() override; 52 | 53 | private: 54 | bool enableMsrEventsImpl( unsigned int msr ) override; 55 | 56 | bool disableMsrEventsImpl( unsigned int msr ) override; 57 | 58 | bool enableCrEventsImpl( unsigned int cr ) override; 59 | 60 | bool disableCrEventsImpl( unsigned int cr ) override; 61 | 62 | bool enableXSETBVEventsImpl() override; 63 | 64 | bool disableXSETBVEventsImpl() override; 65 | 66 | bool enableBreakpointEventsImpl() override; 67 | 68 | bool disableBreakpointEventsImpl() override; 69 | 70 | bool enableVMCALLEventsImpl() override; 71 | 72 | bool disableVMCALLEventsImpl() override; 73 | 74 | bool enableDescriptorEventsImpl() override; 75 | 76 | bool disableDescriptorEventsImpl() override; 77 | 78 | private: 79 | void initXenStore(); 80 | 81 | void initEventChannels(); 82 | 83 | void initMemAccess(); 84 | 85 | int waitForEventOrTimeout( int ms ); 86 | 87 | template void getRequest( Request &req ); 88 | 89 | template void putResponse( const Response &rsp ); 90 | 91 | void resumePage(); 92 | 93 | std::string uuid() override; 94 | 95 | void cleanup(); 96 | 97 | template void setRegisters( Response &rsp ); 98 | 99 | bool setCrEvents( unsigned int cr, bool enable ); 100 | 101 | uint64_t getMsr( unsigned short vcpu, uint32_t msr ) const; 102 | 103 | template void waitForEventsByVMEventVersion(); 104 | 105 | template 106 | void handleMemAccess( const Request &req, Response &rsp, bool &skip ); 107 | 108 | template void handleCrWrite( const Request &req, Response &rsp ); 109 | 110 | template void handleMsrWrite( const Request &req, Response &rsp ); 111 | 112 | template 113 | void handleDescriptorWrite( const Request &req, Response &rsp, bool &skip ); 114 | 115 | template void handleBreakpoint( const Request &req ); 116 | 117 | public: 118 | // Don't allow copying for these objects 119 | XenEventManager( const XenEventManager & ) = delete; 120 | 121 | // Don't allow copying for these objects 122 | XenEventManager &operator=( const XenEventManager & ) = delete; 123 | 124 | private: 125 | XenDriver & driver_; 126 | XC & xc_; 127 | domid_t domain_; 128 | bool stop_{ false }; 129 | xc_evtchn * xce_{ nullptr }; 130 | int port_{ -1 }; 131 | XS xs_; 132 | uint32_t evtchnPort_{ 0 }; 133 | void * backRing_{ nullptr }; 134 | void * ringPage_{ nullptr }; 135 | std::string watchToken_; 136 | std::string controlXenStorePath_; 137 | bool memAccessOn_{ false }; 138 | bool evtchnOn_{ false }; 139 | bool evtchnBindOn_{ false }; 140 | bool firstReleaseWatch_{ true }; 141 | bool firstControlCommand_{ true }; 142 | bool foundEvents_{ false }; 143 | bool handleEmulUnimplemented_{ false }; 144 | uint32_t vmEventInterfaceVersion_{ 0 }; 145 | GuestState guestState_{ RUNNING }; 146 | 147 | using msrs_values_map_t = std::unordered_map; 148 | using vcpu_msrs_t = std::unordered_map; 149 | vcpu_msrs_t msrOldValueCache_; 150 | 151 | using p2m_idx_values_map_t = std::unordered_map; 152 | p2m_idx_values_map_t singlestepP2mIdx; 153 | 154 | #ifdef DEBUG_DUMP_EVENTS 155 | std::ofstream eventsFile_; 156 | #endif 157 | }; 158 | 159 | } // namespace bdvmi 160 | 161 | #endif // __BDVMIXENEVENTMANAGER_H_INCLUDED__ 162 | -------------------------------------------------------------------------------- /src/xenvmevent_v3.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-2019 Bitdefender SRL, All rights reserved. 2 | // 3 | // This library is free software; you can redistribute it and/or 4 | // modify it under the terms of the GNU Lesser General Public 5 | // License as published by the Free Software Foundation; either 6 | // version 3.0 of the License, or (at your option) any later version. 7 | // 8 | // This library is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 | // Lesser General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU Lesser General Public 14 | // License along with this library. 15 | 16 | #ifndef __XEN_PUBLIC_VM_EVENT_V3_H_INCLUDED__ 17 | #define __XEN_PUBLIC_VM_EVENT_V3_H_INCLUDED__ 18 | 19 | #ifdef __cplusplus 20 | extern "C" { 21 | #endif 22 | 23 | #include 24 | 25 | struct vm_event_regs_x86_v3 { 26 | uint64_t rax; 27 | uint64_t rcx; 28 | uint64_t rdx; 29 | uint64_t rbx; 30 | uint64_t rsp; 31 | uint64_t rbp; 32 | uint64_t rsi; 33 | uint64_t rdi; 34 | uint64_t r8; 35 | uint64_t r9; 36 | uint64_t r10; 37 | uint64_t r11; 38 | uint64_t r12; 39 | uint64_t r13; 40 | uint64_t r14; 41 | uint64_t r15; 42 | uint64_t rflags; 43 | uint64_t dr7; 44 | uint64_t rip; 45 | uint64_t cr0; 46 | uint64_t cr2; 47 | uint64_t cr3; 48 | uint64_t cr4; 49 | uint64_t sysenter_cs; 50 | uint64_t sysenter_esp; 51 | uint64_t sysenter_eip; 52 | uint64_t msr_efer; 53 | uint64_t msr_star; 54 | uint64_t msr_lstar; 55 | uint64_t fs_base; 56 | uint64_t gs_base; 57 | uint32_t cs_arbytes; 58 | uint32_t _pad; 59 | }; 60 | 61 | struct vm_event_regs_arm_v3 { 62 | uint64_t ttbr0; 63 | uint64_t ttbr1; 64 | uint64_t ttbcr; 65 | uint64_t pc; 66 | uint32_t cpsr; 67 | uint32_t _pad; 68 | }; 69 | 70 | struct vm_event_mem_access_v3 { 71 | uint64_t gfn; 72 | uint64_t offset; 73 | uint64_t gla; /* if flags has MEM_ACCESS_GLA_VALID set */ 74 | uint32_t flags; /* MEM_ACCESS_* */ 75 | uint32_t _pad; 76 | }; 77 | 78 | struct vm_event_write_ctrlreg_v3 { 79 | uint32_t index; 80 | uint32_t _pad; 81 | uint64_t new_value; 82 | uint64_t old_value; 83 | }; 84 | 85 | struct vm_event_singlestep_v3 { 86 | uint64_t gfn; 87 | }; 88 | 89 | struct vm_event_debug_v3 { 90 | uint64_t gfn; 91 | uint32_t insn_length; 92 | uint8_t type; /* HVMOP_TRAP_* */ 93 | uint8_t _pad[3]; 94 | }; 95 | 96 | struct vm_event_mov_to_msr_v3 { 97 | uint64_t msr; 98 | uint64_t new_value; 99 | uint64_t old_value; 100 | }; 101 | 102 | struct vm_event_desc_access_v3 { 103 | union { 104 | struct { 105 | uint32_t instr_info; /* VMX: VMCS Instruction-Information */ 106 | uint32_t _pad1; 107 | uint64_t exit_qualification; /* VMX: VMCS Exit Qualification */ 108 | } vmx; 109 | struct { 110 | uint64_t exitinfo; /* SVM: VMCB EXITINFO */ 111 | uint64_t _pad2; 112 | } svm; 113 | } arch; 114 | uint8_t descriptor; /* VM_EVENT_DESC_* */ 115 | uint8_t is_write; 116 | uint8_t _pad[6]; 117 | }; 118 | 119 | struct vm_event_cpuid_v3 { 120 | uint32_t insn_length; 121 | uint32_t leaf; 122 | uint32_t subleaf; 123 | uint32_t _pad; 124 | }; 125 | 126 | struct vm_event_interrupt_x86_v3 { 127 | uint32_t vector; 128 | uint32_t type; 129 | uint32_t error_code; 130 | uint32_t _pad; 131 | uint64_t cr2; 132 | }; 133 | 134 | struct vm_event_paging_v3 { 135 | uint64_t gfn; 136 | uint32_t p2mt; 137 | uint32_t flags; 138 | }; 139 | 140 | struct vm_event_sharing_v3 { 141 | uint64_t gfn; 142 | uint32_t p2mt; 143 | uint32_t _pad; 144 | }; 145 | 146 | struct vm_event_emul_read_data_v3 { 147 | uint32_t size; 148 | /* The struct is used in a union with vm_event_regs_x86. */ 149 | uint8_t data[sizeof(struct vm_event_regs_x86_v3) - sizeof(uint32_t)]; 150 | }; 151 | 152 | struct vm_event_emul_insn_data_v3 { 153 | uint8_t data[16]; /* Has to be completely filled */ 154 | }; 155 | 156 | typedef struct vm_event_st_v3 { 157 | uint32_t version; /* VM_EVENT_INTERFACE_VERSION */ 158 | uint32_t flags; /* VM_EVENT_FLAG_* */ 159 | uint32_t reason; /* VM_EVENT_REASON_* */ 160 | uint32_t vcpu_id; 161 | uint16_t altp2m_idx; /* may be used during request and response */ 162 | uint16_t _pad[3]; 163 | 164 | union { 165 | struct vm_event_paging_v3 mem_paging; 166 | struct vm_event_sharing_v3 mem_sharing; 167 | struct vm_event_mem_access_v3 mem_access; 168 | struct vm_event_write_ctrlreg_v3 write_ctrlreg; 169 | struct vm_event_mov_to_msr_v3 mov_to_msr; 170 | struct vm_event_desc_access_v3 desc_access; 171 | struct vm_event_singlestep_v3 singlestep; 172 | struct vm_event_debug_v3 software_breakpoint; 173 | struct vm_event_debug_v3 debug_exception; 174 | struct vm_event_cpuid_v3 cpuid; 175 | union { 176 | struct vm_event_interrupt_x86_v3 x86; 177 | } interrupt; 178 | } u; 179 | 180 | union { 181 | union { 182 | struct vm_event_regs_x86_v3 x86; 183 | struct vm_event_regs_arm_v3 arm; 184 | } regs; 185 | 186 | union { 187 | struct vm_event_emul_read_data_v3 read; 188 | struct vm_event_emul_insn_data_v3 insn; 189 | } emul; 190 | } data; 191 | } vm_event_request_v3_t, vm_event_response_v3_t; 192 | 193 | DEFINE_RING_TYPES(vm_event_v3, vm_event_request_v3_t, vm_event_response_v3_t); 194 | 195 | #ifdef __cplusplus 196 | } 197 | #endif 198 | 199 | #endif // __XEN_PUBLIC_VM_EVENT_V3_H_INCLUDED__ 200 | -------------------------------------------------------------------------------- /src/xenvmevent_v4.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-2019 Bitdefender SRL, All rights reserved. 2 | // 3 | // This library is free software; you can redistribute it and/or 4 | // modify it under the terms of the GNU Lesser General Public 5 | // License as published by the Free Software Foundation; either 6 | // version 3.0 of the License, or (at your option) any later version. 7 | // 8 | // This library is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 | // Lesser General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU Lesser General Public 14 | // License along with this library. 15 | 16 | #ifndef __XEN_PUBLIC_VM_EVENT_V4_H_INCLUDED__ 17 | #define __XEN_PUBLIC_VM_EVENT_V4_H_INCLUDED__ 18 | 19 | #ifdef __cplusplus 20 | extern "C" { 21 | #endif 22 | 23 | #include 24 | 25 | /* The limit field is right-shifted by 12 bits if .ar.g is set. */ 26 | struct vm_event_x86_selector_reg_v4 { 27 | uint32_t limit : 20; 28 | uint32_t ar : 12; 29 | }; 30 | 31 | struct vm_event_regs_x86_v4 { 32 | uint64_t rax; 33 | uint64_t rcx; 34 | uint64_t rdx; 35 | uint64_t rbx; 36 | uint64_t rsp; 37 | uint64_t rbp; 38 | uint64_t rsi; 39 | uint64_t rdi; 40 | uint64_t r8; 41 | uint64_t r9; 42 | uint64_t r10; 43 | uint64_t r11; 44 | uint64_t r12; 45 | uint64_t r13; 46 | uint64_t r14; 47 | uint64_t r15; 48 | uint64_t rflags; 49 | uint64_t dr6; 50 | uint64_t dr7; 51 | uint64_t rip; 52 | uint64_t cr0; 53 | uint64_t cr2; 54 | uint64_t cr3; 55 | uint64_t cr4; 56 | uint64_t sysenter_cs; 57 | uint64_t sysenter_esp; 58 | uint64_t sysenter_eip; 59 | uint64_t msr_efer; 60 | uint64_t msr_star; 61 | uint64_t msr_lstar; 62 | uint32_t cs_base; 63 | uint32_t ss_base; 64 | uint32_t ds_base; 65 | uint32_t es_base; 66 | uint64_t fs_base; 67 | uint64_t gs_base; 68 | struct vm_event_x86_selector_reg_v4 cs; 69 | struct vm_event_x86_selector_reg_v4 ss; 70 | struct vm_event_x86_selector_reg_v4 ds; 71 | struct vm_event_x86_selector_reg_v4 es; 72 | struct vm_event_x86_selector_reg_v4 fs; 73 | struct vm_event_x86_selector_reg_v4 gs; 74 | uint64_t shadow_gs; 75 | uint16_t cs_sel; 76 | uint16_t ss_sel; 77 | uint16_t ds_sel; 78 | uint16_t es_sel; 79 | uint16_t fs_sel; 80 | uint16_t gs_sel; 81 | uint32_t _pad; 82 | }; 83 | 84 | struct vm_event_regs_arm_v4 { 85 | uint64_t ttbr0; 86 | uint64_t ttbr1; 87 | uint64_t ttbcr; 88 | uint64_t pc; 89 | uint32_t cpsr; 90 | uint32_t _pad; 91 | }; 92 | 93 | struct vm_event_mem_access_v4 { 94 | uint64_t gfn; 95 | uint64_t offset; 96 | uint64_t gla; /* if flags has MEM_ACCESS_GLA_VALID set */ 97 | uint32_t flags; /* MEM_ACCESS_* */ 98 | uint32_t _pad; 99 | }; 100 | 101 | struct vm_event_write_ctrlreg_v4 { 102 | uint32_t index; 103 | uint32_t _pad; 104 | uint64_t new_value; 105 | uint64_t old_value; 106 | }; 107 | 108 | struct vm_event_singlestep_v4 { 109 | uint64_t gfn; 110 | }; 111 | 112 | struct vm_event_debug_v4 { 113 | uint64_t gfn; 114 | uint32_t insn_length; 115 | uint8_t type; /* HVMOP_TRAP_* */ 116 | uint8_t _pad[3]; 117 | }; 118 | 119 | struct vm_event_mov_to_msr_v4 { 120 | uint64_t msr; 121 | uint64_t new_value; 122 | uint64_t old_value; 123 | }; 124 | 125 | struct vm_event_desc_access_v4 { 126 | union { 127 | struct { 128 | uint32_t instr_info; /* VMX: VMCS Instruction-Information */ 129 | uint32_t _pad1; 130 | uint64_t exit_qualification; /* VMX: VMCS Exit Qualification */ 131 | } vmx; 132 | struct { 133 | uint64_t exitinfo; /* SVM: VMCB EXITINFO */ 134 | uint64_t _pad2; 135 | } svm; 136 | } arch; 137 | uint8_t descriptor; /* VM_EVENT_DESC_* */ 138 | uint8_t is_write; 139 | uint8_t _pad[6]; 140 | }; 141 | 142 | struct vm_event_cpuid_v4 { 143 | uint32_t insn_length; 144 | uint32_t leaf; 145 | uint32_t subleaf; 146 | uint32_t _pad; 147 | }; 148 | 149 | struct vm_event_interrupt_x86_v4 { 150 | uint32_t vector; 151 | uint32_t type; 152 | uint32_t error_code; 153 | uint32_t _pad; 154 | uint64_t cr2; 155 | }; 156 | 157 | struct vm_event_paging_v4 { 158 | uint64_t gfn; 159 | uint32_t p2mt; 160 | uint32_t flags; 161 | }; 162 | 163 | struct vm_event_sharing_v4 { 164 | uint64_t gfn; 165 | uint32_t p2mt; 166 | uint32_t _pad; 167 | }; 168 | 169 | struct vm_event_emul_read_data_v4 { 170 | uint32_t size; 171 | /* The struct is used in a union with vm_event_regs_x86. */ 172 | uint8_t data[sizeof(struct vm_event_regs_x86_v4) - sizeof(uint32_t)]; 173 | }; 174 | 175 | struct vm_event_emul_insn_data_v4 { 176 | uint8_t data[16]; /* Has to be completely filled */ 177 | }; 178 | 179 | typedef struct vm_event_st_v4 { 180 | uint32_t version; /* VM_EVENT_INTERFACE_VERSION */ 181 | uint32_t flags; /* VM_EVENT_FLAG_* */ 182 | uint32_t reason; /* VM_EVENT_REASON_* */ 183 | uint32_t vcpu_id; 184 | uint16_t altp2m_idx; /* may be used during request and response */ 185 | uint16_t _pad[3]; 186 | 187 | union { 188 | struct vm_event_paging_v4 mem_paging; 189 | struct vm_event_sharing_v4 mem_sharing; 190 | struct vm_event_mem_access_v4 mem_access; 191 | struct vm_event_write_ctrlreg_v4 write_ctrlreg; 192 | struct vm_event_mov_to_msr_v4 mov_to_msr; 193 | struct vm_event_desc_access_v4 desc_access; 194 | struct vm_event_singlestep_v4 singlestep; 195 | struct vm_event_debug_v4 software_breakpoint; 196 | struct vm_event_debug_v4 debug_exception; 197 | struct vm_event_cpuid_v4 cpuid; 198 | union { 199 | struct vm_event_interrupt_x86_v4 x86; 200 | } interrupt; 201 | } u; 202 | 203 | union { 204 | union { 205 | struct vm_event_regs_x86_v4 x86; 206 | struct vm_event_regs_arm_v4 arm; 207 | } regs; 208 | 209 | union { 210 | struct vm_event_emul_read_data_v4 read; 211 | struct vm_event_emul_insn_data_v4 insn; 212 | } emul; 213 | } data; 214 | } vm_event_request_v4_t, vm_event_response_v4_t; 215 | 216 | DEFINE_RING_TYPES(vm_event_v4, vm_event_request_v4_t, vm_event_response_v4_t); 217 | 218 | #ifdef __cplusplus 219 | } 220 | #endif 221 | 222 | #endif // __XEN_PUBLIC_VM_EVENT_V4_H_INCLUDED__ 223 | -------------------------------------------------------------------------------- /src/xenvmevent_v5.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-2019 Bitdefender SRL, All rights reserved. 2 | // 3 | // This library is free software; you can redistribute it and/or 4 | // modify it under the terms of the GNU Lesser General Public 5 | // License as published by the Free Software Foundation; either 6 | // version 3.0 of the License, or (at your option) any later version. 7 | // 8 | // This library is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 | // Lesser General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU Lesser General Public 14 | // License along with this library. 15 | 16 | #ifndef __XEN_PUBLIC_VM_EVENT_V5_H_INCLUDED__ 17 | #define __XEN_PUBLIC_VM_EVENT_V5_H_INCLUDED__ 18 | 19 | #ifdef __cplusplus 20 | extern "C" { 21 | #endif 22 | 23 | #include 24 | 25 | /* The limit field is right-shifted by 12 bits if .ar.g is set. */ 26 | struct vm_event_x86_selector_reg_v5 { 27 | uint32_t limit : 20; 28 | uint32_t ar : 12; 29 | }; 30 | 31 | struct vm_event_regs_x86_v5 { 32 | uint64_t rax; 33 | uint64_t rcx; 34 | uint64_t rdx; 35 | uint64_t rbx; 36 | uint64_t rsp; 37 | uint64_t rbp; 38 | uint64_t rsi; 39 | uint64_t rdi; 40 | uint64_t r8; 41 | uint64_t r9; 42 | uint64_t r10; 43 | uint64_t r11; 44 | uint64_t r12; 45 | uint64_t r13; 46 | uint64_t r14; 47 | uint64_t r15; 48 | uint64_t rflags; 49 | uint64_t dr6; 50 | uint64_t dr7; 51 | uint64_t rip; 52 | uint64_t cr0; 53 | uint64_t cr2; 54 | uint64_t cr3; 55 | uint64_t cr4; 56 | uint64_t sysenter_cs; 57 | uint64_t sysenter_esp; 58 | uint64_t sysenter_eip; 59 | uint64_t msr_efer; 60 | uint64_t msr_star; 61 | uint64_t msr_lstar; 62 | uint64_t gdtr_base; 63 | uint32_t cs_base; 64 | uint32_t ss_base; 65 | uint32_t ds_base; 66 | uint32_t es_base; 67 | uint64_t fs_base; 68 | uint64_t gs_base; 69 | struct vm_event_x86_selector_reg_v5 cs; 70 | struct vm_event_x86_selector_reg_v5 ss; 71 | struct vm_event_x86_selector_reg_v5 ds; 72 | struct vm_event_x86_selector_reg_v5 es; 73 | struct vm_event_x86_selector_reg_v5 fs; 74 | struct vm_event_x86_selector_reg_v5 gs; 75 | uint64_t shadow_gs; 76 | uint16_t gdtr_limit; 77 | uint16_t cs_sel; 78 | uint16_t ss_sel; 79 | uint16_t ds_sel; 80 | uint16_t es_sel; 81 | uint16_t fs_sel; 82 | uint16_t gs_sel; 83 | uint16_t _pad; 84 | }; 85 | 86 | struct vm_event_regs_arm_v5 { 87 | uint64_t ttbr0; 88 | uint64_t ttbr1; 89 | uint64_t ttbcr; 90 | uint64_t pc; 91 | uint32_t cpsr; 92 | uint32_t _pad; 93 | }; 94 | 95 | struct vm_event_mem_access_v5 { 96 | uint64_t gfn; 97 | uint64_t offset; 98 | uint64_t gla; /* if flags has MEM_ACCESS_GLA_VALID set */ 99 | uint32_t flags; /* MEM_ACCESS_* */ 100 | uint32_t _pad; 101 | }; 102 | 103 | struct vm_event_write_ctrlreg_v5 { 104 | uint32_t index; 105 | uint32_t _pad; 106 | uint64_t new_value; 107 | uint64_t old_value; 108 | }; 109 | 110 | struct vm_event_singlestep_v5 { 111 | uint64_t gfn; 112 | }; 113 | 114 | struct vm_event_debug_v5 { 115 | uint64_t gfn; 116 | uint32_t insn_length; 117 | uint8_t type; /* HVMOP_TRAP_* */ 118 | uint8_t _pad[3]; 119 | }; 120 | 121 | struct vm_event_mov_to_msr_v5 { 122 | uint64_t msr; 123 | uint64_t new_value; 124 | uint64_t old_value; 125 | }; 126 | 127 | struct vm_event_desc_access_v5 { 128 | union { 129 | struct { 130 | uint32_t instr_info; /* VMX: VMCS Instruction-Information */ 131 | uint32_t _pad1; 132 | uint64_t exit_qualification; /* VMX: VMCS Exit Qualification */ 133 | } vmx; 134 | struct { 135 | uint64_t exitinfo; /* SVM: VMCB EXITINFO */ 136 | uint64_t _pad2; 137 | } svm; 138 | } arch; 139 | uint8_t descriptor; /* VM_EVENT_DESC_* */ 140 | uint8_t is_write; 141 | uint8_t _pad[6]; 142 | }; 143 | 144 | struct vm_event_cpuid_v5 { 145 | uint32_t insn_length; 146 | uint32_t leaf; 147 | uint32_t subleaf; 148 | uint32_t _pad; 149 | }; 150 | 151 | struct vm_event_interrupt_x86_v5 { 152 | uint32_t vector; 153 | uint32_t type; 154 | uint32_t error_code; 155 | uint32_t _pad; 156 | uint64_t cr2; 157 | }; 158 | 159 | struct vm_event_paging_v5 { 160 | uint64_t gfn; 161 | uint32_t p2mt; 162 | uint32_t flags; 163 | }; 164 | 165 | struct vm_event_sharing_v5 { 166 | uint64_t gfn; 167 | uint32_t p2mt; 168 | uint32_t _pad; 169 | }; 170 | 171 | struct vm_event_emul_read_data_v5 { 172 | uint32_t size; 173 | /* The struct is used in a union with vm_event_regs_x86. */ 174 | uint8_t data[sizeof(struct vm_event_regs_x86_v5) - sizeof(uint32_t)]; 175 | }; 176 | 177 | struct vm_event_emul_insn_data_v5 { 178 | uint8_t data[16]; /* Has to be completely filled */ 179 | }; 180 | 181 | typedef struct vm_event_st_v5 { 182 | uint32_t version; /* VM_EVENT_INTERFACE_VERSION */ 183 | uint32_t flags; /* VM_EVENT_FLAG_* */ 184 | uint32_t reason; /* VM_EVENT_REASON_* */ 185 | uint32_t vcpu_id; 186 | uint16_t altp2m_idx; /* may be used during request and response */ 187 | uint16_t _pad[3]; 188 | 189 | union { 190 | struct vm_event_paging_v5 mem_paging; 191 | struct vm_event_sharing_v5 mem_sharing; 192 | struct vm_event_mem_access_v5 mem_access; 193 | struct vm_event_write_ctrlreg_v5 write_ctrlreg; 194 | struct vm_event_mov_to_msr_v5 mov_to_msr; 195 | struct vm_event_desc_access_v5 desc_access; 196 | struct vm_event_singlestep_v5 singlestep; 197 | struct vm_event_debug_v5 software_breakpoint; 198 | struct vm_event_debug_v5 debug_exception; 199 | struct vm_event_cpuid_v5 cpuid; 200 | union { 201 | struct vm_event_interrupt_x86_v5 x86; 202 | } interrupt; 203 | } u; 204 | 205 | union { 206 | union { 207 | struct vm_event_regs_x86_v5 x86; 208 | struct vm_event_regs_arm_v5 arm; 209 | } regs; 210 | 211 | union { 212 | struct vm_event_emul_read_data_v5 read; 213 | struct vm_event_emul_insn_data_v5 insn; 214 | } emul; 215 | } data; 216 | } vm_event_request_v5_t, vm_event_response_v5_t; 217 | 218 | DEFINE_RING_TYPES(vm_event_v5, vm_event_request_v5_t, vm_event_response_v5_t); 219 | 220 | #ifdef __cplusplus 221 | } 222 | #endif 223 | 224 | #endif // __XEN_PUBLIC_VM_EVENT_V5_H_INCLUDED__ 225 | -------------------------------------------------------------------------------- /src/xswrapper.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-2019 Bitdefender SRL, All rights reserved. 2 | // 3 | // This library is free software; you can redistribute it and/or 4 | // modify it under the terms of the GNU Lesser General Public 5 | // License as published by the Free Software Foundation; either 6 | // version 3.0 of the License, or (at your option) any later version. 7 | // 8 | // This library is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 | // Lesser General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU Lesser General Public 14 | // License along with this library. 15 | 16 | #include "dynamiclibfactory.h" 17 | #include "utils.h" 18 | #include "xswrapper.h" 19 | 20 | extern "C" { 21 | #include 22 | } 23 | 24 | namespace bdvmi { 25 | 26 | using xs_open_fn_t = struct xs_handle *( unsigned long ); 27 | using xs_close_fn_t = void( struct xs_handle * ); 28 | 29 | using xs_read_timeout_fn_t = PrependArg::type; 30 | using xs_write_fn_t = PrependArg::type; 31 | using xs_directory_fn_t = PrependArg::type; 32 | using xs_watch_fn_t = PrependArg::type; 33 | using xs_unwatch_fn_t = PrependArg::type; 34 | using xs_rm_fn_t = PrependArg::type; 35 | using xs_fileno_fn_t = PrependArg::type; 36 | using xs_read_watch_fn_t = PrependArg::type; 37 | using xs_transaction_start_fn_t = PrependArg::type; 38 | using xs_transaction_end_fn_t = PrependArg::type; 39 | using xs_is_domain_introduced_fn_t = PrependArg::type; 40 | 41 | constexpr char xs_open_fn_name[] = "xs_open"; 42 | constexpr char xs_close_fn_name[] = "xs_close"; 43 | constexpr char xs_read_fn_name[] = "xs_read"; 44 | constexpr char xs_write_fn_name[] = "xs_write"; 45 | constexpr char xs_directory_fn_name[] = "xs_directory"; 46 | constexpr char xs_watch_fn_name[] = "xs_watch"; 47 | constexpr char xs_unwatch_fn_name[] = "xs_unwatch"; 48 | constexpr char xs_rm_fn_name[] = "xs_rm"; 49 | constexpr char xs_fileno_fn_name[] = "xs_fileno"; 50 | constexpr char xs_read_watch_fn_name[] = "xs_read_watch"; 51 | constexpr char xs_transaction_start_fn_name[] = "xs_transaction_start"; 52 | constexpr char xs_transaction_end_fn_name[] = "xs_transaction_end"; 53 | constexpr char xs_is_domain_introduced_fn_name[] = "xs_is_domain_introduced"; 54 | 55 | constexpr char xs_read_timeout_fn_name[] = "xs_read_timeout"; 56 | 57 | struct XSFactory; 58 | 59 | template struct XSFactoryImpl { 60 | static std::function lookup( const XSFactory *p, bool required ); 61 | }; 62 | 63 | class XSFactory { 64 | public: 65 | static XSFactory &instance(); 66 | 67 | DynamicLibFactory lib_; 68 | std::unique_ptr createHandle() const; 69 | 70 | template std::function lookup( bool required = true ) const 71 | { 72 | return XSFactoryImpl::lookup( this, required ); 73 | } 74 | 75 | std::function readTimeout; 76 | std::function write; 77 | std::function directory; 78 | std::function watch; 79 | std::function unwatch; 80 | std::function rm; 81 | std::function fileno; 82 | std::function readWatch; 83 | std::function transactionStart; 84 | std::function transactionEnd; 85 | std::function isDomainIntroduced; 86 | 87 | private: 88 | XSFactory(); 89 | }; 90 | 91 | XSFactory &XSFactory::instance() 92 | { 93 | static XSFactory instance; 94 | return instance; 95 | } 96 | 97 | XSFactory::XSFactory() 98 | : lib_{ "libxenstore.so" } 99 | , readTimeout{ lookup() } 100 | , write{ lookup() } 101 | , directory{ lookup() } 102 | , watch{ lookup() } 103 | , unwatch{ lookup() } 104 | , rm{ lookup() } 105 | , fileno{ lookup() } 106 | , readWatch{ lookup() } 107 | , transactionStart{ lookup() } 108 | , transactionEnd{ lookup() } 109 | , isDomainIntroduced{ lookup() } 110 | { 111 | } 112 | 113 | std::unique_ptr XSFactory::createHandle() const 114 | { 115 | auto open_fn = lib_.lookup(); 116 | auto close_fn = lib_.lookup(); 117 | 118 | xs_handle *xsh = open_fn( 0 ); 119 | if ( !xsh ) 120 | throw std::runtime_error( "xs_open() failed" ); 121 | return std::unique_ptr( xsh, close_fn ); 122 | } 123 | 124 | template 125 | std::function XSFactoryImpl::lookup( const XSFactory *p, bool required ) 126 | { 127 | return p->lib_.lookup( required ); 128 | } 129 | 130 | template <> struct XSFactoryImpl { 131 | static std::function lookup( const XSFactory *p, bool ) 132 | { 133 | using fn_t = void *( struct xs_handle *, xs_transaction_t, const char *, unsigned int * ); 134 | fn_t *fn = p->lib_.lookup(); 135 | return [fn]( xs_handle *xsh, xs_transaction_t t, const std::string &path, unsigned int *len, 136 | unsigned int timeout ) { 137 | struct timespec tim, tim2; 138 | const long nanosec_sleep = 1000000; 139 | float seconds_timeout = timeout; 140 | void * ret = nullptr; 141 | int saved_errno; 142 | 143 | do { 144 | tim.tv_sec = 0; 145 | tim.tv_nsec = nanosec_sleep; 146 | 147 | ret = fn( xsh, t, path.c_str(), len ); 148 | 149 | if ( ret || errno != EPERM ) 150 | break; 151 | 152 | saved_errno = errno; 153 | 154 | if ( nanosleep( &tim, &tim2 ) != 0 && errno == EINTR ) 155 | tim.tv_nsec -= tim2.tv_nsec; 156 | 157 | errno = saved_errno; 158 | seconds_timeout -= 1.0e-9 * tim.tv_nsec; 159 | 160 | } while ( seconds_timeout > 0 ); 161 | 162 | return ret; 163 | }; 164 | } 165 | }; 166 | 167 | template <> struct XSFactoryImpl { 168 | static std::function lookup( const XSFactory *p, bool ) 169 | { 170 | using fn_t = bool( struct xs_handle *, xs_transaction_t, const char *, const void *, unsigned int ); 171 | fn_t *fn = p->lib_.lookup(); 172 | return [fn]( xs_handle *xsh, xs_transaction_t t, const std::string &path, const void *data, 173 | unsigned int len ) { return fn( xsh, t, path.c_str(), data, len ); }; 174 | } 175 | }; 176 | 177 | template <> struct XSFactoryImpl { 178 | static std::function lookup( const XSFactory *p, bool ) 179 | { 180 | using fn_t = char **( struct xs_handle *, xs_transaction_t, const char *, unsigned int * ); 181 | fn_t *fn = p->lib_.lookup(); 182 | return 183 | [fn]( xs_handle *xsh, xs_transaction_t t, const std::string &path, std::vector &dir ) { 184 | unsigned int count = 0; 185 | CUniquePtr res( fn( xsh, t, path.c_str(), &count ) ); 186 | 187 | if ( !res ) 188 | return false; 189 | 190 | dir.reserve( count ); 191 | std::copy( res.get(), res.get() + count, std::back_inserter( dir ) ); 192 | 193 | return true; 194 | }; 195 | } 196 | }; 197 | 198 | template <> struct XSFactoryImpl { 199 | static std::function lookup( const XSFactory *p, bool ) 200 | { 201 | using fn_t = bool( struct xs_handle *, const char *, const char * ); 202 | fn_t *fn = p->lib_.lookup(); 203 | return [fn]( xs_handle *xsh, const std::string &path, const std::string &token ) { 204 | return fn( xsh, path.c_str(), token.c_str() ); 205 | }; 206 | } 207 | }; 208 | 209 | template <> struct XSFactoryImpl { 210 | static std::function lookup( const XSFactory *p, bool ) 211 | { 212 | using fn_t = bool( struct xs_handle *, const char *, const char * ); 213 | fn_t *fn = p->lib_.lookup(); 214 | return [fn]( xs_handle *xsh, const std::string &path, const std::string &token ) { 215 | return fn( xsh, path.c_str(), token.c_str() ); 216 | }; 217 | } 218 | }; 219 | 220 | template <> struct XSFactoryImpl { 221 | static std::function lookup( const XSFactory *p, bool ) 222 | { 223 | using fn_t = bool( struct xs_handle *, xs_transaction_t, const char * ); 224 | fn_t *fn = p->lib_.lookup(); 225 | return [fn]( xs_handle *xsh, xs_transaction_t t, const std::string &path ) { 226 | return fn( xsh, t, path.c_str() ); 227 | }; 228 | } 229 | }; 230 | 231 | template <> struct XSFactoryImpl { 232 | static std::function lookup( const XSFactory *p, bool ) 233 | { 234 | using fn_t = char **( struct xs_handle *, unsigned int * ); 235 | fn_t *fn = p->lib_.lookup(); 236 | return [fn]( xs_handle *xsh, std::vector &watch ) { 237 | unsigned int num = 0; 238 | CUniquePtr res( fn( xsh, &num ) ); 239 | 240 | if ( !res ) 241 | return false; 242 | 243 | watch.reserve( num ); 244 | std::copy( res.get(), res.get() + num, std::back_inserter( watch ) ); 245 | 246 | return true; 247 | }; 248 | } 249 | }; 250 | 251 | const xs_transaction_t XS::xbtNull = XBT_NULL; 252 | const uint32_t XS::watchPath = XS_WATCH_PATH; 253 | const uint32_t XS::watchToken = XS_WATCH_TOKEN; 254 | 255 | using namespace std::placeholders; 256 | 257 | XS::XS() 258 | : xsh_{ XSFactory::instance().createHandle() } 259 | , readTimeout{ std::bind( XSFactory::instance().readTimeout, xsh_.get(), _1, _2, _3, _4 ) } 260 | , write{ std::bind( XSFactory::instance().write, xsh_.get(), _1, _2, _3, _4 ) } 261 | , directory{ std::bind( XSFactory::instance().directory, xsh_.get(), _1, _2, _3 ) } 262 | , watch{ std::bind( XSFactory::instance().watch, xsh_.get(), _1, _2 ) } 263 | , unwatch{ std::bind( XSFactory::instance().unwatch, xsh_.get(), _1, _2 ) } 264 | , rm{ std::bind( XSFactory::instance().rm, xsh_.get(), _1, _2 ) } 265 | , fileno{ std::bind( XSFactory::instance().fileno, xsh_.get() ) } 266 | , readWatch{ std::bind( XSFactory::instance().readWatch, xsh_.get(), _1 ) } 267 | , transactionStart{ std::bind( XSFactory::instance().transactionStart, xsh_.get() ) } 268 | , transactionEnd{ std::bind( XSFactory::instance().transactionEnd, xsh_.get(), _1, _2 ) } 269 | , isDomainIntroduced{ std::bind( XSFactory::instance().isDomainIntroduced, xsh_.get(), _1 ) } 270 | { 271 | } 272 | 273 | } // namespace bdvmi 274 | -------------------------------------------------------------------------------- /src/xswrapper.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-2019 Bitdefender SRL, All rights reserved. 2 | // 3 | // This library is free software; you can redistribute it and/or 4 | // modify it under the terms of the GNU Lesser General Public 5 | // License as published by the Free Software Foundation; either 6 | // version 3.0 of the License, or (at your option) any later version. 7 | // 8 | // This library is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 | // Lesser General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU Lesser General Public 14 | // License along with this library. 15 | 16 | #ifndef __BDVMIXSWRAPPER_H_INCLUDED__ 17 | #define __BDVMIXSWRAPPER_H_INCLUDED__ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include "utils.h" 25 | 26 | struct xs_handle; 27 | using xs_transaction_t = uint32_t; 28 | 29 | namespace bdvmi { 30 | 31 | using bdvmi_xs_read_timeout_fn_t = void *( xs_transaction_t, const std::string &, unsigned int *, unsigned int ); 32 | using bdvmi_xs_write_fn_t = bool( xs_transaction_t, const std::string &, const void *, unsigned int ); 33 | using bdvmi_xs_directory_fn_t = bool( xs_transaction_t, const std::string &, std::vector & ); 34 | using bdvmi_xs_watch_fn_t = bool( const std::string &, const std::string & ); 35 | using bdvmi_xs_unwatch_fn_t = bool( const std::string &, const std::string & ); 36 | using bdvmi_xs_rm_fn_t = bool( xs_transaction_t, const std::string & ); 37 | using bdvmi_xs_fileno_fn_t = int(); 38 | using bdvmi_xs_read_watch_fn_t = bool( std::vector & ); 39 | using bdvmi_xs_transaction_start_fn_t = xs_transaction_t(); 40 | using bdvmi_xs_transaction_end_fn_t = bool( xs_transaction_t, bool ); 41 | using bdvmi_xs_is_domain_introduced_fn_t = bool( unsigned int ); 42 | 43 | class XS { 44 | public: 45 | XS(); 46 | 47 | static const xs_transaction_t xbtNull; 48 | static const uint32_t watchPath; 49 | static const uint32_t watchToken; 50 | 51 | private: 52 | std::unique_ptr xsh_; 53 | 54 | public: 55 | NCFunction readTimeout; 56 | NCFunction write; 57 | NCFunction directory; 58 | NCFunction watch; 59 | NCFunction unwatch; 60 | NCFunction rm; 61 | NCFunction fileno; 62 | NCFunction readWatch; 63 | NCFunction transactionStart; 64 | NCFunction transactionEnd; 65 | NCFunction isDomainIntroduced; 66 | }; 67 | 68 | } // namespace bdvmi 69 | 70 | #endif // __BDVMIXSWRAPPER_H_INCLUDED__ 71 | --------------------------------------------------------------------------------