diff --git a/panda/Makefile.panda.target b/panda/Makefile.panda.target index 34a71ce5a8e..f036bc068c7 100644 --- a/panda/Makefile.panda.target +++ b/panda/Makefile.panda.target @@ -56,7 +56,7 @@ extra-plugin-%: plog.pb-c.h plog.pb.h $(PANDA_API_EXT) PLUGIN_SRC_ROOT="$(EXTRA_PLUGINS_PATH)/panda/plugins" \ V="$(V)" PLUGIN_NAME="$*" all,) -all: $(PLUGIN_SUBDIR_RULES) $(EXTRA_PLUGIN_SUBDIR_RULES) +all: $(PLUGIN_SUBDIR_RULES) $(EXTRA_PLUGIN_SUBDIR_RULES) build_guest_plugins PROTO_FILES=$(wildcard $(addsuffix /*.proto,$(ALL_PLUGIN_SUBDIRS))) @@ -147,6 +147,95 @@ clean-panda: rm -f panda/panda_*.so;\ fi +######################################################### +# Guest Plugins + +# determine list of guest plugins +# remove spaces from lines. skip lines starting with a #. concatenate the rest into +# a space-delimited list +PANDA_GUEST_PLUGINS=$(shell tr -d "[:blank:]" < $(SRC_PATH)/panda/guest_plugins/config.panda | grep -v "^\#" | xargs) +GUEST_PLUGIN_SUBDIR_RULES=$(patsubst %,guest-plugin-%, $(PANDA_GUEST_PLUGINS)) +GUEST_PLUGIN_SUBDIR_MAKEFLAGS=$(if $(V),,--no-print-directory) BUILD_DIR=$(BUILD_DIR) + +ALL_GUEST_PLUGIN_RULES=$(GUEST_PLUGIN_SUBDIR_RULES) + +ifdef EXTRA_GUEST_PLUGINS_PATH + EXTRA_GUEST_PLUGINS=$(shell tr -d "[:blank:]" < $(EXTRA_GUEST_PLUGINS_PATH)/config.panda | grep -v "^\#" | xargs) + EXTRA_GUEST_PLUGIN_SUBDIR_RULES=$(patsubst %,extra-guest-plugin-%, $(EXTRA_GUEST_PLUGINS)) + ALL_GUEST_PLUGIN_RULES+=$(EXTRA_GUEST_PLUGIN_SUBDIR_RULES) +endif + +ifeq ($(TARGET_NAME),i386) + GUEST_CC=i486-linux-musl-gcc + GUEST_RUST_TARGET=i686-unknown-linux-musl +else ifeq ($(TARGET_NAME),x86_64) + GUEST_RUST_TARGET=x86_64-unknown-linux-musl +else ifeq ($(TARGET_NAME),mips) + GUEST_CC=mips-linux-musl-gcc + GUEST_RUST_TARGET=mips-unknown-linux-musl +else ifeq ($(TARGET_NAME),mipsel) + GUEST_CC=mipsel-linux-musl-gcc + GUEST_RUST_TARGET=mipsel-unknown-linux-musl +else ifeq ($(TARGET_NAME),mips64) + GUEST_CC=mips64-linux-musl-gcc + GUEST_RUST_TARGET=mips64-unknown-linux-muslabi64 +else ifeq ($(TARGET_NAME),arm) + GUEST_CC=arm-linux-musleabi-gcc + GUEST_RUST_TARGET=armv5te-unknown-linux-musleabi +else ifeq ($(TARGET_NAME),aarch64) + GUEST_CC=aarch64-linux-musl-gcc + GUEST_RUST_TARGET=aarch64-unknown-linux-musl +endif + +HAS_GUEST_TOOLCHAIN="no" +ifeq ($(TARGET_NAME),x86_64) + ifeq (, $(shell rustup target list --installed | grep $(GUEST_RUST_TARGET))) + GUEST_PLUGIN_DISABLE_REASON="rust target ${GUEST_RUST_TARGET} not installed" + HAS_GUEST_TOOLCHAIN="no" + else + HAS_GUEST_TOOLCHAIN="yes" + endif +else ifeq ($(TARGET_NAME),ppc) + HAS_GUEST_TOOLCHAIN="no" + GUEST_PLUGIN_DISABLE_REASON="unsupported on ppc" +else ifneq (, $(shell which $(GUEST_CC))) + ifeq (, $(shell rustup target list --installed | grep $(GUEST_RUST_TARGET))) + GUEST_PLUGIN_DISABLE_REASON="rust target ${GUEST_RUST_TARGET} not installed" + HAS_GUEST_TOOLCHAIN="no" + else + HAS_GUEST_TOOLCHAIN="yes" + endif +else + GUEST_PLUGIN_DISABLE_REASON="musl toolchain not in PATH" +endif + +ifeq ($(HAS_GUEST_TOOLCHAIN),"yes") +build_guest_plugins: $(ALL_GUEST_PLUGIN_RULES) + @echo "GUEST_PLUGINS: ${PANDA_GUEST_PLUGINS} ${EXTRA_GUEST_PLUGINS}" +else +build_guest_plugins: + @echo "GUEST_PLUGINS: disabled on arch ${TARGET_NAME}, ${GUEST_PLUGIN_DISABLE_REASON}" +endif + + +guest-plugin-%: + $(call quiet-command,mkdir -p ../panda/guest_plugins/$*,) + $(call quiet-command,mkdir -p panda/guest_plugins/$*,) + $(call quiet-command,$(MAKE) $(GUEST_PLUGIN_SUBDIR_MAKEFLAGS) \ + -f "$(SRC_PATH)/panda/guest_plugins/panda.mak" \ + -f "$(SRC_PATH)/panda/guest_plugins/$*/Makefile" \ + PLUGIN_SRC_ROOT="$(SRC_PATH)/panda/guest_plugins" \ + V="$(V)" PLUGIN_NAME="$*" all,) + +extra-guest-plugin-%: + $(call quiet-command,mkdir -p ../panda/guest_plugins/$*,) + $(call quiet-command,mkdir -p panda/guest_plugins/$*,) + $(call quiet-command,$(MAKE) $(GUEST_PLUGIN_SUBDIR_MAKEFLAGS) \ + -f "$(SRC_PATH)/panda/guest_plugins/panda.mak" \ + -f "$(EXTRA_GUEST_PLUGINS_PATH)/$*/Makefile" \ + PLUGIN_SRC_ROOT="$(EXTRA_GUEST_PLUGINS_PATH)" \ + V="$(V)" PLUGIN_NAME="$*" all,) + ifdef CONFIG_LLVM ######################################################### # LLVM library diff --git a/panda/dependencies/ubuntu:18.04_build.txt b/panda/dependencies/ubuntu:18.04_build.txt index b0695e00e85..f6b7aedbc90 100644 --- a/panda/dependencies/ubuntu:18.04_build.txt +++ b/panda/dependencies/ubuntu:18.04_build.txt @@ -25,6 +25,9 @@ protobuf-compiler python3-dev zip +# hyperfuse build deps +libfuse-dev + # pypanda dependencies python3-setuptools python3-wheel diff --git a/panda/dependencies/ubuntu:20.04_build.txt b/panda/dependencies/ubuntu:20.04_build.txt index 57a682f20da..453514816a1 100644 --- a/panda/dependencies/ubuntu:20.04_build.txt +++ b/panda/dependencies/ubuntu:20.04_build.txt @@ -21,6 +21,9 @@ python3-dev libpixman-1-dev zip +# hyperfuse build deps +libfuse-dev + # pypanda dependencies python3-setuptools python3-wheel diff --git a/panda/dependencies/ubuntu:22.04_build.txt b/panda/dependencies/ubuntu:22.04_build.txt index 57a682f20da..453514816a1 100644 --- a/panda/dependencies/ubuntu:22.04_build.txt +++ b/panda/dependencies/ubuntu:22.04_build.txt @@ -21,6 +21,9 @@ python3-dev libpixman-1-dev zip +# hyperfuse build deps +libfuse-dev + # pypanda dependencies python3-setuptools python3-wheel diff --git a/panda/docs/guest_plugins.md b/panda/docs/guest_plugins.md new file mode 100644 index 00000000000..74cd40bfa32 --- /dev/null +++ b/panda/docs/guest_plugins.md @@ -0,0 +1,306 @@ +# PANDA Guest Plugins + +### Overview + +PANDA guest plugins are a feature of PANDA that allows you to run non-cooperative guest agents. This means without any control of the guest, you can run programs that can communicate with code running on the host system. This gives the ability to gain a semantic understanding of the guest through stable interfaces, with the drawback of not being usable in replays. + +Some quick links to resources regarding guest plugins: + +* [`rust_example`](/panda/guest_plugins/rust_example) - An example guest plugin written in Rust +* [`guest_plugin_example`](/panda/plugins/guest_plugin_example) - The PANDA (host) plugin that loads and interacts with the guest plugin example +* [`guest_plugin_manager` Rust Documentation](https://docs.rs/panda-re/latest/panda/plugins/guest_plugin_manager/index.html) +* [`guest_plugin_manager`](/panda/plugins/guest_plugin_manager) - Source for the guest plugin manager (the PANDA host plugin which handles loading/unloading guest plugins) + +### Structure of Typical Usage + +PANDA guest plugins are a bit more involved than normal PANDA plugins, due to needing to facilitate communication across the hypervisor: + +* Host-side plugin + * A standard PANDA plugin (a shared object built from `panda/plugins`). + * Responsible for loading the code into the guest using the `guest_plugin_manager` plugin + * Handles communication with the guest plugin + * Sending - queuing up messages for the guest + * Recieving - Provides a callback for messages sent by the guest +* Guest-side plugin + * A standard statically-linked executable cross-compiled for the guest (built from `panda/guest_plugins`) + * Additional guest plugins will be built from `$EXTRA_GUEST_PLUGINS_PATH` + * Requires a `$EXTRA_GUEST_PLUGINS_PATH/config.panda` file containing newline-separated plugin names. Each plugin is built from `$EXTRA_GUEST_PLUGINS_PATH/$plugin_name/`. + * Communicates to the host using hypervisor calls via the [`panda-channels`](https://github.com/panda-re/panda-channels) library. + +### Getting Started + +For starters let's try developing an out-of-tree guest plugin. This process won't be any different than in-tree, so if down the road you wish to upstream your plugin it'll only require a bit of copy/pasting. + +#### Creating a New Plugin + +First up, create a folder to use as your "out-of-tree" plugins folder and set `EXTRA_GUEST_PLUGINS_PATH` accordingly: + +```bash +mkdir guest_plugins +export EXTRA_GUEST_PLUGINS_PATH=`realpath guest_plugins` +``` + +Now let's create a guest plugin using the example plugin as a template: + +1. Copy `panda/guest_plugins/guest_plugins/rust_example` to `$EXTRA_GUEST_PLUGINS_PATH/your_plugin_name` +2. Edit the `Cargo.toml` to change the name to match your folder name: + +```toml +[package] +name = "your_plugin_name" +``` + +3. Create a `config.panda` file in your out-of-tree `guest_plugins` folder. The only thing this needs to contain is your plugin's name: + +``` +your_plugin_name +``` + +Later, if you make more plugins you can add each one on a new line: + +``` +your_plugin_name +your_other_plugin +``` + +#### Adding Some Guest Logic + +For our example, we'll make a guest plugin which informs the host of how many files/directories are in `/etc`. + +First up some imports we'll need: + +```rust +use panda_channels::Channel; +use std::io::Write; +use std::fs; + +fn main() { +} +``` + +We'll need `Channel` and `Write` for communicating with the host, and we'll need `fs` for actually interacting with the filesystem. + +Then in our `main` function we'll read `/etc` using [`read_dir`](https://doc.rust-lang.org/std/fs/fn.read_dir.html) and use [`Iterator::count`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.count): + +```rust +let file_count = fs::read_dir("/etc").unwrap().count(); +``` + +Now let's create a channel to send this information to the host: + +```rust +let mut channel = Channel::main("your_plugin_name").unwrap(); +``` + +We pass the name of our plugin to `Channel::main` to get the main channel for our plugin. This channel is automatically allocated by the `guest_plugin_manager` when we load our plugin and for most usecases it's all we'll need. + +We've marked it as mutable so we can write to it. `Channel` implements Rust's [`Write`](https://doc.rust-lang.org/std/io/trait.Write.html) trait, so all we need to do is serialize our file count to bytes and use [`write_all`](https://doc.rust-lang.org/std/io/trait.Write.html#method.write_all) to send the bytes to the host: + +```rust +channel.write_all(&(file_count as u32).to_le_bytes()).unwrap(); +``` + +We convert `file_count` from `usize` (arch-width integer) to a 32-bit integer to serialize to a fixed number of bytes (that way our host code doesn't need to care about whether our guest is 32 or 64 bit) and then use `to_le_bytes` to convert to little endian bytes for us to write. + +Putting that all together we get our complete guest plugin: + +```rust +use panda_channels::Channel; +use std::io::Write; +use std::fs; + +fn main() { + let file_count = fs::read_dir("/etc").unwrap().count(); + let mut channel = Channel::main("your_plugin_name").unwrap(); + channel.write_all(&(file_count as u32).to_le_bytes()).unwrap(); +} +``` + +If we want to check if it built properly, we can run: + +``` +cargo check +``` + +This will print out any errors that need to be resolved, if there's no issues we'll get: + +``` + Finished dev [unoptimized + debuginfo] target(s) in 0.11s +``` + +This doesn't actually build or link our executable, so it saves a lot of time over doing a full PANDA build any time we want to check for compiler errors. Some other options are [`clippy`](https://github.com/rust-lang/rust-clippy) (A full Rust linter to help write idiomatic Rust) and [`bacon`](https://github.com/Canop/bacon) (Watches your project for changes and keeps a live-updating set of errors/warnings). Also helpful while developing is [`rust-analyzer`](https://rust-analyzer.github.io/), a Language Server implementation for VS Code, Emacs, Vim, etc. + +#### Writing a Host Plugin + +In order for our guest plugin to do anything, we'll need a host PANDA plugin in order to facilitate loading/message passing. + +First up, let's create a new Rust plugin. Similarly to with our guest plugin, we can use an example plugin as a template and just find/replace the names. + +I'd recommend using `panda/plugins/guest_plugin_example` as a base. Change the name in `Cargo.toml` to match the folder name, add the folder name to `panda/plugins/config.panda`, and you should be good to go. + +If you use another plugin as your base, make sure you have a somewhat recent version of `panda-re`, as you'll need at least `0.26` for this: + +```toml +[dependencies] +panda-re = { version = "0.26", default-features = false } +``` + +| Tip | +|:----| +| Install [`cargo-edit`](https://github.com/killercup/cargo-edit) and you can add the latest version of a dependency with `cargo add dep-name` | + +Now onto actually writing the host plugin. First off we'll want to pull the guest plugin management utilities we'll need into scope: + +```rust +use panda::plugins::guest_plugin_manager::{load_guest_plugin, channel_recv}; +use panda::prelude::*; +``` + +We'll need a callback function for handling incoming messages from the guest. The `panda-re` package provides an (`#[channel_recv]`) attribute for this to do most of the work for us, so for the most part we just need to define a function which takes a `u32` (an ID representing the channel we're recieving messages from) and either bytes (`&[u8]`) or a string (`&str`). In this case, since we're dealing with binary data, let's go with a byte slice: + +```rust +#[channel_recv] +fn message_recv(_: u32, data: &[u8]) { +} +``` + +And inside of that, let's just include a bit of code for converting back to an integer and printing it out to our terminal: + +```rust +// convert &[u8] to [u8; 4] +let count_bytes: [u8; 4] = data[..4].try_into().unwrap(); + +// convert [u8; 4] to u32 +let file_count = u32::from_le_bytes(count_bytes); + +// print the file count to the terminal +println!("Guest `/etc` file count: {}", file_count); +``` + +Next up, let's define our `init` function. Since all we need to do when our plugin is load the guest plugin: + +```rust +#[panda::init] +fn init(_: &mut PluginHandle) { + let mut channel = load_guest_plugin("your_guest_plugin_name", message_recv); + + // if we needed to write to the channel at all we could do so here using + // std::io::Write, just like the guest plugin. +} +``` + +Now we have everything we need for a fully-functional host plugin: + +```rust +use panda::plugins::guest_plugin_manager::{load_guest_plugin, channel_recv}; +use panda::prelude::*; + +#[channel_recv] +fn message_recv(_: u32, data: &[u8]) { + // convert &[u8] to [u8; 4] + let count_bytes: [u8; 4] = data[..4].try_into().unwrap(); + + // convert [u8; 4] to u32 + let file_count = u32::from_le_bytes(count_bytes); + + // print the file count to the terminal + println!("Guest `/etc` file count: {}", file_count); +} + +#[panda::init] +fn init(_: &mut PluginHandle) { + load_guest_plugin("your_guest_plugin_name", message_recv); +} +``` + +If your plugin uses Rust 2018 edition then you'll also need to import `std::convert::TryInto`. If you forget this, no worries though, as rustc will remind you and tell you how to fix it: + +``` +help: the following trait is implemented but not in scope; perhaps add a `use` for it: + | +1 | use std::convert::TryInto; + | +``` + +#### Building + +To build, we go through the standard PANDA build process: + +1. Create a `build` folder in the root of your clone of PANDA if you haven't already +2. From within the build folder run `../build.sh`. In our case, we are only going to be testing on x86_64 while developing, so we can save ourselves some build time by only building a single architecture: `../build.sh x86_64-softmmu` + +#### Testing Our Guest Plugin + +The easiest way to test our plugin will be with a pypanda script. An example script can be found in [`panda/plugins/guest_plugin_example/try_it.py`](/panda/plugins/guest_plugin_example/try_it.py). + +```python +from pandare import Panda + +panda = Panda(generic="x86_64") +panda.load_plugin("guest_plugin_example") + +@panda.queue_blocking +def run_cmd(): + panda.revert_sync("root") + panda.run_serial_cmd("cat", no_timeout=True) + panda.run_serial_cmd("cat", no_timeout=True) + + panda.end_analysis() + +panda.run() +``` + +Just replace `"guest_plugin_example"` with the name of your host PANDA plugin, then run the script. You should see roughly the following output: + +``` +$ python3 try_it.py + +[...] +Guest `/etc` file count: 170 +``` + +If you're getting this message, congrats! You've made your first PANDA guest plugin. If you're having trouble, a list of potential problems and solutions has been included below. + +### Troubleshooting + +If you issue is not listed here, ask for help in the PANDA/MIT Rehosting Slack, and we'll try to add it here. + +##### "No guest plugin path was provided but plugin could not be found" + +``` +thread '' panicked at 'No guest plugin path was provided but plugin "your_guest_plugin_name" could not be found, ensure "your_guest_plugin_name" has been built.', src/interface/api.rs:23:21 +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace +fatal runtime error: failed to initiate panic, error 5 +Aborted (core dumped) +``` + +Fix steps: + +1. Ensure your guest plugin is listed in guest_plugins/config.panda +2. Make sure you properly updated the guest plugin name in $host_plugin/src/lib.rs +3. Double check for typos + +#### "Fatal error: could not find path for plugin" + +``` +PANDA[core]:Fatal error: could not find path for plugin your_plugin_name +python3: {...}/panda/src/callbacks.c:166: _panda_load_plugin: Assertion `file name != NULL' failed. +Aborted (core dumped)` +``` + +Fix steps: + +1. Ensure your host plugin is listed in panda/plugins/config.panda +2. Ensure you didn't miss any build errors happening when building your host plugin + + +#### "Failed to find channel number" + +``` +failed to find channel number +``` + +Fix steps: + +1. Ensure the name you include in $guest_plugin/src/main.rs is correct when you call `Channel::main` +2. Ensure the name of the guest plugin itself is correct and contains no typos diff --git a/panda/guest_plugins/config.panda b/panda/guest_plugins/config.panda new file mode 100644 index 00000000000..af2bf46fe04 --- /dev/null +++ b/panda/guest_plugins/config.panda @@ -0,0 +1,3 @@ +#rust_example +tcp_servers +guest_daemon diff --git a/panda/guest_plugins/guest_daemon/Cargo.lock b/panda/guest_plugins/guest_daemon/Cargo.lock new file mode 100644 index 00000000000..eadba358711 --- /dev/null +++ b/panda/guest_plugins/guest_daemon/Cargo.lock @@ -0,0 +1,257 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "cc" +version = "1.0.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "daemonize-me" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "583332de51377006c0faf944fedde7edbfb857d6f79034925eab804cc97470ec" +dependencies = [ + "libc", + "nix", + "snafu", +] + +[[package]] +name = "doc-comment" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" + +[[package]] +name = "guest_daemon" +version = "0.1.0" +dependencies = [ + "daemonize-me", + "libc", + "libloading", + "memfd", + "panda-channels", +] + +[[package]] +name = "instant" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bee0328b1209d157ef001c94dd85b4f8f64139adb0eac2659f4b08382b2f474d" +dependencies = [ + "cfg-if 1.0.0", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.131" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04c3b4822ccebfa39c02fc03d1534441b22ead323fa0f48bb7ddd8e6ba076a40" + +[[package]] +name = "libloading" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f84d96438c15fcd6c3f244c8fce01d1e2b9c6b5623e9c711dc9286d8fc92d6a" +dependencies = [ + "cfg-if 1.0.0", + "winapi", +] + +[[package]] +name = "lock_api" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "memfd" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6627dc657574b49d6ad27105ed671822be56e0d2547d413bfbf3e8d8fa92e7a" +dependencies = [ + "libc", +] + +[[package]] +name = "nix" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50e4785f2c3b7589a0d0c1dd60285e1188adac4006e8abd6dd578e1567027363" +dependencies = [ + "bitflags", + "cc", + "cfg-if 0.1.10", + "libc", + "void", +] + +[[package]] +name = "panda-channels" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "529d17650397380d80c95c6027ffcb48eaf4095a0c513eb7e827f0c3c0e52e9c" +dependencies = [ + "lazy_static", + "parking_lot", +] + +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" +dependencies = [ + "cfg-if 1.0.0", + "instant", + "libc", + "redox_syscall", + "smallvec", + "winapi", +] + +[[package]] +name = "proc-macro2" +version = "1.0.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "redox_syscall" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" +dependencies = [ + "bitflags", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "smallvec" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" + +[[package]] +name = "snafu" +version = "0.6.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eab12d3c261b2308b0d80c26fffb58d17eba81a4be97890101f416b478c79ca7" +dependencies = [ + "doc-comment", + "snafu-derive", +] + +[[package]] +name = "snafu-derive" +version = "0.6.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1508efa03c362e23817f96cde18abed596a25219a8b2c66e8db33c03543d315b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "syn" +version = "1.0.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf" + +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/panda/guest_plugins/guest_daemon/Cargo.toml b/panda/guest_plugins/guest_daemon/Cargo.toml new file mode 100644 index 00000000000..d262ac88a6a --- /dev/null +++ b/panda/guest_plugins/guest_daemon/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "guest_daemon" +version = "0.1.0" +edition = "2018" + +[dependencies] +panda-channels = "0.3" +memfd = "0.4.0" +libloading = "0.7" +daemonize-me = "1" +libc = "0.2" diff --git a/panda/guest_plugins/guest_daemon/Makefile b/panda/guest_plugins/guest_daemon/Makefile new file mode 100644 index 00000000000..1458392b517 --- /dev/null +++ b/panda/guest_plugins/guest_daemon/Makefile @@ -0,0 +1,20 @@ +# Remember to: +# * Add your plugin name to config.panda +# * Keep your plugin name the same as the folder name and Cargo.toml package name + +# Output build artifacts to the build directory +PLUGIN_ARTIFACTS_DIR = $(PLUGIN_TARGET_DIR)/$(PLUGIN_NAME)/target + +# recompile if any of the src/*.rs files changed, or Cargo.toml +RUST_SOURCE = $(wildcard $(PLUGIN_DIR)/src/*.rs) +PLUGIN_DEPS=$(RUST_SOURCE) $(PLUGIN_DIR)/Cargo.toml + +$(PLUGIN_OUT_PATH): BUILD_RESULT="$(PLUGIN_ARTIFACTS_DIR)/$(TARGET_TRIPLE)/release/$(PLUGIN_NAME)" +$(PLUGIN_OUT_PATH): $(PLUGIN_DEPS) + @echo " CARGO $(PLUGIN_NAME) (${TARGET_TRIPLE})" + @CARGO_TERM_PROGRESS_WHEN=never cargo build --release \ + --target=$(TARGET_TRIPLE) \ + --manifest-path=$(PLUGIN_DIR)/Cargo.toml \ + --target-dir=$(PLUGIN_ARTIFACTS_DIR) + @mkdir -p $(PLUGIN_BIN_DIR) + @cp -p $(BUILD_RESULT) $@ diff --git a/panda/guest_plugins/guest_daemon/src/loader.rs b/panda/guest_plugins/guest_daemon/src/loader.rs new file mode 100644 index 00000000000..5b38c926dfd --- /dev/null +++ b/panda/guest_plugins/guest_daemon/src/loader.rs @@ -0,0 +1,44 @@ +use memfd::MemfdOptions; +use std::{ + fs, + io::Write, + os::unix::{fs::OpenOptionsExt, prelude::AsRawFd}, + process::Command, +}; + +pub(crate) fn load_plugin(payload: Vec) { + let (path, mut file) = if let Ok(plugin_file) = MemfdOptions::new().create("pluginfd") { + let fd = plugin_file.as_raw_fd(); + + (format!("/proc/self/fd/{}", fd), plugin_file.into_file()) + } else { + match fs::OpenOptions::new() + .create(true) + .write(true) + .mode(0o777) + .custom_flags(libc::O_CLOEXEC) + .open("/tmp/plugin_file") + { + Ok(file) => (String::from("/tmp/plugin_file"), file), + Err(err) => { + eprintln!("Failed to write to /tmp"); + panic!("{:?}", err); + } + } + }; + + file.write_all(&payload).unwrap(); + let _ = file.flush(); + let _ = file.sync_all(); + + let mut file = Some(file); + + if path.starts_with("/tmp") { + drop(file.take()); + } + + eprintln!("Running guest plugin..."); + Command::new(path) + .spawn() + .expect("Failed to run guest plugin"); +} diff --git a/panda/guest_plugins/guest_daemon/src/main.rs b/panda/guest_plugins/guest_daemon/src/main.rs new file mode 100644 index 00000000000..c527819d346 --- /dev/null +++ b/panda/guest_plugins/guest_daemon/src/main.rs @@ -0,0 +1,65 @@ +use panda_channels::{get_main_raw_channel, hypercall, RawChannel}; +use std::{io::Write, thread, time::Duration}; + +mod loader; + +enum PacketKind { + LoadPlugin = 0, +} + +struct Packet { + kind: PacketKind, + payload: Vec, +} + +fn read_packet(reader: &mut RawChannel) -> Option { + let mut temp_buf = vec![0u8; 4096 as _]; + temp_buf.fill(1); + + let mut payload = vec![]; + loop { + match reader.read_packet(&mut temp_buf) { + 0 => break, + _ => { + payload.write_all(&temp_buf).unwrap(); + } + } + } + + if payload.is_empty() { + return None; + } + + Some(Packet { + kind: PacketKind::LoadPlugin, + payload, + }) +} + +fn main() { + eprintln!("at main.rs in guest_daemon"); + + eprintln!("Daemonizing..."); + daemonize_me::Daemon::new() + .start() + .expect("Failed to daemonize"); + eprintln!("Finished daemonizing"); + + while !hypercall::start() { + thread::yield_now(); + } + + let mut channel = get_main_raw_channel("guest_daemon").unwrap(); + + loop { + match read_packet(&mut channel) { + Some(Packet { + kind: PacketKind::LoadPlugin, + payload, + }) => loader::load_plugin(payload), + None => { + thread::sleep(Duration::from_millis(10)); + } + } + } +} diff --git a/panda/guest_plugins/panda.mak b/panda/guest_plugins/panda.mak new file mode 100644 index 00000000000..c84fb4c1014 --- /dev/null +++ b/panda/guest_plugins/panda.mak @@ -0,0 +1,53 @@ +include config-target.mak + +ifndef PLUGIN_SRC_ROOT +$(error PLUGIN_SRC_ROOT is not set) +endif +ifndef PLUGIN_NAME +$(error PLUGIN_NAME is not set) +endif + +PLUGIN_DIR = $(realpath $(join $(PLUGIN_SRC_ROOT), /$(PLUGIN_NAME)/)) +PLUGIN_TARGET_DIR=panda/guest_plugins +PLUGIN_BIN_DIR=$(PLUGIN_TARGET_DIR)/bin +PLUGIN_OUT_PATH=$(PLUGIN_BIN_DIR)/$(PLUGIN_NAME) + +export CARGO_TARGET_ARMV5TE_UNKNOWN_LINUX_MUSLEABI_LINKER ?= arm-linux-musleabi-cc +export CARGO_TARGET_ARMV5TE_UNKNOWN_LINUX_MUSLEABI_RUSTFLAGS = -C target-cpu=arm926ej-s + +export CARGO_TARGET_MIPS_UNKNOWN_LINUX_MUSL_LINKER ?= mips-linux-musl-cc +#export CARGO_TARGET_MIPS_UNKNOWN_LINUX_MUSL_RUSTFLAGS = "-C linker=mips-linux-musl-cc" + +export CARGO_TARGET_MIPSEL_UNKNOWN_LINUX_MUSL_LINKER ?= mipsel-linux-musl-cc + +export CARGO_TARGET_AARCH64_UNKNOWN_LINUX_MUSL_LINKER ?= aarch64-linux-musl-cc + +export CARGO_TARGET_MIPS64_UNKNOWN_LINUX_MUSLABI64_LINKER ?= mips64-linux-musl-cc + +BUILD_TARGET=$(addprefix build-,$(TARGET_NAME)) + +all: $(BUILD_TARGET) + +build-x86_64: TARGET_TRIPLE=x86_64-unknown-linux-musl +build-x86_64: $(PLUGIN_OUT_PATH) + +build-i386: TARGET_TRIPLE=i686-unknown-linux-musl +build-i386: $(PLUGIN_OUT_PATH) + +build-arm: TARGET_TRIPLE=armv5te-unknown-linux-musleabi +build-arm: $(PLUGIN_OUT_PATH) + +build-aarch64: TARGET_TRIPLE=aarch64-unknown-linux-musl +build-aarch64: $(PLUGIN_OUT_PATH) + +build-mips: TARGET_TRIPLE=mips-unknown-linux-musl +build-mips: $(PLUGIN_OUT_PATH) + +build-mipsel: TARGET_TRIPLE=mipsel-unknown-linux-musl +build-mipsel: $(PLUGIN_OUT_PATH) + +build-mips64: TARGET_TRIPLE=mips64-unknown-linux-muslabi64 +build-mips64: $(PLUGIN_OUT_PATH) + +# Do not build for PowerPC +build-ppc: ; diff --git a/panda/guest_plugins/rust_example/Cargo.lock b/panda/guest_plugins/rust_example/Cargo.lock new file mode 100644 index 00000000000..568faf6b7d8 --- /dev/null +++ b/panda/guest_plugins/rust_example/Cargo.lock @@ -0,0 +1,130 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f98a04dce437184842841303488f70d0188c5f51437d2a834dc097eafa909a01" + +[[package]] +name = "lock_api" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "panda-channels" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a94b07d8bcc852032a8deb91be9d2bbd59421d776a9edb42fc74b40816e7d940" +dependencies = [ + "lazy_static", + "parking_lot", +] + +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" +dependencies = [ + "cfg-if", + "instant", + "libc", + "redox_syscall", + "smallvec", + "winapi", +] + +[[package]] +name = "redox_syscall" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" +dependencies = [ + "bitflags", +] + +[[package]] +name = "rust_example" +version = "0.1.0" +dependencies = [ + "panda-channels", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "smallvec" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/panda/guest_plugins/rust_example/Cargo.toml b/panda/guest_plugins/rust_example/Cargo.toml new file mode 100644 index 00000000000..193c1885fe7 --- /dev/null +++ b/panda/guest_plugins/rust_example/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "rust_example" +version = "0.1.0" +edition = "2021" + +[dependencies] +panda-channels = "0.3" diff --git a/panda/guest_plugins/rust_example/Makefile b/panda/guest_plugins/rust_example/Makefile new file mode 100644 index 00000000000..1458392b517 --- /dev/null +++ b/panda/guest_plugins/rust_example/Makefile @@ -0,0 +1,20 @@ +# Remember to: +# * Add your plugin name to config.panda +# * Keep your plugin name the same as the folder name and Cargo.toml package name + +# Output build artifacts to the build directory +PLUGIN_ARTIFACTS_DIR = $(PLUGIN_TARGET_DIR)/$(PLUGIN_NAME)/target + +# recompile if any of the src/*.rs files changed, or Cargo.toml +RUST_SOURCE = $(wildcard $(PLUGIN_DIR)/src/*.rs) +PLUGIN_DEPS=$(RUST_SOURCE) $(PLUGIN_DIR)/Cargo.toml + +$(PLUGIN_OUT_PATH): BUILD_RESULT="$(PLUGIN_ARTIFACTS_DIR)/$(TARGET_TRIPLE)/release/$(PLUGIN_NAME)" +$(PLUGIN_OUT_PATH): $(PLUGIN_DEPS) + @echo " CARGO $(PLUGIN_NAME) (${TARGET_TRIPLE})" + @CARGO_TERM_PROGRESS_WHEN=never cargo build --release \ + --target=$(TARGET_TRIPLE) \ + --manifest-path=$(PLUGIN_DIR)/Cargo.toml \ + --target-dir=$(PLUGIN_ARTIFACTS_DIR) + @mkdir -p $(PLUGIN_BIN_DIR) + @cp -p $(BUILD_RESULT) $@ diff --git a/panda/guest_plugins/rust_example/src/main.rs b/panda/guest_plugins/rust_example/src/main.rs new file mode 100644 index 00000000000..e77424c9ff7 --- /dev/null +++ b/panda/guest_plugins/rust_example/src/main.rs @@ -0,0 +1,23 @@ +use panda_channels::Channel; +use std::io::{Read, Write}; + +fn main() { + // This print won't be visible outside of the serial log + println!("Hello, world!"); + + // Get the main channel for our plugin by name + let mut channel = Channel::main("rust_example").unwrap(); + + // Write some text to the channel using the standard std::io::Write interface + channel.write_all(b"Hello rust_example channel").unwrap(); + + // Or use formatting utilties to do so + writeln!(&mut channel, "today's lucky number is: {}", 3).unwrap(); + + // The channel can also be read from + let mut buf = [0; 4]; + channel.read_exact(&mut buf).unwrap(); + + let num = u32::from_le_bytes(buf); + writeln!(&mut channel, "the number you sent the guest was: {}", num).unwrap(); +} diff --git a/panda/guest_plugins/tcp_servers/Cargo.lock b/panda/guest_plugins/tcp_servers/Cargo.lock new file mode 100644 index 00000000000..cc542916090 --- /dev/null +++ b/panda/guest_plugins/tcp_servers/Cargo.lock @@ -0,0 +1,217 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" + +[[package]] +name = "lock_api" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "panda-channels" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "529d17650397380d80c95c6027ffcb48eaf4095a0c513eb7e827f0c3c0e52e9c" +dependencies = [ + "lazy_static", + "parking_lot", +] + +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" +dependencies = [ + "cfg-if", + "instant", + "libc", + "redox_syscall", + "smallvec", + "winapi", +] + +[[package]] +name = "proc-macro2" +version = "1.0.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "proc-net-tcp" +version = "1.0.0" +source = "git+https://github.com/panda-re/proc-net-tcp#87de3e9ce7adeda56d75c13dc0b510136ee675b2" + +[[package]] +name = "quote" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "redox_syscall" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" +dependencies = [ + "bitflags", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "serde" +version = "1.0.137" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.137" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "smallvec" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" + +[[package]] +name = "syn" +version = "1.0.96" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0748dd251e24453cb8717f0354206b91557e4ec8703673a4b30208f2abaf1ebf" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tcp_servers" +version = "0.1.0" +dependencies = [ + "bincode", + "panda-channels", + "proc-net-tcp", + "serde", + "tcp_shared_types", +] + +[[package]] +name = "tcp_shared_types" +version = "0.1.0" +dependencies = [ + "serde", +] + +[[package]] +name = "unicode-ident" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/panda/guest_plugins/tcp_servers/Cargo.toml b/panda/guest_plugins/tcp_servers/Cargo.toml new file mode 100644 index 00000000000..6ec634079ae --- /dev/null +++ b/panda/guest_plugins/tcp_servers/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "tcp_servers" +version = "0.1.0" +edition = "2021" + +[dependencies] +panda-channels = "0.3" +bincode = "1" +serde = { version = "1", features = ["derive"] } + +proc-net-tcp = { git = "https://github.com/panda-re/proc-net-tcp" } +tcp_shared_types = { path = "../../plugins/tcp_passthrough/tcp_shared_types" } diff --git a/panda/guest_plugins/tcp_servers/Makefile b/panda/guest_plugins/tcp_servers/Makefile new file mode 100644 index 00000000000..1458392b517 --- /dev/null +++ b/panda/guest_plugins/tcp_servers/Makefile @@ -0,0 +1,20 @@ +# Remember to: +# * Add your plugin name to config.panda +# * Keep your plugin name the same as the folder name and Cargo.toml package name + +# Output build artifacts to the build directory +PLUGIN_ARTIFACTS_DIR = $(PLUGIN_TARGET_DIR)/$(PLUGIN_NAME)/target + +# recompile if any of the src/*.rs files changed, or Cargo.toml +RUST_SOURCE = $(wildcard $(PLUGIN_DIR)/src/*.rs) +PLUGIN_DEPS=$(RUST_SOURCE) $(PLUGIN_DIR)/Cargo.toml + +$(PLUGIN_OUT_PATH): BUILD_RESULT="$(PLUGIN_ARTIFACTS_DIR)/$(TARGET_TRIPLE)/release/$(PLUGIN_NAME)" +$(PLUGIN_OUT_PATH): $(PLUGIN_DEPS) + @echo " CARGO $(PLUGIN_NAME) (${TARGET_TRIPLE})" + @CARGO_TERM_PROGRESS_WHEN=never cargo build --release \ + --target=$(TARGET_TRIPLE) \ + --manifest-path=$(PLUGIN_DIR)/Cargo.toml \ + --target-dir=$(PLUGIN_ARTIFACTS_DIR) + @mkdir -p $(PLUGIN_BIN_DIR) + @cp -p $(BUILD_RESULT) $@ diff --git a/panda/guest_plugins/tcp_servers/src/allow_cancel.rs b/panda/guest_plugins/tcp_servers/src/allow_cancel.rs new file mode 100644 index 00000000000..83da71f9661 --- /dev/null +++ b/panda/guest_plugins/tcp_servers/src/allow_cancel.rs @@ -0,0 +1,110 @@ +use std::io::{self, Read, Seek, SeekFrom, Write}; +use std::sync::{ + atomic::{AtomicBool, Ordering}, + Arc, +}; + +pub struct AllowCancel(T, Arc); + +#[derive(Clone)] +pub struct CancelSignal(Arc); + +impl CancelSignal { + pub fn cancel(&self) { + self.0.store(true, Ordering::SeqCst) + } +} + +impl Clone for AllowCancel { + fn clone(&self) -> Self { + Self(self.0.clone(), Arc::clone(&self.1)) + } +} + +impl AllowCancel { + pub fn new(io: T) -> Self { + Self(io, Arc::new(AtomicBool::new(false))) + } + + pub fn cancel_signal(&self) -> CancelSignal { + CancelSignal(Arc::clone(&self.1)) + } + + pub fn with_signal(self, cancel_signal: CancelSignal) -> Self { + Self(self.0, cancel_signal.0) + } +} + +macro_rules! dbg { + ($expr:expr) => { + //panda_channels::Channel::main(&format!( + // "[{}:{}] {} = {:?}", + // file!(), + // line!(), + // stringify!($expr), + // $expr, + //)) + }; +} + +impl Write for AllowCancel { + fn write(&mut self, buf: &[u8]) -> std::io::Result { + if !self.1.load(Ordering::SeqCst) { + dbg!(buf.len()); + + self.0.write(buf) + } else { + Err(io::Error::new( + io::ErrorKind::ConnectionAborted, + "Connection ended", + )) + } + } + + fn flush(&mut self) -> io::Result<()> { + if !self.1.load(Ordering::SeqCst) { + dbg!("flushing"); + + self.0.flush() + } else { + Err(io::Error::new( + io::ErrorKind::ConnectionAborted, + "Connection ended", + )) + } + } +} + +impl Read for AllowCancel { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + if !self.1.load(Ordering::SeqCst) { + //dbg!(buf.len()); + + self.0.read(buf).map(|len| { + if len != 0 { + dbg!(len); + } + + len + }) + } else { + Err(io::Error::new( + io::ErrorKind::ConnectionAborted, + "Connection ended", + )) + } + } +} + +impl Seek for AllowCancel { + fn seek(&mut self, pos: SeekFrom) -> io::Result { + if !self.1.load(Ordering::SeqCst) { + self.0.seek(pos) + } else { + Err(io::Error::new( + io::ErrorKind::ConnectionAborted, + "Connection ended", + )) + } + } +} diff --git a/panda/guest_plugins/tcp_servers/src/main.rs b/panda/guest_plugins/tcp_servers/src/main.rs new file mode 100644 index 00000000000..4b2c4927410 --- /dev/null +++ b/panda/guest_plugins/tcp_servers/src/main.rs @@ -0,0 +1,99 @@ +use panda_channels::{Channel, RawChannel}; +use proc_net_tcp::socket_info; + +use std::collections::HashMap; +use std::mem::transmute; +use std::net::{Ipv4Addr, TcpStream}; + +use tcp_shared_types::{Request, SocketInfo}; + +mod allow_cancel; +use allow_cancel::{AllowCancel, CancelSignal}; + +fn recv_request(mut channel: &mut Channel) -> Request { + loop { + if let Ok(request) = bincode::deserialize_from(&mut channel) { + break request; + } + + std::thread::sleep(std::time::Duration::from_millis(10)); + } +} + +fn build_socket_list_packet() -> Vec { + let sockets = socket_info() + .into_iter() + .filter_map(|socket| { + socket.ok().map(|socket| SocketInfo { + ip: *socket.local_address.ip(), + port: socket.local_address.port(), + pid: socket.owning_pid, + server: socket.is_listening(), + }) + }) + .collect::>(); + + bincode::serialize(&sockets).unwrap() +} + +fn forward_connection(ip: Ipv4Addr, port: u16, channel_id: u32) -> CancelSignal { + let raw = unsafe { transmute(channel_id) }; + + let mut write_channel = AllowCancel::new(Channel::from_raw(raw)); + let mut read_channel = write_channel.clone(); + + let cancel_signal = write_channel.cancel_signal(); + + let write_socket = TcpStream::connect((ip, port)).unwrap(); + let read_socket = write_socket.try_clone().unwrap(); + + let mut read_socket = AllowCancel::new(read_socket).with_signal(cancel_signal.clone()); + let mut write_socket = AllowCancel::new(write_socket).with_signal(cancel_signal.clone()); + + std::thread::spawn(move || { + let _ = std::io::copy(&mut read_channel, &mut write_socket); + }); + + std::thread::spawn(move || { + let _ = std::io::copy(&mut read_socket, &mut write_channel); + }); + + cancel_signal +} + +fn main() { + let mut channel = Channel::main("tcp_servers").unwrap(); + let mut active_sockets = HashMap::new(); + + loop { + let request = recv_request(&mut channel); + + // debug?? + //let _ = Channel::main(&format!("Request: {:?}", request)); + //panda_channels::debug_output(&); + match request { + Request::GetSocketList { channel_id } => { + eprintln!("Getting socket list..."); + let socket_list_channel: RawChannel = unsafe { transmute(channel_id) }; + + socket_list_channel.write_packet(&build_socket_list_packet()); + } + + Request::ForwardConnection { + ip, + port, + channel_id, + } => { + let cancel_signal = forward_connection(ip, port, channel_id); + + active_sockets.insert(channel_id, cancel_signal); + } + + Request::CloseSocket { channel_id } => { + if let Some(socket) = active_sockets.remove(&channel_id) { + socket.cancel(); + } + } + } + } +} diff --git a/panda/include/panda/plugin.h b/panda/include/panda/plugin.h index e2330623330..1decf7b02f3 100644 --- a/panda/include/panda/plugin.h +++ b/panda/include/panda/plugin.h @@ -158,6 +158,8 @@ char** str_split(char *a_str, const char a_delim); extern gchar *panda_argv[MAX_PANDA_PLUGIN_ARGS]; extern int panda_argc; + +char *panda_guest_plugin_path(const char *name); char* resolve_file_from_plugin_directory(const char* file_name_fmt, const char* name); char *panda_plugin_path(const char *name); char* panda_shared_library_path(const char* name); diff --git a/panda/plugins/config.panda b/panda/plugins/config.panda index 60b8166f4af..92f7580ca38 100644 --- a/panda/plugins/config.panda +++ b/panda/plugins/config.panda @@ -12,12 +12,18 @@ dynamic_symbols edge_coverage filereadmon forcedexec +frida gdb +guest_plugin_example +guest_plugin_manager +guest_shell hooks hooks2 +hyperfuse hw_proc_id libfi lighthouse_coverage +linjector loaded loaded_libs mem_hooks @@ -32,6 +38,7 @@ osi_test pri pri_dwarf pri_simple +tcp_passthrough proc_start_linux proc_trace recctrl diff --git a/panda/plugins/frida/Cargo.lock b/panda/plugins/frida/Cargo.lock new file mode 100644 index 00000000000..5bb3343b3ba --- /dev/null +++ b/panda/plugins/frida/Cargo.lock @@ -0,0 +1,608 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +dependencies = [ + "memchr", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "ctor" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccc0a48a9b826acdf4028595adc9db92caea352f7af011a3034acd172a52a0aa" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "darling" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72" +dependencies = [ + "darling_core", + "quote", + "syn", +] + +[[package]] +name = "dirs" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30baa043103c9d0c2a57cf537cc2f35623889dc0d405e6c3cccfadbc81c71309" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03d86534ed367a67548dc68113a0f5db55432fdfbb6e6f9d77704397d95d5780" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "doc-comment" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" + +[[package]] +name = "env_logger" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "frida" +version = "0.1.0" +dependencies = [ + "log", + "panda-re", + "parking_lot", + "pretty_env_logger", +] + +[[package]] +name = "getrandom" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "ghost" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a5bcf1bbeab73aa4cf2fde60a846858dc036163c7c33bec309f8d17de785479" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "glib-sys" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7e9b997a66e9a23d073f2b1abb4dbfc3925e0b8952f67efd8d9b6e168e4cdc1" +dependencies = [ + "libc", + "system-deps", +] + +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "humantime" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" +dependencies = [ + "quick-error", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "inventory" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0eb5160c60ba1e809707918ee329adb99d222888155835c6feedba19f6c3fd4" +dependencies = [ + "ctor", + "ghost", + "inventory-impl", +] + +[[package]] +name = "inventory-impl" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e41b53715c6f0c4be49510bb82dee2c1e51c8586d885abe65396e82ed518548" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.112" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125" + +[[package]] +name = "libloading" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "351a32417a12d5f7e82c368a66781e307834dae04c6ce0cd4456d52989229883" +dependencies = [ + "cfg-if", + "winapi", +] + +[[package]] +name = "lock_api" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "memchr" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" + +[[package]] +name = "once_cell" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5" + +[[package]] +name = "panda-re" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dfc5b9d238b9f1d4785346b7d611dcc4236f615334e0719afbf3033f8c26e0e" +dependencies = [ + "dirs", + "glib-sys", + "inventory", + "lazy_static", + "libloading", + "once_cell", + "panda-re-macros", + "panda-re-sys", + "paste", + "strum 0.20.0", + "strum_macros 0.20.1", + "thiserror", +] + +[[package]] +name = "panda-re-macros" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be1d7a86fc7fc5c32ca9d7b430e5f12f76b664f381c4213c7071d14e88fc588" +dependencies = [ + "darling", + "doc-comment", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "panda-re-sys" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e00ee000dc315bf4a0a55d78b6d97456a7540d6ed01768da5f5aa89fdb660783" + +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" +dependencies = [ + "cfg-if", + "instant", + "libc", + "redox_syscall", + "smallvec", + "winapi", +] + +[[package]] +name = "paste" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0744126afe1a6dd7f394cb50a716dbe086cb06e255e53d8d0185d82828358fb5" + +[[package]] +name = "pkg-config" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe" + +[[package]] +name = "pretty_env_logger" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "926d36b9553851b8b0005f1275891b392ee4d2d833852c417ed025477350fb9d" +dependencies = [ + "env_logger", + "log", +] + +[[package]] +name = "proc-macro2" +version = "1.0.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f84e92c0f7c9d58328b85a78557813e4bd845130db68d7184635344399423b1" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "quote" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "redox_syscall" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_users" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" +dependencies = [ + "getrandom", + "redox_syscall", +] + +[[package]] +name = "regex" +version = "1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "serde" +version = "1.0.131" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ad69dfbd3e45369132cc64e6748c2d65cdfb001a2b1c232d128b4ad60561c1" + +[[package]] +name = "smallvec" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309" + +[[package]] +name = "strsim" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" + +[[package]] +name = "strum" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57bd81eb48f4c437cadc685403cad539345bf703d78e63707418431cecd4522b" + +[[package]] +name = "strum" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7318c509b5ba57f18533982607f24070a55d353e90d4cae30c467cdb2ad5ac5c" + +[[package]] +name = "strum_macros" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87c85aa3f8ea653bfd3ddf25f7ee357ee4d204731f6aa9ad04002306f6e2774c" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "strum_macros" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee8bc6b87a5112aeeab1f4a9f7ab634fe6cbefc4850006df31267f4cfb9e3149" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "syn" +version = "1.0.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8daf5dd0bb60cbd4137b1b587d2fc0ae729bc07cf01cd70b36a1ed5ade3b9d59" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "system-deps" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f3ecc17269a19353b3558b313bba738b25d82993e30d62a18406a24aba4649b" +dependencies = [ + "heck", + "pkg-config", + "strum 0.18.0", + "strum_macros 0.18.0", + "thiserror", + "toml", + "version-compare", +] + +[[package]] +name = "termcolor" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thiserror" +version = "1.0.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "toml" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" +dependencies = [ + "serde", +] + +[[package]] +name = "unicode-segmentation" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" + +[[package]] +name = "version-compare" +version = "0.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d63556a25bae6ea31b52e640d7c41d1ab27faba4ccb600013837a3d0b3994ca1" + +[[package]] +name = "wasi" +version = "0.10.2+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/panda/plugins/frida/Cargo.toml b/panda/plugins/frida/Cargo.toml new file mode 100644 index 00000000000..a7c8a783ec0 --- /dev/null +++ b/panda/plugins/frida/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "frida" +version = "0.1.0" +authors = ["Jordan McLeod "] +edition = "2018" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +panda-re = { version = "0.26", default-features = false } +parking_lot = "0.11" +log = "0.4" +pretty_env_logger = "0.4" + +[features] +default = ["x86_64"] + +x86_64 = ["panda-re/x86_64"] +i386 = ["panda-re/i386"] +arm = ["panda-re/arm"] +ppc = ["panda-re/ppc"] +mips = ["panda-re/mips"] +mipsel = ["panda-re/mipsel"] +aarch64 = ["panda-re/aarch64"] +mips64 = ["panda-re/mips64"] diff --git a/panda/plugins/frida/Makefile b/panda/plugins/frida/Makefile new file mode 100644 index 00000000000..2234476df57 --- /dev/null +++ b/panda/plugins/frida/Makefile @@ -0,0 +1,18 @@ +# Don't forget to add your plugin to config.panda! + +# Build rust plugins with make! + +# The main rule for your plugin. List all object-file dependencies. + +PANDA_PATH = $(realpath $(shell pwd)/..) +PLUGIN_DIR = $(realpath $(join $(PANDA_PATH), /../panda/plugins/$(PLUGIN_NAME)/)) +RUST_SOURCE = $(wildcard $(PLUGIN_DIR)/src/*.rs) +PLUGIN_ARTIFACTS_DIR = $(PLUGIN_TARGET_DIR)/$(PLUGIN_NAME)/target + +$(PLUGIN_TARGET_DIR)/panda_$(PLUGIN_NAME).so : $(RUST_SOURCE) $(PLUGIN_DIR)/Cargo.toml + @echo " CARGO $(PLUGIN_DIR)" + @CARGO_TERM_PROGRESS_WHEN=never cargo build --release \ + --no-default-features --features=$(TARGET_NAME) \ + --manifest-path=$(PLUGIN_DIR)/Cargo.toml \ + --target-dir=$(PLUGIN_ARTIFACTS_DIR) + @cp -p $(PLUGIN_ARTIFACTS_DIR)/release/lib$(PLUGIN_NAME).so $@ diff --git a/panda/plugins/frida/README.md b/panda/plugins/frida/README.md new file mode 100644 index 00000000000..cbd6557ee87 --- /dev/null +++ b/panda/plugins/frida/README.md @@ -0,0 +1,6 @@ +# Guest Plugin Example + +This is a basic example of how to build a PANDA plugin for communicating with a guest +plugin using Rust. + +See [`guest_plugins/rust_example`](/panda/guest_plugins/rust_example) for the corresponding guest plugin. diff --git a/panda/plugins/frida/src/lib.rs b/panda/plugins/frida/src/lib.rs new file mode 100644 index 00000000000..a721f07e8ec --- /dev/null +++ b/panda/plugins/frida/src/lib.rs @@ -0,0 +1,33 @@ +use panda::{plugins::guest_plugin_manager::*, prelude::*}; +use parking_lot::{const_mutex, Mutex}; +use std::io::Write; +use std::net::{TcpListener, TcpStream}; + +#[channel_recv] +fn message_recv(_: u32, data: &[u8]) { + if let Some(socket) = SOCKET.lock().as_mut() { + socket.write_all(data).unwrap(); + } +} + +static SOCKET: Mutex> = const_mutex(None); + +#[panda::init] +fn init(_: &mut PluginHandle) { + pretty_env_logger::init_custom_env("FRIDA_LOG"); + let mut channel = load_guest_plugin("frida_server", message_recv); + + std::thread::spawn(move || { + let server = TcpListener::bind("localhost:27042").unwrap(); + + for socket in server.incoming() { + let mut socket = socket.unwrap(); + log::debug!("Socket connected"); + SOCKET.lock().replace(socket.try_clone().unwrap()); + log::debug!("Forwarding socket..."); + std::io::copy(&mut socket, &mut channel).unwrap(); + log::debug!("Socket disconnected"); + SOCKET.lock().take(); + } + }); +} diff --git a/panda/plugins/guest_plugin_example/Cargo.lock b/panda/plugins/guest_plugin_example/Cargo.lock new file mode 100644 index 00000000000..6631ad52b15 --- /dev/null +++ b/panda/plugins/guest_plugin_example/Cargo.lock @@ -0,0 +1,489 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "ctor" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccc0a48a9b826acdf4028595adc9db92caea352f7af011a3034acd172a52a0aa" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "darling" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72" +dependencies = [ + "darling_core", + "quote", + "syn", +] + +[[package]] +name = "dirs" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30baa043103c9d0c2a57cf537cc2f35623889dc0d405e6c3cccfadbc81c71309" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03d86534ed367a67548dc68113a0f5db55432fdfbb6e6f9d77704397d95d5780" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "doc-comment" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "getrandom" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "ghost" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a5bcf1bbeab73aa4cf2fde60a846858dc036163c7c33bec309f8d17de785479" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "glib-sys" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7e9b997a66e9a23d073f2b1abb4dbfc3925e0b8952f67efd8d9b6e168e4cdc1" +dependencies = [ + "libc", + "system-deps", +] + +[[package]] +name = "guest_plugin_example" +version = "0.1.0" +dependencies = [ + "panda-re", + "parking_lot", +] + +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "inventory" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0eb5160c60ba1e809707918ee329adb99d222888155835c6feedba19f6c3fd4" +dependencies = [ + "ctor", + "ghost", + "inventory-impl", +] + +[[package]] +name = "inventory-impl" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e41b53715c6f0c4be49510bb82dee2c1e51c8586d885abe65396e82ed518548" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.112" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125" + +[[package]] +name = "libloading" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "351a32417a12d5f7e82c368a66781e307834dae04c6ce0cd4456d52989229883" +dependencies = [ + "cfg-if", + "winapi", +] + +[[package]] +name = "lock_api" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "once_cell" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5" + +[[package]] +name = "panda-re" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dfc5b9d238b9f1d4785346b7d611dcc4236f615334e0719afbf3033f8c26e0e" +dependencies = [ + "dirs", + "glib-sys", + "inventory", + "lazy_static", + "libloading", + "once_cell", + "panda-re-macros", + "panda-re-sys", + "paste", + "strum 0.20.0", + "strum_macros 0.20.1", + "thiserror", +] + +[[package]] +name = "panda-re-macros" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be1d7a86fc7fc5c32ca9d7b430e5f12f76b664f381c4213c7071d14e88fc588" +dependencies = [ + "darling", + "doc-comment", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "panda-re-sys" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e00ee000dc315bf4a0a55d78b6d97456a7540d6ed01768da5f5aa89fdb660783" + +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" +dependencies = [ + "cfg-if", + "instant", + "libc", + "redox_syscall", + "smallvec", + "winapi", +] + +[[package]] +name = "paste" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0744126afe1a6dd7f394cb50a716dbe086cb06e255e53d8d0185d82828358fb5" + +[[package]] +name = "pkg-config" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe" + +[[package]] +name = "proc-macro2" +version = "1.0.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f84e92c0f7c9d58328b85a78557813e4bd845130db68d7184635344399423b1" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "redox_syscall" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_users" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" +dependencies = [ + "getrandom", + "redox_syscall", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "serde" +version = "1.0.131" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ad69dfbd3e45369132cc64e6748c2d65cdfb001a2b1c232d128b4ad60561c1" + +[[package]] +name = "smallvec" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309" + +[[package]] +name = "strsim" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" + +[[package]] +name = "strum" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57bd81eb48f4c437cadc685403cad539345bf703d78e63707418431cecd4522b" + +[[package]] +name = "strum" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7318c509b5ba57f18533982607f24070a55d353e90d4cae30c467cdb2ad5ac5c" + +[[package]] +name = "strum_macros" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87c85aa3f8ea653bfd3ddf25f7ee357ee4d204731f6aa9ad04002306f6e2774c" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "strum_macros" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee8bc6b87a5112aeeab1f4a9f7ab634fe6cbefc4850006df31267f4cfb9e3149" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "syn" +version = "1.0.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8daf5dd0bb60cbd4137b1b587d2fc0ae729bc07cf01cd70b36a1ed5ade3b9d59" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "system-deps" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f3ecc17269a19353b3558b313bba738b25d82993e30d62a18406a24aba4649b" +dependencies = [ + "heck", + "pkg-config", + "strum 0.18.0", + "strum_macros 0.18.0", + "thiserror", + "toml", + "version-compare", +] + +[[package]] +name = "thiserror" +version = "1.0.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "toml" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" +dependencies = [ + "serde", +] + +[[package]] +name = "unicode-segmentation" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" + +[[package]] +name = "version-compare" +version = "0.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d63556a25bae6ea31b52e640d7c41d1ab27faba4ccb600013837a3d0b3994ca1" + +[[package]] +name = "wasi" +version = "0.10.2+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/panda/plugins/guest_plugin_example/Cargo.toml b/panda/plugins/guest_plugin_example/Cargo.toml new file mode 100644 index 00000000000..c9147ac88eb --- /dev/null +++ b/panda/plugins/guest_plugin_example/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "guest_plugin_example" +version = "0.1.0" +authors = ["Jordan McLeod "] +edition = "2018" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +panda-re = { version = "0.26", default-features = false } +parking_lot = "0.11" + +[features] +default = ["x86_64"] + +x86_64 = ["panda-re/x86_64"] +i386 = ["panda-re/i386"] +arm = ["panda-re/arm"] +ppc = ["panda-re/ppc"] +mips = ["panda-re/mips"] +mipsel = ["panda-re/mipsel"] +aarch64 = ["panda-re/aarch64"] +mips64 = ["panda-re/mips64"] diff --git a/panda/plugins/guest_plugin_example/Makefile b/panda/plugins/guest_plugin_example/Makefile new file mode 100644 index 00000000000..2234476df57 --- /dev/null +++ b/panda/plugins/guest_plugin_example/Makefile @@ -0,0 +1,18 @@ +# Don't forget to add your plugin to config.panda! + +# Build rust plugins with make! + +# The main rule for your plugin. List all object-file dependencies. + +PANDA_PATH = $(realpath $(shell pwd)/..) +PLUGIN_DIR = $(realpath $(join $(PANDA_PATH), /../panda/plugins/$(PLUGIN_NAME)/)) +RUST_SOURCE = $(wildcard $(PLUGIN_DIR)/src/*.rs) +PLUGIN_ARTIFACTS_DIR = $(PLUGIN_TARGET_DIR)/$(PLUGIN_NAME)/target + +$(PLUGIN_TARGET_DIR)/panda_$(PLUGIN_NAME).so : $(RUST_SOURCE) $(PLUGIN_DIR)/Cargo.toml + @echo " CARGO $(PLUGIN_DIR)" + @CARGO_TERM_PROGRESS_WHEN=never cargo build --release \ + --no-default-features --features=$(TARGET_NAME) \ + --manifest-path=$(PLUGIN_DIR)/Cargo.toml \ + --target-dir=$(PLUGIN_ARTIFACTS_DIR) + @cp -p $(PLUGIN_ARTIFACTS_DIR)/release/lib$(PLUGIN_NAME).so $@ diff --git a/panda/plugins/guest_plugin_example/README.md b/panda/plugins/guest_plugin_example/README.md new file mode 100644 index 00000000000..cbd6557ee87 --- /dev/null +++ b/panda/plugins/guest_plugin_example/README.md @@ -0,0 +1,6 @@ +# Guest Plugin Example + +This is a basic example of how to build a PANDA plugin for communicating with a guest +plugin using Rust. + +See [`guest_plugins/rust_example`](/panda/guest_plugins/rust_example) for the corresponding guest plugin. diff --git a/panda/plugins/guest_plugin_example/src/lib.rs b/panda/plugins/guest_plugin_example/src/lib.rs new file mode 100644 index 00000000000..5ea9fd93a08 --- /dev/null +++ b/panda/plugins/guest_plugin_example/src/lib.rs @@ -0,0 +1,18 @@ +use panda::{plugins::guest_plugin_manager::*, prelude::*}; +use std::io::Write; + +// Print out all the messages sent from the guest +#[channel_recv] +fn message_recv(_: u32, data: &str) { + println!("[rust_example] {}", data); +} + +#[panda::init] +fn init(_: &mut PluginHandle) { + let mut channel = load_guest_plugin("rust_example", message_recv); + + // the `rust_example` plugin expects to be sent a u32 which it will log + // so let's sent it one. + let num: u32 = 1234; + channel.write_all(&num.to_le_bytes()).unwrap(); +} diff --git a/panda/plugins/guest_plugin_example/try_it.py b/panda/plugins/guest_plugin_example/try_it.py new file mode 100644 index 00000000000..8df6c35a626 --- /dev/null +++ b/panda/plugins/guest_plugin_example/try_it.py @@ -0,0 +1,13 @@ +from pandare import Panda + +panda = Panda(generic="x86_64") +panda.load_plugin("guest_plugin_example") + +@panda.queue_blocking +def run_cmd(): + panda.revert_sync("root") + panda.run_serial_cmd("cat", no_timeout=True) + panda.run_serial_cmd("cat", no_timeout=True) + panda.end_analysis() + +panda.run() diff --git a/panda/plugins/guest_plugin_manager/Cargo.lock b/panda/plugins/guest_plugin_manager/Cargo.lock new file mode 100644 index 00000000000..738462e6c85 --- /dev/null +++ b/panda/plugins/guest_plugin_manager/Cargo.lock @@ -0,0 +1,511 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "crossbeam-queue" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b10ddc024425c88c2ad148c1b0fd53f4c6d38db9697c9f1588381212fa657c9" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db" +dependencies = [ + "cfg-if", + "lazy_static", +] + +[[package]] +name = "ctor" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e98e2ad1a782e33928b96fc3948e7c355e5af34ba4de7670fe8bac2a3b2006d" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "darling" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72" +dependencies = [ + "darling_core", + "quote", + "syn", +] + +[[package]] +name = "dirs" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30baa043103c9d0c2a57cf537cc2f35623889dc0d405e6c3cccfadbc81c71309" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03d86534ed367a67548dc68113a0f5db55432fdfbb6e6f9d77704397d95d5780" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "doc-comment" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "getrandom" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "ghost" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a5bcf1bbeab73aa4cf2fde60a846858dc036163c7c33bec309f8d17de785479" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "glib-sys" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7e9b997a66e9a23d073f2b1abb4dbfc3925e0b8952f67efd8d9b6e168e4cdc1" +dependencies = [ + "libc", + "system-deps", +] + +[[package]] +name = "guest_plugin_manager" +version = "0.1.0" +dependencies = [ + "crossbeam-queue", + "lazy_static", + "once_cell", + "panda-re", + "parking_lot", +] + +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "instant" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "716d3d89f35ac6a34fd0eed635395f4c3b76fa889338a4632e5231a8684216bd" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "inventory" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f0f7efb804ec95e33db9ad49e4252f049e37e8b0a4652e3cd61f7999f2eff7f" +dependencies = [ + "ctor", + "ghost", + "inventory-impl", +] + +[[package]] +name = "inventory-impl" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75c094e94816723ab936484666968f5b58060492e880f3c8d00489a1e244fa51" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320cfe77175da3a483efed4bc0adc1968ca050b098ce4f2f1c13a56626128790" + +[[package]] +name = "libloading" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "351a32417a12d5f7e82c368a66781e307834dae04c6ce0cd4456d52989229883" +dependencies = [ + "cfg-if", + "winapi", +] + +[[package]] +name = "lock_api" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "once_cell" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" + +[[package]] +name = "panda-re" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfd819f91df8381e0b6255a47f749a1dd52589c34a0b007bbee41f27630ff7ee" +dependencies = [ + "dirs", + "glib-sys", + "inventory", + "lazy_static", + "libloading", + "once_cell", + "panda-re-macros", + "panda-re-sys", + "paste", + "strum 0.20.0", + "strum_macros 0.20.1", + "thiserror", +] + +[[package]] +name = "panda-re-macros" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d807aa10d149e5ddde4e9cd386df1791efda6d6716077349da9f78cb6d32460" +dependencies = [ + "darling", + "doc-comment", + "quote", + "syn", +] + +[[package]] +name = "panda-re-sys" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e00ee000dc315bf4a0a55d78b6d97456a7540d6ed01768da5f5aa89fdb660783" + +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" +dependencies = [ + "cfg-if", + "instant", + "libc", + "redox_syscall", + "smallvec", + "winapi", +] + +[[package]] +name = "paste" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf547ad0c65e31259204bd90935776d1c693cec2f4ff7abb7a1bbbd40dfe58" + +[[package]] +name = "pkg-config" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" + +[[package]] +name = "proc-macro2" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0d8caf72986c1a598726adc988bb5984792ef84f5ee5aa50209145ee8077038" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "redox_syscall" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ab49abadf3f9e1c4bc499e8845e152ad87d2ad2d30371841171169e9d75feee" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_users" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" +dependencies = [ + "getrandom", + "redox_syscall", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "serde" +version = "1.0.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03" + +[[package]] +name = "smallvec" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309" + +[[package]] +name = "strsim" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" + +[[package]] +name = "strum" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57bd81eb48f4c437cadc685403cad539345bf703d78e63707418431cecd4522b" + +[[package]] +name = "strum" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7318c509b5ba57f18533982607f24070a55d353e90d4cae30c467cdb2ad5ac5c" + +[[package]] +name = "strum_macros" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87c85aa3f8ea653bfd3ddf25f7ee357ee4d204731f6aa9ad04002306f6e2774c" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "strum_macros" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee8bc6b87a5112aeeab1f4a9f7ab634fe6cbefc4850006df31267f4cfb9e3149" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "syn" +version = "1.0.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1873d832550d4588c3dbc20f01361ab00bfe741048f71e3fecf145a7cc18b29c" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "system-deps" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f3ecc17269a19353b3558b313bba738b25d82993e30d62a18406a24aba4649b" +dependencies = [ + "heck", + "pkg-config", + "strum 0.18.0", + "strum_macros 0.18.0", + "thiserror", + "toml", + "version-compare", +] + +[[package]] +name = "thiserror" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93119e4feac1cbe6c798c34d3a53ea0026b0b1de6a120deef895137c0529bfe2" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "060d69a0afe7796bf42e9e2ff91f5ee691fb15c53d38b4b62a9a53eb23164745" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "toml" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" +dependencies = [ + "serde", +] + +[[package]] +name = "unicode-segmentation" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" + +[[package]] +name = "version-compare" +version = "0.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d63556a25bae6ea31b52e640d7c41d1ab27faba4ccb600013837a3d0b3994ca1" + +[[package]] +name = "wasi" +version = "0.10.2+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/panda/plugins/guest_plugin_manager/Cargo.toml b/panda/plugins/guest_plugin_manager/Cargo.toml new file mode 100644 index 00000000000..04de54370a2 --- /dev/null +++ b/panda/plugins/guest_plugin_manager/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "guest_plugin_manager" +version = "0.1.0" +authors = ["Luke Craig ", "Jordan McLeod "] +edition = "2018" + +[lib] +crate-type = ["cdylib"] +path = "./src/guest_plugin_manager.rs" + +[dependencies] +panda-re = { version = "0.25", default-features = false } +crossbeam-queue = "0.3.2" +parking_lot = "0.11.2" +lazy_static = "1.4.0" +once_cell = "1.8.0" + +[features] +default = ["x86_64"] + +x86_64 = ["panda-re/x86_64"] +i386 = ["panda-re/i386"] +arm = ["panda-re/arm"] +ppc = ["panda-re/ppc"] +mips = ["panda-re/mips"] +mipsel = ["panda-re/mipsel"] +aarch64 = ["panda-re/aarch64"] +mips64 = ["panda-re/mips64"] diff --git a/panda/plugins/guest_plugin_manager/Makefile b/panda/plugins/guest_plugin_manager/Makefile new file mode 100644 index 00000000000..d34fc42957c --- /dev/null +++ b/panda/plugins/guest_plugin_manager/Makefile @@ -0,0 +1,18 @@ +# Don't forget to add your plugin to config.panda! + +# Build rust plugins with make! + +# The main rule for your plugin. List all object-file dependencies. + +PANDA_PATH = $(realpath $(shell pwd)/..) +PLUGIN_DIR = $(realpath $(join $(PANDA_PATH), /../panda/plugins/$(PLUGIN_NAME)/)) +RUST_SOURCE = $(shell find $(PLUGIN_DIR)/src/ -name "*.rs") +PLUGIN_ARTIFACTS_DIR = $(PLUGIN_TARGET_DIR)/$(PLUGIN_NAME)/target + +$(PLUGIN_TARGET_DIR)/panda_$(PLUGIN_NAME).so : $(RUST_SOURCE) $(PLUGIN_DIR)/Cargo.toml + @echo " CARGO $(PLUGIN_DIR)" + @CARGO_TERM_PROGRESS_WHEN=never cargo build --release \ + --no-default-features --features=$(TARGET_NAME) \ + --manifest-path=$(PLUGIN_DIR)/Cargo.toml \ + --target-dir=$(PLUGIN_ARTIFACTS_DIR) + @cp -p $(PLUGIN_ARTIFACTS_DIR)/release/lib$(PLUGIN_NAME).so $@ diff --git a/panda/plugins/guest_plugin_manager/README.md b/panda/plugins/guest_plugin_manager/README.md new file mode 100644 index 00000000000..5a6e48a76c6 --- /dev/null +++ b/panda/plugins/guest_plugin_manager/README.md @@ -0,0 +1,94 @@ +# Guest Plugin Manager + +The guest plugin manager is a PANDA plugin which handles loading guest agent plugins +into the guest, managing communication channels between the guest and the host. +Typical usage involves writing a host PANDA plugin which calls the plugin manager in +order to load the executable, then loading that PANDA plugin as normal (from either the +PANDA command line or from pypanda). + +Currently the guest plugin manager only supports Linux guests via the `linjector` plugin +however support for other guest OS' would be possible in the presence of other backends. +The responsibility of `linjector` is, as the name would imply, inject a single binary +into the guest as a new process. The guest plugin manager uses this capability in order +to load the "Guest Daemon", an executable running the guest responsible for handling +the spawning of future guest processes and is responsible for communicating with the +guest_plugin_manager directly. + +**Note:** injection of `guest_daemon` plugin must be done before guest plugin manager takes effect. + +## APIs and Callbacks + +--- + +Name: **add_guest_plugin** + +Signature: + +```c +typedef ChannelId (*add_guest_plugin)(GuestPlugin); +``` + +Description: Adds a guest plugin to be loaded, returns a channel ID representing the +main channel of the to-be-loaded plugin. Writes to this channel ID before plugin +load will be queued and will thus be available when the plugin begins reading. + +--- + +Name: **channel_write** + +Signature: + +```c +typedef void (*channel_write)(ChannelId, const u8*, size_t); +``` + +Description: Writes bytes from a buffer to the given channel ID, queuing them up for +the next guest plugin read. The buffer is copied into a new allocation before being +added to the queue, so the act of writing has no strict lifetime requirements. + +--- + +Name: **get_channel_from_name** + +Signature: + +```c +typedef ChannelId (*get_channel_from_name)(const char*); +``` + +Description: + +Given the name of a plugin or channel, return the associated channel, panicking +if a channel of the given name cannot be found. Channel name should be passed +as a null-terminated string. + +The provided string has no lifetime requirements, but must be a non-null pointer +to a valid C string. + +--- + +## Types + +```c +// A globally unique identifier for a given channel +typedef uint32_t ChannelId; + +// ChannelId - the unique identifier for the channel the message came from +// const unsigned char* - a pointer to the data being sent from the guest +// size_t - the length of the data buffer in bytes +typedef void (*ChannelCB)(ChannelId, const unsigned char*, size_t); + +// A plugin to be passed to guest_plugin_manager to be registered +typedef struct guest_plugin { + // A unique name for the given plugin, provided as a non-null C string + const char* plugin_name; + + // An optional path to load the guest agent binary. If null, a lookup will be + // performed to find the binary from the given name. If non-null must be a valid + // C string. + const char* guest_binary_path; + + // A callback for when this guest plugin sends a message to the host + ChannelCB msg_recieve_cb; +} GuestPlugin; +``` diff --git a/panda/plugins/guest_plugin_manager/guest_plugin_manager_ppp.h b/panda/plugins/guest_plugin_manager/guest_plugin_manager_ppp.h new file mode 100644 index 00000000000..7f4db0ae3e1 --- /dev/null +++ b/panda/plugins/guest_plugin_manager/guest_plugin_manager_ppp.h @@ -0,0 +1,11 @@ +#ifndef __GUEST_PLUGIN_MANAGER_PPP_H +#define __GUEST_PLUGIN_MANAGER_PPP_H +// BEGIN_PYPANDA_NEEDS_THIS -- do not delete this comment bc pypanda +// api autogen needs it. And don't put any compiler directives +// between this and END_PYPANDA_NEEDS_THIS except includes of other +// files in this directory that contain subsections like this one. + +PPP_CB_TYPEDEF(void,on_guest_agent_load,CPUState *); + +// END_PYPANDA_NEEDS_THIS -- do not delete this comment! +#endif diff --git a/panda/plugins/guest_plugin_manager/rustfmt.toml b/panda/plugins/guest_plugin_manager/rustfmt.toml new file mode 100644 index 00000000000..5c8d9318b3b --- /dev/null +++ b/panda/plugins/guest_plugin_manager/rustfmt.toml @@ -0,0 +1 @@ +max_width = 80 \ No newline at end of file diff --git a/panda/plugins/guest_plugin_manager/src/guest_plugin_manager.rs b/panda/plugins/guest_plugin_manager/src/guest_plugin_manager.rs new file mode 100644 index 00000000000..41868b1fc43 --- /dev/null +++ b/panda/plugins/guest_plugin_manager/src/guest_plugin_manager.rs @@ -0,0 +1,148 @@ +use panda::plugins::guest_plugin_manager::guest_plugin_path; +use panda::prelude::*; +use panda::PppCallback; + +use std::convert::TryFrom; +use std::sync::atomic::{AtomicBool, Ordering}; + +mod hyp_regs; +use hyp_regs::{get_hyp_reg, set_hyp_ret_reg}; + +mod interface; +use interface::hci::{ + hyp_error, hyp_get_channel_by_name, hyp_get_manager, hyp_read, hyp_start, + hyp_stop, hyp_write, +}; + +const MAGIC: usize = 0x1337c0d3; + +#[derive(Copy, Clone)] +pub enum HcCmd { + Start = 1, /* start new action */ + Stop, /* stop action */ + Read, /* read buffer from hypervisor */ + Write, /* write buffer TO hypervisor*/ + Error, /* report error to hypervisor*/ + GetManager, /* returns unique chanenl ID to manager from plugin */ + GetChannelByName, /* returns existing channel mapped to unique name */ +} + +impl TryFrom for HcCmd { + type Error = (); + + fn try_from(value: usize) -> Result { + match value { + 1 => Ok(HcCmd::Start), + 2 => Ok(HcCmd::Stop), + 3 => Ok(HcCmd::Read), + 4 => Ok(HcCmd::Write), + 5 => Ok(HcCmd::Error), + 6 => Ok(HcCmd::GetManager), + 7 => Ok(HcCmd::GetChannelByName), + _ => Err(()), + } + } +} + +#[panda::guest_hypercall] +fn hypercall_handler(cpu: &mut CPUState) -> bool { + let magicval = get_hyp_reg(cpu, 0); + if magicval == MAGIC { + let action = get_hyp_reg(cpu, 1); + // dbg!(action); + let chan_id = get_hyp_reg(cpu, 2) as u32; + let arg1 = get_hyp_reg(cpu, 3); + let arg2 = get_hyp_reg(cpu, 4); + + let retval = match HcCmd::try_from(action) { + Ok(HcCmd::Start) => hyp_start(cpu, chan_id, arg1, arg2), + Ok(HcCmd::Write) => hyp_write(cpu, chan_id, arg1, arg2), + Ok(HcCmd::Read) => hyp_read(cpu, chan_id, arg1, arg2), + Ok(HcCmd::Stop) => hyp_stop(cpu, chan_id, arg1, arg2), + Ok(HcCmd::Error) => hyp_error(cpu, chan_id, arg1, arg2), + Ok(HcCmd::GetManager) => hyp_get_manager(cpu, chan_id, arg1, arg2), + Ok(HcCmd::GetChannelByName) => { + hyp_get_channel_by_name(cpu, chan_id, arg1, arg2) + } + _ => None, + }; + + if let Some(retval) = retval { + set_hyp_ret_reg(cpu, retval); + } + + true + } else { + false + } +} + +#[derive(PandaArgs)] +#[name = "linjector"] +struct Linjector { + guest_binary: String, + proc_name: String, +} + +#[derive(PandaArgs)] +#[name = "guest_plugin_manager"] +struct Args { + #[arg(default = "cat")] + proc_name: String, +} + +panda::plugin_import! { + static LINJECTOR: LinjectorApi = extern "linjector" { + callbacks { + fn before_guest_inject(cpu: &mut CPUState); + } + }; +} + +panda::export_ppp_callback! { + pub(crate) fn on_guest_agent_load(cpu: &mut CPUState); +} + +lazy_static::lazy_static! { + static ref ARGS: Args = Args::from_panda_args(); +} + +static LOADED: AtomicBool = AtomicBool::new(false); + +#[panda::init] +fn init(_: &mut PluginHandle) -> bool { + if LOADED.swap(true, Ordering::SeqCst) { + return true; + } + + lazy_static::initialize(&ARGS); + interface::daemon_manager::init(); + + //let guest_binary = guest_plugin_path("guest_daemon") + // .expect("Failed to retrieve guest_daemon guest plugin path") + // .to_string_lossy() + // .into_owned(); + + //assert!( + // panda::os::family().is_linux(), + // "Guest plugin manager currently only supports Linux" + //); + + //std::thread::spawn(|| { + // // TODO: automatically decide which process to inject into + // panda::require_plugin(&Linjector { + // guest_binary, + // proc_name: ARGS.proc_name.clone(), + // }); + + // PppCallback::new() + // .before_guest_inject(|cpu| on_guest_agent_load::trigger(cpu)); + //}); + + true +} + +#[panda::uninit] +fn exit(_: &mut PluginHandle) { + println!("Exiting"); +} diff --git a/panda/plugins/guest_plugin_manager/src/hyp_regs.rs b/panda/plugins/guest_plugin_manager/src/hyp_regs.rs new file mode 100644 index 00000000000..2a19e082f50 --- /dev/null +++ b/panda/plugins/guest_plugin_manager/src/hyp_regs.rs @@ -0,0 +1,54 @@ +use panda::{ + prelude::*, + regs::{ + get_reg, set_reg, + Reg::{self, *}, + }, +}; + +// =================== Register Order =================== +#[cfg(feature = "i386")] +pub const REG_ORDER: [Reg; 5] = [EAX, EBX, ECX, EDX, EDI]; + +#[cfg(feature = "x86_64")] +pub const REG_ORDER: [Reg; 5] = [RAX, RBX, RCX, RDX, RDI]; + +#[cfg(feature = "arm")] +pub const REG_ORDER: [Reg; 5] = [R0, R1, R2, R3, R4]; + +#[cfg(any(feature = "mips", feature = "mipsel", feature = "mips64"))] +pub const REG_ORDER: [Reg; 5] = [V0, A0, A1, A2, A3]; + +#[cfg(feature = "aarch64")] +pub const REG_ORDER: [Reg; 5] = [X0, X1, X2, X3, X4]; + +#[cfg(feature = "ppc")] +pub const REG_ORDER: [Reg; 5] = [R3, R4, R5, R6, R7]; + +// =================== Return Value =================== +#[cfg(feature = "i386")] +pub const RET_REG: Reg = EAX; + +#[cfg(feature = "x86_64")] +pub const RET_REG: Reg = RAX; + +#[cfg(feature = "arm")] +pub const RET_REG: Reg = R0; + +#[cfg(any(feature = "mips", feature = "mipsel", feature = "mips64"))] +pub const RET_REG: Reg = V0; + +#[cfg(feature = "aarch64")] +pub const RET_REG: Reg = X0; + +#[cfg(feature = "ppc")] +pub const RET_REG: Reg = R3; + +pub fn get_hyp_reg(cpu: &mut CPUState, num: usize) -> usize { + let reg_to_read = REG_ORDER[num]; + get_reg(cpu, reg_to_read) as usize +} + +pub fn set_hyp_ret_reg(cpu: &mut CPUState, value: usize) { + set_reg(cpu, RET_REG, value as target_ulong) +} diff --git a/panda/plugins/guest_plugin_manager/src/interface/api.rs b/panda/plugins/guest_plugin_manager/src/interface/api.rs new file mode 100644 index 00000000000..69988ec855e --- /dev/null +++ b/panda/plugins/guest_plugin_manager/src/interface/api.rs @@ -0,0 +1,80 @@ +use super::channels::add_channel; +use super::daemon_manager::load_binary; +use std::ffi::CStr; +use std::os::raw::c_char; +use std::slice::from_raw_parts; + +use super::channels::{publish_message_to_guest, ChannelCB, ChannelId}; + +#[repr(C)] +pub struct GuestPlugin { + /// A unique name for the given plugin, provided as a non-null C string + pub plugin_name: *const c_char, + + /// An optional path to load the guest agent binary. If null, a lookup will be + /// performed to find the binary from the given name. If non-null must be a valid + /// C string. + pub guest_binary_path: *const c_char, + + /// A callback for when this guest plugin sends a message to the host + pub msg_receive_cb: ChannelCB, +} + +/// Adds a guest plugin to be loaded, returns a channel ID representing the +/// main channel of the to-be-loaded plugin. Writes to this channel ID before plugin +/// load will be queued and will thus be available when the plugin begins reading. +#[no_mangle] +pub extern "C" fn add_guest_plugin(plugin: GuestPlugin) -> ChannelId { + let path_temp; + let name = unsafe { CStr::from_ptr(plugin.plugin_name).to_string_lossy() }; + let binary_path = if plugin.guest_binary_path.is_null() { + match crate::guest_plugin_path(&name) { + Some(path) => { + path_temp = path; + path_temp.to_string_lossy() + } + None => panic!( + "No guest plugin path was provided but plugin {0:?} \ + could not be found, ensure {0:?} has been built.", + name + ), + } + } else { + unsafe { CStr::from_ptr(plugin.guest_binary_path).to_string_lossy() } + }; + load_binary(&binary_path); + add_channel(Some(&name), plugin.msg_receive_cb) +} + +/// Create a new anonymous channel provided a callback for writes performed by the guest, +/// returning the channel ID. +#[no_mangle] +pub unsafe extern "C" fn allocate_channel(callback: ChannelCB) -> ChannelId { + add_channel(None, callback) +} + +/// Writes bytes from a buffer to the given channel ID, queuing them up for the next +/// guest plugin read. The buffer is copied into a new allocation before being added +/// to the queue, so the act of writing has no strict lifetime requirements. +#[no_mangle] +pub unsafe extern "C" fn channel_write( + channel: ChannelId, + buf: *const u8, + buf_len: usize, +) { + publish_message_to_guest(channel, from_raw_parts(buf, buf_len).to_vec()) +} + +/// Given the name of a plugin or channel, return the associated channel, panicking +/// if a channel of the given name cannot be found. Channel name should be passed +/// as a null-terminated string. +/// +/// The provided string has no lifetime requirements, but must be a non-null pointer +/// to a valid C string. +#[no_mangle] +pub extern "C" fn get_channel_from_name( + channel_name: *const c_char, +) -> ChannelId { + let name = unsafe { CStr::from_ptr(channel_name).to_string_lossy() }; + super::channels::get_channel_from_name(&name).unwrap() +} diff --git a/panda/plugins/guest_plugin_manager/src/interface/channels.rs b/panda/plugins/guest_plugin_manager/src/interface/channels.rs new file mode 100644 index 00000000000..8182a6ad902 --- /dev/null +++ b/panda/plugins/guest_plugin_manager/src/interface/channels.rs @@ -0,0 +1,103 @@ +use crossbeam_queue::SegQueue; +use lazy_static::lazy_static; +use parking_lot::RwLock; +use std::collections::HashMap; +use std::sync::atomic::{AtomicU32, Ordering}; + +pub type ChannelId = u32; +pub type ChannelCB = extern "C" fn(ChannelId, *const u8, usize); + +static NEXT_CHANNEL_NUMBER: AtomicU32 = AtomicU32::new(0); + +lazy_static! { + static ref CHANNELS: RwLock> = + RwLock::new(HashMap::new()); +} + +struct Channel { + name: Option, + msg_receive_cb: ChannelCB, + message_queue: SegQueue>, +} + +pub fn add_channel(p_name: Option<&str>, cb: ChannelCB) -> ChannelId { + let mut plugins = CHANNELS.write(); + let channel_id = NEXT_CHANNEL_NUMBER.fetch_add(1, Ordering::SeqCst); + if plugins + .insert( + channel_id, + Channel { + name: p_name.map(ToString::to_string), + msg_receive_cb: cb, + message_queue: SegQueue::new(), + }, + ) + .is_some() + { + panic!("We've somehow added a duplicate ID"); + } + println!("Added channel {} FD: {}", p_name.unwrap_or("?"), channel_id); + channel_id +} + +pub fn poll_plugin_message(channel_id: ChannelId) -> Option> { + let pm = CHANNELS.read(); + if let Some(plugin) = pm.get(&channel_id) { + plugin.message_queue.pop() + } else { + panic!("poll_plugin_message for plugin with incorrect ID"); + } +} + +pub fn requeue_plugin_message(channel_id: ChannelId, message: Vec) { + let pm = CHANNELS.read(); + let plugin = pm.get(&channel_id).unwrap(); + let len = plugin.message_queue.len(); + + plugin.message_queue.push(message); + + // len won't be greater than single digit, this is fine + for _ in 0..len { + plugin + .message_queue + .push(plugin.message_queue.pop().unwrap()); + } +} + +pub fn publish_message_from_guest(channel_id: ChannelId, msg: Vec) { + let pm = CHANNELS.read(); + if let Some(plugin) = pm.get(&channel_id) { + let buf_ptr = msg.as_ptr(); + (plugin.msg_receive_cb)(channel_id, buf_ptr, msg.len()) + } else { + println!("failed publish message to FD {}", channel_id); + } +} + +pub fn publish_message_to_guest(channel_id: ChannelId, msg: Vec) { + let pm = CHANNELS.read(); + if let Some(plugin) = pm.get(&channel_id) { + // println!("message pushed"); + plugin.message_queue.push(msg) + } else { + println!("failed to publish message"); + } +} + +pub fn get_channel_from_name(p_name: &str) -> Option { + // let unnamed = "unnamed".to_owned(); + println!("channel_from_name"); + for ch in CHANNELS.read().iter() { + println!( + "channel name: {} FD: {}", + &ch.1.name.as_ref().unwrap_or(&"unnamed".to_string()), + ch.0 + ); + } + + CHANNELS + .read() + .iter() + .find(|(_, v)| v.name.as_deref() == Some(p_name)) + .map(|x| *x.0) +} diff --git a/panda/plugins/guest_plugin_manager/src/interface/daemon_manager.rs b/panda/plugins/guest_plugin_manager/src/interface/daemon_manager.rs new file mode 100644 index 00000000000..cdd0bf279f5 --- /dev/null +++ b/panda/plugins/guest_plugin_manager/src/interface/daemon_manager.rs @@ -0,0 +1,54 @@ +use super::channels::{add_channel, publish_message_to_guest, ChannelId}; +use once_cell::sync::OnceCell; +use std::path::Path; + +const CHANNEL_NAME: &str = "guest_daemon"; +static CHANNEL_DESC: OnceCell = OnceCell::new(); + +enum PacketKind { + LoadPlugin = 0, +} + +#[allow(dead_code)] +struct Packet { + kind: PacketKind, + payload: Vec, +} + +#[allow(dead_code)] +impl PacketKind { + fn from(kind: u32) -> Option { + match kind { + 0 => Some(Self::LoadPlugin), + _ => None, + } + } +} + +extern "C" fn read_callback( + _channel_id: ChannelId, + _ptr: *const u8, + _len: usize, +) { +} + +pub fn load_binary(binary_path: &str) { + if Path::new(binary_path).is_file() { + if let Ok(binary) = std::fs::read(binary_path) { + for chunk in binary.chunks(4096) { + let cd = CHANNEL_DESC.get().unwrap(); + publish_message_to_guest(*cd, chunk.to_owned()); + } + } else { + panic!("Failed to read binary at {}", binary_path); + } + } else { + panic!("failed to check for file {}", binary_path); + } +} + +pub fn init() { + CHANNEL_DESC + .set(add_channel(Some(CHANNEL_NAME), read_callback)) + .unwrap(); +} diff --git a/panda/plugins/guest_plugin_manager/src/interface/hci.rs b/panda/plugins/guest_plugin_manager/src/interface/hci.rs new file mode 100644 index 00000000000..bcd394cffff --- /dev/null +++ b/panda/plugins/guest_plugin_manager/src/interface/hci.rs @@ -0,0 +1,105 @@ +use super::channels::{ + get_channel_from_name, poll_plugin_message, publish_message_from_guest, + requeue_plugin_message, ChannelId, +}; +use super::plugin_manager::new_manager_channel; +use crate::MAGIC; +use panda::mem::{virtual_memory_read, virtual_memory_write}; +use panda::prelude::*; + +pub fn hyp_start( + _cpu: &mut CPUState, + _channel_id: ChannelId, + _arg1: usize, + _arg2: usize, +) -> Option { + println!("start"); + Some(!MAGIC) +} +pub fn hyp_stop( + _cpu: &mut CPUState, + _channel_id: ChannelId, + _arg1: usize, + _arg2: usize, +) -> Option { + println!("stop"); + None +} +pub fn hyp_read( + cpu: &mut CPUState, + channel_id: ChannelId, + addr: usize, + max_size: usize, +) -> Option { + if let Some(mut msg) = poll_plugin_message(channel_id) { + if msg.len() > max_size { + requeue_plugin_message(channel_id, msg[max_size..].to_owned()); + msg.truncate(max_size); + } + // could check max len more + virtual_memory_write(cpu, addr as target_ulong, &msg); + Some(msg.len()) + } else { + Some(0) + } +} +pub fn hyp_write( + cpu: &mut CPUState, + channel_id: ChannelId, + buf_ptr: usize, + buf_size: usize, +) -> Option { + if let Ok(buf_out) = + virtual_memory_read(cpu, buf_ptr as target_ulong, buf_size) + { + let bytes_read = buf_out.len(); + publish_message_from_guest(channel_id, buf_out); + + Some(bytes_read) + } else { + println!("Failed to read virtual memory in hyp_write"); + None + } +} +pub fn hyp_error( + _cpu: &mut CPUState, + _channel_id: ChannelId, + _arg1: usize, + _arg2: usize, +) -> Option { + println!("error"); + None +} + +pub fn hyp_get_manager( + _cpu: &mut CPUState, + _channel_id: ChannelId, + _arg1: usize, + _arg2: usize, +) -> Option { + dbg!(Some(new_manager_channel() as usize)) +} + +pub fn hyp_get_channel_by_name( + cpu: &mut CPUState, + _channel_id: ChannelId, + buf_ptr: usize, + buf_size: usize, +) -> Option { + println!("channel_by_name"); + if let Ok(buf_out) = + virtual_memory_read(cpu, buf_ptr as target_ulong, buf_size) + { + if let Some(cd) = + get_channel_from_name(dbg!(&String::from_utf8_lossy(&buf_out))) + { + println!("found channel number {}", cd); + Some(cd as usize) + } else { + println!("failed to find channel number"); + Some(-1_isize as usize) + } + } else { + panic!("Failed to read virtual memory in hyp_write"); + } +} diff --git a/panda/plugins/guest_plugin_manager/src/interface/mod.rs b/panda/plugins/guest_plugin_manager/src/interface/mod.rs new file mode 100644 index 00000000000..b732c698581 --- /dev/null +++ b/panda/plugins/guest_plugin_manager/src/interface/mod.rs @@ -0,0 +1,5 @@ +pub mod api; +pub mod plugin_manager; +pub mod hci; +pub mod channels; +pub mod daemon_manager; \ No newline at end of file diff --git a/panda/plugins/guest_plugin_manager/src/interface/plugin_manager.rs b/panda/plugins/guest_plugin_manager/src/interface/plugin_manager.rs new file mode 100644 index 00000000000..228e67db58a --- /dev/null +++ b/panda/plugins/guest_plugin_manager/src/interface/plugin_manager.rs @@ -0,0 +1,61 @@ +use super::channels::{add_channel, publish_message_to_guest, ChannelId}; +use std::convert::TryFrom; +use std::mem::size_of; +use std::slice::from_raw_parts; + +type OperationID = u32; + +enum ManagerOp { + GetChannelFromName = 0, + DebugOutput = 2, +} + +impl TryFrom for ManagerOp { + type Error = (); + + fn try_from(value: usize) -> Result { + match value { + 0 => Ok(ManagerOp::GetChannelFromName), + 2 => Ok(ManagerOp::DebugOutput), + _ => Err(()), + } + } +} + +fn get_channel_from_name(origin_channel: ChannelId, buffer: Vec) { + let plugin_name = String::from_utf8_lossy(&buffer).into_owned(); + if let Some(channel_id) = + super::channels::get_channel_from_name(&plugin_name) + { + println!( + "success got channel from name {} FD is {}", + plugin_name, channel_id + ); + let buf = u32::to_le_bytes(channel_id); + + publish_message_to_guest(origin_channel, buf.to_vec()); + } else { + println!("Failed to get channel from name"); + } +} + +extern "C" fn read_callback(channel_id: ChannelId, ptr: *const u8, len: usize) { + let mut buf = unsafe { from_raw_parts(ptr, len).to_vec() }; + const OPSIZE: usize = size_of::(); + let mut operation: [u8; OPSIZE] = [0; 4]; + operation.copy_from_slice(&buf[..OPSIZE]); + let op_num = OperationID::from_le_bytes(operation); + buf.drain(0..OPSIZE); + match ManagerOp::try_from(op_num as usize) { + Ok(ManagerOp::GetChannelFromName) => { + get_channel_from_name(channel_id, buf) + } + Ok(ManagerOp::DebugOutput) => {} + _ => {} + } +} + +pub fn new_manager_channel() -> ChannelId { + dbg!(add_channel(None, read_callback)) +} + diff --git a/panda/plugins/guest_shell/Cargo.lock b/panda/plugins/guest_shell/Cargo.lock new file mode 100644 index 00000000000..2127edfa02b --- /dev/null +++ b/panda/plugins/guest_shell/Cargo.lock @@ -0,0 +1,489 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "ctor" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccc0a48a9b826acdf4028595adc9db92caea352f7af011a3034acd172a52a0aa" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "darling" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72" +dependencies = [ + "darling_core", + "quote", + "syn", +] + +[[package]] +name = "dirs" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30baa043103c9d0c2a57cf537cc2f35623889dc0d405e6c3cccfadbc81c71309" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03d86534ed367a67548dc68113a0f5db55432fdfbb6e6f9d77704397d95d5780" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "doc-comment" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "getrandom" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "ghost" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a5bcf1bbeab73aa4cf2fde60a846858dc036163c7c33bec309f8d17de785479" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "glib-sys" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7e9b997a66e9a23d073f2b1abb4dbfc3925e0b8952f67efd8d9b6e168e4cdc1" +dependencies = [ + "libc", + "system-deps", +] + +[[package]] +name = "guest_shell" +version = "0.1.0" +dependencies = [ + "panda-re", + "parking_lot", +] + +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "inventory" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0eb5160c60ba1e809707918ee329adb99d222888155835c6feedba19f6c3fd4" +dependencies = [ + "ctor", + "ghost", + "inventory-impl", +] + +[[package]] +name = "inventory-impl" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e41b53715c6f0c4be49510bb82dee2c1e51c8586d885abe65396e82ed518548" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f98a04dce437184842841303488f70d0188c5f51437d2a834dc097eafa909a01" + +[[package]] +name = "libloading" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "351a32417a12d5f7e82c368a66781e307834dae04c6ce0cd4456d52989229883" +dependencies = [ + "cfg-if", + "winapi", +] + +[[package]] +name = "lock_api" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "once_cell" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" + +[[package]] +name = "panda-re" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dfc5b9d238b9f1d4785346b7d611dcc4236f615334e0719afbf3033f8c26e0e" +dependencies = [ + "dirs", + "glib-sys", + "inventory", + "lazy_static", + "libloading", + "once_cell", + "panda-re-macros", + "panda-re-sys", + "paste", + "strum 0.20.0", + "strum_macros 0.20.1", + "thiserror", +] + +[[package]] +name = "panda-re-macros" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be1d7a86fc7fc5c32ca9d7b430e5f12f76b664f381c4213c7071d14e88fc588" +dependencies = [ + "darling", + "doc-comment", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "panda-re-sys" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e00ee000dc315bf4a0a55d78b6d97456a7540d6ed01768da5f5aa89fdb660783" + +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" +dependencies = [ + "cfg-if", + "instant", + "libc", + "redox_syscall", + "smallvec", + "winapi", +] + +[[package]] +name = "paste" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0744126afe1a6dd7f394cb50a716dbe086cb06e255e53d8d0185d82828358fb5" + +[[package]] +name = "pkg-config" +version = "0.3.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1a3ea4f0dd7f1f3e512cf97bf100819aa547f36a6eccac8dbaae839eb92363e" + +[[package]] +name = "proc-macro2" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb37d2df5df740e582f28f8560cf425f52bb267d872fe58358eadb554909f07a" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "redox_syscall" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_users" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" +dependencies = [ + "getrandom", + "redox_syscall", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "serde" +version = "1.0.130" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913" + +[[package]] +name = "smallvec" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309" + +[[package]] +name = "strsim" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" + +[[package]] +name = "strum" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57bd81eb48f4c437cadc685403cad539345bf703d78e63707418431cecd4522b" + +[[package]] +name = "strum" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7318c509b5ba57f18533982607f24070a55d353e90d4cae30c467cdb2ad5ac5c" + +[[package]] +name = "strum_macros" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87c85aa3f8ea653bfd3ddf25f7ee357ee4d204731f6aa9ad04002306f6e2774c" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "strum_macros" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee8bc6b87a5112aeeab1f4a9f7ab634fe6cbefc4850006df31267f4cfb9e3149" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "syn" +version = "1.0.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8daf5dd0bb60cbd4137b1b587d2fc0ae729bc07cf01cd70b36a1ed5ade3b9d59" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "system-deps" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f3ecc17269a19353b3558b313bba738b25d82993e30d62a18406a24aba4649b" +dependencies = [ + "heck", + "pkg-config", + "strum 0.18.0", + "strum_macros 0.18.0", + "thiserror", + "toml", + "version-compare", +] + +[[package]] +name = "thiserror" +version = "1.0.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "toml" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" +dependencies = [ + "serde", +] + +[[package]] +name = "unicode-segmentation" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" + +[[package]] +name = "version-compare" +version = "0.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d63556a25bae6ea31b52e640d7c41d1ab27faba4ccb600013837a3d0b3994ca1" + +[[package]] +name = "wasi" +version = "0.10.2+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/panda/plugins/guest_shell/Cargo.toml b/panda/plugins/guest_shell/Cargo.toml new file mode 100644 index 00000000000..f11c725961c --- /dev/null +++ b/panda/plugins/guest_shell/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "guest_shell" +version = "0.1.0" +authors = ["Luke Craig ", "Jordan McLeod "] +edition = "2018" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +panda-re = { version = "0.26", default-features = false } +parking_lot = "0.11" + +[features] +default = ["x86_64"] + +x86_64 = ["panda-re/x86_64"] +i386 = ["panda-re/i386"] +arm = ["panda-re/arm"] +ppc = ["panda-re/ppc"] +mips = ["panda-re/mips"] +mipsel = ["panda-re/mipsel"] +aarch64 = ["panda-re/aarch64"] +mips64 = ["panda-re/mips64"] diff --git a/panda/plugins/guest_shell/Makefile b/panda/plugins/guest_shell/Makefile new file mode 100644 index 00000000000..2234476df57 --- /dev/null +++ b/panda/plugins/guest_shell/Makefile @@ -0,0 +1,18 @@ +# Don't forget to add your plugin to config.panda! + +# Build rust plugins with make! + +# The main rule for your plugin. List all object-file dependencies. + +PANDA_PATH = $(realpath $(shell pwd)/..) +PLUGIN_DIR = $(realpath $(join $(PANDA_PATH), /../panda/plugins/$(PLUGIN_NAME)/)) +RUST_SOURCE = $(wildcard $(PLUGIN_DIR)/src/*.rs) +PLUGIN_ARTIFACTS_DIR = $(PLUGIN_TARGET_DIR)/$(PLUGIN_NAME)/target + +$(PLUGIN_TARGET_DIR)/panda_$(PLUGIN_NAME).so : $(RUST_SOURCE) $(PLUGIN_DIR)/Cargo.toml + @echo " CARGO $(PLUGIN_DIR)" + @CARGO_TERM_PROGRESS_WHEN=never cargo build --release \ + --no-default-features --features=$(TARGET_NAME) \ + --manifest-path=$(PLUGIN_DIR)/Cargo.toml \ + --target-dir=$(PLUGIN_ARTIFACTS_DIR) + @cp -p $(PLUGIN_ARTIFACTS_DIR)/release/lib$(PLUGIN_NAME).so $@ diff --git a/panda/plugins/guest_shell/README.md b/panda/plugins/guest_shell/README.md new file mode 100644 index 00000000000..81a52bc976b --- /dev/null +++ b/panda/plugins/guest_shell/README.md @@ -0,0 +1,95 @@ +# Rust Skeleton + +This is a basic example of how to build a PANDA plugin with Rust. + +## Building + +To check if the plugin will build: + +``` +cargo check +``` + +To actually build the plugin: + +``` +cargo build --release +``` + +(remove `--release` if you want to build in debug mode) + +The resulting plugin will be located in `target/release/librust_skeleton.so`. + +## Structure + +``` +├── Cargo.toml +├── Makefile +├── README.md +└── src + └── lib.rs +``` + +* Cargo.toml - The core plugin info. This informs `cargo` how to actually go about building the plugin. It includes the name, dependencies, and features of plugins. +* Makefile - Instructions for how the PANDA build system will build the plugin. +* lib.rs - The main source file of your plugin. Additional source files can be referenced from here. + +## Cargo.toml + +The dependencies section: + +```toml +[dependencies] +panda-re = { version = "0.5", default-features = false } +``` + +To add a new dependency, add a new line in the form `name = "version"`. + +For example to add [`libc`](https://docs.rs/libc), simply add the following line: + +```toml +libc = "0.2" +``` + +## Targetting Multiple Architectures + +In PANDA, a plugin is recompiled once per target architecture (that is to say, the architecture of the guest). To enable this behavior in Rust plugins, we use ["features"](https://doc.rust-lang.org/cargo/reference/features.html) in order to specify which architecture we are building for. + +This is controlled by this section of Cargo.toml: + +```toml +[features] +default = ["x86_64"] + +x86_64 = ["panda-re/x86_64"] +i386 = ["panda-re/i386"] +arm = ["panda-re/arm"] +ppc = ["panda-re/ppc"] +mips = ["panda-re/mips"] +mipsel = ["panda-re/mipsel"] +``` + +by default `x86_64` is the only feature enabled (which is why we don't need to specify any features to build), this is primarily so that IDE support (rust-analyzer for VSCode/vim/etc, IntelliJ/CLion integration) works out of the box, as IDEs typically do type checking with the default feature set. + +To build for, say, `arm` you can use the following command: + +``` +cargo build --release --no-default-features --features=arm +``` + +And if you wish to prevent certain code from compiling on certain platforms you can use the following: + +```rust +#[cfg(not(feature = "arm"))] +fn breaks_arm() { + // ... +} +``` + +## Other Resources + +* [panda-rs documentation](https://docs.rs/panda-re) +* [panda-rs announcement blog post](https://panda.re/blog/panda-rs) +* [panda-sys documentation](https://docs.rs/panda-re-sys) +* [The Rust Programming Language](https://doc.rust-lang.org/book/) +* [Some example Rust plugins](https://github.com/panda-re/panda-rs-plugins/) diff --git a/panda/plugins/guest_shell/guest_shell_pty.sh b/panda/plugins/guest_shell/guest_shell_pty.sh new file mode 100755 index 00000000000..8532b6fbda2 --- /dev/null +++ b/panda/plugins/guest_shell/guest_shell_pty.sh @@ -0,0 +1 @@ +socat UNIX-CONNECT:/tmp/guest_shell.sock PTY,link=/tmp/guest_shell_pty & screen /tmp/guest_shell_pty diff --git a/panda/plugins/guest_shell/rusty_shell/Cargo.toml b/panda/plugins/guest_shell/rusty_shell/Cargo.toml new file mode 100644 index 00000000000..230c5c70459 --- /dev/null +++ b/panda/plugins/guest_shell/rusty_shell/Cargo.toml @@ -0,0 +1,4 @@ +[package] +name = "rusty_shell" +version = "0.1.0" +edition = "2018" diff --git a/panda/plugins/guest_shell/rusty_shell/src/hypercall.rs b/panda/plugins/guest_shell/rusty_shell/src/hypercall.rs new file mode 100644 index 00000000000..abf8e6ad513 --- /dev/null +++ b/panda/plugins/guest_shell/rusty_shell/src/hypercall.rs @@ -0,0 +1,113 @@ +use std::{io::Write, marker::PhantomData}; + +const HC_MAGIC: usize = 0x666; + +#[allow(dead_code)] +#[derive(Copy, Clone)] +pub enum HcCmd { + Noop = 0, + Start, /* start new action */ + Stop, /* stop action */ + Read, /* read buffer from hypervisor */ + Write, /* write buffer TO hypervisor*/ + Error, /* report error to hypervisor*/ + ConditionalOp, /* ask the hypervisor if op should be completed*/ + NextStateMachine, /* ask the hypervisor manager to move to the next + state machine*/ +} + +pub struct HyperCall<'a> { + cmd : HcCmd, + args: Vec, + lifetime: PhantomData<&'a ()>, +} + +impl HyperCall<'static> { + pub fn new(cmd: HcCmd) -> Self { + Self { + cmd, + args: vec![0; 2], + lifetime: PhantomData, + } + } +} + +#[allow(dead_code)] +impl<'a> HyperCall<'a> { + pub fn arg(&mut self, arg: usize) -> &mut Self { + self.args.push(arg); + self + } + + pub fn from_string(command: HcCmd, s: &'a str) -> HyperCall<'a> { + Self { + cmd: command, + args: vec![ + s.as_ptr() as usize, + s.len(), + ], + lifetime: PhantomData, + } + } + + pub fn from_buf(command: HcCmd, buf: &'a [u8]) -> HyperCall<'a> { + Self { + cmd: command, + args: vec![ + buf.as_ptr() as usize, + buf.len(), + ], + lifetime: PhantomData, + } + } + + pub fn from_mut_buf(command: HcCmd, buf: &'a mut [u8]) -> HyperCall<'a> { + Self { + cmd: command, + args: vec![ + buf.as_ptr() as usize, + buf.len(), + ], + lifetime: PhantomData, + } + } + + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + pub fn call(&mut self) -> usize { + let ret_val; + + while self.args.len() < 2 { + self.args.push(0); + } + + unsafe { + asm!( + "mov eax, {hc_magic}", + "mov ebx, {command:e}", + "cpuid", + hc_magic = const HC_MAGIC, + command = in(reg) self.cmd as u32, + in("ecx") self.args[0], + in("edx") self.args[1], + out("eax") ret_val, + ); + } + + ret_val + } +} + +struct HyperWriter; + +impl Write for HyperWriter { + fn write(&mut self, buf: &[u8]) -> std::io::Result { + HyperCall::from_buf(HcCmd::Write, buf).call(); + + Ok(buf.len()) + } + + #[inline] + fn flush(&mut self) -> std::io::Result<()> { + Ok(()) + } +} diff --git a/panda/plugins/guest_shell/rusty_shell/src/main.rs b/panda/plugins/guest_shell/rusty_shell/src/main.rs new file mode 100644 index 00000000000..7d1308954f8 --- /dev/null +++ b/panda/plugins/guest_shell/rusty_shell/src/main.rs @@ -0,0 +1,52 @@ +#![feature(asm)] + +mod hypercall; +use std::process::Command; + +use hypercall::{HyperCall, HcCmd}; + +/// Read a line of input from the hypervisor +fn read_line() -> String { + let mut buf = vec![0u8; 1024]; + + let len = loop { + let ret = HyperCall::from_mut_buf(HcCmd::Read, &mut buf).call() as isize; + + if ret > 0 { + break ret + } else { + std::thread::yield_now(); + } + }; + + buf.truncate(len as usize); + + String::from_utf8(buf).unwrap() +} + +/// Write a buffer or string across the hypervisor +fn write(output: impl AsRef<[u8]>) { + HyperCall::from_buf(HcCmd::Write, output.as_ref()).call(); +} + +fn main() { + HyperCall::new(HcCmd::Start).call(); + + loop { + let input = read_line(); + + let args: Vec<&str> = input.trim().split_whitespace().collect(); + + if let [program, args @ ..] = &args[..] { + match Command::new(program).args(args).output() { + Ok(output) => { + write(&output.stdout); + write("[CMD_FINISHED]"); + } + Err(_) => break, + } + } + } + + HyperCall::new(HcCmd::Stop).call(); +} diff --git a/panda/plugins/guest_shell/src/lib.rs b/panda/plugins/guest_shell/src/lib.rs new file mode 100644 index 00000000000..d0ecfde8f15 --- /dev/null +++ b/panda/plugins/guest_shell/src/lib.rs @@ -0,0 +1,42 @@ +use panda::{plugins::guest_plugin_manager::*, prelude::*}; +use parking_lot::{const_mutex, Mutex}; +use std::{ + io::{self, Write}, + os::unix::net::{UnixListener, UnixStream}, +}; + +static STDOUT: Mutex> = const_mutex(None); + +// Copy all messages from the guest to the unix socket +#[channel_recv] +fn message_recv(_: u32, data: &[u8]) { + STDOUT.lock().as_mut().unwrap().write_all(data).ok(); +} + +#[derive(PandaArgs)] +#[name = "guest_shell"] +struct Args { + #[arg(default = "/tmp/guest_shell.sock")] + socket_path: String, +} + +fn get_split_socket(path: &str) -> io::Result<(UnixStream, UnixStream)> { + let (socket, _) = UnixListener::bind(path)?.accept()?; + Ok((socket.try_clone()?, socket)) +} + +#[panda::init] +fn init(_: &mut PluginHandle) -> bool { + let args = Args::from_panda_args(); + let mut guest_channel = load_guest_plugin("guest_shell", message_recv); + + let (stdout, mut stdin) = get_split_socket(&args.socket_path).unwrap(); + STDOUT.lock().replace(stdout); + + std::thread::spawn(move || { + // Copy stdin from unix socket to guest + io::copy(&mut stdin, &mut guest_channel).unwrap(); + }); + + true +} diff --git a/panda/plugins/hyperfuse/Cargo.lock b/panda/plugins/hyperfuse/Cargo.lock new file mode 100644 index 00000000000..23a39475c0b --- /dev/null +++ b/panda/plugins/hyperfuse/Cargo.lock @@ -0,0 +1,749 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +dependencies = [ + "memchr", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "cached" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2bc2fd249a24a9cdd4276f3a3e0461713271ab63b0e9e656e200e8e21c8c927" +dependencies = [ + "hashbrown", + "once_cell", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "crossbeam-queue" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b10ddc024425c88c2ad148c1b0fd53f4c6d38db9697c9f1588381212fa657c9" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db" +dependencies = [ + "cfg-if", + "lazy_static", +] + +[[package]] +name = "ctor" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e98e2ad1a782e33928b96fc3948e7c355e5af34ba4de7670fe8bac2a3b2006d" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "darling" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72" +dependencies = [ + "darling_core", + "quote", + "syn", +] + +[[package]] +name = "dirs" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30baa043103c9d0c2a57cf537cc2f35623889dc0d405e6c3cccfadbc81c71309" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03d86534ed367a67548dc68113a0f5db55432fdfbb6e6f9d77704397d95d5780" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "doc-comment" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" + +[[package]] +name = "env_logger" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "fuser" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "096c834eabc44f7151b8f17d28eb0501e30ea9139b4a2d64f33ad9ef4bdae8d3" +dependencies = [ + "libc", + "log", + "memchr", + "page_size", + "pkg-config", + "serde", + "smallvec", + "users", + "zerocopy", +] + +[[package]] +name = "getrandom" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "ghost" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a5bcf1bbeab73aa4cf2fde60a846858dc036163c7c33bec309f8d17de785479" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "glib-sys" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7e9b997a66e9a23d073f2b1abb4dbfc3925e0b8952f67efd8d9b6e168e4cdc1" +dependencies = [ + "libc", + "system-deps", +] + +[[package]] +name = "hashbrown" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" + +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "humantime" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" +dependencies = [ + "quick-error", +] + +[[package]] +name = "hyperfuse" +version = "0.1.0" +dependencies = [ + "bincode", + "cached", + "crossbeam-queue", + "fuser", + "lazy_static", + "libc", + "panda-re", + "parking_lot", + "pretty_env_logger", + "serde", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "instant" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "716d3d89f35ac6a34fd0eed635395f4c3b76fa889338a4632e5231a8684216bd" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "inventory" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f0f7efb804ec95e33db9ad49e4252f049e37e8b0a4652e3cd61f7999f2eff7f" +dependencies = [ + "ctor", + "ghost", + "inventory-impl", +] + +[[package]] +name = "inventory-impl" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75c094e94816723ab936484666968f5b58060492e880f3c8d00489a1e244fa51" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320cfe77175da3a483efed4bc0adc1968ca050b098ce4f2f1c13a56626128790" + +[[package]] +name = "libloading" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "351a32417a12d5f7e82c368a66781e307834dae04c6ce0cd4456d52989229883" +dependencies = [ + "cfg-if", + "winapi", +] + +[[package]] +name = "lock_api" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "memchr" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" + +[[package]] +name = "once_cell" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" + +[[package]] +name = "page_size" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eebde548fbbf1ea81a99b128872779c437752fb99f217c45245e1a61dcd9edcd" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "panda-re" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dfc5b9d238b9f1d4785346b7d611dcc4236f615334e0719afbf3033f8c26e0e" +dependencies = [ + "dirs", + "glib-sys", + "inventory", + "lazy_static", + "libloading", + "once_cell", + "panda-re-macros", + "panda-re-sys", + "paste", + "strum 0.20.0", + "strum_macros 0.20.1", + "thiserror", +] + +[[package]] +name = "panda-re-macros" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be1d7a86fc7fc5c32ca9d7b430e5f12f76b664f381c4213c7071d14e88fc588" +dependencies = [ + "darling", + "doc-comment", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "panda-re-sys" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e00ee000dc315bf4a0a55d78b6d97456a7540d6ed01768da5f5aa89fdb660783" + +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" +dependencies = [ + "cfg-if", + "instant", + "libc", + "redox_syscall", + "smallvec", + "winapi", +] + +[[package]] +name = "paste" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf547ad0c65e31259204bd90935776d1c693cec2f4ff7abb7a1bbbd40dfe58" + +[[package]] +name = "pkg-config" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" + +[[package]] +name = "pretty_env_logger" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "926d36b9553851b8b0005f1275891b392ee4d2d833852c417ed025477350fb9d" +dependencies = [ + "env_logger", + "log", +] + +[[package]] +name = "proc-macro2" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0d8caf72986c1a598726adc988bb5984792ef84f5ee5aa50209145ee8077038" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "quote" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "redox_syscall" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ab49abadf3f9e1c4bc499e8845e152ad87d2ad2d30371841171169e9d75feee" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_users" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" +dependencies = [ + "getrandom", + "redox_syscall", +] + +[[package]] +name = "regex" +version = "1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "serde" +version = "1.0.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "963a7dbc9895aeac7ac90e74f34a5d5261828f79df35cbed41e10189d3804d43" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "smallvec" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309" + +[[package]] +name = "strsim" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" + +[[package]] +name = "strum" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57bd81eb48f4c437cadc685403cad539345bf703d78e63707418431cecd4522b" + +[[package]] +name = "strum" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7318c509b5ba57f18533982607f24070a55d353e90d4cae30c467cdb2ad5ac5c" + +[[package]] +name = "strum_macros" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87c85aa3f8ea653bfd3ddf25f7ee357ee4d204731f6aa9ad04002306f6e2774c" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "strum_macros" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee8bc6b87a5112aeeab1f4a9f7ab634fe6cbefc4850006df31267f4cfb9e3149" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "syn" +version = "1.0.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1873d832550d4588c3dbc20f01361ab00bfe741048f71e3fecf145a7cc18b29c" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "synstructure" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "474aaa926faa1603c40b7885a9eaea29b444d1cb2850cb7c0e37bb1a4182f4fa" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "unicode-xid", +] + +[[package]] +name = "system-deps" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f3ecc17269a19353b3558b313bba738b25d82993e30d62a18406a24aba4649b" +dependencies = [ + "heck", + "pkg-config", + "strum 0.18.0", + "strum_macros 0.18.0", + "thiserror", + "toml", + "version-compare", +] + +[[package]] +name = "termcolor" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thiserror" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93119e4feac1cbe6c798c34d3a53ea0026b0b1de6a120deef895137c0529bfe2" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "060d69a0afe7796bf42e9e2ff91f5ee691fb15c53d38b4b62a9a53eb23164745" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "toml" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" +dependencies = [ + "serde", +] + +[[package]] +name = "unicode-segmentation" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" + +[[package]] +name = "users" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24cc0f6d6f267b73e5a2cadf007ba8f9bc39c6a6f9666f8cf25ea809a153b032" +dependencies = [ + "libc", + "log", +] + +[[package]] +name = "version-compare" +version = "0.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d63556a25bae6ea31b52e640d7c41d1ab27faba4ccb600013837a3d0b3994ca1" + +[[package]] +name = "wasi" +version = "0.10.2+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "zerocopy" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e59ec1d2457bd6c0dd89b50e7d9d6b0b647809bf3f0a59ac85557046950b7b2" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0fbc82b82efe24da867ee52e015e58178684bd9dd64c34e66bdf21da2582a9f" +dependencies = [ + "proc-macro2", + "syn", + "synstructure", +] diff --git a/panda/plugins/hyperfuse/Cargo.toml b/panda/plugins/hyperfuse/Cargo.toml new file mode 100644 index 00000000000..b8b9dab060c --- /dev/null +++ b/panda/plugins/hyperfuse/Cargo.toml @@ -0,0 +1,33 @@ +[package] +name = "hyperfuse" +version = "0.1.0" +authors = ["Luke Craig ", "Jordan McLeod "] +edition = "2018" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +panda-re = { version = "0.26", default-features = false } +fuser = { version = "0.9", features = ["serializable"] } +#fuser = { git = "https://github.com/cberner/fuser", features = ["serializable"] } +libc = "0.2.98" +pretty_env_logger = "0.4.0" +serde = { version = "1", features = ["derive"] } +bincode = "1.3.3" +lazy_static = "1" +parking_lot = "0.11" +crossbeam-queue = "0.3" +cached = { version = "0.26", default-features = false } + +[features] +default = ["x86_64"] + +x86_64 = ["panda-re/x86_64"] +i386 = ["panda-re/i386"] +arm = ["panda-re/arm"] +ppc = ["panda-re/ppc"] +mips = ["panda-re/mips"] +mipsel = ["panda-re/mipsel"] +aarch64 = ["panda-re/aarch64"] +mips64 = ["panda-re/mips64"] diff --git a/panda/plugins/hyperfuse/Makefile b/panda/plugins/hyperfuse/Makefile new file mode 100644 index 00000000000..2234476df57 --- /dev/null +++ b/panda/plugins/hyperfuse/Makefile @@ -0,0 +1,18 @@ +# Don't forget to add your plugin to config.panda! + +# Build rust plugins with make! + +# The main rule for your plugin. List all object-file dependencies. + +PANDA_PATH = $(realpath $(shell pwd)/..) +PLUGIN_DIR = $(realpath $(join $(PANDA_PATH), /../panda/plugins/$(PLUGIN_NAME)/)) +RUST_SOURCE = $(wildcard $(PLUGIN_DIR)/src/*.rs) +PLUGIN_ARTIFACTS_DIR = $(PLUGIN_TARGET_DIR)/$(PLUGIN_NAME)/target + +$(PLUGIN_TARGET_DIR)/panda_$(PLUGIN_NAME).so : $(RUST_SOURCE) $(PLUGIN_DIR)/Cargo.toml + @echo " CARGO $(PLUGIN_DIR)" + @CARGO_TERM_PROGRESS_WHEN=never cargo build --release \ + --no-default-features --features=$(TARGET_NAME) \ + --manifest-path=$(PLUGIN_DIR)/Cargo.toml \ + --target-dir=$(PLUGIN_ARTIFACTS_DIR) + @cp -p $(PLUGIN_ARTIFACTS_DIR)/release/lib$(PLUGIN_NAME).so $@ diff --git a/panda/plugins/hyperfuse/README.md b/panda/plugins/hyperfuse/README.md new file mode 100644 index 00000000000..81a52bc976b --- /dev/null +++ b/panda/plugins/hyperfuse/README.md @@ -0,0 +1,95 @@ +# Rust Skeleton + +This is a basic example of how to build a PANDA plugin with Rust. + +## Building + +To check if the plugin will build: + +``` +cargo check +``` + +To actually build the plugin: + +``` +cargo build --release +``` + +(remove `--release` if you want to build in debug mode) + +The resulting plugin will be located in `target/release/librust_skeleton.so`. + +## Structure + +``` +├── Cargo.toml +├── Makefile +├── README.md +└── src + └── lib.rs +``` + +* Cargo.toml - The core plugin info. This informs `cargo` how to actually go about building the plugin. It includes the name, dependencies, and features of plugins. +* Makefile - Instructions for how the PANDA build system will build the plugin. +* lib.rs - The main source file of your plugin. Additional source files can be referenced from here. + +## Cargo.toml + +The dependencies section: + +```toml +[dependencies] +panda-re = { version = "0.5", default-features = false } +``` + +To add a new dependency, add a new line in the form `name = "version"`. + +For example to add [`libc`](https://docs.rs/libc), simply add the following line: + +```toml +libc = "0.2" +``` + +## Targetting Multiple Architectures + +In PANDA, a plugin is recompiled once per target architecture (that is to say, the architecture of the guest). To enable this behavior in Rust plugins, we use ["features"](https://doc.rust-lang.org/cargo/reference/features.html) in order to specify which architecture we are building for. + +This is controlled by this section of Cargo.toml: + +```toml +[features] +default = ["x86_64"] + +x86_64 = ["panda-re/x86_64"] +i386 = ["panda-re/i386"] +arm = ["panda-re/arm"] +ppc = ["panda-re/ppc"] +mips = ["panda-re/mips"] +mipsel = ["panda-re/mipsel"] +``` + +by default `x86_64` is the only feature enabled (which is why we don't need to specify any features to build), this is primarily so that IDE support (rust-analyzer for VSCode/vim/etc, IntelliJ/CLion integration) works out of the box, as IDEs typically do type checking with the default feature set. + +To build for, say, `arm` you can use the following command: + +``` +cargo build --release --no-default-features --features=arm +``` + +And if you wish to prevent certain code from compiling on certain platforms you can use the following: + +```rust +#[cfg(not(feature = "arm"))] +fn breaks_arm() { + // ... +} +``` + +## Other Resources + +* [panda-rs documentation](https://docs.rs/panda-re) +* [panda-rs announcement blog post](https://panda.re/blog/panda-rs) +* [panda-sys documentation](https://docs.rs/panda-re-sys) +* [The Rust Programming Language](https://doc.rust-lang.org/book/) +* [Some example Rust plugins](https://github.com/panda-re/panda-rs-plugins/) diff --git a/panda/plugins/hyperfuse/src/lib.rs b/panda/plugins/hyperfuse/src/lib.rs new file mode 100644 index 00000000000..468658441eb --- /dev/null +++ b/panda/plugins/hyperfuse/src/lib.rs @@ -0,0 +1,308 @@ +use cached::{stores::TimedCache, Cached}; +use fuser::{ + Filesystem, MountOption, ReplyAttr, ReplyData, ReplyDirectory, ReplyEntry, ReplyOpen, + ReplyWrite, +}; +use libc::ENOENT; +use panda::prelude::*; +use serde::de::DeserializeOwned; +use serde::Serialize; +use std::borrow::Borrow; +use std::ffi::{OsStr, OsString}; +use std::marker::PhantomData; + +mod types; +use types::*; + +struct HyperFilesystem { + reply: Receiver, + request: Sender, + + link_target_cache: TimedCache>, + lookup_cache: TimedCache<(u64, OsString), LookupCacheEntry>, +} + +macro_rules! on_reply { + ( + $self:ident => $reply:ident ( + $type:ident { $($field:ident),* } + + => $reply_ty:ident $({ $( + $reply_field:ident + ),*})? + + // tuple type + $(( $( + $reply_field_tuple:ident + ),*))? + + => $code:block + ) $(;)? + ) => { + $self.request.send(Request::$type { $( $field ),* }).unwrap(); + + match $self.reply.recv() { + Ok(Reply::$reply_ty + // struct variant + $({ $( $reply_field ),* })? + // tuple variant + $(( $( $reply_field_tuple ),* ))? + ) => $code, + Ok(Reply::Error(err)) => $reply.error(err), + Ok(reply) => panic!("Invalid reply {:?}", reply), + Err(_) => $reply.error(ENOENT), + } + }; +} + +macro_rules! send_reply { + ( + $self:ident => $reply:ident.$method:ident ( + $type:ident { $($field:ident),* } + + => $reply_ty:ident + // struct type + $({$( + $reply_field:ident $( . $reply_field_method:ident () )? + ),*})? + // tuple type + $(($( + $reply_field_tup:ident $( . $reply_field_method_tup:ident () )? + ),*))? + ) $(;)? + ) => { + println!("{}(...)", stringify!($method)); + on_reply! { + $self => $reply ( + $type { $($field),* } + + => $reply_ty + // struct type + $({ $( + $reply_field + ),*})? + // tuple type + $(( $( + $reply_field_tup + ),*))? + + => { + // struct type + $( + $( + let $reply_field = $reply_field $( .$reply_field_method () )?; + )* + $reply.$method( $($reply_field),* ); + )? + $( + $( + let $reply_field_tup = $reply_field_tup $( .$reply_field_method_tup () )?; + )* + $reply.$method( $($reply_field_tup),* ); + )? + } + ) + } + }; +} + +impl Filesystem for HyperFilesystem { + fn lookup(&mut self, _req: &fuser::Request, parent_ino: u64, name: &OsStr, reply: ReplyEntry) { + if let Some(LookupCacheEntry { + ttl, + attr, + generation, + }) = self + .lookup_cache + .cache_get(&(parent_ino, name.to_os_string())) + { + reply.entry(ttl, attr, *generation); + return; + } + + let name = name.to_string_lossy().into_owned(); + send_reply! { + self => reply.entry( + Lookup { parent_ino, name } => Entry { ttl.borrow(), attr.borrow(), generation } + ); + } + } + + fn getattr(&mut self, _req: &fuser::Request, ino: u64, reply: ReplyAttr) { + send_reply! { + self => reply.attr( + GetAttr { ino } => Attr { ttl.borrow(), attr.borrow() } + ); + } + } + + fn read( + &mut self, + _req: &fuser::Request, + ino: u64, + _fh: u64, + offset: i64, + size: u32, + flags: i32, + _lock: Option, + reply: ReplyData, + ) { + send_reply! { + self => reply.data( + Read { ino, offset, size, flags } => Data(data.as_ref()) + ); + } + } + + fn readlink(&mut self, _req: &fuser::Request<'_>, ino: u64, reply: ReplyData) { + if let Some(data) = self.link_target_cache.cache_get(&ino) { + reply.data(&data); + return; + } + + send_reply! { + self => reply.data( + ReadLink { ino } => Data(data.as_ref()) + ); + } + } + + fn readdir( + &mut self, + _req: &fuser::Request, + ino: u64, + _fh: u64, + offset: i64, + mut reply: ReplyDirectory, + ) { + let parent_ino = ino; + on_reply! { + self => reply( + ReadDir { ino, offset } + => Directory { dir_entries } + => { + for DirEntry { ino, offset, kind, name, link_target, lookup_cache } in dir_entries { + if let Some(LinkTarget { path, parent_ino, target_name, target_lookup }) = link_target { + self.link_target_cache.cache_set(ino, path); + self.lookup_cache.cache_set((parent_ino, target_name.into()), target_lookup); + } + self.lookup_cache.cache_set((parent_ino, name.clone().into()), lookup_cache); + if reply.add(ino, offset, kind, name) { + break + } + } + + reply.ok(); + } + ); + } + println!("Finished reply"); + } + + fn open(&mut self, _req: &fuser::Request<'_>, ino: u64, flags: i32, reply: ReplyOpen) { + send_reply! { + self => reply.opened( + Open { ino, flags } => Opened { file_handle, flags } + ); + } + } + + fn write( + &mut self, + _req: &fuser::Request<'_>, + ino: u64, + _fh: u64, + offset: i64, + data: &[u8], + write_flags: u32, + flags: i32, + _lock_owner: Option, + reply: ReplyWrite, + ) { + let data = data.to_owned(); + send_reply! { + self => reply.written( + Write { ino, offset, data, write_flags, flags } => Written { size } + ); + } + } +} + +struct Sender(Channel, PhantomData); + +impl Sender { + fn send(&mut self, val: T) -> Result<(), ()> { + bincode::serialize_into(&mut self.0, &val).map_err(|_| ()) + } +} + +struct Receiver(PhantomData); + +impl Receiver { + fn recv(&self) -> Result { + loop { + match MESSAGE_QUEUE.pop() { + Some(bytes) => break bincode::deserialize(&bytes).map_err(|_| ()), + None => { + println!("Nothing recieved, sleeping..."); + std::thread::sleep(std::time::Duration::from_millis(500)); + } + } + } + } +} + +fn split_channel(channel: Channel) -> (Sender, Receiver) +where + InType: DeserializeOwned, + OutType: Serialize, +{ + (Sender(channel, PhantomData), Receiver(PhantomData)) +} + +fn mount(channel: Channel) { + // TODO: make this programatically configurable via a plugin-to-plugin API + let mountpoint = std::env::var("HYPERFUSE_MOUNT") + .expect("HYPERFUSE_MOUNT is not set but is required by 'hyperfuse' plugin"); + + let options = vec![ + MountOption::FSName("hello".to_string()), + MountOption::AutoUnmount, + ]; + + let (request, reply) = split_channel(channel); + + fuser::mount2( + HyperFilesystem { + request, + reply, + link_target_cache: TimedCache::with_lifespan(1), + lookup_cache: TimedCache::with_lifespan(1), + }, + mountpoint, + &options, + ) + .unwrap(); + println!("Unmounted"); +} + +use crossbeam_queue::SegQueue; +use panda::plugins::guest_plugin_manager::*; //GUEST_PLUGIN_MANAGER; + +static MESSAGE_QUEUE: SegQueue> = SegQueue::new(); + +#[channel_recv] +fn message_recv(_: u32, bytes: Vec) { + MESSAGE_QUEUE.push(bytes.to_owned()); +} + +#[panda::init] +fn init(_: &mut PluginHandle) -> bool { + pretty_env_logger::init_custom_env("HYPERFUSE_LOG"); + + let channel = load_guest_plugin("hyperfuse_guest", message_recv); + + std::thread::spawn(move || mount(channel)); + + true +} diff --git a/panda/plugins/hyperfuse/src/types.rs b/panda/plugins/hyperfuse/src/types.rs new file mode 100644 index 00000000000..262d5eb9540 --- /dev/null +++ b/panda/plugins/hyperfuse/src/types.rs @@ -0,0 +1,104 @@ +use libc::c_int; +use std::time::Duration; + +use fuser::{FileAttr, FileType}; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize)] +pub enum Request { + Lookup { + parent_ino: u64, + name: String, + }, + GetAttr { + ino: u64, + }, + Read { + ino: u64, + offset: i64, + size: u32, + flags: i32, + }, + ReadLink { + ino: u64, + }, + ReadDir { + ino: u64, + offset: i64, + }, + Open { + ino: u64, + flags: i32, + }, + Write { + ino: u64, + offset: i64, + data: Vec, + write_flags: u32, + flags: i32, + }, + Create { + parent: u64, + name: String, + mode: u32, + umask: u32, + flags: u32, + }, +} + +#[derive(Serialize, Deserialize, Debug)] +pub enum Reply { + Entry { + ttl: Duration, + attr: FileAttr, + generation: u64, + }, + Attr { + ttl: Duration, + attr: FileAttr, + }, + Data(Vec), + Directory { + dir_entries: Vec, + }, + Opened { + file_handle: u64, + flags: u32, + }, + Written { + size: u32, + }, + Created { + ttl: Duration, + attr: FileAttr, + generation: u64, + fh: u64, + flags: u32, + }, + Error(c_int), +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct LinkTarget { + pub path: Vec, + pub parent_ino: u64, + pub target_name: String, + pub target_lookup: LookupCacheEntry, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct DirEntry { + pub ino: u64, + pub offset: i64, + pub kind: FileType, + pub name: String, + pub link_target: Option, + pub lookup_cache: LookupCacheEntry, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct LookupCacheEntry { + pub ttl: Duration, + pub attr: FileAttr, + pub generation: u64, +} diff --git a/panda/plugins/linjector/.gitignore b/panda/plugins/linjector/.gitignore new file mode 100644 index 00000000000..bdb80413b49 --- /dev/null +++ b/panda/plugins/linjector/.gitignore @@ -0,0 +1,3 @@ +/target +src/injectables/injector +src/injectables/tiny_mmap diff --git a/panda/plugins/linjector/Cargo.lock b/panda/plugins/linjector/Cargo.lock new file mode 100644 index 00000000000..2250e0b1dbe --- /dev/null +++ b/panda/plugins/linjector/Cargo.lock @@ -0,0 +1,705 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aho-corasick" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +dependencies = [ + "memchr", +] + +[[package]] +name = "array-init" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6945cc5422176fc5e602e590c2878d2c2acd9a4fe20a4baa7c28022521698ec6" + +[[package]] +name = "async-trait" +version = "0.1.51" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44318e776df68115a881de9a8fd1b9e53368d7a4a5ce4cc48517da3393233a5e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "crc32fast" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "ctor" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccc0a48a9b826acdf4028595adc9db92caea352f7af011a3034acd172a52a0aa" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "darling" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72" +dependencies = [ + "darling_core", + "quote", + "syn", +] + +[[package]] +name = "dashmap" +version = "4.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e77a43b28d0668df09411cb0bc9a8c2adc40f9a048afe863e05fd43251e8e39c" +dependencies = [ + "cfg-if", + "num_cpus", +] + +[[package]] +name = "dirs" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30baa043103c9d0c2a57cf537cc2f35623889dc0d405e6c3cccfadbc81c71309" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03d86534ed367a67548dc68113a0f5db55432fdfbb6e6f9d77704397d95d5780" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "doc-comment" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" + +[[package]] +name = "env_logger" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "flate2" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e6988e897c1c9c485f43b47a529cef42fde0547f9d8d41a7062518f1d8fc53f" +dependencies = [ + "cfg-if", + "crc32fast", + "libc", + "miniz_oxide", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "getrandom" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "ghost" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a5bcf1bbeab73aa4cf2fde60a846858dc036163c7c33bec309f8d17de785479" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "glib-sys" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7e9b997a66e9a23d073f2b1abb4dbfc3925e0b8952f67efd8d9b6e168e4cdc1" +dependencies = [ + "libc", + "system-deps", +] + +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "humantime" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" +dependencies = [ + "quick-error", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "inventory" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f0f7efb804ec95e33db9ad49e4252f049e37e8b0a4652e3cd61f7999f2eff7f" +dependencies = [ + "ctor", + "ghost", + "inventory-impl", +] + +[[package]] +name = "inventory-impl" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75c094e94816723ab936484666968f5b58060492e880f3c8d00489a1e244fa51" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8f7255a17a627354f321ef0055d63b898c6fb27eff628af4d1b66b7331edf6" + +[[package]] +name = "libloading" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "351a32417a12d5f7e82c368a66781e307834dae04c6ce0cd4456d52989229883" +dependencies = [ + "cfg-if", + "winapi", +] + +[[package]] +name = "linjector" +version = "0.1.0" +dependencies = [ + "lazy_static", + "log", + "object", + "once_cell", + "panda-re", + "pretty_env_logger", +] + +[[package]] +name = "lock_api" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "memchr" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" + +[[package]] +name = "miniz_oxide" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" +dependencies = [ + "adler", + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "object" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39f37e50073ccad23b6d09bcb5b263f4e76d3bb6038e4a3c08e52162ffa8abc2" +dependencies = [ + "flate2", + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" + +[[package]] +name = "panda-re" +version = "0.38.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b59ef8fd95e7cecece17cf5d4d1c9aeafe79f020cc2b622cec18dd0a903b44ce" +dependencies = [ + "array-init", + "async-trait", + "dashmap", + "dirs", + "glib-sys", + "inventory", + "lazy_static", + "libloading", + "log", + "once_cell", + "panda-re-macros", + "panda-re-sys", + "parking_lot", + "paste", + "strum 0.20.0", + "strum_macros 0.20.1", + "thiserror", +] + +[[package]] +name = "panda-re-macros" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29772398be20723c90088ae4380d62e25cefe54c174d9082532b258985e41d04" +dependencies = [ + "darling", + "doc-comment", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "panda-re-sys" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e00ee000dc315bf4a0a55d78b6d97456a7540d6ed01768da5f5aa89fdb660783" + +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" +dependencies = [ + "cfg-if", + "instant", + "libc", + "redox_syscall", + "smallvec", + "winapi", +] + +[[package]] +name = "paste" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf547ad0c65e31259204bd90935776d1c693cec2f4ff7abb7a1bbbd40dfe58" + +[[package]] +name = "pkg-config" +version = "0.3.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c9b1041b4387893b91ee6746cddfc28516aff326a3519fb2adf820932c5e6cb" + +[[package]] +name = "pretty_env_logger" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "926d36b9553851b8b0005f1275891b392ee4d2d833852c417ed025477350fb9d" +dependencies = [ + "env_logger", + "log", +] + +[[package]] +name = "proc-macro2" +version = "1.0.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "quote" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "redox_syscall" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_users" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" +dependencies = [ + "getrandom", + "redox_syscall", +] + +[[package]] +name = "regex" +version = "1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "serde" +version = "1.0.130" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913" + +[[package]] +name = "smallvec" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309" + +[[package]] +name = "strsim" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" + +[[package]] +name = "strum" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57bd81eb48f4c437cadc685403cad539345bf703d78e63707418431cecd4522b" + +[[package]] +name = "strum" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7318c509b5ba57f18533982607f24070a55d353e90d4cae30c467cdb2ad5ac5c" + +[[package]] +name = "strum_macros" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87c85aa3f8ea653bfd3ddf25f7ee357ee4d204731f6aa9ad04002306f6e2774c" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "strum_macros" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee8bc6b87a5112aeeab1f4a9f7ab634fe6cbefc4850006df31267f4cfb9e3149" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "syn" +version = "1.0.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5239bc68e0fef57495900cfea4e8dc75596d9a319d7e16b1e0a440d24e6fe0a0" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "system-deps" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f3ecc17269a19353b3558b313bba738b25d82993e30d62a18406a24aba4649b" +dependencies = [ + "heck", + "pkg-config", + "strum 0.18.0", + "strum_macros 0.18.0", + "thiserror", + "toml", + "version-compare", +] + +[[package]] +name = "termcolor" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thiserror" +version = "1.0.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "602eca064b2d83369e2b2f34b09c70b605402801927c65c11071ac911d299b88" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bad553cc2c78e8de258400763a647e80e6d1b31ee237275d756f6836d204494c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "toml" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" +dependencies = [ + "serde", +] + +[[package]] +name = "unicode-segmentation" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" + +[[package]] +name = "version-compare" +version = "0.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d63556a25bae6ea31b52e640d7c41d1ab27faba4ccb600013837a3d0b3994ca1" + +[[package]] +name = "wasi" +version = "0.10.2+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/panda/plugins/linjector/Cargo.toml b/panda/plugins/linjector/Cargo.toml new file mode 100644 index 00000000000..20e981ade48 --- /dev/null +++ b/panda/plugins/linjector/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "linjector" +version = "0.1.0" +authors = ["Luke Craig ", "Jordan McLeod "] +edition = "2018" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +panda-re = { version = "0.38.0", default-features = false, features = ["syscall-injection"] } +once_cell = "1.8.0" +object = "0.26.2" +lazy_static = "1.4.0" +log = "0.4" +pretty_env_logger = "0.4" + +[features] +default = ["x86_64"] + +x86_64 = ["panda-re/x86_64"] +i386 = ["panda-re/i386"] +arm = ["panda-re/arm"] +ppc = ["panda-re/ppc"] +mips = ["panda-re/mips"] +mipsel = ["panda-re/mipsel"] +aarch64 = ["panda-re/aarch64"] +mips64 = ["panda-re/mips64"] diff --git a/panda/plugins/linjector/Makefile b/panda/plugins/linjector/Makefile new file mode 100644 index 00000000000..2234476df57 --- /dev/null +++ b/panda/plugins/linjector/Makefile @@ -0,0 +1,18 @@ +# Don't forget to add your plugin to config.panda! + +# Build rust plugins with make! + +# The main rule for your plugin. List all object-file dependencies. + +PANDA_PATH = $(realpath $(shell pwd)/..) +PLUGIN_DIR = $(realpath $(join $(PANDA_PATH), /../panda/plugins/$(PLUGIN_NAME)/)) +RUST_SOURCE = $(wildcard $(PLUGIN_DIR)/src/*.rs) +PLUGIN_ARTIFACTS_DIR = $(PLUGIN_TARGET_DIR)/$(PLUGIN_NAME)/target + +$(PLUGIN_TARGET_DIR)/panda_$(PLUGIN_NAME).so : $(RUST_SOURCE) $(PLUGIN_DIR)/Cargo.toml + @echo " CARGO $(PLUGIN_DIR)" + @CARGO_TERM_PROGRESS_WHEN=never cargo build --release \ + --no-default-features --features=$(TARGET_NAME) \ + --manifest-path=$(PLUGIN_DIR)/Cargo.toml \ + --target-dir=$(PLUGIN_ARTIFACTS_DIR) + @cp -p $(PLUGIN_ARTIFACTS_DIR)/release/lib$(PLUGIN_NAME).so $@ diff --git a/panda/plugins/linjector/README.md b/panda/plugins/linjector/README.md new file mode 100644 index 00000000000..af971ae6d1f --- /dev/null +++ b/panda/plugins/linjector/README.md @@ -0,0 +1,15 @@ +# linjector + +linjector is a PANDA plugin responsible for non-cooperatively injecting a binary into +a linux guest. This process is done via system call injection, chaining system calls +together in order to run the provided executable. It is not recommended to use this directly, but rather to use `guest_plugin_manager` in order to spawn your executable as a child of the PANDA-provided guest agent (`guest_daemon`). + +### Arguments + +* `guest_binary` - string, the path of the executable to load into the guest +* `proc_name` - string, the process name to inject into. Defaults to `[any]`. +* `require_root` - bool, whether or not to require the process being injected into to have a UID of root + +### Compatibility + +Currently linjector only has support for x86_64 and arm guests. For other targets one may need to provide their own process injection mechanism. diff --git a/panda/plugins/linjector/linjector_ppp.h b/panda/plugins/linjector/linjector_ppp.h new file mode 100644 index 00000000000..2a407a8ee0f --- /dev/null +++ b/panda/plugins/linjector/linjector_ppp.h @@ -0,0 +1,11 @@ +#ifndef __LINJECTOR_PPP_H +#define __LINJECTOR_PPP_H +// BEGIN_PYPANDA_NEEDS_THIS -- do not delete this comment bc pypanda +// api autogen needs it. And don't put any compiler directives +// between this and END_PYPANDA_NEEDS_THIS except includes of other +// files in this directory that contain subsections like this one. + +PPP_CB_TYPEDEF(void,before_guest_inject,CPUState *); + +// END_PYPANDA_NEEDS_THIS -- do not delete this comment! +#endif diff --git a/panda/plugins/linjector/rustfmt.toml b/panda/plugins/linjector/rustfmt.toml new file mode 100644 index 00000000000..5c8d9318b3b --- /dev/null +++ b/panda/plugins/linjector/rustfmt.toml @@ -0,0 +1 @@ +max_width = 80 \ No newline at end of file diff --git a/panda/plugins/linjector/src/args.rs b/panda/plugins/linjector/src/args.rs new file mode 100644 index 00000000000..f740916a27a --- /dev/null +++ b/panda/plugins/linjector/src/args.rs @@ -0,0 +1,55 @@ +use once_cell::sync::OnceCell; +use panda::plugins::guest_plugin_manager::guest_plugin_path; +use panda::prelude::*; + +use std::fs; +use std::path::Path; + +static ELF_TO_INJECT: OnceCell> = OnceCell::new(); + +#[derive(PandaArgs)] +#[name = "linjector"] // plugin name +pub struct Args { + #[arg(default = "guest_daemon")] + pub guest_binary: String, + + #[arg(default = "[any]")] + pub proc_name: String, + + #[arg(default = true)] + pub require_root: bool, +} + +lazy_static::lazy_static! { + pub static ref ARGS: Args = Args::from_panda_args(); +} + +pub fn ensure_init() { + lazy_static::initialize(&ARGS); +} + +pub fn load_elf() { + log::info!("Loading binary: {:?}", ARGS.guest_binary); + + let binary_name = &ARGS.guest_binary; + + let guest_binary = match guest_plugin_path(binary_name) { + Some(path) => path.to_string_lossy().into_owned(), + None if Path::new(binary_name).exists() => binary_name.clone(), + None => panic!("Failed to get binary {:?}", binary_name), + }; + + ELF_TO_INJECT.get_or_init(|| fs::read(&guest_binary).unwrap()); +} + +pub fn elf_to_inject() -> &'static [u8] { + &ELF_TO_INJECT.get().expect("No elf file loaded")[..] +} + +pub fn require_root() -> bool { + ARGS.require_root +} + +pub fn proc_name() -> &'static str { + ARGS.proc_name.as_str() +} diff --git a/panda/plugins/linjector/src/injectables/Makefile b/panda/plugins/linjector/src/injectables/Makefile new file mode 100644 index 00000000000..1616672f058 --- /dev/null +++ b/panda/plugins/linjector/src/injectables/Makefile @@ -0,0 +1,31 @@ +.DEFAULT_GOAL := all +LIST=injector tiny_mmap + +all: $(LIST) + +.PHONY: all + +CC=gcc -m32 +EXTRA_GCC_ARGS= -fomit-frame-pointer -nodefaultlibs -nostdlib -fpic + + +hello_world: hello_world.c + $(CC) $(EXTRA_GCC_ARGS) $< -o $@ + +read_file: read_file.c + $(CC) $(EXTRA_GCC_ARGS) $< -o $@ + +read_all_files: read_all_files.c + $(CC) $(EXTRA_GCC_ARGS) $< -o $@ + +injector: injector.c + $(CC) -O3 $(EXTRA_GCC_ARGS) $< -o $@ + +tiny_mmap: tiny_mmap.c + $(CC) $(EXTRA_GCC_ARGS) $< -o $@ + +basic_hello_world: basic_hello_world.c + $(CC) -static $< -o $@ + +clean: + rm -rf $(LIST) diff --git a/panda/plugins/linjector/src/injectables/include/hypercall.h b/panda/plugins/linjector/src/injectables/include/hypercall.h new file mode 100644 index 00000000000..c1235ede477 --- /dev/null +++ b/panda/plugins/linjector/src/injectables/include/hypercall.h @@ -0,0 +1,66 @@ +// stolen from recctrl.h; modified to make more generic +#include "hypercall_constants.h" + + +#if defined(__x86_64__) || defined(__i386__) +static inline __attribute__((always_inline)) int hc_rec(hc_cmd action, char *s, int len) { + int eax = HC_MAGIC; + int ret = HC_ERROR; + + asm __volatile__( + "mov %1, %%eax \t\n\ + mov %2, %%ebx \t\n\ + mov %3, %%ecx \t\n\ + mov %4, %%edx \t\n\ + cpuid \t\n\ + mov %%eax, %0 \t\n\ + " + : "=g"(ret) /* output operand */ + : "g" (eax), "g" (action), "g" (s), "g" (len)/* input operands */ + : "eax", "ebx", "ecx", "edx" /* clobbered registers */ + ); + + return ret; +} +static inline __attribute__((always_inline)) int hc(hc_cmd action, char *s) { + int eax = HC_MAGIC; + int ret = HC_ERROR; + + asm __volatile__( + "mov %1, %%eax \t\n\ + mov %2, %%ebx \t\n\ + mov %3, %%ecx \t\n\ + cpuid \t\n\ + mov %%eax, %0 \t\n\ + " + : "=g"(ret) /* output operand */ + : "g" (eax), "g" (action), "g" (s) /* input operands */ + : "eax", "ebx", "ecx", "edx" /* clobbered registers */ + ); + + return ret; +} +#elif defined(__arm__) +static inline __attribute__((always_inline)) int hc(hc_cmd action, char *s) { + unsigned long r0 = HC_MAGIC; + int ret = HC_ERROR; + + asm __volatile__( + "push {r0-r4} \t\n\ + ldr r0, %1 \t\n\ + ldr r1, %2 \t\n\ + ldr r2, %3 \t\n\ + ldr p7, 0, r0, c0, c0, 0 \t\n\ + sdr r0, %0 \t\n\ + pop {r0-r4} \t\n\ + " + : "=g"(ret) /* output operand */ + : "g" (r0), "g" (action), "g" (s) /* input operands */ + : "r0", "r1", "r2", "r3" /* clobbered registers */ + ); + + return ret; +} +#else +#error Unsupported platform. +#endif diff --git a/panda/plugins/linjector/src/injectables/include/hypercall_constants.h b/panda/plugins/linjector/src/injectables/include/hypercall_constants.h new file mode 100644 index 00000000000..d2b234195f8 --- /dev/null +++ b/panda/plugins/linjector/src/injectables/include/hypercall_constants.h @@ -0,0 +1,15 @@ +/** @brief Magic code to use in cpuid hypercall. */ +#define HC_MAGIC 0x10adc0d3 + +typedef enum { + HC_NOOP = 0, + HC_START, /* start new action */ + HC_STOP, /* stop action */ + HC_READ, /* read buffer from hypervisor */ + HC_WRITE, /* write buffer TO hypervisor*/ + HC_ERROR, /* report error to hypervisor*/ + HC_CONDITIONAL_OP, /* ask the hypervisor if op should be completed*/ + HC_NEXT_STATE_MACHINE, /* ask the hypervisor manager to move to the next + state machine*/ +} hc_cmd; + diff --git a/panda/plugins/linjector/src/injectables/include/syscall_x86.h b/panda/plugins/linjector/src/injectables/include/syscall_x86.h new file mode 100644 index 00000000000..cf20621a6d7 --- /dev/null +++ b/panda/plugins/linjector/src/injectables/include/syscall_x86.h @@ -0,0 +1,103 @@ +#ifndef BASE_C_EXAMPLE +#include "/usr/include/i386-linux-gnu/asm/unistd_32.h" +#include "/usr/include/asm-generic/fcntl.h" +#define _SYS_MMAN_H // it's a lie. but it's a good intention +#define __USE_MISC +#include "/usr/include/bits/mman-linux.h" +#endif +#define NULL 0L + +#define SYSINL static inline __attribute__((always_inline)) + +/* +* All the syscall stuff is from musl /arch/i386/syscall_arch.h +*/ + +#define SYSCALL_INSNS "int $128" + +#define SYSCALL_INSNS_12 "xchg %%ebx,%%edx ; " SYSCALL_INSNS " ; xchg %%ebx,%%edx" +#define SYSCALL_INSNS_34 "xchg %%ebx,%%edi ; " SYSCALL_INSNS " ; xchg %%ebx,%%edi" + + +SYSINL long syscall_0(long n) +{ + unsigned long __ret; + __asm__ __volatile__ (SYSCALL_INSNS : "=a"(__ret) : "a"(n) : "memory"); + return __ret; +} + +SYSINL long syscall_1(long n, long a1) +{ + unsigned long __ret; + __asm__ __volatile__ (SYSCALL_INSNS_12 : "=a"(__ret) : "a"(n), "d"(a1) : "memory"); + return __ret; +} + +SYSINL long syscall_2(long n, long a1, long a2) +{ + unsigned long __ret; + __asm__ __volatile__ (SYSCALL_INSNS_12 : "=a"(__ret) : "a"(n), "d"(a1), "c"(a2) : "memory"); + return __ret; +} + +SYSINL long syscall_3(long n, long a1, long a2, long a3) +{ + unsigned long __ret; +#if !defined(__PIC__) || !defined(BROKEN_EBX_ASM) + __asm__ __volatile__ (SYSCALL_INSNS : "=a"(__ret) : "a"(n), "b"(a1), "c"(a2), "d"(a3) : "memory"); +#else + __asm__ __volatile__ (SYSCALL_INSNS_34 : "=a"(__ret) : "a"(n), "D"(a1), "c"(a2), "d"(a3) : "memory"); +#endif + return __ret; +} + +SYSINL long syscall_4(long n, long a1, long a2, long a3, long a4) +{ + unsigned long __ret; +#if !defined(__PIC__) || !defined(BROKEN_EBX_ASM) + __asm__ __volatile__ (SYSCALL_INSNS : "=a"(__ret) : "a"(n), "b"(a1), "c"(a2), "d"(a3), "S"(a4) : "memory"); +#else + __asm__ __volatile__ (SYSCALL_INSNS_34 : "=a"(__ret) : "a"(n), "D"(a1), "c"(a2), "d"(a3), "S"(a4) : "memory"); +#endif + return __ret; +} + +SYSINL long syscall_5(long n, long a1, long a2, long a3, long a4, long a5) +{ + unsigned long __ret; +#if !defined(__PIC__) || !defined(BROKEN_EBX_ASM) + __asm__ __volatile__ (SYSCALL_INSNS + : "=a"(__ret) : "a"(n), "b"(a1), "c"(a2), "d"(a3), "S"(a4), "D"(a5) : "memory"); +#else + __asm__ __volatile__ ("pushl %2 ; push %%ebx ; mov 4(%%esp),%%ebx ; " SYSCALL_INSNS " ; pop %%ebx ; add $4,%%esp" + : "=a"(__ret) : "a"(n), "g"(a1), "c"(a2), "d"(a3), "S"(a4), "D"(a5) : "memory"); +#endif + return __ret; +} + +SYSINL long syscall_6(long n, long a1, long a2, long a3, long a4, long a5, long a6) +{ + unsigned long __ret; +#if !defined(__PIC__) || !defined(BROKEN_EBX_ASM) + __asm__ __volatile__ ("pushl %7 ; push %%ebp ; mov 4(%%esp),%%ebp ; " SYSCALL_INSNS " ; pop %%ebp ; add $4,%%esp" + : "=a"(__ret) : "a"(n), "b"(a1), "c"(a2), "d"(a3), "S"(a4), "D"(a5), "g"(a6) : "memory"); +#else + unsigned long a1a6[2] = { a1, a6 }; + __asm__ __volatile__ ("pushl %1 ; push %%ebx ; push %%ebp ; mov 8(%%esp),%%ebx ; mov 4(%%ebx),%%ebp ; mov (%%ebx),%%ebx ; " SYSCALL_INSNS " ; pop %%ebp ; pop %%ebx ; add $4,%%esp" + : "=a"(__ret) : "g"(&a1a6), "a"(n), "c"(a2), "d"(a3), "S"(a4), "D"(a5) : "memory"); +#endif + return __ret; +} + + + + +static inline void* memset(void *buf, int num, int l){ + char* writer = (char*) buf; + void* end = buf + l; + while ((void*)writer < end){ + *writer = num; + writer++; + } + return buf; +} \ No newline at end of file diff --git a/panda/plugins/linjector/src/injectables/injector.c b/panda/plugins/linjector/src/injectables/injector.c new file mode 100644 index 00000000000..4dfdd114ab6 --- /dev/null +++ b/panda/plugins/linjector/src/injectables/injector.c @@ -0,0 +1,54 @@ +#include "include/syscall_x86.h" +#include "include/hypercall.h" +#define MFD_CLOEXEC 0x0001U + +int _start(void){ + int pid = syscall_0(__NR_fork); + if (pid == 0){ + // child process + int val = 0; + while(!val){ + hc(HC_STOP, (char*)&val); + syscall_0(__NR_sched_yield); + } + char none = '\0'; + int fd = syscall_2(__NR_memfd_create, (int)&none, MFD_CLOEXEC); + char buf[512]; + int rlen; + while ((rlen = hc_rec(HC_WRITE, (char*)&buf,sizeof(buf)/sizeof(buf[0])))>0){ + syscall_3(__NR_write, fd, (int)buf, rlen); + } + hc(HC_NEXT_STATE_MACHINE, (char*)0); + unsigned char execbuf[] = {47, 112, 114, 111, 99, 47, 115, 101, 108, 102, 47, 102, 100, 47, 48, 0}; + execbuf[14] += fd; + char* argv[] = {(char*)0}; + syscall_3(__NR_execve, (int)execbuf, (int)argv, (int)argv); + }else{ + // parent process + int pathname = hc(HC_READ,(char*)pid); + int argv = hc(HC_READ, (char*) pid); + int envp = hc(HC_READ, (char*) pid); + syscall_3(__NR_execve, pathname, argv, envp); + } +} + + //int pc = hc(HC_READ, (char*)pid); + //int eax = hc(HC_READ, (char*)pid); + //int ecx = hc(HC_READ, (char*)pid); + //int edx = hc(HC_READ, (char*)pid); + //int ebx = hc(HC_READ, (char*)pid); + //int esp = hc(HC_READ, (char*)pid); + //int ebp = hc(HC_READ, (char*)pid); + //int esi = hc(HC_READ, (char*)pid); + //int edi = hc(HC_READ, (char*)pid); + //asm volatile("mov %%eax, %0" : : "r"(eax)); + //asm volatile("mov %%ecx, %0" : : "r"(ecx)); + //asm volatile("mov %%edx, %0" : : "r"(edx)); + //asm volatile("mov %%ebx, %0" : : "r"(ebx)); + //asm volatile("mov %%esi, %0" : : "r"(esi)); + //asm volatile("mov %%edi, %0" : : "r"(edi)); + //asm volatile("mov %%esp, %0" : : "r"(esp)); + //asm volatile("mov %%ebp, %0" : : "r"(ebp)); + ////asm volatile ("jmp *%0" : : "r" (pc)); + //asm volatile ("jmp -2"); + //while(1); \ No newline at end of file diff --git a/panda/plugins/linjector/src/injectables/tiny_mmap.c b/panda/plugins/linjector/src/injectables/tiny_mmap.c new file mode 100644 index 00000000000..7ea79d1250e --- /dev/null +++ b/panda/plugins/linjector/src/injectables/tiny_mmap.c @@ -0,0 +1,11 @@ +#include "include/syscall_x86.h" +#include "include/hypercall.h" + +// how much memory we give the injector +#define PAGE_SIZE 0x1000 + +int _start(void){ + void* region = syscall_6(__NR_mmap2, NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED | MAP_ANON,-1,0); + hc(HC_START,(char*)region); + (*(void(*)()) region)(); +} \ No newline at end of file diff --git a/panda/plugins/linjector/src/lib.rs b/panda/plugins/linjector/src/lib.rs new file mode 100644 index 00000000000..f37592a7df2 --- /dev/null +++ b/panda/plugins/linjector/src/lib.rs @@ -0,0 +1,274 @@ +use panda::{ + current_asid, enums::MemRWStatus, mem::virtual_memory_write, + plugins::osi::OSI, prelude::*, sys::get_cpu, +}; + +#[cfg(not(feature = "ppc"))] +use panda::{ + plugins::syscalls2::SYSCALLS, + syscall_injection::{fork, run_injector}, +}; + +use std::sync::atomic::{AtomicBool, Ordering}; + +mod args; + +#[cfg(not(feature = "ppc"))] +mod syscalls; + +#[cfg(not(feature = "ppc"))] +use syscalls::{ + chdir, close, do_execve, do_memfd_create, do_mmap, do_write, getpid, open, + setsid, O_CLOEXEC, O_CREAT, O_RDWR, O_TRUNC, PAGE_SIZE, +}; + +#[cfg(not(feature = "ppc"))] +/// mmap a buffer and ensure it's paged in, then return the address to it +async fn get_guest_buffer() -> target_ptr_t { + // mmap in a new page + let mmap_addr = do_mmap().await; + log::debug!("mmap addr {:#x}", mmap_addr); + + if (mmap_addr as target_long).is_negative() && mmap_addr > 0xffff_0000 { + log::error!("linjector mmap error: {}", mmap_addr as target_long); + } + + // Ensure the page is mapped in + let chdir_return = chdir(mmap_addr).await; + log::debug!("Chdir return: {:#x}", chdir_return); + + mmap_addr as target_ptr_t +} + +fn current_process_name(cpu: &mut CPUState) -> String { + let proc = OSI.get_current_process(cpu); + proc.map(|name| name.get_name().into_owned()) + .unwrap_or_default() +} + +/// Convert to bytes and add null terminator +fn cstr_bytes(string: impl Into) -> Vec { + let mut string = string.into().into_bytes(); + string.push(0); + string +} + +/// Format a string and copy it to the guest +macro_rules! guest_string { + ($cpu:ident, $($tt:tt)*) => {{ + let bytes = cstr_bytes(format!($($tt)*)); + let guest_buf = get_guest_buffer().await; + + let write_result = virtual_memory_write($cpu, guest_buf, &bytes); + + if !matches!(write_result, MemRWStatus::MemTxOk) { + log::error!("Write to guest status: {:?}", write_result); + } + + guest_buf + }}; +} + +panda::export_ppp_callback! { + pub(crate) fn before_guest_inject(cpu: &mut CPUState); +} + +#[cfg(not(feature = "ppc"))] +extern "C" fn on_sys_enter( + cpu: &mut CPUState, + pc: SyscallPc, + syscall_num: target_ulong, +) { + // Only check process name when a target process name is provided + if args::proc_name() != "[any]" { + let proc_name = current_process_name(cpu); + + // Only inject into this process if the process matches the provided name + if proc_name == args::proc_name() { + log::trace!("Injecting into process {:?}", proc_name); + } else { + log::trace!("Not injecting into process {:?}", proc_name); + return; + } + } + + // Once we inject to a process stop looking for syscalls to inject into + SYSCALLS.remove_callback_on_all_sys_enter(on_sys_enter); + + log::debug!("Attempting injection into syscall {}", syscall_num); + let file_data = args::elf_to_inject(); + + // Inject our syscall chain into the current system call. This injector + // copies our ELF to a memory file descriptor then forks and runs it as + // a daemon process. + run_injector(pc, async move { + let cpu = unsafe { &mut *get_cpu() }; + if args::require_root() { + if getpid().await == 0 { + log::debug!("Got root!"); + } else { + // Set the injector back up for next syscall + log::trace!("Not root, retrying next syscall..."); + SYSCALLS.add_callback_on_all_sys_enter(on_sys_enter); + return; + } + } + + log::debug!("current asid: {:x}", current_asid(cpu)); + + // mmap a region so we have a buffer in the guest to use + let guest_buf = get_guest_buffer().await; + + // Create a memory file descriptor for loading our binary into + let mem_fd = loop { + match do_memfd_create(guest_buf).await { + 0 => log::trace!("Got memfd of 0, retrying..."), + fd => break fd, + } + }; + log::debug!("Got memory fd {:#x}", mem_fd); + + let (fd, is_mem_fd) = if (mem_fd as target_long).is_negative() { + log::error!("linjector mem_fd error: {}", mem_fd as target_long); + + log::debug!("linjector trying to write to /tmp instead..."); + + let path = guest_string!(cpu, "/tmp/payload"); + let fd = + open(path, O_CREAT | O_CLOEXEC | O_RDWR | O_TRUNC, 0o777).await; + + log::debug!("open of /tmp/payload returned {}", fd); + + if (fd as target_long).is_negative() { + log::error!("open of /tmp/payload returned error {}", fd); + } + + (fd, false) + } else { + (mem_fd, true) + }; + + // Write our file to our memory fd + let mut elf_write_pos = 0; + while elf_write_pos < file_data.len() { + // Calculate max size to attempt to copy to our guest buffer + let attempt_write_size = + usize::min(PAGE_SIZE as usize, file_data.len() - elf_write_pos); + + // Calculate the end of the range we're attempting to copy + let end_write = elf_write_pos + attempt_write_size; + + log::debug!( + "Writing {} bytes [{}-{}]... (file len: {})", + PAGE_SIZE, + elf_write_pos, + end_write, + file_data.len(), + ); + + // Copy to guest buffer + virtual_memory_write( + cpu, + guest_buf, + &file_data[elf_write_pos..end_write], + ); + + // Write guest buffer to memory file descriptor + let written = do_write(fd, guest_buf, PAGE_SIZE).await; + + if written < 0 { + log::error!("Write returned error {}", written); + panic!(); + } else { + elf_write_pos += written as usize; + } + } + + log::debug!("Finished writing to memfd"); + + if !is_mem_fd { + let close_ret = close(fd).await; + if close_ret != 0 { + log::error!("Close of fd failed: {}", close_ret); + } + } + + log::debug!("Forking..."); + + // Fork and have the child process spawn the injected elf + let child_pid = fork(async move { + log::debug!("Child process began"); + log::debug!( + "Child process pid: {:#x?}, Child's parent: {:#x?}", + OSI.get_current_process(cpu).map(|proc| proc.pid), + OSI.get_current_process(cpu).map(|proc| proc.ppid), + ); + log::debug!("Child asid: {:#x?}", panda::current_asid(cpu)); + + // Daemonize child process + let session_id = setsid().await; + log::debug!("Session id: {:#x}", session_id); + + // Path should be "/proc/self/fd/#" where # is the memory file descriptor we + // loaded our executable into, + let guest_path_buf = if is_mem_fd { + guest_string!(cpu, "/proc/self/fd/{}", fd) + } else { + guest_string!(cpu, "/tmp/payload") + }; + + before_guest_inject::trigger(cpu); + + // Execute the guest binary + log::debug!("Performing execve"); + dbg!(do_execve(guest_path_buf, 0, 0).await); + panic!(); + }) + .await; + + log::debug!("Fork returned pid: {:#x?}", child_pid); + let cpu = unsafe { &mut *get_cpu() }; + log::debug!( + "Parent process pid: {:#x?}, Parent's parent: {:#x?}", + OSI.get_current_process(cpu).map(|proc| proc.pid), + OSI.get_current_process(cpu).map(|proc| proc.ppid), + ); + log::debug!("Parent asid: {:#x?}", panda::current_asid(cpu)); + + // Allow the original process to resume executing + }); +} + +static LOADED: AtomicBool = AtomicBool::new(false); + +#[cfg(not(feature = "ppc"))] +#[panda::init] +fn init(_: &mut PluginHandle) -> bool { + if LOADED.swap(true, Ordering::SeqCst) { + return true; + } + + args::ensure_init(); + SYSCALLS.add_callback_on_all_sys_enter(on_sys_enter); + + pretty_env_logger::init_custom_env("LINJECTOR_LOG"); + args::load_elf(); + + log::info!("linjector loaded"); + if args::require_root() { + log::info!("linjector requiring root"); + } else { + log::info!("linjector not requiring root"); + } + + true +} + +#[cfg(feature = "ppc")] +#[panda::init] +fn init(_: &mut PluginHandle) -> bool { + panic!("linjector not supported on PowerPC") +} + +#[panda::uninit] +fn exit(_: &mut PluginHandle) {} diff --git a/panda/plugins/linjector/src/regs.rs b/panda/plugins/linjector/src/regs.rs new file mode 100644 index 00000000000..c3bfe36d056 --- /dev/null +++ b/panda/plugins/linjector/src/regs.rs @@ -0,0 +1,16 @@ +use panda::regs::Reg; + +// =================== Register Order =================== +#[cfg(feature = "i386")] +pub const REG_ORDER: [Reg; 4] = [Reg::EAX, Reg::EBX, Reg::ECX, Reg::EDX]; + +// XXX: is this right? +#[cfg(feature = "x86_64")] +pub const REG_ORDER: [Reg; 4] = [Reg::RAX, Reg::RBX, Reg::RCX, Reg::RDX]; + +// =================== Return Value =================== +#[cfg(feature = "i386")] +pub const RET_REG: Reg = Reg::EAX; + +#[cfg(feature = "x86_64")] +pub const RET_REG: Reg = Reg::RAX; diff --git a/panda/plugins/linjector/src/syscalls.rs b/panda/plugins/linjector/src/syscalls.rs new file mode 100644 index 00000000000..5ba9ac0f6fe --- /dev/null +++ b/panda/plugins/linjector/src/syscalls.rs @@ -0,0 +1,107 @@ +use panda::prelude::*; +use panda::syscall_injection::{syscall, syscall_no_return}; + +// i386 +// const MMAP2: target_ulong = 192; +// const WRITE: target_ulong = 4; +// const FORK: target_ulong = 2; +// const EXECVE: target_ulong = 11; +// const MEMFD_CREATE: target_ulong = 356; + +#[cfg(feature = "x86_64")] +#[path = "syscalls/x86_64.rs"] +mod sys_nums; + +#[cfg(feature = "i386")] +#[path = "syscalls/i386.rs"] +mod sys_nums; + +#[cfg(feature = "arm")] +#[path = "syscalls/arm.rs"] +mod sys_nums; + +#[cfg(any(feature = "mips", feature = "mipsel"))] +#[path = "syscalls/mips.rs"] +mod sys_nums; + +#[cfg(feature = "mips64")] +#[path = "syscalls/mips64.rs"] +mod sys_nums; + +#[cfg(feature = "aarch64")] +#[path = "syscalls/aarch64.rs"] +mod sys_nums; + +use sys_nums::*; + +const NULL: target_ulong = 0; +const NEG_1: target_ulong = u32::MAX as target_ulong; +pub const PAGE_SIZE: target_ulong = 1024; + +pub async fn do_mmap() -> target_ulong { + syscall( + MMAP, + ( + 0u64, + PAGE_SIZE, + PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_ANON, + NEG_1, + NULL, + ), + ) + .await +} + +pub const O_CREAT: i32 = 0o100; +pub const O_RDWR: i32 = 0o002; +pub const O_CLOEXEC: i32 = 0o2000000; +pub const O_TRUNC: i32 = 0o1000; + +const MFD_CLOEXEC: target_ulong = 1; + +pub async fn do_memfd_create(mmap_addr: target_ulong) -> target_ulong { + // we use the mmap_addr for the name because we've zeroed it + // so it will be a '\0' literal name + syscall(MEMFD_CREATE, (mmap_addr, MFD_CLOEXEC)).await +} + +pub async fn do_write( + mem_fd: target_ulong, + mmap_addr: target_ulong, + len: target_ulong, +) -> target_long { + syscall(WRITE, (mem_fd, mmap_addr, len)).await as target_long +} + +pub async fn do_execve( + path: target_ulong, + argv: target_ulong, + envp: target_ulong, +) -> target_ulong { + syscall_no_return(EXECVE, (path, argv, envp)).await +} + +pub async fn getpid() -> target_ulong { + syscall(GETPID, ()).await +} + +pub async fn chdir(addr: target_ulong) -> target_ulong { + syscall(CHDIR, (addr,)).await +} + +pub async fn setsid() -> target_ulong { + syscall(SETSID, ()).await +} + +pub async fn close(fd: target_ulong) -> target_ulong { + syscall(CLOSE, (fd,)).await +} + +pub async fn open( + path_ptr: target_ulong, + flags: i32, + mode: target_ulong, +) -> target_ulong { + syscall(OPEN, (path_ptr, flags as target_long as target_ulong, mode)).await +} diff --git a/panda/plugins/linjector/src/syscalls/aarch64.rs b/panda/plugins/linjector/src/syscalls/aarch64.rs new file mode 100644 index 00000000000..781a05afeb4 --- /dev/null +++ b/panda/plugins/linjector/src/syscalls/aarch64.rs @@ -0,0 +1,17 @@ +use panda::prelude::*; + +pub(crate) const GETPID: target_ulong = 0xAC; +pub(crate) const MMAP: target_ulong = 222; +pub(crate) const WRITE: target_ulong = 64; +pub(crate) const EXECVE: target_ulong = 221; +pub(crate) const MEMFD_CREATE: target_ulong = 279; +pub(crate) const CHDIR: target_ulong = 49; +pub(crate) const SETSID: target_ulong = 157; +pub(crate) const OPEN: target_ulong = 0x400; +pub(crate) const CLOSE: target_ulong = 0x39; + +pub(crate) const PROT_READ: target_ulong = 1; +pub(crate) const PROT_WRITE: target_ulong = 2; + +pub(crate) const MAP_SHARED: target_ulong = 1; +pub(crate) const MAP_ANON: target_ulong = 0x20; diff --git a/panda/plugins/linjector/src/syscalls/arm.rs b/panda/plugins/linjector/src/syscalls/arm.rs new file mode 100644 index 00000000000..a03a0e16dd8 --- /dev/null +++ b/panda/plugins/linjector/src/syscalls/arm.rs @@ -0,0 +1,17 @@ +use panda::prelude::*; + +pub(crate) const GETPID: target_ulong = 20; +pub(crate) const MMAP: target_ulong = 192; // mmap2, must not use page offset != 0 +pub(crate) const WRITE: target_ulong = 4; +pub(crate) const EXECVE: target_ulong = 11; +pub(crate) const MEMFD_CREATE: target_ulong = 385; +pub(crate) const CHDIR: target_ulong = 12; +pub(crate) const SETSID: target_ulong = 66; +pub(crate) const OPEN: target_ulong = 5; +pub(crate) const CLOSE: target_ulong = 6; + +pub(crate) const PROT_READ: target_ulong = 1; +pub(crate) const PROT_WRITE: target_ulong = 2; + +pub(crate) const MAP_SHARED: target_ulong = 0x1; +pub(crate) const MAP_ANON: target_ulong = 0x20; diff --git a/panda/plugins/linjector/src/syscalls/i386.rs b/panda/plugins/linjector/src/syscalls/i386.rs new file mode 100644 index 00000000000..bbb840bf76e --- /dev/null +++ b/panda/plugins/linjector/src/syscalls/i386.rs @@ -0,0 +1,19 @@ +use panda::prelude::*; + +pub(crate) const GETPID: target_ulong = 20; +pub(crate) const MMAP: target_ulong = 192; +pub(crate) const WRITE: target_ulong = 4; +pub(crate) const EXECVE: target_ulong = 11; +pub(crate) const MEMFD_CREATE: target_ulong = 356; +pub(crate) const CHDIR: target_ulong = 12; +pub(crate) const SETSID: target_ulong = 66; +pub(crate) const OPEN: target_ulong = 5; +pub(crate) const CLOSE: target_ulong = 6; + +pub(crate) const PROT_READ: target_ulong = 1; +pub(crate) const PROT_WRITE: target_ulong = 2; + +pub(crate) const MAP_SHARED: target_ulong = 0x1; +pub(crate) const MAP_ANON: target_ulong = 0x20; +//pub(crate) const MAP_SHARED: target_ulong = 0x2; +//pub(crate) const MAP_ANON: target_ulong = 0x20; diff --git a/panda/plugins/linjector/src/syscalls/mips.rs b/panda/plugins/linjector/src/syscalls/mips.rs new file mode 100644 index 00000000000..0c540f5ff44 --- /dev/null +++ b/panda/plugins/linjector/src/syscalls/mips.rs @@ -0,0 +1,17 @@ +use panda::prelude::*; + +pub(crate) const GETPID: target_ulong = 4020; +pub(crate) const MMAP: target_ulong = 4090; +pub(crate) const WRITE: target_ulong = 4004; +pub(crate) const EXECVE: target_ulong = 4011; +pub(crate) const MEMFD_CREATE: target_ulong = 4354; +pub(crate) const CHDIR: target_ulong = 4012; +pub(crate) const SETSID: target_ulong = 4066; +pub(crate) const OPEN: target_ulong = 4005; +pub(crate) const CLOSE: target_ulong = 4006; + +pub(crate) const PROT_READ: target_ulong = 1; +pub(crate) const PROT_WRITE: target_ulong = 2; + +pub(crate) const MAP_SHARED: target_ulong = 0x1; +pub(crate) const MAP_ANON: target_ulong = 0x800; diff --git a/panda/plugins/linjector/src/syscalls/mips64.rs b/panda/plugins/linjector/src/syscalls/mips64.rs new file mode 100644 index 00000000000..780119d5ba7 --- /dev/null +++ b/panda/plugins/linjector/src/syscalls/mips64.rs @@ -0,0 +1,17 @@ +use panda::prelude::*; + +pub(crate) const GETPID: target_ulong = 5038; +pub(crate) const MMAP: target_ulong = 5009; +pub(crate) const WRITE: target_ulong = 5001; +pub(crate) const EXECVE: target_ulong = 5057; +pub(crate) const MEMFD_CREATE: target_ulong = 5314; +pub(crate) const CHDIR: target_ulong = 5078; +pub(crate) const SETSID: target_ulong = 5110; +pub(crate) const OPEN: target_ulong = 5002; +pub(crate) const CLOSE: target_ulong = 5003; + +pub(crate) const PROT_READ: target_ulong = 1; +pub(crate) const PROT_WRITE: target_ulong = 2; + +pub(crate) const MAP_SHARED: target_ulong = 1; +pub(crate) const MAP_ANON: target_ulong = 0x800; diff --git a/panda/plugins/linjector/src/syscalls/x86_64.rs b/panda/plugins/linjector/src/syscalls/x86_64.rs new file mode 100644 index 00000000000..d24db3c7786 --- /dev/null +++ b/panda/plugins/linjector/src/syscalls/x86_64.rs @@ -0,0 +1,17 @@ +use panda::prelude::*; + +pub(crate) const GETPID: target_ulong = 39; +pub(crate) const MMAP: target_ulong = 9; +pub(crate) const WRITE: target_ulong = 1; +pub(crate) const EXECVE: target_ulong = 59; +pub(crate) const MEMFD_CREATE: target_ulong = 319; +pub(crate) const CHDIR: target_ulong = 80; +pub(crate) const SETSID: target_ulong = 112; +pub(crate) const OPEN: target_ulong = 2; +pub(crate) const CLOSE: target_ulong = 3; + +pub(crate) const PROT_READ: target_ulong = 1; +pub(crate) const PROT_WRITE: target_ulong = 2; + +pub(crate) const MAP_SHARED: target_ulong = 0x1; +pub(crate) const MAP_ANON: target_ulong = 0x20; diff --git a/panda/plugins/rust_skeleton/Cargo.lock b/panda/plugins/rust_skeleton/Cargo.lock index 20f84875f86..f50fe556365 100644 --- a/panda/plugins/rust_skeleton/Cargo.lock +++ b/panda/plugins/rust_skeleton/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "array-init" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6945cc5422176fc5e602e590c2878d2c2acd9a4fe20a4baa7c28022521698ec6" + [[package]] name = "bitflags" version = "1.2.1" @@ -182,17 +188,25 @@ dependencies = [ "winapi", ] +[[package]] +name = "once_cell" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225" + [[package]] name = "panda-re" -version = "0.14.0" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03153860245f365c1f01452404eddd0a0741beafd88acf6e6afe167d1ac6c874" +checksum = "6848dfa0312ec610a889292351238c728a1e2622d9fbff94194475dc0eb29de0" dependencies = [ + "array-init", "dirs", "glib-sys", "inventory", "lazy_static", "libloading", + "once_cell", "panda-re-macros", "panda-re-sys", "paste", @@ -203,21 +217,22 @@ dependencies = [ [[package]] name = "panda-re-macros" -version = "0.10.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0ebc6c9d873a7285c7a09bfe4c80dc80efa8d3ea28bcb18a1d6a933dd3242be" +checksum = "29772398be20723c90088ae4380d62e25cefe54c174d9082532b258985e41d04" dependencies = [ "darling", "doc-comment", + "proc-macro2", "quote", "syn", ] [[package]] name = "panda-re-sys" -version = "0.5.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b9fe3ab684d3cf027c816a724de1ea40373b6438dc2240d64bdca0ca99f2e01" +checksum = "e00ee000dc315bf4a0a55d78b6d97456a7540d6ed01768da5f5aa89fdb660783" [[package]] name = "paste" diff --git a/panda/plugins/rust_skeleton/Cargo.toml b/panda/plugins/rust_skeleton/Cargo.toml index e213def62c5..251bce5f44d 100644 --- a/panda/plugins/rust_skeleton/Cargo.toml +++ b/panda/plugins/rust_skeleton/Cargo.toml @@ -8,7 +8,7 @@ edition = "2018" crate-type = ["cdylib"] [dependencies] -panda-re = { version = "0.14.0", default-features = false } +panda-re = { version = "0.34.0", default-features = false } [features] default = ["x86_64"] diff --git a/panda/plugins/rust_skeleton/src/lib.rs b/panda/plugins/rust_skeleton/src/lib.rs index 91a376fc22b..0648edae7d3 100644 --- a/panda/plugins/rust_skeleton/src/lib.rs +++ b/panda/plugins/rust_skeleton/src/lib.rs @@ -1,16 +1,10 @@ use panda::prelude::*; #[panda::init] -fn init(_: &mut PluginHandle) -> bool { +fn init(_: &mut PluginHandle) { println!("Initialized!"); - true } -#[panda::uninit] -fn exit(_: &mut PluginHandle) { - println!("Exiting"); -} - -#[panda::before_block_exec] -fn bbe(_cpu: &mut CPUState, _tb: &mut TranslationBlock){ -} +//#[panda::before_block_exec] +//fn bbe(_cpu: &mut CPUState, _tb: &mut TranslationBlock){ +//} diff --git a/panda/plugins/snake_hook/Cargo.lock b/panda/plugins/snake_hook/Cargo.lock index a0924079ab1..605dfa90f77 100644 --- a/panda/plugins/snake_hook/Cargo.lock +++ b/panda/plugins/snake_hook/Cargo.lock @@ -163,9 +163,9 @@ dependencies = [ [[package]] name = "inline-python" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c178e725a9d7a2cd53fedcc0411424c48b240f7d7416a4803a46381a0ef8788d" +checksum = "e2090a070ce14a62b0605bb08e545b28ff785b24b9fabfc56a402a5987e7a299" dependencies = [ "inline-python-macros", "pyo3", @@ -173,9 +173,9 @@ dependencies = [ [[package]] name = "inline-python-macros" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7156c4a14ca399598b2a2c5d26d8c421721661445a1c22e906d3aa77952610bc" +checksum = "f772582b7328d339524184f3980438daf380bf75edb05543356790192a17fafc" dependencies = [ "libc", "proc-macro2", diff --git a/panda/plugins/syscalls2/generated/syscall_switch_enter_linux_arm.cpp b/panda/plugins/syscalls2/generated/syscall_switch_enter_linux_arm.cpp index bd5c554b0d2..79073223a06 100644 --- a/panda/plugins/syscalls2/generated/syscall_switch_enter_linux_arm.cpp +++ b/panda/plugins/syscalls2/generated/syscall_switch_enter_linux_arm.cpp @@ -5376,7 +5376,11 @@ void syscall_enter_switch_linux_arm(CPUState *cpu, target_ptr_t pc, int static_c if (!panda_noreturn) { struct hook h; h.addr = ctx.retaddr; - h.asid = ctx.asid; + if (ctx.double_return) { + h.asid = 0; + } else { + h.asid = ctx.asid; + } //h.cb.start_block_exec = hook_syscall_return; //h.type = PANDA_CB_START_BLOCK_EXEC; h.cb.before_tcg_codegen = hook_syscall_return; @@ -5385,9 +5389,9 @@ void syscall_enter_switch_linux_arm(CPUState *cpu, target_ptr_t pc, int static_c h.km = MODE_ANY; //you'd expect this to be user only hooks_add_hook(&h); - running_syscalls[std::make_pair(ctx.retaddr, ctx.asid)] = ctx; + running_syscalls[std::make_pair(ctx.retaddr, h.asid)] = ctx; } #endif } -/* vim: set tabstop=4 softtabstop=4 noexpandtab ft=cpp: */ \ No newline at end of file +/* vim: set tabstop=4 softtabstop=4 noexpandtab ft=cpp: */ diff --git a/panda/plugins/syscalls2/generated/syscall_switch_enter_linux_x64.cpp b/panda/plugins/syscalls2/generated/syscall_switch_enter_linux_x64.cpp index 5ede06d2a4e..48ba3b352dd 100644 --- a/panda/plugins/syscalls2/generated/syscall_switch_enter_linux_x64.cpp +++ b/panda/plugins/syscalls2/generated/syscall_switch_enter_linux_x64.cpp @@ -4918,4 +4918,4 @@ void syscall_enter_switch_linux_x64(CPUState *cpu, target_ptr_t pc, int static_c #endif } -/* vim: set tabstop=4 softtabstop=4 noexpandtab ft=cpp: */ \ No newline at end of file +/* vim: set tabstop=4 softtabstop=4 noexpandtab ft=cpp: */ diff --git a/panda/plugins/syscalls2/generated/syscall_switch_return_linux_arm.cpp b/panda/plugins/syscalls2/generated/syscall_switch_return_linux_arm.cpp index 3a68fa3f9ac..6ebafcc2493 100644 --- a/panda/plugins/syscalls2/generated/syscall_switch_return_linux_arm.cpp +++ b/panda/plugins/syscalls2/generated/syscall_switch_return_linux_arm.cpp @@ -42,6 +42,7 @@ void syscall_return_switch_linux_arm(CPUState *cpu, target_ptr_t pc, const sysca case 2: { if (PPP_CHECK_CB(on_sys_fork_return) || PPP_CHECK_CB(on_all_sys_return2)) { } + printf("fork return\n"); PPP_RUN_CB(on_sys_fork_return, cpu, pc) ; }; break; // 3 long sys_read ['unsigned int fd', 'char __user *buf', 'size_t count'] @@ -4032,4 +4033,4 @@ void syscall_return_switch_linux_arm(CPUState *cpu, target_ptr_t pc, const sysca #endif } -/* vim: set tabstop=4 softtabstop=4 noexpandtab ft=cpp: */ \ No newline at end of file +/* vim: set tabstop=4 softtabstop=4 noexpandtab ft=cpp: */ diff --git a/panda/plugins/tcp_passthrough/Cargo.lock b/panda/plugins/tcp_passthrough/Cargo.lock new file mode 100644 index 00000000000..6f4968914ae --- /dev/null +++ b/panda/plugins/tcp_passthrough/Cargo.lock @@ -0,0 +1,728 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "ansi-parser" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcb2392079bf27198570d6af79ecbd9ec7d8f16d3ec6b60933922fdb66287127" +dependencies = [ + "heapless", + "nom", +] + +[[package]] +name = "ansi-str" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90cb0ceb8c444d026166795e474e9dfe54b443bdc07cc21bd6c5073f5e637482" +dependencies = [ + "ansi-parser", +] + +[[package]] +name = "array-init" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6945cc5422176fc5e602e590c2878d2c2acd9a4fe20a4baa7c28022521698ec6" + +[[package]] +name = "arrayvec" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" + +[[package]] +name = "as-slice" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45403b49e3954a4b8428a0ac21a4b7afadccf92bfd96273f1a58cd4812496ae0" +dependencies = [ + "generic-array 0.12.4", + "generic-array 0.13.3", + "generic-array 0.14.5", + "stable_deref_trait", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "ctor" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccc0a48a9b826acdf4028595adc9db92caea352f7af011a3034acd172a52a0aa" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "darling" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72" +dependencies = [ + "darling_core", + "quote", + "syn", +] + +[[package]] +name = "dashmap" +version = "5.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "391b56fbd302e585b7a9494fb70e40949567b1cf9003a8e4a6041a1687c26573" +dependencies = [ + "cfg-if", + "hashbrown", + "lock_api", +] + +[[package]] +name = "dirs" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30baa043103c9d0c2a57cf537cc2f35623889dc0d405e6c3cccfadbc81c71309" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03d86534ed367a67548dc68113a0f5db55432fdfbb6e6f9d77704397d95d5780" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "doc-comment" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "generic-array" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd" +dependencies = [ + "typenum", +] + +[[package]] +name = "generic-array" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f797e67af32588215eaaab8327027ee8e71b9dd0b2b26996aedf20c030fce309" +dependencies = [ + "typenum", +] + +[[package]] +name = "generic-array" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" +dependencies = [ + "typenum", + "version_check 0.9.4", +] + +[[package]] +name = "getrandom" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "ghost" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a5bcf1bbeab73aa4cf2fde60a846858dc036163c7c33bec309f8d17de785479" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "glib-sys" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7e9b997a66e9a23d073f2b1abb4dbfc3925e0b8952f67efd8d9b6e168e4cdc1" +dependencies = [ + "libc", + "system-deps", +] + +[[package]] +name = "hash32" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4041af86e63ac4298ce40e5cca669066e75b6f1aa3390fe2561ffa5e1d9f4cc" +dependencies = [ + "byteorder", +] + +[[package]] +name = "hashbrown" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db0d4cf898abf0081f964436dc980e96670a0f36863e4b83aaacdb65c9d7ccc3" + +[[package]] +name = "heapless" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74911a68a1658cfcfb61bc0ccfbd536e3b6e906f8c2f7883ee50157e3e2184f1" +dependencies = [ + "as-slice", + "generic-array 0.13.3", + "hash32", + "stable_deref_trait", +] + +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "inventory" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0eb5160c60ba1e809707918ee329adb99d222888155835c6feedba19f6c3fd4" +dependencies = [ + "ctor", + "ghost", + "inventory-impl", +] + +[[package]] +name = "inventory-impl" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e41b53715c6f0c4be49510bb82dee2c1e51c8586d885abe65396e82ed518548" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.112" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125" + +[[package]] +name = "libloading" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "351a32417a12d5f7e82c368a66781e307834dae04c6ce0cd4456d52989229883" +dependencies = [ + "cfg-if", + "winapi", +] + +[[package]] +name = "lock_api" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "nom" +version = "4.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6" +dependencies = [ + "memchr", + "version_check 0.1.5", +] + +[[package]] +name = "once_cell" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5" + +[[package]] +name = "owo-colors" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "decf7381921fea4dcb2549c5667eda59b3ec297ab7e2b5fc33eac69d2e7da87b" + +[[package]] +name = "panda-re" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6848dfa0312ec610a889292351238c728a1e2622d9fbff94194475dc0eb29de0" +dependencies = [ + "array-init", + "dirs", + "glib-sys", + "inventory", + "lazy_static", + "libloading", + "once_cell", + "panda-re-macros", + "panda-re-sys", + "paste", + "strum 0.20.0", + "strum_macros 0.20.1", + "thiserror", +] + +[[package]] +name = "panda-re-macros" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29772398be20723c90088ae4380d62e25cefe54c174d9082532b258985e41d04" +dependencies = [ + "darling", + "doc-comment", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "panda-re-sys" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e00ee000dc315bf4a0a55d78b6d97456a7540d6ed01768da5f5aa89fdb660783" + +[[package]] +name = "papergrid" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63709d10e2c2ec58f7bd91d8258d27ce80de090064b0ddf3a4bf38b907b61b8a" +dependencies = [ + "strip-ansi-escapes", + "unicode-width", +] + +[[package]] +name = "paste" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0744126afe1a6dd7f394cb50a716dbe086cb06e255e53d8d0185d82828358fb5" + +[[package]] +name = "pkg-config" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe" + +[[package]] +name = "proc-macro2" +version = "1.0.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f84e92c0f7c9d58328b85a78557813e4bd845130db68d7184635344399423b1" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "redox_syscall" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_users" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" +dependencies = [ + "getrandom", + "redox_syscall", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "serde" +version = "1.0.131" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ad69dfbd3e45369132cc64e6748c2d65cdfb001a2b1c232d128b4ad60561c1" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.131" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b710a83c4e0dff6a3d511946b95274ad9ca9e5d3ae497b63fda866ac955358d2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "strip-ansi-escapes" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "011cbb39cf7c1f62871aea3cc46e5817b0937b49e9447370c93cacbe93a766d8" +dependencies = [ + "vte", +] + +[[package]] +name = "strsim" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" + +[[package]] +name = "strum" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57bd81eb48f4c437cadc685403cad539345bf703d78e63707418431cecd4522b" + +[[package]] +name = "strum" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7318c509b5ba57f18533982607f24070a55d353e90d4cae30c467cdb2ad5ac5c" + +[[package]] +name = "strum_macros" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87c85aa3f8ea653bfd3ddf25f7ee357ee4d204731f6aa9ad04002306f6e2774c" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "strum_macros" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee8bc6b87a5112aeeab1f4a9f7ab634fe6cbefc4850006df31267f4cfb9e3149" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "syn" +version = "1.0.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8daf5dd0bb60cbd4137b1b587d2fc0ae729bc07cf01cd70b36a1ed5ade3b9d59" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "system-deps" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f3ecc17269a19353b3558b313bba738b25d82993e30d62a18406a24aba4649b" +dependencies = [ + "heck", + "pkg-config", + "strum 0.18.0", + "strum_macros 0.18.0", + "thiserror", + "toml", + "version-compare", +] + +[[package]] +name = "tabled" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d15827061abcf689257b1841c8e2732b1dfcc3ef825b24ce6c606e1e9e1a7bde" +dependencies = [ + "ansi-str", + "papergrid", + "tabled_derive", +] + +[[package]] +name = "tabled_derive" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "278ea3921cee8c5a69e0542998a089f7a14fa43c9c4e4f9951295da89bd0c943" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tcp_passthrough" +version = "0.1.0" +dependencies = [ + "bincode", + "dashmap", + "once_cell", + "owo-colors", + "panda-re", + "serde", + "tabled", + "tcp_shared_types", +] + +[[package]] +name = "tcp_shared_types" +version = "0.1.0" +dependencies = [ + "serde", +] + +[[package]] +name = "thiserror" +version = "1.0.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "toml" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" +dependencies = [ + "serde", +] + +[[package]] +name = "typenum" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" + +[[package]] +name = "unicode-segmentation" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" + +[[package]] +name = "unicode-width" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" + +[[package]] +name = "utf8parse" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "936e4b492acfd135421d8dca4b1aa80a7bfc26e702ef3af710e0752684df5372" + +[[package]] +name = "version-compare" +version = "0.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d63556a25bae6ea31b52e640d7c41d1ab27faba4ccb600013837a3d0b3994ca1" + +[[package]] +name = "version_check" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "vte" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6cbce692ab4ca2f1f3047fcf732430249c0e971bfdd2b234cf2c47ad93af5983" +dependencies = [ + "arrayvec", + "utf8parse", + "vte_generate_state_changes", +] + +[[package]] +name = "vte_generate_state_changes" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d257817081c7dffcdbab24b9e62d2def62e2ff7d00b1c20062551e6cccc145ff" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "wasi" +version = "0.10.2+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/panda/plugins/tcp_passthrough/Cargo.toml b/panda/plugins/tcp_passthrough/Cargo.toml new file mode 100644 index 00000000000..41bff9ea788 --- /dev/null +++ b/panda/plugins/tcp_passthrough/Cargo.toml @@ -0,0 +1,31 @@ +[package] +name = "tcp_passthrough" +version = "0.1.0" +authors = ["Jordan McLeod "] +edition = "2018" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +panda-re = { version = "0.34", default-features = false } +bincode = "1" +serde = { version = "1", features = ["derive"] } +tabled = { version = "0.6", features = ["color"] } +once_cell = "1" +owo-colors = "3" +dashmap = "5" + +tcp_shared_types = { path = "./tcp_shared_types" } + +[features] +default = ["x86_64"] + +x86_64 = ["panda-re/x86_64"] +i386 = ["panda-re/i386"] +arm = ["panda-re/arm"] +ppc = ["panda-re/ppc"] +mips = ["panda-re/mips"] +mipsel = ["panda-re/mipsel"] +aarch64 = ["panda-re/aarch64"] +mips64 = ["panda-re/mips64"] diff --git a/panda/plugins/tcp_passthrough/Makefile b/panda/plugins/tcp_passthrough/Makefile new file mode 100644 index 00000000000..2234476df57 --- /dev/null +++ b/panda/plugins/tcp_passthrough/Makefile @@ -0,0 +1,18 @@ +# Don't forget to add your plugin to config.panda! + +# Build rust plugins with make! + +# The main rule for your plugin. List all object-file dependencies. + +PANDA_PATH = $(realpath $(shell pwd)/..) +PLUGIN_DIR = $(realpath $(join $(PANDA_PATH), /../panda/plugins/$(PLUGIN_NAME)/)) +RUST_SOURCE = $(wildcard $(PLUGIN_DIR)/src/*.rs) +PLUGIN_ARTIFACTS_DIR = $(PLUGIN_TARGET_DIR)/$(PLUGIN_NAME)/target + +$(PLUGIN_TARGET_DIR)/panda_$(PLUGIN_NAME).so : $(RUST_SOURCE) $(PLUGIN_DIR)/Cargo.toml + @echo " CARGO $(PLUGIN_DIR)" + @CARGO_TERM_PROGRESS_WHEN=never cargo build --release \ + --no-default-features --features=$(TARGET_NAME) \ + --manifest-path=$(PLUGIN_DIR)/Cargo.toml \ + --target-dir=$(PLUGIN_ARTIFACTS_DIR) + @cp -p $(PLUGIN_ARTIFACTS_DIR)/release/lib$(PLUGIN_NAME).so $@ diff --git a/panda/plugins/tcp_passthrough/README.md b/panda/plugins/tcp_passthrough/README.md new file mode 100644 index 00000000000..4842c9a0a6c --- /dev/null +++ b/panda/plugins/tcp_passthrough/README.md @@ -0,0 +1,5 @@ +# Guest Agent TCP Passthrough + +A plugin for using the PANDA guest agent in order to perform passthrough of TCP servers present in the guest. + +See `try_it.py` for example on how to forward an HTTP server running on port 8000 in the guest to port 4343 on the host, as well as print out a table of the sockets listening in the guest. diff --git a/panda/plugins/tcp_passthrough/cbindgen.toml b/panda/plugins/tcp_passthrough/cbindgen.toml new file mode 100644 index 00000000000..dfad82285b5 --- /dev/null +++ b/panda/plugins/tcp_passthrough/cbindgen.toml @@ -0,0 +1,7 @@ +language = "C" +no_includes = true +after_includes = """// BEGIN_PYPANDA_NEEDS_THIS -- do not delete this comment bc pypanda +// api autogen needs it. And don't put any compiler directives +// between this and END_PYPANDA_NEEDS_THIS except includes of other +// files in this directory that contain subsections like this one.""" +trailer = "// END_PYPANDA_NEEDS_THIS -- do not delete this comment!\n" diff --git a/panda/plugins/tcp_passthrough/generate_header.sh b/panda/plugins/tcp_passthrough/generate_header.sh new file mode 100755 index 00000000000..5c6cdb5d8cb --- /dev/null +++ b/panda/plugins/tcp_passthrough/generate_header.sh @@ -0,0 +1,3 @@ +#!/bin/sh +cbindgen -o tcp_passthrough.h +echo "^^^ ignore those warnings thanks :)" diff --git a/panda/plugins/tcp_passthrough/src/display.rs b/panda/plugins/tcp_passthrough/src/display.rs new file mode 100644 index 00000000000..c7ee37c0e69 --- /dev/null +++ b/panda/plugins/tcp_passthrough/src/display.rs @@ -0,0 +1,70 @@ +use std::collections::HashMap; +use std::net::Ipv4Addr; + +use once_cell::sync::Lazy; +use owo_colors::OwoColorize; +use tabled::{object::FirstRow, style::Style, Format, Modify, Table, Tabled}; + +use tcp_shared_types::SocketInfo; + +#[derive(Tabled)] +struct TableEntry { + #[tabled(rename = "Listening")] + listening: &'static str, + + #[tabled(rename = "Local IP")] + ip: Ipv4Addr, + + #[tabled(rename = "Port")] + port: u16, + + #[tabled(rename = "PID")] + pid: String, + + #[tabled(rename = "Description")] + description: &'static str, +} + +static TCP_NAMES_CSV: &str = include_str!("tcp.csv"); + +static PORT_TO_NAME: Lazy> = Lazy::new(|| { + TCP_NAMES_CSV + .trim() + .split('\n') + .filter(|line| !line.is_empty()) + .filter_map(|line| line.split_once(',')) + .filter_map(|(port, name)| port.parse().ok().map(move |port| (port, name))) + .collect() +}); + +const CHECK_MARK: &str = "\u{1f5f8}"; + +pub(crate) fn print_table(sockets: Vec) { + let tcp_server_table = sockets + .into_iter() + .map(|socket| TableEntry { + listening: if socket.server { CHECK_MARK } else { " " }, + ip: socket.ip.clone(), + port: socket.port, + pid: socket + .pid + .as_ref() + .map(ToString::to_string) + .unwrap_or_else(|| String::from("")), + description: PORT_TO_NAME.get(&socket.port).copied().unwrap_or(""), + }) + .collect::>(); + + println!( + "\n\n{}\n", + Table::new(tcp_server_table) + .with(Style::modern()) + .with(Modify::new(FirstRow).with(Format::new(|text| text.bold().to_string()))) + .with(tabled::Header("TCP Sockets")) + .with( + Modify::new(FirstRow) + .with(tabled::Alignment::center()) + .with(Format::new(|text| text.bold().to_string())) + ) + ); +} diff --git a/panda/plugins/tcp_passthrough/src/forward_socket.rs b/panda/plugins/tcp_passthrough/src/forward_socket.rs new file mode 100644 index 00000000000..ff024539d3f --- /dev/null +++ b/panda/plugins/tcp_passthrough/src/forward_socket.rs @@ -0,0 +1,72 @@ +use dashmap::DashMap; +use once_cell::sync::Lazy; +use panda::plugins::guest_plugin_manager::*; +use std::io::Write; +use std::net::Ipv4Addr; +use std::net::{TcpListener, TcpStream}; +use std::sync::Mutex; +use std::thread; + +use tcp_shared_types::Request; + +static CONNECTIONS: Lazy>> = Lazy::new(DashMap::new); + +#[channel_recv] +fn incoming_tcp(channel_id: u32, data: &[u8]) { + eprintln!("[{channel_id}] TCP data: len={}", data.len()); + if let Some(channel) = CONNECTIONS.get(&channel_id) { + channel.lock().unwrap().write_all(data).unwrap(); + eprintln!("[{channel_id}] TCP data written"); + } +} + +pub fn forward(ip: Ipv4Addr, guest_port: u16, host_port: u16, localhost_only: bool) { + thread::spawn(move || { + let listener = TcpListener::bind(( + if localhost_only { + "localhost" + } else { + "0.0.0.0" + }, + host_port, + )) + .expect("Could not bind to host port"); + eprintln!("Listening on localhost:{}...", host_port); + + for stream in listener.incoming() { + match stream { + Ok(mut outgoing_tcp_stream) => { + println!( + "Incoming connection for port {} (guest port {})", + host_port, guest_port + ); + let mut incoming_channel = Channel::new(incoming_tcp); + + CONNECTIONS.insert( + incoming_channel.id(), + Mutex::new(outgoing_tcp_stream.try_clone().unwrap()), + ); + + let channel_id = incoming_channel.id(); + + thread::spawn(move || { + if let Err(err) = + std::io::copy(&mut outgoing_tcp_stream, &mut incoming_channel) + { + eprintln!("Connection Closed for host port {}: {:?}", host_port, err); + } + }); + + crate::send_request(Request::ForwardConnection { + ip, + port: guest_port, + channel_id, + }); + } + Err(_) => { + eprintln!("Failed to accept connection to localhost:{}", host_port); + } + } + } + }); +} diff --git a/panda/plugins/tcp_passthrough/src/lib.rs b/panda/plugins/tcp_passthrough/src/lib.rs new file mode 100644 index 00000000000..53a5b8f91a4 --- /dev/null +++ b/panda/plugins/tcp_passthrough/src/lib.rs @@ -0,0 +1,138 @@ +use once_cell::sync::Lazy; +use panda::{plugins::guest_plugin_manager::*, prelude::*}; +use std::ffi::CStr; +use std::net::Ipv4Addr; +use std::os::raw::c_char; +use std::sync::Mutex; + +mod display; +mod forward_socket; +mod send_ext; +mod socket_list; + +use send_ext::SendExt; + +use tcp_shared_types::Request; + +/// Request that a table of sockets be printed once guest execution resumes +#[no_mangle] +pub extern "C" fn print_socket_info() { + socket_list::on_get_socket_list(display::print_table); +} + +fn forward_socket_internal(ip: Ipv4Addr, port: u16, host_port: u16) { + forward_socket::forward(ip, port, host_port, false); +} + +/// Information about a given socket binding +#[repr(C)] +pub struct SocketInfo { + pub ip: [u8; 4], + pub pid: u64, + pub port: u16, + pub server: bool, +} + +/// Provide a callback for receiving a socket list that will get called once the guest +/// resumes execution +#[no_mangle] +pub extern "C" fn on_get_socket_list(callback: extern "C" fn(*const SocketInfo, usize)) { + socket_list::on_get_socket_list(move |socket_list| { + let socket_list: Vec = socket_list + .into_iter() + .map( + |tcp_shared_types::SocketInfo { + ip, + port, + pid, + server, + }| { + SocketInfo { + ip: ip.octets(), + port, + pid: pid.unwrap_or(u64::MAX), + server, + } + }, + ) + .collect(); + + callback(socket_list.as_ptr(), socket_list.len()); + + drop(socket_list); + }) +} + +/// Forward a socket from the guest, returning true if no issue is hit. Returns `false` if +/// the IP address fails to parse. A null IP address is treated as 0.0.0.0 +/// +/// Guest must resume execution for an unspecified amount of time before TCP traffic +/// will actually be processed. +#[no_mangle] +pub unsafe extern "C" fn forward_socket( + ip: *const c_char, + guest_port: u16, + host_port: u16, +) -> bool { + let ip = if ip.is_null() { + "0.0.0.0".parse().unwrap() + } else { + let ip = CStr::from_ptr(ip); + + if let Ok(ip) = ip.to_str().unwrap().parse() { + ip + } else { + return false; + } + }; + + forward_socket_internal(ip, guest_port, host_port); + + true +} + +#[channel_recv] +fn main_channel_cb(_: u32, _: &[u8]) { + // TODO: support for guest closing the socket +} + +static MAIN_CHANNEL: Lazy> = + Lazy::new(|| Mutex::new(load_guest_plugin("tcp_servers", main_channel_cb))); + +fn send_request(req: Request) { + MAIN_CHANNEL.lock().unwrap().send(req) +} + +#[derive(PandaArgs)] +#[name = "tcp_passthrough"] +struct Args { + print_sockets: bool, + forward_port: u32, + host_port: u32, +} + +static ARGS: Lazy = Lazy::new(Args::from_panda_args); + +#[panda::init] +fn init(_: &mut PluginHandle) { + // TODO: switch to pretty_env_logger + + if ARGS.print_sockets { + print_socket_info(); + } + + let forward_port = ARGS.forward_port as u16; + let host_port = ARGS.host_port as u16; + if forward_port != 0 { + Lazy::force(&MAIN_CHANNEL); + + forward_socket_internal( + "0.0.0.0".parse().unwrap(), + forward_port, + match host_port { + 0 => forward_port, + port => port, + }, + ); + } +} diff --git a/panda/plugins/tcp_passthrough/src/send_ext.rs b/panda/plugins/tcp_passthrough/src/send_ext.rs new file mode 100644 index 00000000000..dca58b0a02e --- /dev/null +++ b/panda/plugins/tcp_passthrough/src/send_ext.rs @@ -0,0 +1,12 @@ +use panda::plugins::guest_plugin_manager::Channel; +use serde::Serialize; + +pub(crate) trait SendExt { + fn send(&mut self, val: T); +} + +impl SendExt for Channel { + fn send(&mut self, val: T) { + self.write_packet(&bincode::serialize(&val).unwrap()); + } +} diff --git a/panda/plugins/tcp_passthrough/src/socket_list.rs b/panda/plugins/tcp_passthrough/src/socket_list.rs new file mode 100644 index 00000000000..d45778c9200 --- /dev/null +++ b/panda/plugins/tcp_passthrough/src/socket_list.rs @@ -0,0 +1,51 @@ +use crate::send_request; +use once_cell::sync::Lazy; +use panda::plugins::guest_plugin_manager::*; +use std::sync::Mutex; + +use tcp_shared_types::{Request, SocketInfo}; + +type SocketListCb = Box) + Send + 'static>; + +static SOCKET_LIST_CHANNEL: Lazy = Lazy::new(|| Channel::new(recv_socket_info)); + +static SOCKET_INFO_CALLBACK: Lazy>> = Lazy::new(|| Mutex::new(None)); + +#[channel_recv] +fn recv_socket_info(_: u32, data: &[u8]) { + if let Some(callback) = take_callback() { + callback(bincode::deserialize(data).unwrap()); + } +} + +fn take_callback() -> Option { + SOCKET_INFO_CALLBACK.lock().unwrap().take() +} + +fn set_callback(cb: SocketListCb) { + SOCKET_INFO_CALLBACK.lock().unwrap().replace(cb); +} + +pub(crate) fn on_get_socket_list(new_callback: CallbackFn) +where + CallbackFn: FnOnce(Vec) + Send + 'static, +{ + let callback = if let Some(existing_callback) = take_callback() { + // pending callback, chain them + let replacement_callback = move |sockets: Vec| { + existing_callback(sockets.clone()); + new_callback(sockets); + }; + + Box::new(replacement_callback) as SocketListCb + } else { + // no callback pending, queue a request for listing + send_request(Request::GetSocketList { + channel_id: SOCKET_LIST_CHANNEL.id(), + }); + + Box::new(new_callback) as SocketListCb + }; + + set_callback(callback); +} diff --git a/panda/plugins/tcp_passthrough/src/tcp.csv b/panda/plugins/tcp_passthrough/src/tcp.csv new file mode 100644 index 00000000000..143907685e3 --- /dev/null +++ b/panda/plugins/tcp_passthrough/src/tcp.csv @@ -0,0 +1,3266 @@ +0,Reserved +1,Port Service Multiplexer +2,Management Utility +3,Compression Process +4,Unassigned +5,Remote Job Entry +6,Unassigned +7,Echo +8,Unassigned +9,Discard +10,Unassigned +11,Active Users +12,Unassigned +13,Daytime (RFC 867) +14,Unassigned +15,Unassigned [was netstat] +16,Unassigned +17,Quote of the Day +18,Message Send Protocol +19,Character Generator +20,File Transfer [Default Data] +21,File Transfer [Control] +22,SSH Remote Login Protocol +23,Telnet +24,any private mail system +25,Simple Mail Transfer +26,Unassigned +27,NSW User System FE +28,Unassigned +29,MSG ICP +30,Unassigned +31,MSG Authentication +32,Unassigned +33,Display Support Protocol +34,Unassigned +35,any private printer server +36,Unassigned +37,Time / W32.Sober.I virus +38,Route Access Protocol +39,Resource Location Protocol +40,Unassigned +41,Graphics +42,Host Name Server +43,WhoIs +44,MPM FLAGS Protocol +45,Message Processing Module [recv] +46,MPM [default send] +47,NI FTP +48,Digital Audit Daemon +49,Login Host Protocol (TACACS) +50,Remote Mail Checking Protocol +51,IMP Logical Address Maintenance +52,XNS Time Protocol +53,Domain Name Server +54,XNS Clearinghouse +55,ISI Graphics Language +56,XNS Authentication +57,any private terminal access +58,XNS Mail +59,any private file service +60,Unassigned +61,NI MAIL +62,ACA Services +63,whois++ +64,Communications Integrator (CI) +65,TACACS-Database Service +66,Oracle SQL*NET +67,Bootstrap Protocol Server +68,Bootstrap Protocol Client +69,Trivial File Transfer +70,Gopher +71,Remote Job Service +72,Remote Job Service +73,Remote Job Service +74,Remote Job Service +75,any private dial out service +76,Distributed External Object Store +77,any private RJE service +78,vettcp +79,Finger +80,World Wide Web HTTP +81,HOSTS2 Name Server / Bagle-AZ worm / Win32.Rbot worm +82,XFER Utility +83,MIT ML Device +84,Common Trace Facility +85,MIT ML Device +86,Micro Focus Cobol +87,any private terminal link +88,Kerberos +89,SU/MIT Telnet Gateway +90,DNSIX Securit Attribute Token Map +91,MIT Dover Spooler +92,Network Printing Protocol +93,Device Control Protocol +94,Tivoli Object Dispatcher +95,SUPDUP +96,DIXIE Protocol Specification +97,Swift Remote Virtural File Protocol +98,Linuxconf / TAC News +99,Metagram Relay +100,[unauthorized use] +101,NIC Host Name Server +102,MSExchangeMTA X.400 / ISO-TSAP Class 0 +103,Genesis Point-to-Point Trans Net +104,ACR-NEMA Digital Imag. & Comm. 300 +105,Mailbox Name Nameserver +106,3COM-TSMUX +107,Remote Telnet Service +108,SNA Gateway Access Server +109,Post Office Protocol - Version 2 +110,Post Office Protocol - Version 3 +111,SUN Remote Procedure Call +112,McIDAS Data Transmission Protocol +113,Authentication Service +114,Audio News Multicast +115,Simple File Transfer Protocol +116,ANSA REX Notify +117,UUCP Path Service +118,SQL Services +119,Network News Transfer Protocol +120,CFDPTKT +121,Encore Expedited Remote Pro.Call +122,SMAKYNET +123,Network Time Protocol +124,ANSA REX Trader +125,Locus PC-Interface Net Map Ser +126,Unisys Unitary Login +127,Locus PC-Interface Conn Server +128,GSS X License Verification +129,Password Generator Protocol +130,cisco FNATIVE +131,cisco TNATIVE +132,cisco SYSMAINT +133,Statistics Service +134,INGRES-NET Service +135,DCE endpoint resolution +136,PROFILE Naming System +137,NETBIOS Name Service +138,NETBIOS Datagram Service +139,NETBIOS Session Service +140,EMFIS Data Service +141,EMFIS Control Service +142,Britton-Lee IDM +143,Internet Message Access Protocol +144,Universal Management Architecture +145,UAAC Protocol +146,ISO-IP0 +147,ISO-IP +148,Jargon +149,AED 512 Emulation Service +150,SQL-NET +151,HEMS +152,Background File Transfer Program +153,SGMP +154,NETSC +155,NETSC +156,SQL Service +157,KNET/VM Command/Message Protocol +158,PCMail Server +159,NSS-Routing +160,SGMP-TRAPS +161,SNMP +162,SNMPTRAP +163,CMIP/TCP Manager +164,CMIP/TCP Agent +165,Xerox +166,Sirius Systems +167,NAMP +168,RSVD +169,SEND +170,Network PostScript +171,Network Innovations Multiplex +172,Network Innovations CL/1 +173,Xyplex +174,MAILQ +175,VMNET +176,GENRAD-MUX +177,X Display Manager Control Protocol +178,NextStep Window Server +179,Border Gateway Protocol +180,Intergraph +181,Unify +182,Unisys Audit SITP +183,OCBinder +184,OCServer +185,Remote-KIS +186,KIS Protocol +187,Application Communication Interface +188,Plus Five's MUMPS +189,Queued File Transport +190,Gateway Access Control Protocol +191,Prospero Directory Service +192,OSU Network Monitoring System +193,Spider Remote Monitoring Protocol +194,Internet Relay Chat Protocol +195,DNSIX Network Level Module Audit +196,DNSIX Session Mgt Module Audit Redir +197,Directory Location Service +198,Directory Location Service Monitor +199,SMUX +200,IBM System Resource Controller +201,AppleTalk Routing Maintenance +202,AppleTalk Name Binding +203,AppleTalk Unused +204,AppleTalk Echo +205,AppleTalk Unused +206,AppleTalk Zone Information +207,AppleTalk Unused +208,AppleTalk Unused +209,The Quick Mail Transfer Protocol +210,ANSI Z39.50 +211,Texas Instruments 914C/G Terminal +212,ATEXSSTR +213,IPX +214,VM PWSCS +215,Insignia Solutions +216,Computer Associates Int'l License Server +217,dBASE Unix +218,Netix Message Posting Protocol +219,Unisys ARPs +220,Interactive Mail Access Protocol v3 +221,Berkeley rlogind with SPX auth +222,Berkeley rshd with SPX auth +223,Certificate Distribution Center +224,masqdialer +242,Direct +243,Survey Measurement +244,inbusiness +245,LINK +246,Display Systems Protocol +247,SUBNTBCST_TFTP +248,bhfhs +256,RAP/Checkpoint SNMP +257,Check Point / Secure Electronic Transaction +258,Check Point / Yak Winsock Personal Chat +259,Check Point Firewall-1 telnet auth / Efficient Short Remote Operations +260,Openport +261,IIOP Name Service over TLS/SSL +262,Arcisdms +263,HDAP +264,BGMP / Check Point +265,X-Bone CTL +266,SCSI on ST +267,Tobit David Service Layer +268,Tobit David Replica +280,HTTP-mgmt +281,Personal Link +282,Cable Port A/X +283,rescap +284,corerjd +286,FXP-1 +287,K-BLOCK +308,Novastor Backup +309,EntrustTime +310,bhmds +311,AppleShare IP WebAdmin +312,VSLMP +313,Magenta Logic +314,Opalis Robot +315,DPSI +316,decAuth +317,Zannet +318,PKIX TimeStamp +319,PTP Event +320,PTP General +321,PIP +322,RTSPS +333,Texar Security Port +344,Prospero Data Access Protocol +345,Perf Analysis Workbench +346,Zebra server +347,Fatmen Server +348,Cabletron Management Protocol +349,mftp +350,MATIP Type A +351,bhoetty (added 5/21/97) +352,bhoedap4 (added 5/21/97) +353,NDSAUTH +354,bh611 +355,DATEX-ASN +356,Cloanto Net 1 +357,bhevent +358,Shrinkwrap +359,Tenebris Network Trace Service +360,scoi2odialog +361,Semantix +362,SRS Send +363,RSVP Tunnel +364,Aurora CMGR +365,DTK +366,ODMR +367,MortgageWare +368,QbikGDP +369,rpc2portmap +370,codaauth2 +371,Clearcase +372,ListProcessor +373,Legent Corporation +374,Legent Corporation +375,Hassle +376,Amiga Envoy Network Inquiry Proto +377,NEC Corporation +378,NEC Corporation +379,TIA/EIA/IS-99 modem client +380,TIA/EIA/IS-99 modem server +381,hp performance data collector +382,hp performance data managed node +383,hp performance data alarm manager +384,A Remote Network Server System +385,IBM Application +386,ASA Message Router Object Def. +387,Appletalk Update-Based Routing Pro. +388,Unidata LDM +389,Lightweight Directory Access Protocol / Internet Locator Service (ILS) +390,UIS +391,SynOptics SNMP Relay Port +392,SynOptics Port Broker Port +393,Data Interpretation System +394,EMBL Nucleic Data Transfer +395,NETscout Control Protocol +396,Novell Netware over IP +397,Multi Protocol Trans. Net. +398,Kryptolan +399,ISO Transport Class 2 Non-Control over TCP +400,Workstation Solutions +401,Uninterruptible Power Supply +402,Genie Protocol +403,decap +404,nced +405,ncld +406,Interactive Mail Support Protocol +407,Timbuktu +408,Prospero Resource Manager Sys. Man. +409,Prospero Resource Manager Node Man. +410,DECLadebug Remote Debug Protocol +411,Remote MT Protocol +412,NeoModus Direct Connect (Windows file sharing program) / Trap Convention Port +413,SMSP +414,InfoSeek +415,BNet +416,Silverplatter +417,Onmux +418,Hyper-G +419,Ariel +420,SMPTE +421,Ariel +422,Ariel +423,IBM Operations Planning and Control Start +424,IBM Operations Planning and Control Track +425,ICAD +426,smartsdp +427,Server Location +428,OCS_CMU +429,OCS_AMU +430,UTMPSD +431,UTMPCD +432,IASD +433,NNSP +434,MobileIP-Agent +435,MobilIP-MN +436,DNA-CML +437,comscm +438,dsfgw +439,dasp +440,sgcp +441,decvms-sysmgt +442,cvc_hostd +443,HTTP protocol over TLS/SSL +444,Simple Network Paging Protocol +445,Microsoft-DS +446,DDM-RDB +447,DDM-RFM +448,DDM-SSL +449,AS Server Mapper +450,TServer +451,Cray Network Semaphore server +452,Cray SFS config server +453,CreativeServer +454,ContentServer +455,CreativePartnr +456,macon-tcp +457,scohelp +458,apple quick time +459,ampr-rcmd +460,skronk +461,DataRampSrv +462,DataRampSrvSec +463,alpes +464,kpasswd +465,SMTPS +466,digital-vrc +467,mylex-mapd +468,proturis +469,Radio Control Protocol +470,scx-proxy +471,Mondex +472,ljk-login +473,hybrid-pop +474,tn-tl-w1 +475,tcpnethaspsrv +476,tn-tl-fd1 +477,ss7ns +478,spsc +479,iafserver +480,iafdbase +481,Ph service +482,bgs-nsi +483,ulpnet +484,Integra Software Management Environment +485,Air Soft Power Burst +486,avian +487,saft Simple Asynchronous File Transfer +488,gss-HTTP +489,nest-protocol +490,micom-pfs +491,go-login +492,Transport Independent Convergence for FNA +493,Transport Independent Convergence for FNA +494,POV-Ray +495,intecourier +496,PIM-RP-DISC +497,dantz +498,siam +499,ISO ILL Protocol +500,ISAKMP +501,STMF +502,asa-appl-proto +503,Intrinsa +504,citadel +505,mailbox-lm +506,ohimsrv +507,crs +508,xvttp +509,snare +510,FirstClass Protocol +511,PassGo +512,Remote process execution +513,Remote Login +514,Remote Shell +515,spooler +516,videotex +517,like tenex link but across +518,talkd +519,unixtime +520,extended file name server +521,ripng +522,User Location Service / ULP +523,IBM-DB2 +524,NCP +525,timeserver +526,newdate +527,Stock IXChange +528,Customer IXChange +529,IRC-SERV +530,rpc +531,chat +532,readnews +533,for emergency broadcasts +534,MegaMedia Admin +535,iiop +536,opalis-rdv +537,Networked Media Streaming Protocol +538,gdomap +539,Apertus Technologies Load Determination +540,uucpd +541,uucp-rlogin +542,commerce +543,kerberos (v4/v5) +544,krcmd +545,appleqtcsrvr +546,DHCPv6 Client +547,DHCPv6 Server +548,AppleShare AFP over TCP +549,IDFP +550,new-who +551,cybercash +552,deviceshare +553,pirp +554,Real Time Stream Control Protocol +555,phAse Zero backdoor (Win 9x, NT) / dsf +556,rfs server +557,openvms-sysipc +558,SDNSKMP +559,TEEDTAP / Backdoor.Domwis Win32 trojan +560,rmonitord +561,monitor +562,chcmd +563,AOL IM / NNTP protocol over TLS/SSL +564,plan 9 file service +565,whoami +566,streettalk +567,banyan-rpc +568,microsoft shuttle +569,microsoft rome +570,demon +571,udemon +572,sonar +573,banyan-vip +574,FTP Software Agent System +575,VEMMI +576,ipcd +577,vnas +578,ipdd +579,decbsrv +580,SNTP HEARTBEAT +581,Bundle Discovery Protocol +582,SCC Security +583,Philips Video-Conferencing +584,Key Server +585,IMAP4+SSL +586,Password Change +587,Message Submission (Sendmail) +588,CAL +589,EyeLink +590,TNS CML +591,FileMaker Inc. - HTTP Alternate +592,Eudora Set +593,HTTP RPC Ep Map +594,TPIP +595,CAB Protocol +596,SMSD +597,PTC Name Service +598,SCO Web Server Manager 3 +599,Aeolon Core Protocol +600,Sun IPC server +606,Cray Unified Resource Manager +607,nqs +608,Sender-Initiated/Unsolicited File Transfer +609,npmp-trap +610,Apple Admin Service / npmp-local +611,npmp-gui +612,HMMP Indication +613,HMMP Operation +614,SSLshell +615,Internet Configuration Manager +616,SCO System Administration Server +617,SCO Desktop Administration Server +618,DEI-ICDA +619,Digital EVM +620,SCO WebServer Manager +621,ESCP +622,Collaborator +623,Aux Bus Shunt +624,Crypto Admin +625,DEC DLM +626,ASIA +627,PassGo Tivoli +628,QMQP +629,3Com AMP3 +630,RDA +631,IPP (Internet Printing Protocol) +632,bmpp +633,Service Status update (Sterling Software) +634,ginad +635,RLZ DBase +636,LDAP protocol over TLS/SSL +637,lanserver +638,mcns-sec +639,MSDP +640,entrust-sps +641,repcmd +642,ESRO-EMSDP V1.3 +643,SANity +644,dwr +645,PSSC +646,LDP +647,DHCP Failover +648,Registry Registrar Protocol (RRP) +649,Aminet +650,OBEX +651,IEEE MMS +652,UDLR_DTCP +653,RepCmd +654,AODV +655,TINC +656,SPMP +657,RMC +658,TenFold +659,URL Rendezvous +660,MacOS Server Admin +661,HAP +662,PFTP +663,PureNoise +664,Secure Aux Bus +665,Sun DR +666,doom Id Software +667,campaign contribution disclosures - SDR Technologies +668,MeComm +669,MeRegister +670,VACDSM-SWS +671,VACDSM-APP +672,VPPS-QUA +673,CIMPLEX +674,ACAP +675,DCTP +676,VPPS Via +677,Virtual Presence Protocol +678,GNU Gereration Foundation NCP +679,MRM +680,entrust-aaas +681,entrust-aams +682,XFR +683,CORBA IIOP +684,CORBA IIOP SSL +685,MDC Port Mapper +686,Hardware Control Protocol Wismar +687,asipregistry +688,REALM-RUSD +689,NMAP +690,VATP +691,MS Exchange Routing +692,Hyperwave-ISP +693,connendp +694,ha-cluster +695,IEEE-MMS-SSL +696,RUSHD +697,UUIDGEN +698,OLSR +704,errlog copy/server daemon +705,AgentX +706,SILC +707,W32.Nachi Worm / Borland DSJ +709,Entrust Key Management Service Handler +710,Entrust Administration Service Handler +711,Cisco TDP +729,IBM NetView DM/6000 Server/Client +730,IBM NetView DM/6000 send/tcp +731,IBM NetView DM/6000 receive/tcp +740,(old) NETscout Control Protocol (old) +741,netGW +742,Network based Rev. Cont. Sys. +744,Flexible License Manager +747,Fujitsu Device Control +748,Russell Info Sci Calendar Manager +749,kerberos administration +750,rfile +751,pump +752,Kerberos password server +753,Kerberos userreg server +754,send +758,nlogin +759,con +760,kreg, kerberos/4 registration +761,kpwd, Kerberos/4 password +762,quotad +763,cycleserv +764,omserv +765,webster +767,phone +769,vid +770,cadlock +771,rtip +772,cycleserv2 +773,submit +774,rpasswd +775,entomb +776,wpages +777,Multiling HTTP +780,wpgs +781,HP performance data collector +782,node HP performance data managed node +783,HP performance data alarm manager +786,Concert +787,QSC +799,ControlIT / Remotely Possible +800,mdbs_daemon / Remotely Possible +801,device +808,CCProxy +810,FCP +828,itm-mcell-s +829,PKIX-3 CA/RA +871,SUP server +873,rsync +886,ICL coNETion locate server +887,ICL coNETion server info +888,CD Database Protocol +900,Check Point Firewall-1 HTTP administration / OMG Initial Refs +901,Samba Web Administration Tool / Realsecure / SMPNAMERES/ NetDevil trojan +902,VMware Authentication Daemon / IDEAFARM-CHAT +903,IDEAFARM-CATCH / NetDevil trojan +911,xact-backup +912,VMware Authentication Daemon +989,FTP protocol data over TLS/SSL +990,FTP protocol control over TLS/SSL +991,Netnews Administration System +992,Telnet protocol over TLS/SSL +993,IMAP4 protocol over TLS/SSL +994,IRC protocol over TLS/SSL +995,POP3 protocol over TLS/SSL +996,vsinet +997,maitrd +998,busboy +999,puprouter +1000,cadlock +1002,Microsoft Site Server Internet Locator Service (Netmeeting/ICF) +1008,UFS-aware server +1010,surf +1011,Doly (Windows Trojan) +1015,Doly (Windows Trojan) +1023,Reserved +1024,Reserved +1025,MSTASK / network blackjack +1026,MSTASK / Remote Login Network Terminal +1030,BBN IAD +1031,InetInfo / BBN IAD +1032,BBN IAD +1042,W32.Mydoom.L virus +1047,Sun's NEO Object Request Broker +1048,Sun's NEO Object Request Broker +1049,Tobit David Postman VPMN +1050,CORBA Management Agent +1051,Optima VNET +1052,Dynamic DNS Tools +1053,Remote Assistant (RA) +1054,BRVREAD +1055,ANSYS - License Manager +1056,VFO +1057,STARTRON +1058,nim +1059,nimreg +1060,POLESTAR +1061,KIOSK +1062,Veracity +1063,KyoceraNetDev +1064,JSTEL +1065,SYSCOMLAN +1066,FPO-FNS +1067,Installation Bootstrap Proto. Serv. +1068,Installation Bootstrap Proto. Cli. +1069,COGNEX-INSIGHT +1070,GMRUpdateSERV +1071,BSQUARE-VOIP +1072,CARDAX +1073,BridgeControl +1074,FASTechnologies License Manager +1075,RDRMSHC +1076,DAB STI-C +1077,IMGames +1078,eManageCstp +1079,ASPROVATalk +1080,Socks / W32.Beagle.AB trojan +1081,PVUNIWIEN +1082,AMT-ESD-PROT +1083,Anasoft License Manager +1084,Anasoft License Manager +1085,Web Objects +1086,CPL Scrambler Logging +1087,CPL Scrambler Internal +1088,CPL Scrambler Alarm Log +1089,FF Annunciation +1090,FF Fieldbus Message Specification +1091,FF System Management +1092,OBRPD +1093,PROOFD +1094,ROOTD +1095,NICELink +1096,Common Name Resolution Protocol +1097,Sun Cluster Manager +1098,RMI Activation +1099,RMI Registry +1100,MCTP +1101,PT2-DISCOVER +1102,ADOBE SERVER 1 +1103,ADOBE SERVER 2 +1104,XRL +1105,FTRANHC +1106,ISOIPSIGPORT-1 +1107,ISOIPSIGPORT-2 +1108,ratio-adp +1109,Pop with Kerberos +1110,Cluster status info +1111,LM Social Server +1112,Intelligent Communication Protocol +1114,Mini SQL +1115,ARDUS Transfer +1116,ARDUS Control +1117,ARDUS Multicast Transfer +1123,Murray +1127,SUP debugging +1155,Network File Access +1161,Health Polling +1162,Health Trap +1169,TRIPWIRE +1178,SKK (kanji input) +1180,Millicent Client Proxy +1188,HP Web Admin +1200,SCOL +1201,Nucleus Sand +1202,caiccipc +1203,License Validation +1204,Log Request Listener +1205,Accord-MGC +1206,Anthony Data +1207,MetaSage +1208,SEAGULL AIS +1209,IPCD3 +1210,EOSS +1211,Groove DPP +1212,lupa +1213,MPC LIFENET +1214,KAZAA (Morpheus) +1215,scanSTAT 1.0 +1216,ETEBAC 5 +1217,HPSS-NDAPI +1218,AeroFlight-ADs +1219,AeroFlight-Ret +1220,QT SERVER ADMIN +1221,SweetWARE Apps +1222,SNI R&D network +1223,TGP +1224,VPNz +1225,SLINKYSEARCH +1226,STGXFWS +1227,DNS2Go +1228,FLORENCE +1229,Novell ZFS +1234,W32.Beagle.Y trojan / Infoseek Search Agent +1239,NMSD +1241,Nessus Daemon / remote message service +1243,SubSeven (Windows Trojan) +1245,Subseven backdoor remote access tool +1248,hermes +1270,Microsoft Operations Manager MOM-Encrypted +1300,H323 Host Call Secure +1310,Husky +1311,RxMon +1312,STI Envision +1313,BMC_PATROLDB +1314,Photoscript Distributed Printing System +1319,Panja-ICSP +1320,Panja-AXBNET +1321,PIP +1335,Digital Notary Protocol +1345,VPJP +1346,Alta Analytics License Manager +1347,multi media conferencing +1348,multi media conferencing +1349,Registration Network Protocol +1350,Registration Network Protocol +1351,Digital Tool Works (MIT) +1352,Lotus Notes +1353,Relief Consulting +1354,RightBrain Software +1355,Intuitive Edge +1356,CuillaMartin Company +1357,Electronic PegBoard +1358,CONNLCLI +1359,FTSRV +1360,MIMER +1361,LinX +1362,TimeFlies +1363,Network DataMover Requester +1364,Network DataMover Server +1365,Network Software Associates +1366,Novell NetWare Comm Service Platform +1367,DCS +1368,ScreenCast +1369,GlobalView to Unix Shell +1370,Unix Shell to GlobalView +1371,Fujitsu Config Protocol +1372,Fujitsu Config Protocol +1373,Chromagrafx +1374,EPI Software Systems +1375,Bytex +1376,IBM Person to Person Software +1377,Cichlid License Manager +1378,Elan License Manager +1379,Integrity Solutions +1380,Telesis Network License Manager +1381,Apple Network License Manager +1382,udt_os +1383,GW Hannaway Network License Manager +1384,Objective Solutions License Manager +1385,Atex Publishing License Manager +1386,CheckSum License Manager +1387,Computer Aided Design Software Inc LM +1388,Objective Solutions DataBase Cache +1389,Document Manager +1390,Storage Controller +1391,Storage Access Server +1392,Print Manager +1393,Network Log Server +1394,Network Log Client +1395,PC Workstation Manager software +1396,DVL Active Mail +1397,Audio Active Mail +1398,Video Active Mail +1399,Cadkey License Manager +1400,Cadkey Tablet Daemon +1401,Goldleaf License Manager +1402,Prospero Resource Manager +1403,Prospero Resource Manager +1404,Infinite Graphics License Manager +1405,IBM Remote Execution Starter +1406,NetLabs License Manager +1407,DBSA License Manager +1408,Sophia License Manager +1409,Here License Manager +1410,HiQ License Manager +1411,AudioFile +1412,InnoSys +1413,Innosys-ACL +1414,IBM MQSeries +1415,DBStar +1416,Novell LU6.2 +1417,Timbuktu Service 1 Port +1418,Timbuktu Service 2 Port +1419,Timbuktu Service 3 Port +1420,Timbuktu Service 4 Port +1421,Gandalf License Manager +1422,Autodesk License Manager +1423,Essbase Arbor Software +1424,Hybrid Encryption Protocol +1425,Zion Software License Manager +1426,Satellite-data Acquisition System 1 +1427,mloadd monitoring tool +1428,Informatik License Manager +1429,Hypercom NMS +1430,Hypercom TPDU +1431,Reverse Gossip Transport +1432,Blueberry Software License Manager +1433,Microsoft-SQL-Server +1434,Microsoft-SQL-Monitor +1435,IBM CICS +1436,Satellite-data Acquisition System 2 +1437,Tabula +1438,Eicon Security Agent/Server +1439,Eicon X25/SNA Gateway +1440,Eicon Service Location Protocol +1441,Cadis License Management +1442,Cadis License Management +1443,Integrated Engineering Software +1444,Marcam License Management +1445,Proxima License Manager +1446,Optical Research Associates License Manager +1447,Applied Parallel Research LM +1448,OpenConnect License Manager +1449,PEport +1450,Tandem Distributed Workbench Facility +1451,IBM Information Management +1452,GTE Government Systems License Man +1453,Genie License Manager +1454,interHDL License Manager +1455,ESL License Manager +1456,DCA +1457,Valisys License Manager +1458,Nichols Research Corp. +1459,Proshare Notebook Application +1460,Proshare Notebook Application +1461,IBM Wireless LAN +1462,World License Manager +1463,Nucleus +1464,MSL License Manager +1465,Pipes Platform +1466,Ocean Software License Manager +1467,CSDMBASE +1468,CSDM +1469,Active Analysis Limited License Manager +1470,Universal Analytics +1471,csdmbase +1472,csdm +1473,OpenMath +1474,Telefinder +1475,Taligent License Manager +1476,clvm-cfg +1477,ms-sna-server +1478,ms-sna-base +1479,dberegister +1480,PacerForum +1481,AIRS +1482,Miteksys License Manager +1483,AFS License Manager +1484,Confluent License Manager +1485,LANSource +1486,nms_topo_serv +1487,LocalInfoSrvr +1488,DocStor +1489,dmdocbroker +1490,insitu-conf +1491,anynetgateway +1492,stone-design-1 +1493,netmap_lm +1494,Citrix/ica +1495,cvc +1496,liberty-lm +1497,rfx-lm +1498,Sybase SQL Any +1499,Federico Heinz Consultora +1500,VLSI License Manager +1501,Satellite-data Acquisition System 3 +1502,Shiva +1503,MS Netmeeting / T.120 / Databeam +1504,EVB Software Engineering License Manager +1505,Funk Software Inc. +1506,Universal Time daemon (utcd) +1507,symplex +1508,diagmond +1509,Robcad Ltd. License Manager +1510,Midland Valley Exploration Ltd. Lic. Man. +1511,3l-l1 +1512,Microsoft's Windows Internet Name Service +1513,Fujitsu Systems Business of America Inc +1514,Fujitsu Systems Business of America Inc +1515,ifor-protocol +1516,Virtual Places Audio data +1517,Virtual Places Audio control +1518,Virtual Places Video data +1519,Virtual Places Video control +1520,atm zip office +1521,Oracle8i Listener / nCube License Manager +1522,Ricardo North America License Manager +1523,cichild +1524,dtspcd / ingres +1525,Oracle / Prospero Directory Service non-priv +1526,Prospero Data Access Prot non-priv +1527,oracle +1528,micautoreg +1529,oracle +1530,Oracle ExtProc (PLSExtProc) / rap-service +1531,rap-listen +1532,miroconnect +1533,Virtual Places Software +1534,micromuse-lm +1535,ampr-info +1536,ampr-inter +1537,isi-lm +1538,3ds-lm +1539,Intellistor License Manager +1540,rds +1541,rds2 +1542,gridgen-elmd +1543,simba-cs +1544,aspeclmd +1545,vistium-share +1546,abbaccuray +1547,laplink +1548,Axon License Manager +1549,Shiva Hose +1550,Image Storage license manager 3M Company +1551,HECMTL-DB +1552,pciarray +1553,sna-cs +1554,CACI Products Company License Manager +1555,livelan +1556,AshWin CI Tecnologies +1557,ArborText License Manager +1558,xingmpeg +1559,web2host +1560,asci-val +1561,facilityview +1562,pconnectmgr +1563,Cadabra License Manager +1564,Pay-Per-View +1565,WinDD +1566,CORELVIDEO +1567,jlicelmd +1568,tsspmap +1569,ets +1570,orbixd +1571,Oracle Remote Data Base +1572,Chipcom License Manager +1573,itscomm-ns +1574,mvel-lm +1575,oraclenames +1576,moldflow-lm +1577,hypercube-lm +1578,Jacobus License Manager +1579,ioc-sea-lm +1580,tn-tl-r1 +1581,MIL-2045-47001 +1582,MSIMS +1583,simbaexpress +1584,tn-tl-fd2 +1585,intv +1586,ibm-abtact +1587,pra_elmd +1588,triquest-lm +1589,VQP +1590,gemini-lm +1591,ncpm-pm +1592,commonspace +1593,mainsoft-lm +1594,sixtrak +1595,radio +1596,radio-sm +1597,orbplus-iiop +1598,picknfs +1599,simbaservices +1600,Bofra-A worm / issd +1601,aas +1602,inspect +1603,pickodbc +1604,icabrowser +1605,Salutation Manager (Salutation Protocol) +1606,Salutation Manager (SLM-API) +1607,stt +1608,Smart Corp. License Manager +1609,isysg-lm +1610,taurus-wh +1611,Inter Library Loan +1612,NetBill Transaction Server +1613,NetBill Key Repository +1614,NetBill Credential Server +1615,NetBill Authorization Server +1616,NetBill Product Server +1617,Nimrod Inter-Agent Communication +1618,skytelnet +1619,xs-openstorage +1620,faxportwinport +1621,softdataphone +1622,ontime +1623,jaleosnd +1624,udp-sr-port +1625,svs-omagent +1626,Shockwave +1627,T.128 Gateway +1628,LonTalk normal +1629,LonTalk urgent +1630,Oracle Net8 Cman +1631,Visit view +1632,PAMMRATC +1633,PAMMRPC +1634,Log On America Probe +1635,EDB Server 1 +1636,CableNet Control Protocol +1637,CableNet Admin Protocol +1638,Bofra-A worm / CableNet Info Protocol +1639,cert-initiator +1640,cert-responder +1641,InVision +1642,isis-am +1643,isis-ambc +1644,Satellite-data Acquisition System 4 +1645,datametrics +1646,sa-msg-port +1647,rsap +1648,concurrent-lm +1649,kermit +1650,nkd +1651,shiva_confsrvr +1652,xnmp +1653,alphatech-lm +1654,stargatealerts +1655,dec-mbadmin +1656,dec-mbadmin-h +1657,fujitsu-mmpdc +1658,sixnetudr +1659,Silicon Grail License Manager +1660,skip-mc-gikreq +1661,netview-aix-1 +1662,netview-aix-2 +1663,netview-aix-3 +1664,netview-aix-4 +1665,netview-aix-5 +1666,netview-aix-6 +1667,netview-aix-7 +1668,netview-aix-8 +1669,netview-aix-9 +1670,netview-aix-10 +1671,netview-aix-11 +1672,netview-aix-12 +1673,Intel Proshare Multicast +1674,Intel Proshare Multicast +1675,Pacific Data Products +1676,netcomm1 +1677,groupwise +1678,prolink +1679,darcorp-lm +1680,microcom-sbp +1681,sd-elmd +1682,lanyon-lantern +1683,ncpm-hip +1684,SnareSecure +1685,n2nremote +1686,cvmon +1687,nsjtp-ctrl +1688,nsjtp-data +1689,firefox +1690,ng-umds +1691,empire-empuma +1692,sstsys-lm +1693,rrirtr +1694,rrimwm +1695,rrilwm +1696,rrifmm +1697,rrisat +1698,RSVP-ENCAPSULATION-1 +1699,RSVP-ENCAPSULATION-2 +1700,mps-raft +1701,l2tp / AOL +1702,deskshare +1703,hb-engine +1704,bcs-broker +1705,slingshot +1706,jetform +1707,vdmplay +1708,gat-lmd +1709,centra +1710,impera +1711,pptconference +1712,resource monitoring service +1713,ConferenceTalk +1714,sesi-lm +1715,houdini-lm +1716,xmsg +1717,fj-hdnet +1718,h323gatedisc +1719,h323gatestat +1720,h323hostcall +1721,caicci +1722,HKS License Manager +1723,pptp +1724,csbphonemaster +1725,iden-ralp +1726,IBERIAGAMES +1727,winddx +1728,TELINDUS +1729,CityNL License Management +1730,roketz +1731,MS Netmeeting / Audio call control / MSICCP +1732,proxim +1733,SIMS - SIIPAT Protocol for Alarm Transmission +1734,Camber Corporation License Management +1735,PrivateChat +1736,street-stream +1737,ultimad +1738,GameGen1 +1739,webaccess +1740,encore +1741,cisco-net-mgmt +1742,3Com-nsd +1743,Cinema Graphics License Manager +1744,ncpm-ft +1745,ISA Server proxy autoconfig / Remote Winsock +1746,ftrapid-1 +1747,ftrapid-2 +1748,oracle-em1 +1749,aspen-services +1750,Simple Socket Library's PortMaster +1751,SwiftNet +1752,Leap of Faith Research License Manager +1753,Translogic License Manager +1754,oracle-em2 +1755,Microsoft Streaming Server +1756,capfast-lmd +1757,cnhrp +1758,tftp-mcast +1759,SPSS License Manager +1760,www-ldap-gw +1761,cft-0 +1762,cft-1 +1763,cft-2 +1764,cft-3 +1765,cft-4 +1766,cft-5 +1767,cft-6 +1768,cft-7 +1769,bmc-net-adm +1770,bmc-net-svc +1771,vaultbase +1772,EssWeb Gateway +1773,KMSControl +1774,global-dtserv +1776,Federal Emergency Management Information System +1777,powerguardian +1778,prodigy-internet +1779,pharmasoft +1780,dpkeyserv +1781,answersoft-lm +1782,HP JetSend +1783,Port 04/14/00 fujitsu.co.jp +1784,Finle License Manager +1785,Wind River Systems License Manager +1786,funk-logger +1787,funk-license +1788,psmond +1789,hello +1790,Narrative Media Streaming Protocol +1791,EA1 +1792,ibm-dt-2 +1793,rsc-robot +1794,cera-bcm +1795,dpi-proxy +1796,Vocaltec Server Administration +1797,UMA +1798,Event Transfer Protocol +1799,NETRISK +1800,ANSYS-License manager +1801,Microsoft Message Queuing +1802,ConComp1 +1803,HP-HCIP-GWY +1804,ENL +1805,ENL-Name +1806,Musiconline +1807,Fujitsu Hot Standby Protocol +1808,Oracle-VP2 +1809,Oracle-VP1 +1810,Jerand License Manager +1811,Scientia-SDB +1812,RADIUS +1813,RADIUS Accounting / HackTool.SkSocket +1814,TDP Suite +1815,MMPFT +1816,HARP +1817,RKB-OSCS +1818,Enhanced Trivial File Transfer Protocol +1819,Plato License Manager +1820,mcagent +1821,donnyworld +1822,es-elmd +1823,Unisys Natural Language License Manager +1824,metrics-pas +1825,DirecPC Video +1826,ARDT +1827,ASI +1828,itm-mcell-u +1829,Optika eMedia +1830,Oracle Net8 CMan Admin +1831,Myrtle +1832,ThoughtTreasure +1833,udpradio +1834,ARDUS Unicast +1835,ARDUS Multicast +1836,ste-smsc +1837,csoft1 +1838,TALNET +1839,netopia-vo1 +1840,netopia-vo2 +1841,netopia-vo3 +1842,netopia-vo4 +1843,netopia-vo5 +1844,DirecPC-DLL +1850,GSI +1851,ctcd +1860,SunSCALAR Services +1861,LeCroy VICP +1862,techra-server +1863,MSN Messenger +1864,Paradym 31 Port +1865,ENTP +1870,SunSCALAR DNS Service +1871,Cano Central 0 +1872,Cano Central 1 +1873,Fjmpjps +1874,Fjswapsnp +1881,IBM MQSeries +1895,Vista 4GL +1899,MC2Studios +1900,SSDP +1901,Fujitsu ICL Terminal Emulator Program A +1902,Fujitsu ICL Terminal Emulator Program B +1903,Local Link Name Resolution +1904,Fujitsu ICL Terminal Emulator Program C +1905,Secure UP.Link Gateway Protocol +1906,TPortMapperReq +1907,IntraSTAR +1908,Dawn +1909,Global World Link +1910,ultrabac +1911,Starlight Networks Multimedia Transport Protocol +1912,rhp-iibp +1913,armadp +1914,Elm-Momentum +1915,FACELINK +1916,Persoft Persona +1917,nOAgent +1918,Candle Directory Service - NDS +1919,Candle Directory Service - DCH +1920,Candle Directory Service - FERRET +1921,NoAdmin +1922,Tapestry +1923,SPICE +1924,XIIP +1930,Drive AppServer +1931,AMD SCHED +1944,close-combat +1945,dialogic-elmd +1946,tekpls +1947,hlserver +1948,eye2eye +1949,ISMA Easdaq Live +1950,ISMA Easdaq Test +1951,bcs-lmserver +1952,mpnjsc +1953,Rapid Base +1961,BTS APPSERVER +1962,BIAP-MP +1963,WebMachine +1964,SOLID E ENGINE +1965,Tivoli NPM +1966,Slush +1967,SNS Quote +1972,Cache +1973,Data Link Switching Remote Access Protocol +1974,DRP +1975,TCO Flash Agent +1976,TCO Reg Agent +1977,TCO Address Book +1978,UniSQL +1979,UniSQL Java +1984,BB +1985,Hot Standby Router Protocol +1986,cisco license management +1987,cisco RSRB Priority 1 port +1988,cisco RSRB Priority 2 port +1989,MHSnet system +1990,cisco STUN Priority 1 port +1991,cisco STUN Priority 2 port +1992,IPsendmsg +1993,cisco SNMP TCP port +1994,cisco serial tunnel port +1995,cisco perf port +1996,cisco Remote SRB port +1997,cisco Gateway Discovery Protocol +1998,cisco X.25 service (XOT) +1999,cisco identification port / SubSeven (Windows Trojan) / Backdoor (Windows Trojan) +2000,Remotely Anywhere / VIA NET.WORKS PostOffice Plus +2001,Cisco mgmt / Remotely Anywhere +2002,globe +2003,GNU finger +2004,mailbox +2005,encrypted symmetric telnet/login +2006,invokator +2007,dectalk +2008,conf +2009,news +2010,search +2011,raid +2012,ttyinfo +2013,raid-am +2014,troff +2015,cypress +2016,bootserver +2017,cypress-stat +2018,terminaldb +2019,whosockami +2020,xinupageserver +2021,servexec +2022,down +2023,xinuexpansion3 +2024,xinuexpansion4 +2025,ellpack +2026,scrabble +2027,shadowserver +2028,submitserver +2030,device2 +2032,blackboard +2033,glogger +2034,scoremgr +2035,imsldoc +2038,objectmanager +2040,lam +2041,W32.Korgo Worm / interbase +2042,isis +2043,isis-bcast +2044,rimsl +2045,cdfunc +2046,sdfunc +2047,dls +2048,dls-monitor +2049,Network File System - Sun Microsystems +2053,Kerberos de-multiplexer +2054,distrib-net +2065,Data Link Switch Read Port Number +2067,Data Link Switch Write Port Number +2080,Wingate +2090,Load Report Protocol +2091,PRP +2092,Descent 3 +2093,NBX CC +2094,NBX AU +2095,NBX SER +2096,NBX DIR +2097,Jet Form Preview +2098,Dialog Port +2099,H.225.0 Annex G +2100,amiganetfs +2101,Microsoft Message Queuing / rtcm-sc104 +2102,Zephyr server +2103,Microsoft Message Queuing RPC / Zephyr serv-hm connection +2104,Zephyr hostmanager +2105,Microsoft Message Queuing RPC / MiniPay +2106,MZAP +2107,Microsoft Message Queuing Management / BinTec Admin +2108,Comcam +2109,Ergolight +2110,UMSP +2111,DSATP +2112,Idonix MetaNet +2113,HSL StoRM +2114,NEWHEIGHTS +2115,KDM / Bugs (Windows Trojan) +2116,CCOWCMR +2117,MENTACLIENT +2118,MENTASERVER +2119,GSIGATEKEEPER +2120,Quick Eagle Networks CP +2121,CCProxy FTP / SCIENTIA-SSDB +2122,CauPC Remote Control +2123,GTP-Control Plane (3GPP) +2124,ELATELINK +2125,LOCKSTEP +2126,PktCable-COPS +2127,INDEX-PC-WB +2128,Net Steward Control +2129,cs-live.com +2130,SWC-XDS +2131,Avantageb2b +2132,AVAIL-EPMAP +2133,ZYMED-ZPP +2134,AVENUE +2135,Grid Resource Information Server +2136,APPWORXSRV +2137,CONNECT +2138,UNBIND-CLUSTER +2139,IAS-AUTH +2140,IAS-REG +2141,IAS-ADMIND +2142,TDM-OVER-IP +2143,Live Vault Job Control +2144,Live Vault Fast Object Transfer +2145,Live Vault Remote Diagnostic Console Support +2146,Live Vault Admin Event Notification +2147,Live Vault Authentication +2148,VERITAS UNIVERSAL COMMUNICATION LAYER +2149,ACPTSYS +2150,DYNAMIC3D +2151,DOCENT +2152,GTP-User Plane (3GPP) +2165,X-Bone API +2166,IWSERVER +2180,Millicent Vendor Gateway Server +2181,eforward +2190,TiVoConnect Beacon +2191,TvBus Messaging +2200,ICI +2201,Advanced Training System Program +2202,Int. Multimedia Teleconferencing Cosortium +2213,Kali +2220,Ganymede +2221,Rockwell CSP1 +2222,Rockwell CSP2 +2223,Rockwell CSP3 +2232,IVS Video default +2233,INFOCRYPT +2234,DirectPlay +2235,Sercomm-WLink +2236,Nani +2237,Optech Port1 License Manager +2238,AVIVA SNA SERVER +2239,Image Query +2240,RECIPe +2241,IVS Daemon +2242,Folio Remote Server +2243,Magicom Protocol +2244,NMS Server +2245,HaO +2279,xmquery +2280,LNVPOLLER +2281,LNVCONSOLE +2282,LNVALARM +2283,Dumaru.Y (Windows trojan) / LNVSTATUS +2284,LNVMAPS +2285,LNVMAILMON +2286,NAS-Metering +2287,DNA +2288,NETML +2294,Konshus License Manager (FLEX) +2295,Advant License Manager +2296,Theta License Manager (Rainbow) +2297,D2K DataMover 1 +2298,D2K DataMover 2 +2299,PC Telecommute +2300,CVMMON +2301,Compaq HTTP +2302,Bindery Support +2303,Proxy Gateway +2304,Attachmate UTS +2305,MT ScaleServer +2306,TAPPI BoxNet +2307,pehelp +2308,sdhelp +2309,SD Server +2310,SD Client +2311,Message Service +2313,IAPP (Inter Access Point Protocol) +2314,CR WebSystems +2315,Precise Sft. +2316,SENT License Manager +2317,Attachmate G32 +2318,Cadence Control +2319,InfoLibria +2320,Siebel NS +2321,RDLAP over UDP +2322,ofsd +2323,3d-nfsd +2324,Cosmocall +2325,Design Space License Management +2326,IDCP +2327,xingcsm +2328,Netrix SFTM +2329,NVD +2330,TSCCHAT +2331,AGENTVIEW +2332,RCC Host +2333,SNAPP +2334,ACE Client Auth +2335,ACE Proxy +2336,Apple UG Control +2337,ideesrv +2338,Norton Lambert +2339,3Com WebView +2340,WRS Registry +2341,XIO Status +2342,Seagate Manage Exec +2343,nati logos +2344,fcmsys +2345,dbm +2346,Game Connection Port +2347,Game Announcement and Location +2348,Information to query for game status +2349,Diagnostics Port +2350,psbserver +2351,psrserver +2352,pslserver +2353,pspserver +2354,psprserver +2355,psdbserver +2356,GXT License Managemant +2357,UniHub Server +2358,Futrix +2359,FlukeServer +2360,NexstorIndLtd +2361,TL1 +2362,digiman +2363,Media Central NFSD +2364,OI-2000 +2365,dbref +2366,qip-login +2367,Service Control +2368,OpenTable +2369,ACS2000 DSP +2370,L3-HBMon +2381,Compaq HTTPS +2382,Microsoft OLAP +2383,Microsoft OLAP +2384,SD-REQUEST +2389,OpenView Session Mgr +2390,RSMTP +2391,3COM Net Management +2392,Tactical Auth +2393,MS OLAP 1 +2394,MS OLAP 2 +2395,LAN900 Remote +2396,Wusage +2397,NCL +2398,Orbiter +2399,FileMaker Inc. - Data Access Layer +2400,OpEquus Server +2401,cvspserver +2402,TaskMaster 2000 Server +2403,TaskMaster 2000 Web +2404,IEC870-5-104 +2405,TRC Netpoll +2406,JediServer +2407,Orion +2408,OptimaNet +2409,SNS Protocol +2410,VRTS Registry +2411,Netwave AP Management +2412,CDN +2413,orion-rmi-reg +2414,Interlingua +2415,COMTEST +2416,RMT Server +2417,Composit Server +2418,cas +2419,Attachmate S2S +2420,DSL Remote Management +2421,G-Talk +2422,CRMSBITS +2423,RNRP +2424,KOFAX-SVR +2425,Fujitsu App Manager +2426,Appliant TCP +2427,Media Gateway Control Protocol Gateway +2428,One Way Trip Time +2429,FT-ROLE +2430,venus +2431,venus-se +2432,codasrv +2433,codasrv-se +2434,pxc-epmap +2435,OptiLogic +2436,TOP/X +2437,UniControl +2438,MSP +2439,SybaseDBSynch +2440,Spearway Lockers +2441,pvsw-inet +2442,Netangel +2443,PowerClient Central Storage Facility +2444,BT PP2 Sectrans +2445,DTN1 +2446,bues_service +2447,OpenView NNM daemon +2448,hpppsvr +2449,RATL +2450,netadmin +2451,netchat +2452,SnifferClient +2453,madge-om +2454,IndX-DDS +2455,WAGO-IO-SYSTEM +2456,altav-remmgt +2457,Rapido_IP +2458,griffin +2459,Community +2460,ms-theater +2461,qadmifoper +2462,qadmifevent +2463,Symbios Raid +2464,DirecPC SI +2465,Load Balance Management +2466,Load Balance Forwarding +2467,High Criteria +2468,qip_msgd +2469,MTI-TCS-COMM +2470,taskman port +2471,SeaODBC +2472,C3 +2473,Aker-cdp +2474,Vital Analysis +2475,ACE Server +2476,ACE Server Propagation +2477,SecurSight Certificate Valifation Service +2478,SecurSight Authentication Server (SLL) +2479,SecurSight Event Logging Server (SSL) +2480,Lingwood's Detail +2481,Oracle GIOP +2482,Oracle GIOP SSL +2483,Oracle TTC +2484,Oracle TTC SSL +2485,Net Objects1 +2486,Net Objects2 +2487,Policy Notice Service +2488,Moy Corporation +2489,TSILB +2490,qip_qdhcp +2491,Conclave CPP +2492,GROOVE +2493,Talarian MQS +2494,BMC AR +2495,Fast Remote Services +2496,DIRGIS +2497,Quad DB +2498,ODN-CasTraq +2499,UniControl +2500,Resource Tracking system server +2501,Resource Tracking system client +2502,Kentrox Protocol +2503,NMS-DPNSS +2504,WLBS +2505,torque-traffic +2506,jbroker +2507,spock +2508,JDataStore +2509,fjmpss +2510,fjappmgrbulk +2511,Metastorm +2512,Citrix IMA +2513,Citrix ADMIN +2514,Facsys NTP +2515,Facsys Router +2516,Main Control +2517,H.323 Annex E call signaling transport +2518,Willy +2519,globmsgsvc +2520,pvsw +2521,Adaptec Manager +2522,WinDb +2523,Qke LLC V.3 +2524,Optiwave License Management +2525,MS V-Worlds +2526,EMA License Manager +2527,IQ Server +2528,NCR CCL +2529,UTS FTP +2530,VR Commerce +2531,ITO-E GUI +2532,OVTOPMD +2533,SnifferServer +2534,Combox Web Access +2535,W32.Beagle trojan / MADCAP +2536,btpp2audctr1 +2537,Upgrade Protocol +2538,vnwk-prapi +2539,VSI Admin +2540,LonWorks +2541,LonWorks2 +2542,daVinci +2543,REFTEK +2544,Novell ZEN +2545,sis-emt +2546,vytalvaultbrtp +2547,vytalvaultvsmp +2548,vytalvaultpipe +2549,IPASS +2550,ADS +2551,ISG UDA Server +2552,Call Logging +2553,efidiningport +2554,VCnet-Link v10 +2555,Compaq WCP +2556,W32.Beagle.N trojan / MADCAP / nicetec-nmsvc +2557,nicetec-mgmt +2558,PCLE Multi Media +2559,LSTP +2560,labrat +2561,MosaixCC +2562,Delibo +2563,CTI Redwood +2564,HP 3000 NS/VT block mode telnet +2565,Coordinator Server +2566,pcs-pcw +2567,Cisco Line Protocol +2568,SPAM TRAP +2569,Sonus Call Signal +2570,HS Port +2571,CECSVC +2572,IBP +2573,Trust Establish +2574,Blockade BPSP +2575,HL7 +2576,TCL Pro Debugger +2577,Scriptics Lsrvr +2578,RVS ISDN DCP +2579,mpfoncl +2580,Tributary +2581,ARGIS TE +2582,ARGIS DS +2583,MON / Wincrash2 +2584,cyaserv +2585,NETX Server +2586,NETX Agent +2587,MASC +2588,Privilege +2589,quartus tcl +2590,idotdist +2591,Maytag Shuffle +2592,netrek +2593,MNS Mail Notice Service +2594,Data Base Server +2595,World Fusion 1 +2596,World Fusion 2 +2597,Homestead Glory +2598,Citrix MA Client +2599,Meridian Data +2600,HPSTGMGR +2601,discp client +2602,discp server +2603,Service Meter +2604,NSC CCS +2605,NSC POSA +2606,Dell Netmon +2607,Dell Connection +2608,Wag Service +2609,System Monitor +2610,VersaTek +2611,LIONHEAD +2612,Qpasa Agent +2613,SMNTUBootstrap +2614,Never Offline +2615,firepower +2616,appswitch-emp +2617,Clinical Context Managers +2618,Priority E-Com +2619,bruce +2620,LPSRecommender +2621,Miles Apart Jukebox Server +2622,MetricaDBC +2623,LMDP +2624,Aria +2625,Blwnkl Port +2626,gbjd816 +2627,Moshe Beeri +2628,DICT +2629,Sitara Server +2630,Sitara Management +2631,Sitara Dir +2632,IRdg Post +2633,InterIntelli +2634,PK Electronics +2635,Back Burner +2636,Solve +2637,Import Document Service +2638,Sybase Anywhere +2639,AMInet +2640,Sabbagh Associates Licence Manager +2641,HDL Server +2642,Tragic +2643,GTE-SAMP +2644,Travsoft IPX Tunnel +2645,Novell IPX CMD +2646,AND Licence Manager +2647,SyncServer +2648,Upsnotifyprot +2649,VPSIPPORT +2650,eristwoguns +2651,EBInSite +2652,InterPathPanel +2653,Sonus +2654,Corel VNC Admin +2655,UNIX Nt Glue +2656,Kana +2657,SNS Dispatcher +2658,SNS Admin +2659,SNS Query +2660,GC Monitor +2661,OLHOST +2662,BinTec-CAPI +2663,BinTec-TAPI +2664,Command MQ GM +2665,Command MQ PM +2666,extensis +2667,Alarm Clock Server +2668,Alarm Clock Client +2669,TOAD +2670,TVE Announce +2671,newlixreg +2672,nhserver +2673,First Call 42 +2674,ewnn +2675,TTC ETAP +2676,SIMSLink +2677,Gadget Gate 1 Way +2678,Gadget Gate 2 Way +2679,Sync Server SSL +2680,pxc-sapxom +2681,mpnjsomb +2682,SRSP +2683,NCDLoadBalance +2684,mpnjsosv +2685,mpnjsocl +2686,mpnjsomg +2687,pq-lic-mgmt +2688,md-cf-HTTP +2689,FastLynx +2690,HP NNM Embedded Database +2691,IT Internet +2692,Admins LMS +2693,belarc-HTTP +2694,pwrsevent +2695,VSPREAD +2696,Unify Admin +2697,Oce SNMP Trap Port +2698,MCK-IVPIP +2699,Csoft Plus Client +2700,tqdata +2701,SMS Remote Control (control) +2702,SMS Remote Control (data) +2703,SMS Remote Control (chat) +2704,SMS Remote File Transfer +2705,SDS Admin +2706,NCD Mirroring +2707,EMCSYMAPIPORT +2708,Banyan-Net +2709,Supermon +2710,SSO Service +2711,SSO Control +2712,Axapta Object Communication Protocol +2713,Raven1 +2714,Raven2 +2715,HPSTGMGR2 +2716,Inova IP Disco +2717,PN REQUESTER +2718,PN REQUESTER 2 +2719,Scan & Change +2720,wkars +2721,Smart Diagnose +2722,Proactive Server +2723,WatchDog NT +2724,qotps +2725,SQL Analysis Services / MSOLAP PTP2 +2726,TAMS +2727,Media Gateway Control Protocol Call Agent +2728,SQDR +2729,TCIM Control +2730,NEC RaidPlus +2731,NetDragon Messanger +2732,G5M +2733,Signet CTF +2734,CCS Software +2735,Monitor Console +2736,RADWIZ NMS SRV +2737,SRP Feedback +2738,NDL TCP-OSI Gateway +2739,TN Timing +2740,Alarm +2741,TSB +2742,TSB2 +2743,murx +2744,honyaku +2745,W32.Beagle.C trojan) / URBISNET +2746,CPUDPENCAP +2747,yk.fujitsu.co.jp +2748,yk.fujitsu.co.jp +2749,yk.fujitsu.co.jp +2750,yk.fujitsu.co.jp +2751,yk.fujitsu.co.jp +2752,RSISYS ACCESS +2753,de-spot +2754,APOLLO CC +2755,Express Pay +2756,simplement-tie +2757,CNRP +2758,APOLLO Status +2759,APOLLO GMS +2760,Saba MS +2761,DICOM ISCL +2762,DICOM TLS +2763,Desktop DNA +2764,Data Insurance +2765,qip-audup +2766,Compaq SCP +2767,UADTC +2768,UACS +2769,Single Point MVS +2770,Veronica +2771,Vergence CM +2772,auris +2773,PC Backup +2774,PC Backup +2775,SMMP +2776,Ridgeway Systems & Software +2777,Ridgeway Systems & Software +2778,Gwen-Sonya +2779,LBC Sync +2780,LBC Control +2781,whosells +2782,everydayrc +2783,AISES +2784,world wide web - development +2785,aic-np +2786,aic-oncrpc - Destiny MCD database +2787,piccolo - Cornerstone Software +2788,NetWare Loadable Module - Seagate Software +2789,Media Agent +2790,PLG Proxy +2791,MT Port Registrator +2792,f5-globalsite +2793,initlsmsad +2794,aaftp +2795,LiveStats +2796,ac-tech +2797,esp-encap +2798,TMESIS-UPShot +2799,ICON Discover +2800,ACC RAID +2801,IGCP +2802,Veritas TCP1 +2803,btprjctrl +2804,Telexis VTU +2805,WTA WSP-S +2806,cspuni +2807,cspmulti +2808,J-LAN-P +2809,CORBA LOC +2810,Active Net Steward +2811,GSI FTP +2812,atmtcp +2813,llm-pass +2814,llm-csv +2815,LBC Measurement +2816,LBC Watchdog +2817,NMSig Port +2818,rmlnk +2819,FC Fault Notification +2820,UniVision +2821,vml_dms +2822,ka0wuc +2823,CQG Net/LAN +2826,slc systemlog +2827,slc ctrlrloops +2828,ITM License Manager +2829,silkp1 +2830,silkp2 +2831,silkp3 +2832,silkp4 +2833,glishd +2834,EVTP +2835,EVTP-DATA +2836,catalyst +2837,Repliweb +2838,Starbot +2839,NMSigPort +2840,l3-exprt +2841,l3-ranger +2842,l3-hawk +2843,PDnet +2844,BPCP POLL +2845,BPCP TRAP +2846,AIMPP Hello +2847,AIMPP Port Req +2848,AMT-BLC-PORT +2849,FXP +2850,MetaConsole +2851,webemshttp +2852,bears-01 +2853,ISPipes +2854,InfoMover +2856,cesdinv +2857,SimCtIP +2858,ECNP +2859,Active Memory +2860,Dialpad Voice 1 +2861,Dialpad Voice 2 +2862,TTG Protocol +2863,Sonar Data +2864,main 5001 cmd +2865,pit-vpn +2866,lwlistener +2867,esps-portal +2868,NPEP Messaging +2869,SSDP event notification / ICSLAP +2870,daishi +2871,MSI Select Play +2872,CONTRACT +2873,PASPAR2 ZoomIn +2874,dxmessagebase1 +2875,dxmessagebase2 +2876,SPS Tunnel +2877,BLUELANCE +2878,AAP +2879,ucentric-ds +2880,synapse +2881,NDSP +2882,NDTP +2883,NDNP +2884,Flash Msg +2885,TopFlow +2886,RESPONSELOGIC +2887,aironet +2888,SPCSDLOBBY +2889,RSOM +2890,CSPCLMULTI +2891,CINEGRFX-ELMD License Manager +2892,SNIFFERDATA +2893,VSECONNECTOR +2894,ABACUS-REMOTE +2895,NATUS LINK +2896,ECOVISIONG6-1 +2897,Citrix RTMP +2898,APPLIANCE-CFG +2899,case.nm.fujitsu.co.jp +2900,magisoft.com +2901,ALLSTORCNS +2902,NET ASPI +2903,SUITCASE +2904,M2UA +2905,M3UA +2906,CALLER9 +2907,WEBMETHODS B2B +2908,mao +2909,Funk Dialout +2910,TDAccess +2911,Blockade +2912,Epicon +2913,Booster Ware +2914,Game Lobby +2915,TK Socket +2916,Elvin Server +2917,Elvin Client +2918,Kasten Chase Pad +2919,ROBOER +2920,ROBOEDA +2921,CESD Contents Delivery Management +2922,CESD Contents Delivery Data Transfer +2923,WTA-WSP-WTP-S +2924,PRECISE-VIP +2925,Firewall Redundancy Protocol +2926,MOBILE-FILE-DL +2927,UNIMOBILECTRL +2928,REDSTONE-CPSS +2929,PANJA-WEBADMIN +2930,PANJA-WEBLINX +2931,Circle-X +2932,INCP +2933,4-TIER OPM GW +2934,4-TIER OPM CLI +2935,QTP +2936,OTPatch +2937,PNACONSULT-LM +2938,SM-PAS-1 +2939,SM-PAS-2 +2940,SM-PAS-3 +2941,SM-PAS-4 +2942,SM-PAS-5 +2943,TTNRepository +2944,Megaco H-248 +2945,H248 Binary +2946,FJSVmpor +2947,GPSD +2948,WAP PUSH +2949,WAP PUSH SECURE +2950,ESIP +2951,OTTP +2952,MPFWSAS +2953,OVALARMSRV +2954,OVALARMSRV-CMD +2955,CSNOTIFY +2956,OVRIMOSDBMAN +2957,JAMCT5 +2958,JAMCT6 +2959,RMOPAGT +2960,DFOXSERVER +2961,BOLDSOFT-LM +2962,IPH-POLICY-CLI +2963,IPH-POLICY-ADM +2964,BULLANT SRAP +2965,BULLANT RAP +2966,IDP-INFOTRIEVE +2967,SSC-AGENT +2968,ENPP +2969,UPnP / ESSP +2970,INDEX-NET +2971,Net Clip +2972,PMSM Webrctl +2973,SV Networks +2974,Signal +2975,Fujitsu Configuration Management Service +2976,CNS Server Port +2977,TTCs Enterprise Test Access Protocol - NS +2978,TTCs Enterprise Test Access Protocol - DS +2979,H.263 Video Streaming +2980,Instant Messaging Service +2981,MYLXAMPORT +2982,IWB-WHITEBOARD +2983,NETPLAN +2984,HPIDSADMIN +2985,HPIDSAGENT +2986,STONEFALLS +2987,IDENTIFY +2988,CLASSIFY +2989,ZARKOV +2990,BOSCAP +2991,WKSTN-MON +2992,ITB301 +2993,VERITAS VIS1 +2994,VERITAS VIS2 +2995,IDRS +2996,vsixml +2997,REBOL +2998,Real Secure +2999,RemoteWare Unassigned +3000,RemoteWare Client +3001,Phatbot Worm / Redwood Broker +3002,RemoteWare Server +3003,CGMS +3004,Csoft Agent +3005,Genius License Manager +3006,Instant Internet Admin +3007,Lotus Mail Tracking Agent Protocol +3008,Midnight Technologies +3009,PXC-NTFY +3010,Telerate Workstation +3011,Trusted Web +3012,Trusted Web Client +3013,Gilat Sky Surfer +3014,Broker Service +3015,NATI DSTP +3016,Notify Server +3017,Event Listener +3018,Service Registry +3019,Resource Manager +3020,CIFS +3021,AGRI Server +3022,CSREGAGENT +3023,magicnotes +3024,NDS_SSO +3025,Arepa Raft +3026,AGRI Gateway +3027,LiebDevMgmt_C +3028,LiebDevMgmt_DM +3029,LiebDevMgmt_A +3030,Arepa Cas +3031,AgentVU +3032,Redwood Chat +3033,PDB +3034,Osmosis AEEA +3035,FJSV gssagt +3036,Hagel DUMP +3037,HP SAN Mgmt +3038,Santak UPS +3039,Cogitate Inc. +3040,Tomato Springs +3041,di-traceware +3042,journee +3043,BRP +3045,ResponseNet +3046,di-ase +3047,Fast Security HL Server +3048,Sierra Net PC Trader +3049,NSWS +3050,gds_db +3051,Galaxy Server +3052,APCPCNS +3053,dsom-server +3054,AMT CNF PROT +3055,Policy Server +3056,CDL Server +3057,GoAhead FldUp +3058,videobeans +3059,qsoft +3060,interserver +3061,cautcpd +3062,ncacn-ip-tcp +3063,ncadg-ip-udp +3065,slinterbase +3066,NETATTACHSDMP +3067,W32.Korgo Worm / FJHPJP +3068,ls3 Broadcast +3069,ls3 +3070,MGXSWITCH +3075,Orbix 2000 Locator +3076,Orbix 2000 Config +3077,Orbix 2000 Locator SSL +3078,Orbix 2000 Locator SSL +3079,LV Front Panel +3080,stm_pproc +3081,TL1-LV +3082,TL1-RAW +3083,TL1-TELNET +3084,ITM-MCCS +3085,PCIHReq +3086,JDL-DBKitchen +3105,Cardbox +3106,Cardbox HTTP +3127,W32.Mydoom.A virus +3128,Squid HTTP Proxy / W32.Mydoom.B virus +3129,Master's Paradise (Windows Trojan) +3130,ICPv2 +3131,Net Book Mark +3141,VMODEM +3142,RDC WH EOS +3143,Sea View +3144,Tarantella +3145,CSI-LFAP +3147,RFIO +3148,NetMike Game Administrator +3149,NetMike Game Server +3150,NetMike Assessor Administrator +3151,NetMike Assessor +3180,Millicent Broker Server +3181,BMC Patrol Agent +3182,BMC Patrol Rendezvous +3262,NECP +3264,cc:mail/lotus +3265,Altav Tunnel +3266,NS CFG Server +3267,IBM Dial Out +3268,Microsoft Global Catalog +3269,Microsoft Global Catalog with LDAP/SSL +3270,Verismart +3271,CSoft Prev Port +3272,Fujitsu User Manager +3273,Simple Extensible Multiplexed Protocol +3274,Ordinox Server +3275,SAMD +3276,Maxim ASICs +3277,AWG Proxy +3278,LKCM Server +3279,admind +3280,VS Server +3281,SYSOPT +3282,Datusorb +3283,Net Assistant +3284,4Talk +3285,Plato +3286,E-Net +3287,DIRECTVDATA +3288,COPS +3289,ENPC +3290,CAPS LOGISTICS TOOLKIT - LM +3291,S A Holditch & Associates - LM +3292,Cart O Rama +3293,fg-fps +3294,fg-gip +3295,Dynamic IP Lookup +3296,Rib License Manager +3297,Cytel License Manager +3298,Transview +3299,pdrncs +3300,bmc-patrol-agent +3301,Unathorised use by SAP R/3 +3302,MCS Fastmail +3303,OP Session Client +3304,OP Session Server +3305,ODETTE-FTP +3306,MySQL +3307,OP Session Proxy +3308,TNS Server +3309,TNS ADV +3310,Dyna Access +3311,MCNS Tel Ret +3312,Application Management Server +3313,Unify Object Broker +3314,Unify Object Host +3315,CDID +3316,AICC/CMI +3317,VSAI PORT +3318,Swith to Swith Routing Information Protocol +3319,SDT License Manager +3320,Office Link 2000 +3321,VNSSTR +3325,isi.edu +3326,SFTU +3327,BBARS +3328,Eaglepoint License Manager +3329,HP Device Disc +3330,MCS Calypso ICF +3331,MCS Messaging +3332,MCS Mail Server +3333,DEC Notes +3334,Direct TV Webcasting +3335,Direct TV Software Updates +3336,Direct TV Tickers +3337,Direct TV Data Catalog +3338,OMF data b +3339,OMF data l +3340,OMF data m +3341,OMF data h +3342,WebTIE +3343,MS Cluster Net +3344,BNT Manager +3345,Influence +3346,Trnsprnt Proxy +3347,Phoenix RPC +3348,Pangolin Laser +3349,Chevin Services +3350,FINDVIATV +3351,BTRIEVE +3352,SSQL +3353,FATPIPE +3354,SUITJD +3355,Hogle (proxy backdoor) / Ordinox Dbase +3356,UPNOTIFYPS +3357,Adtech Test IP +3358,Mp Sys Rmsvr +3359,WG NetForce +3360,KV Server +3361,KV Agent +3362,DJ ILM +3363,NATI Vi Server +3364,Creative Server +3365,Content Server +3366,Creative Partner +3371,ccm.jf.intel.com +3372,Microsoft Distributed Transaction Coordinator (MSDTC) / TIP 2 +3373,Lavenir License Manager +3374,Cluster Disc +3375,VSNM Agent +3376,CD Broker +3377,Cogsys Network License Manager +3378,WSICOPY +3379,SOCORFS +3380,SNS Channels +3381,Geneous +3382,Fujitsu Network Enhanced Antitheft function +3383,Enterprise Software Products License Manager +3384,Cluster Management Services +3385,qnxnetman +3386,GPRS Data +3387,Back Room Net +3388,CB Server +3389,MS Terminal Server +3390,Distributed Service Coordinator +3391,SAVANT +3392,EFI License Management +3393,D2K Tapestry Client to Server +3394,D2K Tapestry Server to Server +3395,Dyna License Manager (Elam) +3396,Printer Agent +3397,Cloanto License Manager +3398,Mercantile +3399,CSMS +3400,CSMS2 +3401,filecast +3410,Backdoor.OptixPro.13 +3421,Bull Apprise portmapper +3454,Apple Remote Access Protocol +3455,RSVP Port +3456,VAT default data +3457,VAT default control +3458,D3WinOsfi +3459,TIP Integral +3460,EDM Manger +3461,EDM Stager +3462,EDM STD Notify +3463,EDM ADM Notify +3464,EDM MGR Sync +3465,EDM MGR Cntrl +3466,WORKFLOW +3467,RCST +3468,TTCM Remote Controll +3469,Pluribus +3470,jt400 +3471,jt400-ssl +3535,MS-LA +3563,Watcom Debug +3572,harlequin.co.uk +3672,harlequinorb +3689,Apple Digital Audio Access Protocol +3802,VHD +3845,V-ONE Single Port Proxy +3862,GIGA-POCKET +3875,PNBSCADA +3900,Unidata UDT OS +3984,MAPPER network node manager +3985,MAPPER TCP/IP server +3986,MAPPER workstation server +3987,Centerline +4000,Terabase +4001,Cisco mgmt / NewOak +4002,pxc-spvr-ft +4003,pxc-splr-ft +4004,pxc-roid +4005,pxc-pin +4006,pxc-spvr +4007,pxc-splr +4008,NetCheque accounting +4009,Chimera HWM +4010,Samsung Unidex +4011,Alternate Service Boot +4012,PDA Gate +4013,ACL Manager +4014,TAICLOCK +4015,Talarian Mcast +4016,Talarian Mcast +4017,Talarian Mcast +4018,Talarian Mcast +4019,Talarian Mcast +4045,nfs-lockd +4096,BRE (Bridge Relay Element) +4097,Patrol View +4098,drmsfsd +4099,DPCP +4132,NUTS Daemon +4133,NUTS Bootp Server +4134,NIFTY-Serve HMI protocol +4141,Workflow Server +4142,Document Server +4143,Document Replication +4144,Compuserve pc windows +4160,Jini Discovery +4199,EIMS ADMIN +4299,earth.path.net +4300,Corel CCam +4321,Remote Who Is +4333,mini-sql server +4343,UNICALL +4344,VinaInstall +4345,Macro 4 Network AS +4346,ELAN LM +4347,LAN Surveyor +4348,ITOSE +4349,File System Port Map +4350,Net Device +4351,PLCY Net Services +4353,F5 iQuery +4397,Phatbot Worm +4442,Saris +4443,Pharos +4444,AdSubtract / NV Video default +4445,UPNOTIFYP +4446,N1-FWP +4447,N1-RMGMT +4448,ASC Licence Manager +4449,PrivateWire +4450,Camp +4451,CTI System Msg +4452,CTI Program Load +4453,NSS Alert Manager +4454,NSS Agent Manager +4455,PR Chat User +4456,PR Chat Server +4457,PR Register +4500,sae-urn +4501,urn-x-cdchoice +4545,WorldScores +4546,SF License Manager (Sentinel) +4547,Lanner License Manager +4557,FAX transmission service +4559,HylaFAX client-service protocol +4567,TRAM +4568,BMC Reporting +4600,Piranha1 +4601,Piranha2 +4661,eDonkey2k +4662,eDonkey2k +4663,eDonkey +4665,eDonkey2k +4672,remote file access server +4675,eMule +4711,eMule +4751,W32.Beagle.V trojan +4772,eMule +4800,Icona Instant Messenging System +4801,Icona Web Embedded Chat +4802,Icona License System Server +4820,Backdoor.Tuxter +4827,HTCP +4837,Varadero-0 +4838,Varadero-1 +4868,Photon Relay +4869,Photon Relay Debug +4885,ABBS +4899,RAdmin Win32 remote control +4983,AT&T Intercom +5000,UPnP / filmaker.com / Socket de Troie (Windows Trojan) +5001,filmaker.com / Socket de Troie (Windows Trojan) +5002,radio free ethernet +5003,FileMaker Inc. - Proprietary transport +5004,avt-profile-1 +5005,avt-profile-2 +5006,wsm server +5007,wsm server ssl +5010,TelepathStart +5011,TelepathAttack +5020,zenginkyo-1 +5021,zenginkyo-2 +5042,asnaacceler8db +5050,Yahoo Messenger / multimedia conference control tool +5051,ITA Agent +5052,ITA Manager +5055,UNOT +5060,SIP +5069,I/Net 2000-NPR +5071,PowerSchool +5093,Sentinel LM +5099,SentLM Srv2Srv +5101,Yahoo! Messenger +5145,RMONITOR SECURE +5150,Ascend Tunnel Management Protocol +5151,ESRI SDE Instance +5152,ESRI SDE Instance Discovery +5165,ife_1corp +5190,America-Online +5191,AmericaOnline1 +5192,AmericaOnline2 +5193,AmericaOnline3 +5200,Targus AIB 1 +5201,Targus AIB 2 +5202,Targus TNTS 1 +5203,Targus TNTS 2 +5222,Jabber Server +5232,SGI Distribution Graphics +5236,padl2sim +5272,PK +5300,HA cluster heartbeat +5301,HA cluster general services +5302,HA cluster configuration +5303,HA cluster probing +5304,HA Cluster Commands +5305,HA Cluster Test +5306,Sun MC Group +5307,SCO AIP +5308,CFengine +5309,J Printer +5310,Outlaws +5311,TM Login +5373,W32.Gluber.B@mm +5400,Excerpt Search / Blade Runner (Windows Trojan) +5401,Excerpt Search Secure / Blade Runner (Windows Trojan) +5402,MFTP / Blade Runner (Windows Trojan) +5403,HPOMS-CI-LSTN +5404,HPOMS-DPS-LSTN +5405,NetSupport +5406,Systemics Sox +5407,Foresyte-Clear +5408,Foresyte-Sec +5409,Salient Data Server +5410,Salient User Manager +5411,ActNet +5412,Continuus +5413,WWIOTALK +5414,StatusD +5415,NS Server +5416,SNS Gateway +5417,SNS Agent +5418,MCNTP +5419,DJ-ICE +5420,Cylink-C +5421,Net Support 2 +5422,Salient MUX +5423,VIRTUALUSER +5426,DEVBASIC +5427,SCO-PEER-TTA +5428,TELACONSOLE +5429,Billing and Accounting System Exchange +5430,RADEC CORP +5431,PARK AGENT +5432,postgres database server +5435,Data Tunneling Transceiver Linking (DTTL) +5454,apc-tcp-udp-4 +5455,apc-tcp-udp-5 +5456,apc-tcp-udp-6 +5461,SILKMETER +5462,TTL Publisher +5465,NETOPS-BROKER +5490,Squid HTTP Proxy +5500,fcp-addr-srvr1 +5501,fcp-addr-srvr2 +5502,fcp-srvr-inst1 +5503,fcp-srvr-inst2 +5504,fcp-cics-gw1 +5510,ACE/Server Services +5520,ACE/Server Services +5530,ACE/Server Services +5540,ACE/Server Services +5550,ACE/Server Services / Xtcp 2.0x +5554,Sasser Worm FTP backdoor / SGI ESP HTTP +5555,Personal Agent / W32.Mimail.P@mm +5556,Mtbd (mtb backup) +5559,Enterprise Security Remote Install axent.com +5599,Enterprise Security Remote Install +5600,Enterprise Security Manager +5601,Enterprise Security Agent +5602,A1-MSC +5603,A1-BS +5604,A3-SDUNode +5605,A4-SDUNode +5631,pcANYWHEREdata +5632,pcANYWHEREstat +5678,LinkSys EtherFast Router Remote Administration / Remote Replication Agent Connection +5679,Direct Cable Connect Manager +5680,Canna (Japanese Input) +5713,proshare conf audio +5714,proshare conf video +5715,proshare conf data +5716,proshare conf request +5717,proshare conf notify +5729,Openmail User Agent Layer +5741,IDA Discover Port 1 +5742,IDA Discover Port 2 / Wincrash (Windows Trojan) +5745,fcopy-server +5746,fcopys-server +5755,OpenMail Desk Gateway server +5757,OpenMail X.500 Directory Server +5766,OpenMail NewMail Server +5767,OpenMail Suer Agent Layer (Secure) +5768,OpenMail CMTS Server +5771,NetAgent +5800,VNC Virtual Network Computing +5801,VNC Virtual Network Computing +5813,ICMPD +5859,WHEREHOO +5882,Y3k +5900,VNC Virtual Network Computing +5901,VNC Virtual Network Computing +5968,mppolicy-v5 +5969,mppolicy-mgr +5977,NCD preferences TCP port +5978,NCD diagnostic TCP port +5979,NCD configuration TCP port +5980,VNC Virtual Network Computing +5981,VNC Virtual Network Computing +5987,Solaris Web Enterprise Management RMI +5997,NCD preferences telnet port +5998,NCD diagnostic telnet port +5999,CVSup +6000,X-Windows / W32.LoveGate.ak virus +6001,Cisco mgmt +6003,Half-Life WON server +6063,X Windows System mit.edu +6064,NDL-AHP-SVC +6065,WinPharaoh +6066,EWCTSP +6067,SRB +6068,GSMP +6069,TRIP +6070,Messageasap +6071,SSDTP +6072,DIAGNOSE-PROC +6073,DirectPlay8 +6100,SynchroNet-db +6101,SynchroNet-rtc +6102,SynchroNet-upd +6103,RETS +6104,DBDB +6105,Prima Server +6106,MPS Server +6107,ETC Control +6108,Sercomm-SCAdmin +6109,GLOBECAST-ID +6110,HP SoftBench CM +6111,HP SoftBench Sub-Process Control +6112,dtspcd / Blizzard Battlenet +6123,Backup Express +6129,DameWare +6141,Meta Corporation License Manager +6142,Aspen Technology License Manager +6143,Watershed License Manager +6144,StatSci License Manager - 1 +6145,StatSci License Manager - 2 +6146,Lone Wolf Systems License Manager +6147,Montage License Manager +6148,Ricardo North America License Manager +6149,tal-pod +6253,CRIP +6321,Empress Software Connectivity Server 1 +6322,Empress Software Connectivity Server 2 +6346,Gnutella/Bearshare file sharing Application +6348,Limewire P2P +6389,clariion-evr01 +6400,saegatesoftware.com +6401,saegatesoftware.com +6402,saegatesoftware.com +6403,saegatesoftware.com +6404,saegatesoftware.com +6405,saegatesoftware.com +6406,saegatesoftware.com +6407,saegatesoftware.com +6408,saegatesoftware.com +6409,saegatesoftware.com +6410,saegatesoftware.com +6455,SKIP Certificate Receive +6456,SKIP Certificate Send +6471,LVision License Manager +6500,BoKS Master +6501,BoKS Servc +6502,BoKS Servm +6503,BoKS Clntd +6505,BoKS Admin Private Port +6506,BoKS Admin Public Port +6507,BoKS Dir Server Private Port +6508,BoKS Dir Server Public Port +6547,apc-tcp-udp-1 +6548,apc-tcp-udp-2 +6549,apc-tcp-udp-3 +6550,fg-sysupdate +6558,xdsxdm +6588,AnalogX Web Proxy +6665,Internet Relay Chat +6666,IRC / Windows Media Unicast Service +6667,IRC +6668,IRC +6669,IRC +6670,Vocaltec Global Online Directory / Deep Throat 2 (Windows Trojan) +6672,vision_server +6673,vision_elmd +6699,Napster +6700,Napster / Carracho (server) +6701,KTI/ICAD Nameserver +6701,Napster / Carracho (server) +6711,SubSeven (Windows Trojan) +6723,DDOS communication TCP +6767,BMC PERFORM AGENT +6768,BMC PERFORM MGRD +6776,SubSeven/BackDoor-G (Windows Trojan) +6777,W32.Beagle.A trojan +6789,IBM DB2 +6790,HNMP / IBM DB2 +6831,ambit-lm +6841,Netmo Default +6842,Netmo HTTP +6850,ICCRUSHMORE +6881,BitTorrent Network +6888,MUSE +6891,MS Messenger file transfer +6901,MS Messenger voice calls +6961,JMACT3 +6962,jmevt2 +6963,swismgr1 +6964,swismgr2 +6965,swistrap +6966,swispol +6969,acmsoda +6998,IATP-highPri +6999,IATP-normalPri +7000,IRC / file server itself +7001,WebLogic Server / Callbacks to cache managers +7002,WebLogic Server (SSL) / Half-Life Auth Server / Users & groups database +7003,volume location database +7004,AFS/Kerberos authentication service +7005,volume managment server +7006,error interpretation service +7007,Windows Media Services / basic overseer process +7008,server-to-server updater +7009,remote cache manager service +7010,onlinet uninterruptable power supplies +7011,Talon Discovery Port +7012,Talon Engine +7013,Microtalon Discovery +7014,Microtalon Communications +7015,Talon Webserver +7020,DP Serve +7021,DP Serve Admin +7070,ARCP +7099,lazy-ptop +7100,X Font Service +7121,Virtual Prototypes License Manager +7141,vnet.ibm.com +7161,Catalyst +7174,Clutild +7200,FODMS FLIP +7201,DLIP +7323,3.11 Remote Administration +7326,Internet Citizen's Band +7390,The Swiss Exchange swx.ch +7395,winqedit +7426,OpenView DM Postmaster Manager +7427,OpenView DM Event Agent Manager +7428,OpenView DM Log Agent Manager +7429,OpenView DM rqt communication +7430,OpenView DM xmpv7 api pipe +7431,OpenView DM ovc/xmpv3 api pipe +7437,Faximum +7491,telops-lmd +7511,pafec-lm +7544,FlowAnalyzer DisplayServer +7545,FlowAnalyzer UtilityServer +7566,VSI Omega +7570,Aries Kfinder +7588,Sun License Manager +7597,TROJAN WORM +7633,PMDF Management +7640,CUSeeMe +7777,Oracle App server / cbt +7778,Windows Media Services / Interwise +7781,accu-lmgr +7786,MINIVEND +7932,Tier 2 Data Resource Manager +7933,Tier 2 Business Rules Manager +7967,Supercell +7979,Micromuse-ncps +7980,Quest Vista +7999,iRDMI2 +8000,HTTP/iRDMI +8001,HTTP/VCOM Tunnel +8002,HTTP/Teradata ORDBMS +8007,Apache JServ Protocol +8008,HTTP Alternate +8009,Apache JServ Protocol +8010,Wingate HTTP Proxy +8032,ProEd +8033,MindPrint +8080,HTTP / HTTP Proxy +8081,HTTP / HTTP Proxy +8082,BlackICE Capture +8129,Snapstream PVS Server +8130,INDIGO-VRMI +8131,INDIGO-VBCP +8160,Patrol +8161,Patrol SNMP +8181,IPSwitch IMail / Monitor +8200,TRIVNET +8201,TRIVNET +8204,LM Perfworks +8205,LM Instmgr +8206,LM Dta +8207,LM SServer +8208,LM Webwatcher +8351,Server Find +8376,Cruise ENUM +8377,Cruise SWROUTE +8378,Cruise CONFIG +8379,Cruise DIAGS +8380,Cruise UPDATE +8383,Web Email +8400,cvd +8401,sabarsd +8402,abarsd +8403,admind +8431,Micro PC-Cilin +8450,npmp +8473,Virtual Point to Point +8484,Ipswitch IMail +8554,RTSP Alternate (see port 554) +8733,iBus +8763,MC-APPSERVER +8764,OPENQUEUE +8765,Ultraseek HTTP +8804,truecm +8866,W32.Beagle.B trojan +8880,CDDBP +8888,NewsEDGE server TCP / AnswerBook2 +8889,Desktop Data TCP 1 +8890,Desktop Data TCP 2 +8891,Desktop Data TCP 3: NESS application +8892,Desktop Data TCP 4: FARM product +8893,Desktop Data TCP 5: NewsEDGE/Web application +8894,Desktop Data TCP 6: COAL application +8900,JMB-CDS 1 +8901,JMB-CDS 2 +8967,Win32/Dabber (Windows worm) +8999,Firewall +9000,CSlistener +9001,cisco-xremote +9090,WebSM +9100,HP JetDirect +9160,NetLOCK1 +9161,NetLOCK2 +9162,NetLOCK3 +9163,NetLOCK4 +9164,NetLOCK5 +9200,WAP connectionless session service +9201,WAP session service +9202,WAP secure connectionless session service +9203,WAP secure session service +9204,WAP vCard +9205,WAP vCal +9206,WAP vCard Secure +9207,WAP vCal Secure +9273,BackGate (Windows rootkit) +9274,BackGate (Windows rootkit) +9275,BackGate (Windows rootkit) +9276,BackGate (Windows rootkit) +9277,BackGate (Windows rootkit) +9278,BackGate (Windows rootkit) +9280,HP JetDirect Embedded Web Server +9290,HP JetDirect +9291,HP JetDirect +9292,HP JetDirect +9321,guibase +9343,MpIdcMgr +9344,Mphlpdmc +9374,fjdmimgr +9396,fjinvmgr +9397,MpIdcAgt +9400,InCommand +9500,ismserver +9535,Remote man server +9537,Remote man server, testing +9594,Message System +9595,Ping Discovery Service +9600,MICROMUSE-NCPW +9753,rasadv +9876,Session Director +9888,CYBORG Systems +9898,MonkeyCom / Win32/Dabber (Windows worm) +9899,SCTP TUNNELING +9900,IUA +9909,domaintime +9950,APCPCPLUSWIN1 +9951,APCPCPLUSWIN2 +9952,APCPCPLUSWIN3 +9992,Palace +9993,Palace +9994,Palace +9995,Palace +9996,Sasser Worm shell / Palace +9997,Palace +9998,Distinct32 +9999,distinct / Win32/Dabber (Windows worm) +10000,Webmin / Network Data Management Protocol/ Dumaru.Y (Windows trojan) +10001,queue +10002,poker +10003,gateway +10004,remp +10005,Secure telnet +10007,MVS Capacity +10012,qmaster +10080,Amanda / MyDoom.B (Windows trojan) +10082,Amanda Indexing +10083,Amanda Tape Indexing +10113,NetIQ Endpoint +10114,NetIQ Qcheck +10115,Ganymede Endpoint +10128,BMC-PERFORM-SERVICE DAEMON +10202,Computer Associate License Manager +10203,Computer Associate License Manager +10204,Computer Associate License Manager +10288,Blocks +10520,Acid Shivers (Windows Trojan) +11000,IRISA +11001,Metasys +11111,Viral Computing Environment (VCE) +11117,W32.Beagle.L trojan / URBISNET +11367,ATM UHAS +11523,AOL / AdSubtract AOL Proxy +11720,h323 Call Signal Alternate +11722,RK Test +12000,IBM Enterprise Extender SNA XID Exchange +12001,IBM Enterprise Extender SNA COS Network Priority +12002,IBM Enterprise Extender SNA COS High Priority +12003,IBM Enterprise Extender SNA COS Medium Priority +12004,IBM Enterprise Extender SNA COS Low Priority +12172,HiveP +12345,Netbus (Windows Trojan) +12346,NetBus (Windows Trojan) +12348,BioNet (Windows Trojan) +12349,BioNet (Windows Trojan) +12361,Whack-a-mole (Windows Trojan) +12362,Whack-a-mole (Windows Trojan) +12753,tsaf port +12754,DDOS communication TCP +13160,I-ZIPQD +13223,PowWow Client +13224,PowWow Server +13326,game +13720,BPRD Protocol (VERITAS NetBackup) +13721,BPBRM Protocol (VERITAS NetBackup) +13722,BP Java MSVC Protocol +13782,VERITAS NetBackup +13783,VOPIED Protnocol +13818,DSMCC Config +13819,DSMCC Session Messages +13820,DSMCC Pass-Thru Messages +13821,DSMCC Download Protocol +13822,DSMCC Channel Change Protocol +14001,ITU SCCP (SS7) +14237,Palm Network Hotsync +14247,Mitglieder.H trojan +15104,DDOS communication TCP +16360,netserialext1 +16361,netserialext2 +16367,netserialext3 +16368,netserialext4 +16660,Stacheldraht distributed attack tool client +16959,Subseven DEFCON8 2.1 backdoor remote access tool +16991,INTEL-RCI-MP +17007,isode-dua +17219,Chipper +17300,Kuang2 (Windows trojan) +17569,Infector +17990,Worldspan gateway +18000,Beckman Instruments Inc. +18181,OPSEC CVP +18182,OPSEC UFP +18183,OPSEC SAM +18184,OPSEC LEA +18185,OPSEC OMI +18187,OPSEC ELA +18463,AC Cluster +18753,Shaft distributed attack tool handler agent +18888,APCNECMP +19216,BackGate (Windows rootkit) +19283,Key Server for SASSAFRAS +19315,Key Shadow for SASSAFRAS +19410,hp-sco +19411,hp-sca +19412,HP-SESSMON +19541,JCP Client +20000,DNP +20005,xcept4 (German Telekom's CEPT videotext service) +20031,BakBone NetVault +20034,NetBus 2 Pro (Windows Trojan) +20432,Shaft distributed attack client +20670,Track +20742,Mitglieder.E trojan +20999,At Hand MMP +21554,Girlfriend (Windows Trojan) +21590,VoFR Gateway +21845,webphone +21846,NetSpeak Corp. Directory Services +21847,NetSpeak Corp. Connection Services +21848,NetSpeak Corp. Automatic Call Distribution +21849,NetSpeak Corp. Credit Processing System +22000,SNAPenetIO +22001,OptoControl +22156,Phatbot Worm +22273,wnn6 +22289,Wnn6 (Chinese Input) +22305,Wnn6 (Korean Input) +22321,Wnn6 (Taiwanese Input) +22555,Vocaltec Web Conference +22800,Telerate Information Platform LAN +22951,Telerate Information Platform WAN +23005,W32.HLLW.Nettrash +23006,W32.HLLW.Nettrash +23432,Asylum +23476,Donald Dick +23477,Donald Dick +23485,Shareasa file sharing +24000,med-ltp +24001,med-fsp-rx +24002,med-fsp-tx +24003,med-supp +24004,med-ovw +24005,med-ci +24006,med-net-svc +24386,Intel RCI +24554,BINKP +25000,icl-twobase1 +25001,icl-twobase2 +25002,icl-twobase3 +25003,icl-twobase4 +25004,icl-twobase5 +25005,icl-twobase6 +25006,icl-twobase7 +25007,icl-twobase8 +25008,icl-twobase9 +25009,icl-twobase10 +25555,Mitglieder.D trojan +25793,Vocaltec Address Server +25867,WebCam32 Admin +26000,quake +26208,wnn6-ds +26274,Delta Source (Windows Trojan) +27347,SubSeven / Linux.Ramen.Worm (RedHat Linux) +27374,SubSeven / Linux.Ramen.Worm (RedHat Linux) +27665,Trinoo distributed attack tool Master server control port +27999,TW Authentication/Key Distribution and +30100,Netsphere (Windows Trojan) +30101,Netsphere (Windows Trojan) +30102,Netsphere (Windows Trojan) +30999,Kuang +31337,BO2K +31785,Hack-A-Tack (Windows Trojan) +31787,Hack-A-Tack (Windows Trojan) +31788,Hack-A-Tack (Windows Trojan) +31789,Hack-A-Tack (Windows Trojan) +31791,Hack-A-Tack (Windows Trojan) +32000,XtraMail v1.11 +32768,Filenet TMS +32769,Filenet RPC +32770,Filenet NCH +32771,Solaris RPC +32772,Solaris RPC +32773,Solaris RPC +32774,Solaris RPC +32775,Solaris RPC +32776,Solaris RPC +32777,Solaris RPC +32780,RPC +33434,traceroute use +34324,Big Gluck (Windows Trojan) +36865,KastenX Pipe +40421,Master's Paradise (Windows Trojan) +40422,Master's Paradise (Windows Trojan) +40423,Master's Paradise (Windows Trojan) +40426,Master's Paradise (Windows Trojan) +40841,CSCP +42424,ASP.NET Session State +43118,Reachout +43188,Reachout +44333,Kerio WinRoute Firewall Administration +44334,Kerio Personal Firewall Administration +44337,Kerio MailServer Administration +44444,Prosiak +44818,Rockwell Encapsulation +45092,BackGate (Windows rootkit) +45678,EBA PRISE +45966,SSRServerMgr +47262,Delta Source (Windows Trojan) +47557,Databeam Corporation +47624,Direct Play Server +47806,ALC Protocol +47808,Building Automation and Control Networks +48000,Nimbus Controller +48001,Nimbus Spooler +48002,Nimbus Hub +48003,Nimbus Gateway +49400,Compaq Insight Manager +49401,Compaq Insight Manager +50300,O&O Defrag +51515,Microsoft Operations Manager MOM-Clear +52673,Stickies +54283,SubSeven +54320,Orifice 2000 (TCP) +54321,Orifice 2000 (TCP) +60000,DeepThroat +65000,distributed attack tool / Devil (Windows Trojan) +65301,pcAnywhere-def +65506,PhatBot, Agobot, Gaobot (Windows trojans) diff --git a/panda/plugins/tcp_passthrough/tcp_passthrough.h b/panda/plugins/tcp_passthrough/tcp_passthrough.h new file mode 100644 index 00000000000..3af6dc322cc --- /dev/null +++ b/panda/plugins/tcp_passthrough/tcp_passthrough.h @@ -0,0 +1,36 @@ +// BEGIN_PYPANDA_NEEDS_THIS -- do not delete this comment bc pypanda +// api autogen needs it. And don't put any compiler directives +// between this and END_PYPANDA_NEEDS_THIS except includes of other +// files in this directory that contain subsections like this one. + +/** + * Information about a given socket binding + */ +typedef struct SocketInfo { + uint8_t ip[4]; + uint64_t pid; + uint16_t port; + bool server; +} SocketInfo; + +/** + * Request that a table of sockets be printed once guest execution resumes + */ +void print_socket_info(void); + +/** + * Provide a callback for receiving a socket list that will get called once the guest + * resumes execution + */ +void on_get_socket_list(void (*callback)(const struct SocketInfo*, uintptr_t)); + +/** + * Forward a socket from the guest, returning true if no issue is hit. Returns `false` if + * the IP address fails to parse. A null IP address is treated as 0.0.0.0 + * + * Guest must resume execution for an unspecified amount of time before TCP traffic + * will actually be processed. + */ +bool forward_socket(const char *ip, uint16_t guest_port, uint16_t host_port); + +// END_PYPANDA_NEEDS_THIS -- do not delete this comment! diff --git a/panda/plugins/tcp_passthrough/tcp_shared_types/Cargo.lock b/panda/plugins/tcp_passthrough/tcp_shared_types/Cargo.lock new file mode 100644 index 00000000000..80f047aed59 --- /dev/null +++ b/panda/plugins/tcp_passthrough/tcp_shared_types/Cargo.lock @@ -0,0 +1,65 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "proc-macro2" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "serde" +version = "1.0.137" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.137" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "syn" +version = "1.0.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ff7c592601f11445996a06f8ad0c27f094a58857c2f89e97974ab9235b92c52" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "tcp_shared_types" +version = "0.1.0" +dependencies = [ + "serde", +] + +[[package]] +name = "unicode-xid" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" diff --git a/panda/plugins/tcp_passthrough/tcp_shared_types/Cargo.toml b/panda/plugins/tcp_passthrough/tcp_shared_types/Cargo.toml new file mode 100644 index 00000000000..124d2ac4406 --- /dev/null +++ b/panda/plugins/tcp_passthrough/tcp_shared_types/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "tcp_shared_types" +version = "0.1.0" +edition = "2021" + +[dependencies] +serde = { version = "1", features = ["derive"] } diff --git a/panda/plugins/tcp_passthrough/tcp_shared_types/src/lib.rs b/panda/plugins/tcp_passthrough/tcp_shared_types/src/lib.rs new file mode 100644 index 00000000000..6f5d221b79d --- /dev/null +++ b/panda/plugins/tcp_passthrough/tcp_shared_types/src/lib.rs @@ -0,0 +1,29 @@ +use serde::{Deserialize, Serialize}; +use std::net::Ipv4Addr; + +pub type Pid = u64; + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct SocketInfo { + pub ip: Ipv4Addr, + pub port: u16, + pub pid: Option, + pub server: bool, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub enum Request { + /// Request a Vec be sent to a given channel + GetSocketList { channel_id: u32 }, + + /// Connect to the given TCP port at the provided IP and forward the connection + /// over the given channel + ForwardConnection { + ip: Ipv4Addr, + port: u16, + channel_id: u32, + }, + + /// Closes a socket so the TCP server knows the connection ended + CloseSocket { channel_id: u32 }, +} diff --git a/panda/plugins/tcp_passthrough/try_it.py b/panda/plugins/tcp_passthrough/try_it.py new file mode 100644 index 00000000000..deb08c83362 --- /dev/null +++ b/panda/plugins/tcp_passthrough/try_it.py @@ -0,0 +1,34 @@ +from pandare import Panda + +panda = Panda(generic="x86_64") + +@panda.queue_blocking +def run_cmd(): + panda.revert_sync("root") + + # Start up an HTTP server as a background job + panda.run_serial_cmd("python3 -m http.server &") + + # Give the HTTP server time to start up before pulling socket info + panda.run_serial_cmd("sleep 2") + + # Print a table of the TCP servers in the guest + panda.tcp.print_socket_info() + + # Forward a socket from localhost:8000 in the guest to localhost:4343 on the host + panda.tcp.forward_socket(8000, 4343) + + # print out the socket list ourselves too + @panda.tcp.on_get_socket_list + def callback(socket_info: list): + print(" Ip Address\tPID\tIs Server?") + print("====================================") + for socket in socket_info: + print(f" {socket.ip}:{socket.port}\t{socket.pid}\t{socket.is_server}") + + # Injecting into a cat command, but this could be anything + panda.run_serial_cmd("cat", no_timeout=True) + + panda.end_analysis() + +panda.run() diff --git a/panda/python/core/create_panda_datatypes.py b/panda/python/core/create_panda_datatypes.py index 0285a655eeb..80695f0676a 100755 --- a/panda/python/core/create_panda_datatypes.py +++ b/panda/python/core/create_panda_datatypes.py @@ -306,6 +306,8 @@ def expand_ppp_def(line): define_clean_header(ffi, include_dir + "/proc_start_linux_ppp.h") define_clean_header(ffi, include_dir + "/forcedexec_ppp.h") define_clean_header(ffi, include_dir + "/stringsearch_ppp.h") + define_clean_header(ffi, include_dir + "/guest_plugin_manager_ppp.h") + define_clean_header(ffi, include_dir + "/linjector_ppp.h") # END PPP headers define_clean_header(ffi, include_dir + "/breakpoints.h") @@ -381,10 +383,13 @@ def main(install=False,recompile=True): # TODO: programtically copy anything that ends with _ppp.h copy_ppp_header("%s/%s" % (PLUGINS_DIR+"/forcedexec", "forcedexec_ppp.h")) copy_ppp_header("%s/%s" % (PLUGINS_DIR+"/stringsearch", "stringsearch_ppp.h")) + copy_ppp_header("%s/%s" % (PLUGINS_DIR+"/guest_plugin_manager", "guest_plugin_manager_ppp.h")) + copy_ppp_header("%s/%s" % (PLUGINS_DIR+"/linjector", "linjector_ppp.h")) create_pypanda_header("%s/%s" % (PLUGINS_DIR+"/hooks2", "hooks2.h")) - + copy_ppp_header("%s/%s" % (PLUGINS_DIR+"/proc_start_linux", "proc_start_linux_ppp.h")) create_pypanda_header("%s/%s" % (PLUGINS_DIR+"/proc_start_linux", "proc_start_linux.h")) + create_pypanda_header("%s/%s" % (PLUGINS_DIR+"/tcp_passthrough", "tcp_passthrough.h")) copy_ppp_header("%s/taint2/taint2.h" % PLUGINS_DIR) with open(os.path.join(OUTPUT_DIR, "panda_datatypes.py"), "w") as pdty: diff --git a/panda/python/core/pandare/panda.py b/panda/python/core/pandare/panda.py index 5143799194b..69501ee4c03 100755 --- a/panda/python/core/pandare/panda.py +++ b/panda/python/core/pandare/panda.py @@ -39,6 +39,7 @@ from .qcows import Qcows from .qemu_logging import QEMU_Log_Manager from .arch import ArmArch, Aarch64Arch, MipsArch, Mips64Arch, X86Arch, X86_64Arch +from .tcp_passthrough import TcpPassthrough, SocketInfo # Might be worth importing and auto-initilizing a PLogReader # object within Panda for the current architecture? @@ -91,6 +92,7 @@ def __init__(self, arch="i386", mem="128M", self.os_type = os self.qcow = qcow self.plugins = plugin_list(self) + self.tcp = TcpPassthrough(self) self.expect_prompt = expect_prompt self.lambda_cnt = 0 self.__sighandler = None @@ -676,6 +678,8 @@ def load_plugin(self, name, args={}): argstrs_ffi = [] if isinstance(args, dict): for k,v in args.items(): + if type(v) is bool: + v = "true" if v else "false" this_arg_s = "{}={}".format(k,v) this_arg = self.ffi.new("char[]", bytes(this_arg_s, "utf-8")) argstrs_ffi.append(this_arg) diff --git a/panda/python/core/pandare/tcp_passthrough.py b/panda/python/core/pandare/tcp_passthrough.py new file mode 100644 index 00000000000..1ebcdf2c986 --- /dev/null +++ b/panda/python/core/pandare/tcp_passthrough.py @@ -0,0 +1,88 @@ +from dataclasses import dataclass +from ipaddress import IPv4Address +from typing import Callable + +@dataclass +class SocketInfo: + ''' + Information about a socket running in the guest. + + Fields: + * `ip`: `IPv4Address` - the IP address within the guest being bound to + * `pid`: `int` - the Process ID of the process which is bound to the socket + * `port`: `int` - the TCP port (0-65565) within the guest being used + * `is_server`: `bool` - Whether the socket within the guest is a listener or an outgoing connection + ''' + + ip: IPv4Address + pid: int + port: int + is_server: bool + + def from_ffi(raw): + ''' + Takes a C FFI instances of SocketInfo and converts it to a python-native type + ''' + + ip = IPv4Address(bytes([raw.ip[i] for i in range(4)])) + pid = raw.pid + port = raw.port + is_server = raw.server + + return SocketInfo(ip, pid, port, is_server) + +class TcpPassthrough: + ''' + Object to interact with the `tcp_passthrough` PANDA plugin. An instance can be found + at `panda.tcp`, where `panda` is a `Panda` object. + ''' + + def __init__(self, panda): + self.panda = panda + + def forward_socket(self, guest_port: int, host_port: int): + ''' + Forward TCP connections performed on a host port to a TCP server running in the + guest. This could, for example, be used to allow access to a guest HTTP server. + + ``` + # Allow connecting to the guest localhost:80 via the host localhost:8500 + panda.tcp.forward_socket(80, 8500) + ``` + ''' + self.panda.plugins["tcp_passthrough"].forward_socket( + self.panda.ffi.cast("const char*", self.panda.ffi.NULL), + self.panda.ffi.cast("uint16_t", guest_port), + self.panda.ffi.cast("uint16_t", host_port) + ) + + def on_get_socket_list(self, callback: Callable[[list], None]): + ''' + Request a list of sockets from the guest, running a provided callback when they + are available. The callback is given a `list` of `SocketInfo`s. + + ``` + @panda.tcp.on_get_socket_list + def with_sockets(sockets): + for socket in sockets: + print(f"Socket bound on guest port {socket.port}") + ``` + ''' + @self.panda.ffi.callback("void(*)(const struct SocketInfo*, uintptr_t)") + def cb(ptr, length): + callback([SocketInfo.from_ffi(ptr[i]) for i in range(length)]) + + self.socket_list = (self.__dict__.get("socket_list") or []) + [cb] + + self.panda.plugins["tcp_passthrough"].on_get_socket_list(cb) + + def print_socket_info(self): + ''' + Request that a list of sockets in the guest is printed as a table to stdout, + including information about what the given port is typically reserved for. + + ``` + panda.tcp.print_socket_info() + ``` + ''' + self.panda.plugins["tcp_passthrough"].print_socket_info() diff --git a/panda/python/core/setup.py b/panda/python/core/setup.py index 602d05d4de9..dbb3a3c4a97 100644 --- a/panda/python/core/setup.py +++ b/panda/python/core/setup.py @@ -62,6 +62,7 @@ def copy_objs(): softmmu = arch+"-softmmu" path = os.path.join(*[build_root, softmmu, libname]) plugindir = os.path.join(*[build_root, softmmu, "panda", "plugins"]) + guestplugindir = os.path.join(*[build_root, softmmu, "panda", "guest_plugins"]) llvm1 = os.path.join(*[build_root, softmmu, "llvm-helpers.bc1"]) llvm2 = os.path.join(*[build_root, softmmu, f"llvm-helpers-{arch}.bc"]) @@ -82,6 +83,12 @@ def copy_objs(): shutil.copytree(plugindir, new_plugindir, ignore=shutil.ignore_patterns('*.o', '*.d')) + new_guestplugindir = os.path.join(lib_dir, softmmu, "panda/guest_plugins") + print("\n\n") + print(guestplugindir, new_guestplugindir) + if os.path.exists(guestplugindir): + shutil.copytree(guestplugindir, new_guestplugindir, ignore=shutil.ignore_patterns('*.o', '*.d')) + # Strip libpandas and plugins to save space (Need <100mb for pypi) if pypi_build: check_output(f"find {lib_dir} -type f -executable -exec strip {{}} \;", shell=True) @@ -163,6 +170,8 @@ def run(self): 'data/*-softmmu/llvm-helpers*.bc*', # Llvm-helpers 'data/*-softmmu/panda/plugins/*', # All plugins 'data/*-softmmu/panda/plugins/**/*',# All plugin files + 'data/*-softmmu/panda/guest_plugins/*', # All plugins + 'data/*-softmmu/panda/guest_plugins/**/*',# All plugin files 'data/pypanda/include/*.h', # Includes files 'data/pc-bios/*', # BIOSes ]}, diff --git a/panda/python/examples/guest_shell.py b/panda/python/examples/guest_shell.py new file mode 100644 index 00000000000..8963b47e35b --- /dev/null +++ b/panda/python/examples/guest_shell.py @@ -0,0 +1,26 @@ +# See panda/plugins/guest_shell/guest_shell_pty.sh for actually interacting with the shell +from pandare import Panda +import os + +if os.path.exists("/tmp/guest_shell.sock"): + os.remove("/tmp/guest_shell.sock") + +panda = Panda(generic="x86_64") + +@panda.queue_blocking +def run_cmd(): + panda.revert_sync("root") + panda.load_plugin("guest_shell") + + # if it's worth running it's worth running twice + # (don't ask, and definitely don't remove either line) + panda.load_plugin("linjector", { + "guest_binary": "guest_daemon", + "proc_name": "cat" + }) + panda.run_serial_cmd("cat", no_timeout=True) + panda.run_serial_cmd("cat", no_timeout=True) + + panda.end_analysis() + +panda.run() diff --git a/panda/python/examples/hyperfuse.py b/panda/python/examples/hyperfuse.py new file mode 100644 index 00000000000..9ec21609eea --- /dev/null +++ b/panda/python/examples/hyperfuse.py @@ -0,0 +1,22 @@ +from pandare import Panda +import os + +panda = Panda(generic="x86_64") +panda.load_plugin("hyperfuse", {}) + +@panda.queue_blocking +def run_cmd(): + panda.revert_sync("root") + + # if it's worth running it's worth running twice + # (don't ask, and definitely don't remove either line) + panda.load_plugin("linjector", { + "guest_binary": "guest_daemon", + "proc_name": "cat" + }) + panda.run_serial_cmd("cat", no_timeout=True) + panda.run_serial_cmd("cat", no_timeout=True) + + panda.end_analysis() + +panda.run() diff --git a/panda/python/examples/linject.py b/panda/python/examples/linject.py new file mode 100644 index 00000000000..50987c3b367 --- /dev/null +++ b/panda/python/examples/linject.py @@ -0,0 +1,31 @@ +from pandare import Panda +from termcolor import colored +import os + +# Please don't do it this way normally +code = """#include +#include + +int main() { + printf("Hello World!\\n"); + sleep(3); + + return 0; +} +""" +os.system(f'printf {repr(code)} | gcc -x c - -o hello_world_x86_64') + +panda = Panda(generic="x86_64") +panda.load_plugin("linjector", { + "require_root": False, + "guest_binary": "hello_world_x86_64", + "proc_name": "cat" +}) + +@panda.queue_blocking +def run_cmd(): + panda.revert_sync("root") + print(colored(panda.run_serial_cmd("cat /proc/cpuinfo"), "white", attrs=['bold'])) + panda.end_analysis() + +panda.run() diff --git a/panda/python/examples/tcp_passthrough.py b/panda/python/examples/tcp_passthrough.py new file mode 100644 index 00000000000..98aedcaed51 --- /dev/null +++ b/panda/python/examples/tcp_passthrough.py @@ -0,0 +1,51 @@ +from pandare import Panda + +panda = Panda(generic="x86_64") + +page = "

Guest Web Server

CPU Info:

" + +@panda.queue_blocking +def run_cmd(): + panda.revert_sync("root") + + panda.run_serial_cmd("echo '
' > cpuinfo.html")
+    panda.run_serial_cmd("cat /proc/cpuinfo >> cpuinfo.html")
+    panda.run_serial_cmd("echo '
' >> cpuinfo.html") + panda.run_serial_cmd(f"echo '{page}' > index.html") + + #print(panda.run_serial_cmd("mknod -m 777 fifo p")) + #print(panda.run_serial_cmd("head -c10000 fifo | netcat -l -k localhost 1234 > fifo")) + + # Start up an HTTP server as a background job + panda.run_serial_cmd("python3 -m http.server &") + + # Give the HTTP server time to start up before pulling socket info + panda.run_serial_cmd("sleep 2") + + # Print a table of the TCP servers in the guest + panda.tcp.print_socket_info() + + # Forward a socket from localhost:8000 in the guest to localhost:8000 on the host + panda.tcp.forward_socket(8000, 8000) + + # Forward a socket from localhost:1234 in the guest to localhost:1234 on the host + panda.tcp.forward_socket(1234, 1234) + + # print out the socket list ourselves too + @panda.tcp.on_get_socket_list + def callback(socket_info: list): + print(" Ip Address\tPID\tIs Server?") + print("====================================") + for socket in socket_info: + print(f" {socket.ip}:{socket.port}\t{socket.pid}\t{socket.is_server}") + + # Injecting into a cat command, but this could be anything + panda.load_plugin("linjector", { + "guest_binary": "guest_daemon", + "proc_name": "cat" + }) + panda.run_serial_cmd("cat", no_timeout=True) + + panda.end_analysis() + +panda.run() diff --git a/panda/scripts/musl_toolchains.sh b/panda/scripts/musl_toolchains.sh new file mode 100755 index 00000000000..e23ad58494f --- /dev/null +++ b/panda/scripts/musl_toolchains.sh @@ -0,0 +1,337 @@ +#!/bin/bash + +TARGETS=(i486-linux-musl-cross mips-linux-musl-cross mipsel-linux-musl-cross mips64-linux-musl-cross arm-linux-musleabi-cross aarch64-linux-musl-cross) + +bold=$(tput bold) +red=$(tput setaf 1) +cyan=$(tput setaf 6) +normal=$(tput sgr0) + +CMD_NAME="./musl_toolchains.sh" + +function error { + >&2 echo "${bold}${red}error${normal}: $@" +} + +function suggest { + >&2 echo " ${bold}${cyan}help${normal}: $@" +} + +function help { + >&2 echo "${bold}Usage:${normal}" + >&2 echo " ${CMD_NAME} [subcommand]" + >&2 echo "" + >&2 echo "${bold}Subcommands:${normal}" + >&2 echo " install Install all needed musl toolchains to the current directory" + >&2 echo " uninstall Remove all installed musl toolchains from the current directory" + >&2 echo " list List the musl toolchains supported or installed by this script" + >&2 echo " check-installed Checks if a target or set of targets are installed" + >&2 echo " help Print this help text" +} + +function install_help { + >&2 echo "${bold}Usage:${normal}" + >&2 echo " ${CMD_NAME} install [args]" + >&2 echo "" + >&2 echo "Install all the toolchains supported by this script" + >&2 echo "" + >&2 echo "${bold}Arguments:${normal}" + >&2 echo " --help Print this help text" + >&2 echo " --to Install the toolchains inside of the directory (default: cwd)" +} + +function uninstall_help { + >&2 echo "${bold}Usage:${normal}" + >&2 echo " ${CMD_NAME} uninstall [args]" + >&2 echo "" + >&2 echo "Uninstall all the toolchains supported by this script" + >&2 echo "" + >&2 echo "${bold}Arguments:${normal}" + >&2 echo " --help Print this help text" + >&2 echo " --from Uninstall any toolchains inside of the directory (default: cwd)" +} + +function list_targets_help { + >&2 echo "${bold}Usage:${normal}" + >&2 echo " ${CMD_NAME} list [args]" + >&2 echo "" + >&2 echo "List the target triples supported or installed by this script" + >&2 echo "" + >&2 echo "${bold}Arguments:${normal}" + >&2 echo " --help Print this help text" + >&2 echo " --installed Show only installed targets" + >&2 echo " --in When checking for installed toolchains, look inside of the directory (default: cwd)" +} + +function check_installed_help { + >&2 echo "${bold}Usage:${normal}" + >&2 echo " ${CMD_NAME} check-installed [args]" + >&2 echo "" + >&2 echo "Checks if a set of targets are installed" + >&2 echo "" + >&2 echo "${bold}Arguments:${normal}" + >&2 echo " --help Print this help text" + >&2 echo " --all Check that all available targets are selected" + >&2 echo " --in When checking for installed toolchains, look inside of the directory (default: cwd)" + >&2 echo " A list of targets to check are installed" +} + +function install { + cwd=`pwd` + args=("$@") + + while [[ ${#args[@]} -ne 0 ]] + do + case ${args[0]} in + "--help" | "-h") + install_help + exit 0 + ;; + "--to") + cwd="${args[1]}" + args=("${args[@]:2}") + ;; + *) + error "Found '${args[0]}'" + install_help + exit 1 + ;; + esac + done + + if [[ $cwd == "" ]] + then + error "empty directory to install to" + exit 1 + fi + + if ! [[ -d $cwd ]] + then + >&2 echo "Directory '$cwd' does not exist, creating for you..." + mkdir -p $cwd + fi + + path_prefix="" + + for target in ${TARGETS[@]} + do + full_path="$cwd/$target/bin" + if [ -d $full_path ] + then + echo "$target is already installed" + else + echo "${bold}Downloading $target...${normal}" + curl -o "$cwd/$target.tgz" https://musl.cc/$target.tgz && tar -xzf "$cwd/$target.tgz" + rm "$cwd/$target.tgz" + fi + + path_prefix="$full_path:$path_prefix" + done + + QUOTE='"' + DOLLAR='$' + + >&2 echo "" + >&2 echo "${bold}Add to PATH using:${normal}" + echo " export PATH=${QUOTE}${path_prefix}${DOLLAR}PATH${QUOTE}" +} + +function uninstall { + cwd=`pwd` + args=("$@") + + while [[ ${#args[@]} -ne 0 ]] + do + case ${args[0]} in + "--help" | "-h") + uninstall_help + exit 0 + ;; + "--from") + cwd="${args[1]}" + args=("${args[@]:2}") + ;; + *) + error "Found '${args[0]}'" + uninstall_help + exit 1 + ;; + esac + done + + if [[ $cwd == "" ]] + then + error "empty directory to uninstall from" + exit 1 + fi + + for target in ${TARGETS[@]} + do + full_path="$cwd/$target/bin" + if [ -d $full_path ] + then + rm -rf "$cwd/$target" && echo "Removed $target" + >/dev/null 2>/dev/null rm $target.tgz || true + else + >/dev/null 2>/dev/null rm $target.tgz || true + fi + done + + echo "" + echo "All targets uninstalled" +} + +function list_targets { + check_installed=false + cwd_set=false + + cwd=`pwd` + args=("$@") + + while [[ ${#args[@]} -ne 0 ]] + do + case ${args[0]} in + "--help" | "-h") + list_targets_help + exit 0 + ;; + "--installed") + check_installed=true + args=("${args[@]:1}") + ;; + "--in") + cwd_set=true + cwd="${args[1]}" + args=("${args[@]:2}") + ;; + *) + error "Found '${args[0]}', unexpected for 'list' subcommand" + list_targets_help + exit 1 + ;; + esac + done + + if [[ $cwd_set = true && $check_installed = false ]] + then + error "'--in' was passed, requires '--installed' to be passed as well" + exit 1 + fi + + at_least_one_installed=false + + for target in ${TARGETS[@]} + do + full_path="$cwd/$target/bin" + + if [[ $check_installed = false || -d $full_path ]] + then + echo $target + at_least_one_installed=true + fi + done + + if [[ $check_installed = true && $at_least_one_installed = false ]] + then + >&2 echo "${bold}No targets installed${normal}" + fi +} + +containsElement () { + local e match="$1" + shift + + for e; do [[ "$e" == "$match" ]] && return 0; done + + return 1 +} + +function check_installed { + check_installed=false + cwd_set=false + + cwd=`pwd` + args=("$@") + + selected_targets=() + + while [[ ${#args[@]} -ne 0 ]] + do + case ${args[0]} in + "--help" | "-h") + check_installed_help + exit 0 + ;; + "--all") + check_all=true + args=("${args[@]:1}") + ;; + "--in") + cwd="${args[1]}" + args=("${args[@]:2}") + ;; + *) + if containsElement "${args[0]}" "${TARGETS[@]}"; then + selected_targets+=("${args[0]}") + args=("${args[@]:1}") + else + error "Found '${args[0]}', unexpected for 'check-installed' subcommand, not a valid flag or target name" + suggest "use '${CMD_NAME} list' to see a list of valid targets" + >&2 echo "" + check_installed_help + exit 1 + fi + ;; + esac + done + + if [[ $check_all = true ]]; then + selected_targets=("${TARGETS[@]}") + fi + + if [[ ${#selected_targets[@]} -eq 0 ]]; then + error "No targets specified" + suggest "pass '--all' or a space-separated list of toolchain names" + exit 1 + fi + + for target in ${selected_targets[@]} + do + full_path="$cwd/$target/bin" + + if ! [[ -d $full_path ]] + then + error "Toolchain '$target' is not installed in '$cwd'" + exit 1 + fi + done + + >&2 echo "All toolchains are installed." +} + +if [[ $# -lt 1 ]] +then + help + exit 1 +fi + +case $1 in + help | "-h" | "--help") + help + ;; + list) + list_targets ${@:2} + ;; + install) + install ${@:2} + ;; + uninstall | remove | delete) + uninstall ${@:2} + ;; + "check-installed") + check_installed ${@:2} + ;; + *) + >&2 echo "Invalid usage" + help +esac diff --git a/panda/src/callbacks.c b/panda/src/callbacks.c index e58d3e73424..7715156237b 100644 --- a/panda/src/callbacks.c +++ b/panda/src/callbacks.c @@ -251,6 +251,30 @@ bool _panda_load_plugin(const char *filename, const char *plugin_name, bool libr extern const char *qemu_file; +char *panda_guest_plugin_path(const char *plugin_name) { + gchar* plugin_path; + // Note qemu_file is set in the first call to main_aux + // so if this is called (likely via load_plugin) qemu_file must be set directly + assert(qemu_file != NULL); + + // try relative to PANDA binary as it would be in the build or install directory + char *dir = g_path_get_dirname(qemu_file); + plugin_path = g_strdup_printf("%s/panda/guest_plugins/bin/%s", dir, + plugin_name); + + g_free(dir); + if (TRUE == g_file_test(plugin_path, G_FILE_TEST_EXISTS)) { + char* path = strdup(plugin_path); + g_free(plugin_path); + return path; + } + printf("Failed to find guest plugin '%s' at '%s'", plugin_name, plugin_path); + g_free(plugin_path); + + // Return null if plugin resolution failed. + return NULL; +} + // Resolve a file in the plugin directory to a path. If the file doesn't // exist in any of the search paths, then NULL is returned. The search order // for files is as follows: