WSLPlugins-rs is a Rust framework for building WSL plugins. It wraps the raw WSL plugin API with safer, more idiomatic Rust types and provides a procedural macro for generating plugin entry points and hook wiring. The project is intended for Windows hosts that load plugins through WSL. It includes:
- a runtime crate:
wslplugins-rs - a proc-macro crate:
wslplugins-macro - examples that build real plugin DLLs
- Safe and ergonomic wrappers around the WSL plugin API
- A
#[wsl_plugin_v1(...)]macro that generates the exported entry points - Support for WSL metadata, session information, and command execution
- Examples that can be built, signed, and loaded into WSL
Install the following tools on Windows:
- Rust stable and Cargo
- PowerShell
- OpenSSL for certificate generation in the signing script
SignTool.exefrom the Windows SDK
Notes:
SignTool.exeis easiest to access from a Visual Studio Developer Command Prompt or a shell where the Windows SDK tools are onPATH.sign-plugin.ps1requires an elevated PowerShell session.- Running the signing step with
-Trustinstalls the generated certificate into the local machine trusted root store.
The workspace is organized around a small public API surface and separate macro implementation crates:
wslplugins-rs: the main framework crate, with safe wrappers around the WSL plugin API, shared plugin context, typed identifiers, and plugin traits.wslplugins-macro: the procedural macro crate re-exported bywslplugins-rswhen themacrofeature is enabled.wslplugins-macro-core: the internal parsing and code generation implementation used by the procedural macro.wslplugins-macro-tests: compile-time tests for macro-generated plugin code.
This split keeps plugin authors focused on wslplugins-rs, while the macro parsing and generated WSL entry-point wiring stay isolated in internal crates.
- The wslplugins-rs Book explains the development flow from first plugin to packaging.
- docs.rs contains the generated API reference.
To build the book locally, install mdBook with Cargo and run:
cargo install mdbook
mdbook build bookAdd the crate with the macro feature:
[dependencies]
wslplugins-rs = { version = "0.1.0-beta.4", features = ["macro"] }Then implement a plugin:
use wslplugins_rs::prelude::*;
pub(crate) struct MyPlugin {
context: &'static WSLContext,
}
#[wsl_plugin_v1]
impl WSLPluginV1 for MyPlugin {
fn try_new(context: &'static WSLContext) -> WinResult<Self> {
Ok(Self { context })
}
}The macro feature re-exports the wsl_plugin_v1 attribute and generates the WSL entry points for a WSLPluginV1 implementation.
The macro argument controls the WSL Plugin API support checked before your plugin is initialized. Use no argument when the plugin only needs the base entry point:
use wslplugins_rs::prelude::*;
pub(crate) struct MyPlugin {
context: &'static WSLContext,
}
#[wsl_plugin_v1]
impl WSLPluginV1 for MyPlugin {
fn try_new(context: &'static WSLContext) -> WinResult<Self> {
Ok(Self { context })
}
}Use #[wsl_plugin_v1(major, minor)] or #[wsl_plugin_v1(major, minor, revision)] when the whole
plugin requires a known API version before it can run.
For plugins that require named API capabilities, pass one or more
WSLVersionCapability values:
use wslplugins_rs::prelude::*;
pub(crate) struct RegistrationLogger {
context: &'static WSLContext,
}
#[wsl_plugin_v1(
WSLVersionCapability::DistributionRegisteredHook
| WSLVersionCapability::DistributionUnregisteredHook
)]
impl WSLPluginV1 for RegistrationLogger {
fn try_new(context: &'static WSLContext) -> WinResult<Self> {
Ok(Self { context })
}
}Hooks introduced after the base API, such as distribution registration and unregistration notifications, are wired only when the host API version supports the corresponding capability. See the book's Version Capabilities chapter for the capability list and cross-references to command execution and plugin events.
Use ApiV1::new_command to build and execute a Linux command from a plugin session.
use wslplugins_rs::api::{ApiV1, WSLCommandExecution};
use wslplugins_rs::SessionID;
fn run_version(api: &ApiV1) -> Result<(), Box<dyn std::error::Error>> {
let stream = api
.new_command(SessionID::from(0), "/bin/cat")
.with_arg("/proc/version")
.execute()?;
drop(stream);
Ok(())
}Notes:
- Program paths must be Linux UTF-8 paths such as
/bin/echo argv[0]defaults to the program path and can be overridden withwith_arg0with_distribution_idtargets a specific user distribution and requires theExecuteBinaryInDistributioncapabilityexecute()returns aTcpStreamconnected to process stdin/stdout- stderr is forwarded to Linux
dmesg
Example plugins are included:
examples/minimal: a close Rust translation of Microsoft's sample pluginexamples/dist-info: a plugin focused on distribution metadata and tracingexamples/unpackaged-distro-blacklist-policy: a policy plugin that blocks unpackaged distributions
Build one of them in release mode:
cargo build --release -p minimalor:
cargo build --release -p dist-infoThe resulting plugin DLLs are produced in target\release\.
Sign the built DLL with the provided PowerShell script:
.\sign-plugin.ps1 -PluginPath .\target\release\minimal.dll -Trustor:
.\sign-plugin.ps1 -PluginPath .\target\release\dist_info.dll -TrustIf you do not want to install the certificate automatically, omit -Trust.
Microsoft's WSL plugin documentation also requires Windows test signing for test-signed plugin DLLs. If WSL rejects a locally signed plugin with TRUST_E_NOSIGNATURE, enable test signing on the test machine and reboot if required:
Bcdedit.exe -set TESTSIGNING ONRegister the signed DLL in the WSL plugins registry key:
reg.exe add "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Lxss\Plugins" /v minimal /d "C:\path\to\wslplugins-rs\target\release\minimal.dll" /t REG_SZAdjust the registry value name and DLL path for the plugin you want to load.
Restart the WSL service after registration, then run a WSL command to load the plugin:
Stop-Service -Name "wslservice" -Force
wsl.exe echo "test"After loading the plugin:
- inspect the log output produced by the example
- verify the DLL path in the registry
- confirm the DLL was signed successfully
The minimal example writes to C:\wsl-plugin-demo.txt.
The repository release workflow is centered on these commands:
cargo test --workspace --all-features
cargo clippy --workspace --all-targets --all-features
cargo fmt --all -- --check
cargo publish --workspace --dry-runContributions are welcome. See CONTRIBUTING.md for branch, validation, and pull request guidance.
Please report security issues privately. See SECURITY.md.
Licensed under either MIT or Apache-2.0.