Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 10 additions & 85 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -117,32 +117,22 @@ jobs:
runs-on: ubuntu-22.04

steps:
- name: clone Icebox repository
run: git clone https://github.com/thalium/icebox --depth 1
- name: Compile and install FDP library
run: |
cd icebox/src/FDP
g++ -std=c++11 -shared -fPIC FDP.cpp -o libFDP.so -lrt
sudo cp include/* /usr/local/include
sudo cp libFDP.so /usr/local/lib
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@1.99.0
with:
components: clippy
- uses: actions/checkout@v1
- name: build and check VirtualBox driver
run: |
cargo build --features virtualbox
cargo clippy --features virtualbox -- -D warnings
cargo build --features virtualbox-api
cargo clippy --features virtualbox-api -- -D warnings
cargo test --features virtualbox-api --test virtualbox_errors
cargo build --features virtualbox-vmi
cargo clippy --features virtualbox-vmi -- -D warnings
cargo clippy --features virtualbox-api,virtualbox-vmi --tests -- -D warnings
cargo test --features virtualbox-vmi --test virtualbox_errors
env:
LIBRARY_PATH: /usr/local/lib
LD_LIBRARY_PATH: /usr/local/lib
cargo build --features virtualbox
cargo clippy --features virtualbox -- -D warnings
cargo clippy --features virtualbox --tests -- -D warnings

virtualbox_windows:
runs-on: windows-2022
Expand All @@ -153,41 +143,16 @@ jobs:
with:
components: clippy

- name: Clone Icebox repository
uses: actions/checkout@v2
with:
repository: thalium/icebox
path: icebox

- uses: actions/checkout@v2
with:
path: libmicrovmi

# adds cl.exe in the PATH
- name: Setup command prompt for Microsoft Visual C++
uses: ilammy/msvc-dev-cmd@v1

- name: Compile and install FDP library
- name: compile-check VirtualBox API bindings (runtime unavailable on Windows)
run: |
# install in C:\FDP to avoid issues with quotes etc
cl /c FDP.cpp /out:FDP.obj
cl /LD FDP.obj /link /out:FDP.dll
lib /NOLOGO FDP.obj /OUT:FDP.lib
dir
New-Item -Path "C:\FDP" -ItemType "directory"
copy FDP.dll "C:\FDP"
copy FDP.lib "C:\FDP"
copy "include\*" "C:\FDP"
working-directory: icebox/src/FDP

- name: Install Clang
run: choco install llvm

- name: build VirtualBox driver
run: cargo build --manifest-path libmicrovmi/Cargo.toml --features virtualbox
env:
BINDGEN_EXTRA_CLANG_ARGS: -I"C:\FDP" -L"C:\FDP"
CARGO_BUILD_RUSTFLAGS: -L C:\FDP
cargo build --manifest-path libmicrovmi/Cargo.toml --features virtualbox-api
cargo clippy --manifest-path libmicrovmi/Cargo.toml --features virtualbox-api -- -D warnings

c_api:
runs-on: ${{ matrix.os }}
Expand Down Expand Up @@ -264,7 +229,7 @@ jobs:
run: python3 -c 'from microvmi import Microvmi, DriverType, CommonInitParamsPy, DriverInitParamsPy, KVMInitParamsPy, VBoxInitParamsPy'

- name: Build Wheels with manylinux
run: nox -r -s generate_wheels -- --features xen,kvm,virtualbox,virtualbox-api,virtualbox-vmi,mflow --release
run: nox -r -s generate_wheels -- --features xen,kvm,virtualbox,mflow --release
working-directory: python

# upload all generated wheels *.whl
Expand All @@ -286,18 +251,6 @@ jobs:
- name: install Xen headers
run: sudo apt-get install -y libxen-dev

- name: clone Icebox
uses: actions/checkout@v2
with:
repository: thalium/icebox
path: icebox

- name: install VirtualBox's FDP headers
run: |
g++ -std=c++11 -shared -fPIC FDP.cpp -o libFDP.so -lrt
sudo cp include/* /usr/local/include
sudo cp libFDP.so /usr/local/lib
working-directory: icebox/src/FDP

- name: clone libkvmi
uses: actions/checkout@v2
Expand Down Expand Up @@ -352,41 +305,13 @@ jobs:
with:
components: clippy

- name: Clone Icebox repository
uses: actions/checkout@v2
with:
repository: thalium/icebox
path: icebox

- uses: actions/checkout@v2
with:
path: libmicrovmi

# adds cl.exe in the PATH
- name: Setup command prompt for Microsoft Visual C++
uses: ilammy/msvc-dev-cmd@v1

- name: Compile and install FDP library
run: |
# install in C:\FDP to avoid issues with quotes etc
cl /c FDP.cpp /out:FDP.obj
cl /LD FDP.obj /link /out:FDP.dll
lib /NOLOGO FDP.obj /OUT:FDP.lib
dir
New-Item -Path "C:\FDP" -ItemType "directory"
copy FDP.dll "C:\FDP"
copy FDP.lib "C:\FDP"
copy "include\*" "C:\FDP"
working-directory: icebox/src/FDP

- name: Install Clang
run: choco install llvm

- name: build libmicrovmi with virtualbox and memflow driver
run: cargo build --manifest-path libmicrovmi/Cargo.toml --features virtualbox,mflow --release
env:
BINDGEN_EXTRA_CLANG_ARGS: -I"C:\FDP" -L"C:\FDP"
CARGO_BUILD_RUSTFLAGS: -L C:\FDP
- name: build Windows artifact with compile-only VirtualBox API bindings and memflow
run: cargo build --manifest-path libmicrovmi/Cargo.toml --features virtualbox-api,mflow --release

- name: create output directory and copy artifact content
run: |
Expand Down
8 changes: 0 additions & 8 deletions .gitpod.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,6 @@ RUN git clone https://github.com/bitdefender/libkvmi.git \
&& cd .. \
&& rm -rf libkvmi

RUN git clone --depth 1 https://github.com/thalium/icebox \
&& cd icebox/src/FDP \
&& g++ -std=c++11 -shared -fPIC FDP.cpp -o libFDP.so \
&& sudo mv include/* /usr/local/include/ \
&& sudo mv libFDP.so /usr/local/lib/ \
&& cd - \
&& rm -rf icebox

RUN rustup default stable \
&& cargo install cbindgen \
&& rustup component add clippy rustfmt
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Changelog

## Unreleased

### Changed

- **Breaking:** removed the legacy FDP VirtualBox access method and its icebox/libFDP dependency.
VirtualBox callers must now select `MachineDebugger` or `VBoxVMI` explicitly in Rust, C and
Python; omitting the access method is an error.
- The `virtualbox` Cargo feature now enables both `virtualbox-api` and `virtualbox-vmi` on Unix.
Windows CI still compiles `virtualbox-api`, but neither replacement method currently works at
runtime on Windows: VBoxVMI is Unix-only, and `vboxapi` has no `VBoxCAPI.dll` loader.
6 changes: 1 addition & 5 deletions CONTEXT.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,14 @@ One way a single **Driver** reaches its hypervisor, selected at init time. A Dri
_Avoid_: backend, mode, transport

**VBoxVMI**:
A VMI protocol served from inside a patched VirtualBox VM process over a Unix domain socket, with one client per VM. Successor to FDP; not compatible with it.
A VMI protocol served from inside a patched VirtualBox VM process over a Unix domain socket, with one client per VM.

**VBoxVMI method**:
The VirtualBox **access method** that speaks **VBoxVMI**. Fastest option and the path toward **VMI events**; requires a patched VirtualBox.

**MachineDebugger method**:
The VirtualBox **access method** that uses VirtualBox's public `IMachineDebugger` COM API. Slower (cross-process RPC per call, and each memory access waits for the vCPU) and limited to **VM state access**, but intended to need no patched VirtualBox once upstreamed.

**FDP**:
Legacy protocol from the icebox project, for a patched VirtualBox 5.2 over shared memory. Superseded by **VBoxVMI**.
_Avoid_: using "FDP" for the new protocol

**RAM ranges**:
The list of guest-physical address ranges backed by RAM. The highest address in it is the guest's max physical address, which can exceed the RAM size because of the MMIO hole below 4 GiB.
_Avoid_: "memory size" as a stand-in for max physical address
Expand Down
30 changes: 0 additions & 30 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 3 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,11 @@ xen = [
]
# KVM driver
kvm = ["kvmi"]
# VirtualBox driver
# FDP access method (legacy; selected when no VBoxInitParams is given)
virtualbox = ["fdp"]
# VirtualBox driver (MachineDebugger and VBoxVMI access methods)
virtualbox = ["virtualbox-api", "virtualbox-vmi"]
# MachineDebugger access method
virtualbox-api = ["vboxapi"]
# VBoxVMI access method (Linux only)
# VBoxVMI access method (Unix only)
virtualbox-vmi = ["vboxvmi"]
# memflow driver
# feature name is "mflow" to avoid conflict with the dependency
Expand All @@ -52,7 +51,6 @@ xenforeignmemory = { version = "=0.3.0", optional = true }
xenevtchn = { version = "=0.2.0", optional = true }
xenvmevent-sys = { version = "=0.2.0", optional = true }
kvmi = { version = "=0.5.0", optional = true }
fdp = { version = "=0.3.0", optional = true }
vboxapi = { git = "https://github.com/Wenzel/rs-vboxapi", rev = "5ba8d86d1cc58a5935208588580782a31fb2d27c", optional = true }
vboxvmi = { git = "https://github.com/Wenzel/rs-vboxvmi", rev = "9a349ca535b612232a0d0b26031fedadd3d0ecb0", optional = true }
winapi = { version = "0.3", features = [
Expand Down
2 changes: 1 addition & 1 deletion c_examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ if (NOT WIN32)
# disable pause example for windows
add_executable(pause pause.c "${CMAKE_CURRENT_BINARY_DIR}/libmicrovmi.h")
target_link_libraries(pause PRIVATE microvmi)
# VirtualBox MachineDebugger access method (Linux only)
# VirtualBox access-method example
add_executable(vbox-read-page vbox-read-page.c "${CMAKE_CURRENT_BINARY_DIR}/libmicrovmi.h")
target_link_libraries(vbox-read-page PRIVATE microvmi)
endif ()
6 changes: 3 additions & 3 deletions c_examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,6 @@ LD_LIBRARY_PATH="$LD_LIBRARY_PATH:../../target/debug" <example> <vm_name>
~~~

`vbox-read-page <vm_name> [physical_address]` selects the VirtualBox MachineDebugger access method
(build libmicrovmi with `--features virtualbox-api`) and prints one page of guest physical memory.
Given a VBoxVMI socket path instead of a VM name (`vbox-read-page /path/to/<VM UUID>.sock`), it uses
the VBoxVMI access method (`--features virtualbox-vmi`).
and prints one page of guest physical memory. Given a VBoxVMI socket path instead of a VM name
(`vbox-read-page /path/to/<VM UUID>.sock`), it uses the VBoxVMI access method. Build either with the
method-specific feature or build both on Unix with `--features virtualbox`.
1 change: 0 additions & 1 deletion doc/src/explanation/vmi_ecosystem.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ See our talk at FOSDEM 2020: [Rustifying the Virtual Machine Introspection ecosy
## Debugging

- [pyvmidbg](https://github.com/Wenzel/pyvmidbg)
- [icebox](https://github.com/thalium/icebox)
- [rVMI](https://github.com/fireeye/rvmi)

## Live Memory Forensics
Expand Down
2 changes: 1 addition & 1 deletion doc/src/reference/api/python_api.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ micro = Microvmi(DriverType.KVM, init_params)
### Selecting the VirtualBox access method

`init_params.virtualbox` takes a `VBoxInitParamsPy`, the equivalent of the Rust `VBoxInitParams`.
Without it, the VirtualBox driver uses its default access method.
VirtualBox initialization requires one of its two access methods explicitly.

~~~Python
from microvmi import Microvmi, DriverType, DriverInitParamsPy, CommonInitParamsPy, VBoxInitParamsPy
Expand Down
44 changes: 15 additions & 29 deletions doc/src/reference/drivers/virtualbox.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
# VirtualBox

The VirtualBox driver offers three access methods, selected at init time by `DriverInitParams.virtualbox`.
MachineDebugger and FDP name the VM with `common.vm_name`; VBoxVMI names it by its socket.
The VirtualBox driver offers two access methods, selected explicitly at init time by
`DriverInitParams.virtualbox`. MachineDebugger names the VM with `common.vm_name`; VBoxVMI names it
by its socket. The `virtualbox` Cargo feature enables both methods on Unix; the method-specific
features remain available separately.

VirtualBox has one EFER register: `X86Registers::efer` and `msr_efer` both read it, and a register
write with MachineDebugger or VBoxVMI fails (before writing anything) unless they are equal.

| Access method | Cargo feature | Selected by |
|---------------|---------------|-------------|
| VBoxVMI | `virtualbox-vmi` | `VBoxInitParams::VBoxVMI { socket_path }` |
| MachineDebugger | `virtualbox-api` | `VBoxInitParams::MachineDebugger` |
| FDP (legacy) | `virtualbox` | no `virtualbox` parameter |
| VBoxVMI | `virtualbox-vmi` or `virtualbox` | `VBoxInitParams::VBoxVMI { socket_path }` |
| MachineDebugger | `virtualbox-api` or `virtualbox` | `VBoxInitParams::MachineDebugger` |

## VBoxVMI method

Expand Down Expand Up @@ -79,17 +80,22 @@ Not implemented yet: writing guest physical memory.
### Requirements

- Platform: Linux
- A VirtualBox whose `IMachineDebugger::readPhysicalMemory` is implemented. Stock VirtualBox releases return "not implemented"; it needs a VirtualBox built with the IMachineDebugger memory methods patch.
- The VM is running, and owned by the user running libmicrovmi (the API attaches a shared session through that user's `VBoxSVC`).
- The VirtualBox C API library `VBoxXPCOMC.so` is found in `VBOX_APP_HOME`, else in `/opt/VirtualBox` or `/usr/lib/virtualbox`. Set `VBOX_APP_HOME` to the directory of a VirtualBox that is not installed (e.g. a build output `out/linux.amd64/release/bin`).
- A VirtualBox whose `IMachineDebugger::readPhysicalMemory` is implemented. Stock VirtualBox
releases return "not implemented"; it needs a VirtualBox built with the IMachineDebugger memory
methods patch.
- The VM is running and owned by the user running libmicrovmi (the API attaches a shared session
through that user's VirtualBox service).
- The VirtualBox C API runtime must be installed. On Linux, `VBoxXPCOMC.so` is found in
`VBOX_APP_HOME`, `/opt/VirtualBox` or `/usr/lib/virtualbox`; set `VBOX_APP_HOME` to a build output
such as `out/linux.amd64/release/bin`.
- The driver must be used on the thread that initialized it.

### Initialization parameters

- `vm_name`: required
- `virtualbox`: `VBoxInitParams::MachineDebugger`
- Python: `init_params.virtualbox = VBoxInitParamsPy.MachineDebugger()`
- C: `.virtualbox = { .access_method = VBOX_ACCESS_METHOD_MACHINE_DEBUGGER }` (`VBOX_ACCESS_METHOD_NONE`, the zero value, means no `VBoxInitParams`; see `c_examples/vbox-read-page.c`)
- C: `.virtualbox = { .access_method = VBOX_ACCESS_METHOD_MACHINE_DEBUGGER }` (see `c_examples/vbox-read-page.c`)

~~~
$ cargo build --features virtualbox-api --examples
Expand All @@ -104,23 +110,3 @@ $ python3 python/examples/mem-dump.py -d <vm_name> --vbox-machinedebugger

The binding comes from the [vboxapi](https://github.com/Wenzel/rs-vboxapi) crate. To build against a local checkout of it, override the git dependency:
`cargo build --features virtualbox-api --config 'patch."https://github.com/Wenzel/rs-vboxapi".vboxapi.path="../rs-vboxapi"'`

## FDP method (legacy)

### Requirements

- virtualbox modified via [icebox](https://github.com/thalium/icebox) project
- Platform: Windows/Linux

To compile `libFDP`
~~~
$ git clone --depth 1 https://github.com/thalium/icebox
$ cd icebox/src/FDP
$ g++ -std=c++11 -shared -fPIC FDP.cpp -o libFDP.so
$ sudo mv include/* /usr/local/include/
$ sudo mv libFDP.so /usr/local/lib/
~~~

### Initialization parameters

- `vm_name`: required
4 changes: 3 additions & 1 deletion doc/src/tutorial/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,11 @@ It contains both the library and the headers to get started with C development
- `libmicrovmi.h`

Bundled drivers:
- Virtualbox
- memflow

The Windows artifact compile-checks `virtualbox-api`, but no VirtualBox access method currently
works at runtime on Windows: VBoxVMI is Unix-only, and `vboxapi` does not yet load `VBoxCAPI.dll`.

## Python - PyPI

libmicrovmi is exposing a Python interface through a native extension.
Expand Down
Loading
Loading