├── .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